alepha
Version:
Easy-to-use modern TypeScript framework for building many kind of applications.
1,263 lines • 57.4 kB
TypeScript
import { Alepha, Static, TSchema } from "alepha";
import { AlephaCliUtils, AppEntry, BuildCloudflareTask, PackageManagerUtils } from "alepha/cli";
import { Asker, EnvUtils, Runner, RunnerMethod } from "alepha/command";
import { ConsoleColorProvider } from "alepha/logger";
import { FileSystemProvider, ShellProvider } from "alepha/system";
import { DateTimeProvider } from "alepha/datetime";
//#region ../../src/cli/platform-lib/providers/PlatformCacheProvider.d.ts
interface PlatformCache {
[adapter: string]: {
lastLoginCheck: number;
accountId?: string;
};
}
/**
* Caches cloud provider login state to avoid slow auth checks.
*
* Stored in node_modules/.alepha/platform.json (gitignored, project-scoped).
* TTL: 4 hours.
*/
declare class PlatformCacheProvider {
protected static readonly TTL_MS: number;
protected readonly fs: FileSystemProvider;
protected readonly dateTime: DateTimeProvider;
protected cachePath(root: string): string;
isLoginFresh(root: string, adapter: string): Promise<boolean>;
getAccountId(root: string, adapter: string): Promise<string | undefined>;
recordLogin(root: string, adapter: string, accountId?: string): Promise<void>;
protected readCache(root: string): Promise<PlatformCache>;
protected writeCache(root: string, cache: PlatformCache): Promise<void>;
}
//#endregion
//#region ../../src/cli/platform-lib/schemas/cloudflare.d.ts
declare const cloudflareAccountSchema: import("zod").ZodObject<{
id: import("zod").ZodString;
name: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
type CloudflareAccount = Static<typeof cloudflareAccountSchema>;
declare const cloudflareD1Schema: import("zod").ZodObject<{
uuid: import("zod").ZodString;
name: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
type CloudflareD1 = Static<typeof cloudflareD1Schema>;
declare const cloudflareKVSchema: import("zod").ZodObject<{
id: import("zod").ZodString;
title: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
type CloudflareKV = Static<typeof cloudflareKVSchema>;
declare const cloudflareR2Schema: import("zod").ZodObject<{
name: import("zod").ZodString;
creation_date: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>;
type CloudflareR2 = Static<typeof cloudflareR2Schema>;
declare const cloudflareR2ListSchema: import("zod").ZodObject<{
buckets: import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
creation_date: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>>;
}, import("zod/v4/core").$strip>;
declare const cloudflareQueueSchema: import("zod").ZodObject<{
queue_id: import("zod").ZodString;
queue_name: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
type CloudflareQueue = Static<typeof cloudflareQueueSchema>;
declare const cloudflareQueueConsumerSchema: import("zod").ZodObject<{
consumer_id: import("zod").ZodString;
service: import("zod").ZodString;
environment: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>;
type CloudflareQueueConsumer = Static<typeof cloudflareQueueConsumerSchema>;
declare const cloudflareHyperdriveOriginSchema: import("zod").ZodObject<{
host: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
declare const cloudflareHyperdriveSchema: import("zod").ZodObject<{
id: import("zod").ZodString;
name: import("zod").ZodString;
origin: import("zod").ZodObject<{
host: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
}, import("zod/v4/core").$strip>;
type CloudflareHyperdrive = Static<typeof cloudflareHyperdriveSchema>;
declare const cloudflareWorkerSchema: import("zod").ZodObject<{
id: import("zod").ZodString;
created_on: import("zod").ZodString;
modified_on: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
type CloudflareWorker = Static<typeof cloudflareWorkerSchema>;
declare const cloudflareDeploymentVersionSchema: import("zod").ZodObject<{
version_id: import("zod").ZodString;
percentage: import("zod").ZodNumber;
}, import("zod/v4/core").$strip>;
declare const cloudflareDeploymentSchema: import("zod").ZodObject<{
id: import("zod").ZodString;
versions: import("zod").ZodArray<import("zod").ZodObject<{
version_id: import("zod").ZodString;
percentage: import("zod").ZodNumber;
}, import("zod/v4/core").$strip>>;
created_on: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
type CloudflareDeployment = Static<typeof cloudflareDeploymentSchema>;
declare const cloudflareDeploymentListSchema: import("zod").ZodObject<{
deployments: import("zod").ZodArray<import("zod").ZodObject<{
id: import("zod").ZodString;
versions: import("zod").ZodArray<import("zod").ZodObject<{
version_id: import("zod").ZodString;
percentage: import("zod").ZodNumber;
}, import("zod/v4/core").$strip>>;
created_on: import("zod").ZodString;
}, import("zod/v4/core").$strip>>;
}, import("zod/v4/core").$strip>;
declare const cloudflareVersionSchema: import("zod").ZodObject<{
id: import("zod").ZodString;
metadata: import("zod").ZodObject<{
created_on: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
annotations: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodString>>;
}, import("zod/v4/core").$strip>;
type CloudflareVersion = Static<typeof cloudflareVersionSchema>;
declare const cloudflareVersionListSchema: import("zod").ZodObject<{
items: import("zod").ZodArray<import("zod").ZodObject<{
id: import("zod").ZodString;
metadata: import("zod").ZodObject<{
created_on: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
annotations: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodString>>;
}, import("zod/v4/core").$strip>>;
}, import("zod/v4/core").$strip>;
declare const cloudflareSecretSchema: import("zod").ZodObject<{
name: import("zod").ZodString;
type: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
type CloudflareSecret = Static<typeof cloudflareSecretSchema>;
declare const createD1BodySchema: import("zod").ZodObject<{
name: import("zod").ZodString;
primary_location_hint: import("zod").ZodOptional<import("zod").ZodString>;
jurisdiction: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>;
declare const createKVBodySchema: import("zod").ZodObject<{
title: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
declare const createR2BodySchema: import("zod").ZodObject<{
name: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
declare const cloudflareR2TokenSchema: import("zod").ZodObject<{
id: import("zod").ZodString;
accessKeyId: import("zod").ZodString;
secretAccessKey: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
type CloudflareR2Token = Static<typeof cloudflareR2TokenSchema>;
declare const createR2TokenBodySchema: import("zod").ZodObject<{
name: import("zod").ZodString;
policies: import("zod").ZodArray<import("zod").ZodObject<{
effect: import("zod").ZodString;
permissions: import("zod").ZodArray<import("zod").ZodString>;
buckets: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
}, import("zod/v4/core").$strip>>;
}, import("zod/v4/core").$strip>;
declare const createQueueBodySchema: import("zod").ZodObject<{
queue_name: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
declare const createHyperdriveOriginSchema: import("zod").ZodObject<{
scheme: import("zod").ZodString;
host: import("zod").ZodString;
port: import("zod").ZodNumber;
database: import("zod").ZodString;
user: import("zod").ZodString;
password: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
declare const createHyperdriveBodySchema: import("zod").ZodObject<{
name: import("zod").ZodString;
origin: import("zod").ZodObject<{
scheme: import("zod").ZodString;
host: import("zod").ZodString;
port: import("zod").ZodNumber;
database: import("zod").ZodString;
user: import("zod").ZodString;
password: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
}, import("zod/v4/core").$strip>;
declare const putSecretBodySchema: import("zod").ZodObject<{
name: import("zod").ZodString;
text: import("zod").ZodString;
type: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
declare const cloudflareApiErrorSchema: import("zod").ZodObject<{
code: import("zod").ZodNumber;
message: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
type CloudflareApiError = Static<typeof cloudflareApiErrorSchema>;
//#endregion
//#region ../../src/cli/platform-lib/services/WranglerApi.d.ts
/**
* Wraps wrangler CLI commands that are kept as shell-outs.
*
* Only used for operations where wrangler provides value
* beyond a raw API call: OAuth login, worker deploy (bundling/upload),
* D1 migrations, and secret bulk push.
*/
declare class WranglerApi {
protected readonly log: import("alepha/logger").Logger;
protected readonly shell: ShellProvider;
protected readonly utils: AlephaCliUtils;
protected readonly pm: PackageManagerUtils;
protected runShell(command: string, options?: Parameters<ShellProvider["run"]>[1]): Promise<string>;
/**
* Ensure wrangler is installed in the project.
*/
ensureInstalled(root: string): Promise<void>;
/**
* Check if the user is authenticated. Returns the whoami output.
*/
whoami(): Promise<string>;
/**
* Open the browser-based OAuth login flow.
*/
login(): Promise<void>;
/**
* Get the current auth token from wrangler (auto-refreshes if expired).
*/
getAuthToken(): Promise<string>;
/**
* Deploy a worker via wrangler (handles bundling and upload).
*
* Returns the workers.dev URL if found in the output.
*/
deploy(workerName: string, configPath: string, root?: string): Promise<string | undefined>;
/**
* Apply D1 migrations remotely.
*/
d1MigrationsApply(dbName: string, configPath: string, root?: string): Promise<void>;
}
//#endregion
//#region ../../src/cli/platform-lib/services/CloudflareApi.d.ts
/**
* Thin wrapper over the Cloudflare REST API.
*
* Uses `wrangler auth token` to obtain credentials,
* then calls `fetch()` directly for all CRUD operations.
*/
declare class CloudflareApi {
protected static readonly BASE = "https://api.cloudflare.com/client/v4";
protected readonly log: import("alepha/logger").Logger;
protected readonly alepha: Alepha;
protected readonly wrangler: WranglerApi;
protected token?: string;
protected accountId?: string;
protected jurisdiction?: "eu" | "fedramp";
/**
* Set the Cloudflare data jurisdiction for R2 and D1 resources.
*
* R2 buckets and D1 databases created under a jurisdiction live in a
* separate namespace — every R2 API call (list/create/delete) must include
* the `cf-r2-jurisdiction` header, and D1 create must include the field
* in the request body. Omit / pass `undefined` for the default (global).
*/
setJurisdiction(jurisdiction?: "eu" | "fedramp"): void;
/**
* Override the Cloudflare account ID (from platform config).
*
* When unset, `resolveAccountId` falls back to `CLOUDFLARE_ACCOUNT_ID` env
* var or the token's single account.
*/
setAccountId(accountId?: string): void;
/**
* Obtain the current auth token from wrangler.
*/
resolveToken(): Promise<string>;
/**
* Resolve the Cloudflare account ID.
*
* Calls /accounts and picks the first one. Cached after first call.
*/
resolveAccountId(): Promise<string>;
listD1(): Promise<CloudflareD1[]>;
createD1(name: string, location?: string): Promise<CloudflareD1>;
deleteD1(databaseId: string): Promise<void>;
listKV(): Promise<CloudflareKV[]>;
createKV(title: string): Promise<CloudflareKV>;
deleteKV(namespaceId: string): Promise<void>;
listR2(): Promise<CloudflareR2[]>;
createR2(name: string): Promise<void>;
deleteR2(name: string): Promise<void>;
/**
* Mint a bucket-scoped R2 API token (S3 access key + secret) using the
* current bearer token. Used by teardown to wipe a bucket over the S3
* protocol without requiring users to pre-create R2 access keys.
*
* The returned token should be revoked with `deleteR2Token` as soon as the
* wipe is done.
*/
createR2Token(name: string, bucket: string): Promise<CloudflareR2Token>;
deleteR2Token(tokenId: string): Promise<void>;
listQueues(): Promise<CloudflareQueue[]>;
createQueue(name: string): Promise<CloudflareQueue>;
deleteQueue(queueId: string): Promise<void>;
listQueueConsumers(queueId: string): Promise<CloudflareQueueConsumer[]>;
deleteQueueConsumer(queueId: string, consumerService: string): Promise<void>;
listHyperdrive(): Promise<CloudflareHyperdrive[]>;
createHyperdrive(name: string, connectionString: string): Promise<CloudflareHyperdrive>;
deleteHyperdrive(configId: string): Promise<void>;
getWorker(scriptName: string): Promise<CloudflareWorker | undefined>;
deleteWorker(scriptName: string): Promise<void>;
listDeployments(scriptName: string): Promise<CloudflareDeployment[]>;
listVersions(scriptName: string): Promise<CloudflareVersion[]>;
listSecrets(scriptName: string): Promise<CloudflareSecret[]>;
putSecret(scriptName: string, name: string, value: string): Promise<void>;
/**
* Fetch the current worker bindings via the script-settings endpoint.
* Used to merge new secrets into the existing binding set in one PATCH
* (avoids the per-secret `putSecret` calls, each of which creates a
* Cloudflare deployment — pushing 7 secrets meant 7 deployment rows).
*
* Secret bindings come back with `name` + `type` but no `text` (they're
* write-only on Cloudflare's side); to preserve them across a PATCH we
* forward each one as `{ type, name }` and Cloudflare keeps the stored
* value.
*/
getWorkerSettings(scriptName: string): Promise<{
bindings: Array<{
type: string;
name: string;
text?: string;
}>;
}>;
/**
* Replace the worker's binding set in one call (= one Cloudflare
* deployment, regardless of how many secrets are being updated).
*
* The endpoint expects multipart FormData with a `settings` field whose
* value is a JSON-encoded `{ bindings: [...] }` — the `fetch` helper
* above is JSON-only, so this one bypasses it and calls `globalThis.fetch`
* directly. Mirrors what `wrangler secret bulk` does internally.
*/
patchWorkerBindings(scriptName: string, bindings: Array<{
type: string;
name: string;
text?: string;
}>): Promise<void>;
protected fetch<T = unknown>(path: string, options?: {
method?: string;
body?: unknown;
bodySchema?: TSchema;
schema?: TSchema;
query?: Record<string, string>;
}): Promise<T>;
/**
* Paginate a page-based list endpoint (`result_info.total_pages`).
*
* Cloudflare defaults to `per_page=20`; we push it to 1000 (max on most
* list endpoints) and loop if more pages exist. Each page is validated
* against the item schema.
*/
protected paginate<T>(path: string, itemSchema: TSchema, perPage?: number): Promise<T[]>;
/**
* Paginate a cursor-based list endpoint where `result` is an object
* containing both the items array and a `cursor` field (R2 buckets,
* Workers versions). Returns the flattened item array.
*/
protected paginateCursor<T>(path: string, itemsKey: string, itemSchema: TSchema, perPage?: number): Promise<T[]>;
/**
* Parse a postgres:// connection string into Hyperdrive origin fields.
*/
protected parseConnectionString(connectionString: string): {
scheme: string;
host: string;
port: number;
database: string;
user: string;
password: string;
};
}
//#endregion
//#region ../../src/cli/platform-lib/atoms/platformOptions.d.ts
/**
* Platform deployment configuration atom.
*
* Filled from the `platform` section of `alepha.config.ts`.
* Read by `PlatformCommand` to resolve environments and adapters.
*/
declare const platformOptions: import("alepha").Atom<import("zod").ZodOptional<import("zod").ZodObject<{
name: import("zod").ZodOptional<import("zod").ZodString>;
default: import("zod").ZodOptional<import("zod").ZodString>;
tenancy: import("zod").ZodOptional<import("zod").ZodEnum<{
none: "none";
optional: "optional";
required: "required";
}>>;
secrets: import("zod").ZodOptional<import("zod").ZodObject<{
keys: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
store: import("zod").ZodOptional<import("zod").ZodEnum<{
github: "github";
}>>;
environmentPattern: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>>;
environments: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodObject<{
adapter: import("zod").ZodEnum<{
cloudflare: "cloudflare";
vercel: "vercel";
}>;
domain: import("zod").ZodOptional<import("zod").ZodString>;
zone: import("zod").ZodOptional<import("zod").ZodString>;
services: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
binding: import("zod").ZodString;
service: import("zod").ZodString;
}, import("zod/v4/core").$strip>>>;
jurisdiction: import("zod").ZodOptional<import("zod").ZodEnum<{
eu: "eu";
fedramp: "fedramp";
}>>;
accountId: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>>;
}, import("zod/v4/core").$strip>>, "alepha.cli.platform.options">;
/**
* Type for platform options.
*/
type PlatformOptions = Static<typeof platformOptions.schema>;
/**
* Configuration for a single named environment.
*/
interface EnvironmentConfig {
adapter: "cloudflare" | "vercel";
domain?: string;
zone?: string;
vars?: Record<string, string>;
jurisdiction?: "eu" | "fedramp";
accountId?: string;
services?: Array<{
binding: string;
service: string;
}>;
}
//#endregion
//#region ../../src/cli/platform-lib/services/NamingService.d.ts
/**
* Multi-tenancy mode for an app's deployments.
*
* - `none` (default): single-instance app. Passing `--tenant` is an
* error — guards a non-tenanted app (e.g. the SaaS console) from
* accidentally getting a tenant prefix.
* - `required`: every deploy targets a tenant. Omitting `--tenant` is an
* error — kills the "forgot the flag → deployed to the apex" footgun.
* - `optional`: both work — a base instance (no `--tenant`) and per-tenant
* instances coexist (distinct names + hosts).
*/
type Tenancy = "none" | "optional" | "required";
/**
* Validate a `--tenant` value against the app's declared `tenancy` and
* return the effective tenant (or `undefined` for a base/non-tenanted
* deploy). Throws on any matrix violation so a misconfigured deploy fails
* fast instead of landing on the wrong resource names / host.
*/
declare function resolveTenant(tenancy: Tenancy | undefined, tenant: string | undefined): string | undefined;
/**
* Resolve the host a deploy is served on.
*
* - `override` (V2 custom domains, e.g. `reservation.club-b14.fr`) wins
* outright when supplied — not wired to a flag today, but the single
* seam a future `--domain` / Rocket `config.hostname` plugs into.
* - else a tenant becomes the leftmost DNS label: `b14` + `alepha.club`
* → `b14.alepha.club`.
* - else the base domain is used as-is.
*/
declare function tenantDomain(base: string | undefined, tenant: string | undefined, override?: string): string | undefined;
/**
* Generates deterministic resource names for cloud deployments.
*
* Pattern: `<tenant>-<project>-<env>` (tenant segment omitted when the
* deploy isn't tenanted).
*
* All segments are slugified (lowercase, alphanumeric + dashes, max 63
* chars). One app per workspace — see `alepha platform`.
*/
declare class NamingService {
forContext(project: string, env: string, tenant?: string): NamingContext;
slugify(name: string): string;
}
declare class NamingContext {
protected readonly prefix: string;
constructor(prefix: string);
worker(): string;
d1(): string;
hyperdrive(): string;
r2(): string;
kv(): string;
queue(): string;
}
//#endregion
//#region ../../src/cli/platform-lib/adapters/PlatformAdapter.d.ts
/**
* Options for {@link PlatformAdapter.exportDb}.
*/
interface ExportDbOptions {
/**
* Destination file for the local snapshot. Adapter-specific default —
* Cloudflare/D1 writes the dev SQLite at
* `node_modules/.alepha/sqlite.db`.
*/
output?: string;
/**
* Keep the intermediate `.sql` dump instead of deleting it after import.
*/
keepSql?: boolean;
}
interface DetectedResources {
hasDatabase: boolean;
hasBucket: boolean;
hasKV: boolean;
hasQueue: boolean;
hasCron: boolean;
}
/**
* One workspace = one app. Used to be a per-app definition in a
* monorepo-aware orchestrator; flattened into `PlatformContext` after
* the `apps:` field was removed from platform options.
*/
interface PlatformContext {
/**
* Slugified project name (from package.json or platform config).
*/
project: string;
/**
* Environment key (e.g., "production", "staging", "tmp-bug001").
*/
env: string;
/**
* Environment configuration from alepha.config.ts.
*/
envConfig: EnvironmentConfig;
/**
* Workspace root path.
*/
root: string;
/**
* Resolved entry points for the workspace. Stub (`{ root, server: "" }`)
* in pre-built / manifest mode since no source booting happens.
*/
entry: AppEntry;
/**
* Cloud resources the workspace uses — discovered at build time, read
* from `dist/manifest.json` at deploy time.
*/
resources: DetectedResources;
/**
* Resource name generator bound to this project+env(+tenant).
*/
naming: NamingContext;
/**
* Active tenant slug for this deploy (apps with `tenancy: optional |
* required`), or `undefined` for a base / non-tenanted deploy. Shapes
* the served host (`<tenant>.<domain>`); resource names already fold it
* in via {@link naming}.
*/
tenant?: string;
/**
* Pre-built mode. When true, the adapter's `build()` should skip the
* Vite bundle steps and only regenerate the deploy config
* (wrangler.jsonc, Dockerfile, etc.) so it reflects current bindings +
* per-tenant overrides.
*/
prebuilt?: boolean;
}
/**
* @deprecated Same as `PlatformContext` since the `apps:` collapse —
* kept as a type alias so existing adapter signatures still compile.
*/
type AppContext = PlatformContext;
interface ResourceState {
name: string;
exists: boolean;
id?: string;
detail?: string;
}
interface WorkerState extends ResourceState {
version?: string;
tag?: string;
createdAt?: string;
}
interface SecretState {
name: string;
deployed: boolean;
}
interface PlatformState {
workers: WorkerState[];
databases: ResourceState[];
buckets: ResourceState[];
kvNamespaces: ResourceState[];
queues: ResourceState[];
secrets: SecretState[];
}
/**
* Abstract platform adapter.
*
* Each cloud provider (Cloudflare, AKS, docker-compose) implements this.
* The PlatformOrchestrator calls these methods in the correct order.
*/
declare abstract class PlatformAdapter {
/**
* Ensure the user is authenticated with the cloud provider.
* May use cached credentials to avoid slow checks.
*/
abstract authenticate(ctx: PlatformContext, run: RunnerMethod): Promise<void>;
/**
* Build artifacts for a single app.
*/
abstract build(ctx: AppContext, run: RunnerMethod): Promise<void>;
/**
* Deploy a single app (upload + activate atomically, e.g., wrangler deploy).
* Returns the live URL if the platform provides one.
*/
abstract deploy(ctx: AppContext, run: RunnerMethod): Promise<string | undefined>;
/**
* Create/ensure cloud resources exist (DB, buckets, queues).
* Not all adapters provision -- AKS defers to Helm.
*/
provision(_ctx: PlatformContext, _run: RunnerMethod): Promise<void>;
/**
* Run database migrations.
*/
migrate(_ctx: PlatformContext, _run: RunnerMethod): Promise<void>;
/**
* Export the deployed database to a local file — the remote → local dev
* snapshot workflow. Adapter/dialect specific; the default refuses.
*/
exportDb(_ctx: PlatformContext, _run: RunnerMethod, _options?: ExportDbOptions): Promise<void>;
/**
* Push runtime secrets to the deployed worker(s).
*
* Reads secrets from `.env.{env}` files (parsed, not from process.env),
* filters out vars already handled by bindings (DATABASE_URL, R2, etc.),
* and pushes the rest via the platform's secret management.
*/
secrets(_ctx: PlatformContext, _run: RunnerMethod): Promise<void>;
/**
* Detect existing resources and their state.
* Used by `plan` and `status` commands.
*/
abstract inspect(ctx: PlatformContext, run: RunnerMethod): Promise<PlatformState>;
/**
* Tear down all resources for an environment.
*/
abstract teardown(ctx: PlatformContext, run: RunnerMethod): Promise<void>;
}
//#endregion
//#region ../../src/cli/platform-lib/adapters/CloudflareAdapter.d.ts
/**
* Cloudflare Workers adapter.
*
* Uses the Cloudflare REST API (via CloudflareApi) for resource provisioning
* and teardown, and wrangler CLI (via WranglerApi) for login, deploy,
* D1 migrations, and secret bulk push.
*/
declare class CloudflareAdapter extends PlatformAdapter {
protected readonly log: import("alepha/logger").Logger;
protected readonly fs: FileSystemProvider;
protected readonly shell: ShellProvider;
protected readonly cache: PlatformCacheProvider;
protected readonly alepha: Alepha;
protected readonly envUtils: EnvUtils;
protected readonly api: CloudflareApi;
protected readonly wrangler: WranglerApi;
protected readonly runner: Runner;
protected readonly buildTask: BuildCloudflareTask;
protected readonly options: Readonly<{
name?: string | undefined;
default?: string | undefined;
tenancy?: "none" | "optional" | "required" | undefined;
secrets?: {
keys?: string[] | undefined;
store?: "github" | undefined;
environmentPattern?: string | undefined;
} | undefined;
environments: Record<string, {
adapter: "cloudflare" | "vercel";
domain?: string | undefined;
zone?: string | undefined;
services?: {
binding: string;
service: string;
}[] | undefined;
jurisdiction?: "eu" | "fedramp" | undefined;
accountId?: string | undefined;
}>;
} | undefined>;
protected provisionedD1Id?: string;
protected provisionedHyperdriveId?: string;
protected provisionedKVIds: Map<string, string>;
/**
* Check if the user's DATABASE_URL points to an external Postgres database.
* If so, we use Hyperdrive instead of D1.
*
* Reads from `.env.{env}` first, falls back to `process.env`.
*/
protected isPostgres(ctx: PlatformContext): Promise<boolean>;
/**
* Propagate the environment's data-jurisdiction setting to the API client.
*
* Must be invoked at the top of every entry point (authenticate, build,
* deploy, secrets, provision, migrate, inspect, teardown) because
* CloudflareApi is a singleton reused across env invocations.
*/
protected configureApi(ctx: PlatformContext): void;
protected runShell(command: string, options?: Parameters<ShellProvider["run"]>[1]): Promise<string>;
authenticate(ctx: PlatformContext, run: RunnerMethod): Promise<void>;
build(ctx: AppContext, run: RunnerMethod): Promise<void>;
/**
* Library-embed of `alepha build -t cloudflare --prebuilt`. Loads the
* pre-built `dist/manifest.json`, sets the per-tenant env vars on
* `process.env` for the duration of the call (the task's enhance*
* methods read them directly), then runs `BuildCloudflareTask`
* against a synthetic context.
*
* `ctx.alepha` is intentionally null — in manifest mode the task
* reads resources/crons/containers from `ctx.manifest` and never
* dereferences `ctx.alepha`. Same for `entry` and `hasClient`:
* prebuilt mode skips the bundle tasks; only the wrangler.jsonc /
* worker-entrypoint emission runs.
*/
protected runBuildInProcess(root: string, env: Record<string, string>): Promise<void>;
deploy(ctx: AppContext, run: RunnerMethod): Promise<string | undefined>;
/**
* Vars that are handled by wrangler bindings or build config.
* These should not be pushed as secrets.
*/
static readonly EXCLUDED_SECRET_KEYS: Set<string>;
/**
* Read the build manifest's `env` list (every key the app declares via
* `$env`) from `dist/manifest.json`. Used as the default worker-secret
* allowlist. Returns `undefined` when the manifest is absent or predates
* the `env` field, so the caller falls back to the `.env` file keys.
*/
protected readManifestEnvKeys(root: string): Promise<string[] | undefined>;
secrets(ctx: PlatformContext, run: RunnerMethod): Promise<void>;
/**
* Public base URL for this deploy, derived from the configured domain
* (honoring tenant subdomains). Returns undefined when no domain is set or
* the host is a wildcard — there's no single resolvable origin to point at.
*/
protected publicUrl(ctx: PlatformContext): string | undefined;
/**
* Plain-text binding used to fingerprint the deployed secret set so the
* next `up` can skip the PATCH when nothing has changed.
*/
static readonly SECRETS_HASH_BINDING = "ALEPHA_SECRETS_HASH";
provision(ctx: PlatformContext, run: RunnerMethod): Promise<void>;
migrate(ctx: PlatformContext, run: RunnerMethod): Promise<void>;
exportDb(ctx: PlatformContext, run: RunnerMethod, options?: ExportDbOptions): Promise<void>;
protected migrateD1(ctx: PlatformContext, run: RunnerMethod): Promise<void>;
protected migratePostgres(ctx: PlatformContext, run: RunnerMethod): Promise<void>;
inspect(ctx: PlatformContext, run: RunnerMethod): Promise<PlatformState>;
teardown(ctx: PlatformContext, run: RunnerMethod): Promise<void>;
protected ensureD1(name: string): Promise<string>;
protected ensureHyperdrive(name: string, connectionString: string): Promise<string>;
protected ensureR2(name: string): Promise<void>;
/** Whether a Cloudflare error message indicates the bucket is already gone. */
protected isMissingBucketError(msg: string): boolean;
/**
* Resolve S3 credentials for wiping an R2 bucket over the S3 protocol.
*
* Prefers the account's R2 S3 credentials from the environment
* (`S3_ACCESS_KEY_ID` / `S3_SECRET_ACCESS_KEY`) — these are already
* provisioned for the deploy (artifact registry) and are account-scoped,
* so they can empty any bucket without minting anything. Returns `null`
* when not configured, letting the caller fall back to token minting.
*/
protected resolveR2Credentials(): {
accessKeyId: string;
secretAccessKey: string;
} | null;
/**
* Delete an R2 bucket, emptying it first only when necessary.
*
* Cloudflare's REST `DELETE /r2/buckets/:name` succeeds on an empty bucket
* but rejects a non-empty one. So we attempt the delete directly (the
* common teardown case — no objects, no creds needed), and only on failure
* empty the bucket over the S3 protocol and retry. A missing bucket is a
* no-op, so teardown is idempotent.
*/
protected deleteR2Bucket(name: string, ctx: PlatformContext): Promise<void>;
/**
* Empty an R2 bucket via the S3-compatible API.
*
* Cloudflare's REST API has no object-level endpoints — objects must be
* listed and deleted over the S3 protocol. We use the account's R2 S3
* credentials (`S3_ACCESS_KEY_ID` / `S3_SECRET_ACCESS_KEY`) when present;
* otherwise we fall back to minting a short-lived bucket-scoped token via
* the CF API (requires a user-scoped `CLOUDFLARE_API_TOKEN`) and revoke it
* after. When neither is available the wipe is skipped with a warning —
* the caller still attempts the delete, which succeeds for empty buckets.
*
* Also aborts any pending multipart uploads — those count as bucket
* contents from R2's perspective and would otherwise block the delete.
*/
protected wipeR2Bucket(bucketName: string, ctx: PlatformContext): Promise<void>;
protected ensureKV(name: string): Promise<string>;
protected ensureQueue(name: string): Promise<void>;
/**
* Get the currently active deployment for a worker.
*/
protected getActiveDeployment(workerName: string): Promise<{
versionId: string;
tag?: string;
createdAt?: string;
} | undefined>;
}
//#endregion
//#region ../../src/cli/platform-lib/schemas/vercel.d.ts
declare const vercelProjectSchema: import("zod").ZodObject<{
id: import("zod").ZodString;
name: import("zod").ZodString;
accountId: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
type VercelProject = Static<typeof vercelProjectSchema>;
declare const createProjectBodySchema: import("zod").ZodObject<{
name: import("zod").ZodString;
framework: import("zod").ZodOptional<import("zod").ZodNull>;
}, import("zod/v4/core").$strip>;
declare const vercelDeploymentSchema: import("zod").ZodObject<{
uid: import("zod").ZodString;
name: import("zod").ZodString;
url: import("zod").ZodString;
state: import("zod").ZodOptional<import("zod").ZodString>;
readyState: import("zod").ZodOptional<import("zod").ZodString>;
created: import("zod").ZodOptional<import("zod").ZodNumber>;
target: import("zod").ZodOptional<import("zod").ZodString>;
alias: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
}, import("zod/v4/core").$strip>;
type VercelDeployment = Static<typeof vercelDeploymentSchema>;
declare const vercelEnvVarSchema: import("zod").ZodObject<{
id: import("zod").ZodString;
key: import("zod").ZodString;
value: import("zod").ZodOptional<import("zod").ZodString>;
type: import("zod").ZodString;
target: import("zod").ZodArray<import("zod").ZodString>;
}, import("zod/v4/core").$strip>;
type VercelEnvVar = Static<typeof vercelEnvVarSchema>;
declare const createEnvVarBodySchema: import("zod").ZodObject<{
key: import("zod").ZodString;
value: import("zod").ZodString;
type: import("zod").ZodString;
target: import("zod").ZodArray<import("zod").ZodString>;
}, import("zod/v4/core").$strip>;
//#endregion
//#region ../../src/cli/platform-lib/services/VercelCli.d.ts
/**
* Wraps Vercel CLI commands and token management.
*
* Used for operations where the Vercel CLI provides value:
* OAuth login, prebuilt deploy, and auth token extraction.
*/
declare class VercelCli {
protected readonly log: import("alepha/logger").Logger;
protected readonly shell: ShellProvider;
protected readonly fs: FileSystemProvider;
protected readonly utils: AlephaCliUtils;
protected readonly pm: PackageManagerUtils;
protected runShell(command: string, options?: Parameters<ShellProvider["run"]>[1]): Promise<string>;
/**
* Ensure vercel CLI is installed in the project.
*/
ensureInstalled(root: string): Promise<void>;
/**
* Get the Vercel auth token.
*
* Priority:
* 1. VERCEL_TOKEN environment variable (CI/CD)
* 2. Vercel CLI auth.json file (local dev)
*/
getAuthToken(): Promise<string>;
/**
* Validate the current auth token.
*/
whoami(): Promise<string>;
/**
* Open the browser-based login flow.
*/
login(): Promise<void>;
/**
* Deploy a prebuilt .vercel/output/ directory.
*
* Returns the deployment URL.
*/
deploy(distDir: string, options: {
prod?: boolean;
token?: string;
}): Promise<string | undefined>;
/**
* Resolve the path to Vercel CLI auth.json.
*/
protected getAuthFilePath(): string;
}
//#endregion
//#region ../../src/cli/platform-lib/services/VercelApi.d.ts
/**
* Thin wrapper over the Vercel REST API.
*
* Uses the auth token from VercelCli for all requests.
*/
declare class VercelApi {
protected static readonly BASE = "https://api.vercel.com";
protected readonly log: import("alepha/logger").Logger;
protected readonly alepha: Alepha;
protected readonly vercelCli: VercelCli;
protected token?: string;
/**
* Obtain the current auth token from the Vercel CLI.
*/
resolveToken(): Promise<string>;
listProjects(): Promise<VercelProject[]>;
getProject(nameOrId: string): Promise<VercelProject | undefined>;
createProject(name: string): Promise<VercelProject>;
updateProject(nameOrId: string, settings: {
framework?: null;
}): Promise<void>;
deleteProject(nameOrId: string): Promise<void>;
listDeployments(projectId: string, options?: {
limit?: number;
target?: string;
}): Promise<VercelDeployment[]>;
listEnvVars(projectId: string): Promise<VercelEnvVar[]>;
upsertEnvVars(projectId: string, vars: Array<{
key: string;
value: string;
target: string[];
}>): Promise<void>;
deleteEnvVar(projectId: string, envVarId: string): Promise<void>;
protected fetch<T = unknown>(path: string, options?: {
method?: string;
body?: unknown;
bodySchema?: TSchema;
schema?: TSchema;
query?: Record<string, string>;
}): Promise<T>;
}
//#endregion
//#region ../../src/cli/platform-lib/adapters/VercelAdapter.d.ts
/**
* Vercel platform adapter.
*
* Uses the Vercel CLI for login and deploy (--prebuilt),
* and the Vercel REST API for project management, env vars, and inspection.
*
* v1 scope: deploy pipeline only. No DB/storage/KV provisioning.
*/
declare class VercelAdapter extends PlatformAdapter {
protected readonly log: import("alepha/logger").Logger;
protected readonly fs: FileSystemProvider;
protected readonly shell: ShellProvider;
protected readonly utils: AlephaCliUtils;
protected readonly cache: PlatformCacheProvider;
protected readonly alepha: Alepha;
protected readonly envUtils: EnvUtils;
protected readonly api: VercelApi;
protected readonly vercelCli: VercelCli;
/**
* Vars that should not be pushed as env vars.
* These are either handled by the build or are internal.
*/
static readonly EXCLUDED_SECRET_KEYS: Set<string>;
protected runShell(command: string, options?: Parameters<ShellProvider["run"]>[1]): Promise<string>;
authenticate(ctx: PlatformContext, run: RunnerMethod): Promise<void>;
build(ctx: AppContext, run: RunnerMethod): Promise<void>;
deploy(ctx: AppContext, run: RunnerMethod): Promise<string | undefined>;
secrets(ctx: PlatformContext, run: RunnerMethod): Promise<void>;
inspect(ctx: PlatformContext, run: RunnerMethod): Promise<PlatformState>;
teardown(ctx: PlatformContext, run: RunnerMethod): Promise<void>;
}
//#endregion
//#region ../../src/cli/platform-lib/providers/SecretStoreProvider.d.ts
/**
* A secret stored in a remote secret store.
*/
interface RemoteSecret {
name: string;
updatedAt?: string;
}
/**
* Abstract provider for managing secrets in an external store.
*
* Implementations: GitHubSecretStore, MemorySecretStore
*/
declare abstract class SecretStoreProvider {
/**
* Verify the backing store is reachable and authenticated.
*/
abstract ensureAvailable(): Promise<void>;
/**
* Ensure the target environment exists in the store, creating it if needed.
*/
abstract ensureEnvironment(environment: string): Promise<void>;
/**
* List all secrets in a given environment.
*/
abstract list(environment: string): Promise<RemoteSecret[]>;
/**
* Set (create or update) a secret in a given environment.
*/
abstract set(environment: string, key: string, value: string): Promise<void>;
/**
* Delete a secret from a given environment.
*/
abstract delete(environment: string, key: string): Promise<void>;
}
//#endregion
//#region ../../src/cli/platform-lib/providers/GitHubSecretStore.d.ts
/**
* GitHub Actions secret store backed by the `gh` CLI.
*
* Requires the GitHub CLI (`gh`) to be installed and authenticated.
* Pushes secrets into GitHub Actions environments.
*/
declare class GitHubSecretStore implements SecretStoreProvider {
protected readonly log: import("alepha/logger").Logger;
protected readonly shell: ShellProvider;
protected readonly fs: FileSystemProvider;
/**
* Verify that `gh` is installed and authenticated.
*/
ensureAvailable(): Promise<void>;
/**
* Create the GitHub Actions environment if it doesn't exist.
*/
ensureEnvironment(environment: string): Promise<void>;
/**
* List all secrets in a GitHub Actions environment.
*/
list(environment: string): Promise<RemoteSecret[]>;
/**
* Set a secret in a GitHub Actions environment.
*
* Writes a dotenv-formatted file and uses `gh secret set --env-file` to
* avoid shell pipe issues with NodeShellProvider escaping the `|` character.
*/
set(environment: string, key: string, value: string): Promise<void>;
/**
* Delete a secret from a GitHub Actions environment.
*/
delete(environment: string, key: string): Promise<void>;
}
//#endregion
//#region ../../src/cli/platform-lib/providers/MemorySecretStore.d.ts
interface MemorySecretStoreCall {
method: "ensureAvailable" | "ensureEnvironment" | "list" | "set" | "delete";
environment?: string;
key?: string;
value?: string;
}
/**
* In-memory implementation of SecretStoreProvider for testing.
* Records all operations and stores secrets in a nested Map.
*/
declare class MemorySecretStore implements SecretStoreProvider {
/**
* Secrets keyed by environment, then by key.
*/
secrets: Map<string, Map<string, string>>;
/**
* All recorded operations.
*/
calls: MemorySecretStoreCall[];
/**
* When set, ensureAvailable() will throw with this message.
*/
availableError: string | null;
ensureAvailable(): Promise<void>;
ensureEnvironment(environment: string): Promise<void>;
list(environment: string): Promise<RemoteSecret[]>;
set(environment: string, key: string, value: string): Promise<void>;
delete(environment: string, key: string): Promise<void>;
/**
* Check if set() was called for a given environment and key.
*/
wasSet(environment: string, key: string): boolean;
/**
* Check if delete() was called for a given environment and key.
*/
wasDeleted(environment: string, key: string): boolean;
/**
* Get all set() calls for a given environment.
*/
getSetCalls(environment: string): Array<{
key: string;
value: string;
}>;
/**
* Reset all state.
*/
reset(): void;
}
//#endregion
//#region ../../src/cli/platform-lib/schemas/platform.d.ts
declare const platformStatusWorkerSchema: import("zod").ZodObject<{
name: import("zod").ZodString;
exists: import("zod").ZodBoolean;
id: import("zod").ZodOptional<import("zod").ZodString>;
detail: import("zod").ZodOptional<import("zod").ZodString>;
version: import("zod").ZodOptional<import("zod").ZodString>;
tag: import("zod").ZodOptional<import("zod").ZodString>;
createdAt: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>;
declare const platformStatusResourceSchema: import("zod").ZodObject<{
name: import("zod").ZodString;
exists: import("zod").ZodBoolean;
id: import("zod").ZodOptional<import("zod").ZodString>;
detail: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>;
declare const platformStatusSecretSchema: import("zod").ZodObject<{
name: import("zod").ZodString;
deployed: import("zod").ZodBoolean;
}, import("zod/v4/core").$strip>;
declare const platformStatusSchema: import("zod").ZodObject<{
project: import("zod").ZodString;
env: import("zod").ZodString;
adapter: import("zod").ZodString;
workers: import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
exists: import("zod").ZodBoolean;
id: import("zod").ZodOptional<import("zod").ZodString>;
detail: import("zod").ZodOptional<import("zod").ZodString>;
version: import("zod").ZodOptional<import("zod").ZodString>;
tag: import("zod").ZodOptional<import("zod").ZodString>;
createdAt: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>>;
databases: import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
exists: import("zod").ZodBoolean;
id: import("zod").ZodOptional<import("zod").ZodString>;
detail: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>>;
buckets: import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
exists: import("zod").ZodBoolean;
id: import("zod").ZodOptional<import("zod").ZodString>;
detail: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>>;
kvNamespaces: import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
exists: import("zod").ZodBoolean;
id: import("zod").ZodOptional<import("zod").ZodString>;
detail: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>>;
queues: import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
exists: import("zod").ZodBoolean;
id: import("zod").ZodOptional<import("zod").ZodString>;
detail: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>>;
secrets: import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
deployed: import("zod").ZodBoolean;
}, import("zod/v4/core").$strip>>;
}, import("zod/v4/core").$strip>;
type PlatformStatusOutput = Static<typeof platformStatusSchema>;
declare const platformPlanAppResourcesSchema: import("zod").ZodObject<{
hasDatabase: import("zod").ZodBoolean;
hasBucket: import("zod").ZodBoolean;
hasKV: import("zod").ZodBoolean;
hasQueue: import("zod").ZodBoolean;
hasCron: import("zod").ZodBoolean;
}, import("zod/v4/core").$strip>;
declare const platformPlanAppSchema: import("zod").ZodObject<{
name: import("zod").ZodString;
path: import("zod").ZodString;
resources: import("zod").ZodObject<{
hasDatabase: import("zod").ZodBoolean;
hasBucket: import("zod").ZodBoolean;
hasKV: import("zod").ZodBoolean;
hasQueue: import("zod").ZodBoolean;
hasCron: import("zod").ZodBoolean;
}, import("zod/v4/core").$strip>;
}, import("zod/v4/core").$strip>;
declare const platformPlanEnvironmentSchema: import("zod").ZodObject<{
adapter: import("zod").ZodString;
domain: import("zod").ZodOptional<import("zod").ZodString>;
zone: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>;
declare const platformPlanResourceSchema: import("zod").ZodObject<{
label: import("zod").ZodString;
value: import("zod").ZodString;
}, import("zod/v4/core").$strip>;
declare const platformPlanSchema: import("zod").ZodObject<{
project: import("zod").ZodString;
env: import("zod").ZodString;
mode: import("zod").ZodEnum<{
monorepo: "monorepo";
standalone: "standalone";
}>;
apps: import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
path: import("zod").ZodString;
resources: import("zod").ZodObject<{
hasDatabase: import("zod").ZodBoolean;
hasBucket: import("zod").ZodBoolean;
hasKV: import("zod").ZodBoolean;
hasQueue: import("zod").ZodBoolean;
hasCron: import("zod").ZodBoolean;
}, import("zod/v4/core").$strip>;
}, import("zod/v4/core").$strip>>;
environments: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodObject<{
adapter: import("zod").ZodString;
domain: import("zod").ZodOptional<import("zod").ZodString>;
zone: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>>;
resources: import("zod").ZodArray<import("zod").ZodObject<{
label: import("zod").ZodString;
value: import("zod").ZodString;
}, import("zod/v4/core").$strip>>;
secretCount: import("zod").ZodNumber;
}, import("zod/v4/core").$strip>;
type PlatformPlanOutput = Static<typeof platformPlanSchema>;
//#endregion
//#region ../../src/cli/platform-lib/services/PlatformInspector.d.ts
interface ResolvedPlatformConfig {
project: string;
defaultEnv: string;
/** App tenancy mode (undefined ⇒ "none"). */
tenancy?: Tenancy;
environments: Record<string, EnvironmentConfig>;
}
/**
* Reads platform config and resolves project topology.
*
* Validates project name and environment configuration. Does NOT
* introspect app code for resources — that happens at deploy time via
* ViteBuildProvider.
*
* Each app self-declares its platform topology via its own
* `alepha.config.ts`. Run `alepha platform <op>` from the app's
* directory; no monorepo-root orchestration here.
*/
declare class PlatformInspector {
protected readonly log: import("alepha/logger").Logger;
protected readonly alepha: Alepha;
protected readonly fs: FileSystemProvider;
protected readonly asker: Asker;
protected readonly options: Readonly<{
name?: string | undefined;
default?: string | undefined;
tenancy?: "none" | "optional" | "required" | undefined;
secrets?: {
keys?: string[] | undefined;
store?: "github" | undefined;
environmentPattern?: string | undefined;
} | undefined;
environments: Record<string, {
adapter: "cloudflare" | "vercel";
domain?: string | undefined;
zone?: string | undefined;
services?: {
binding: string;
service: string;
}[] | undefined;
jurisdiction?: "eu" | "fedramp" | undefined;
accountId?: string | undefined;
}>;
} | undefined>;
protected readonly naming: NamingService;
/**
* Resolve and validate the full platform configuration.
*
* Source priority:
* 1. `platformOptions` atom (set by `alepha.config.ts` during the
* configure hook) — local dev / from-source deploys.
* 2. `dist/manifest.json` (written by `alepha build`) — pre-built
* deploys via Alepha Rocket or any `--prebuilt` c