/** * The deployment-adapter contract. * * A deployment target = one npm package implementing `DomainAdapter`. * The adapter is GENERIC over its own `Params` so envs AND provider settings * stay 100% adapter-specific (a Cloudflare adapter's `{ route, secrets }` is * nothing like a Node adapter's `{ port }`). The CLI resolves * `envs[] → Params` via `adapter.params(env)` and then drives the adapter * with the resolved params — install of the resulting URL and the `requires` * check are generic and live in the CLI, never in the adapter. * * The central guarantee: `watch()` and `deploy()` both return a `url` — that's * what the CLI prints, what `astrale domain install ` consumes, and * the worker's `iss` identity. The URL is an OUTPUT of watch/deploy; nothing * in the contract asks an adapter to predict it ahead of time. */ /** * Generic, target-independent domain metadata the CLI hands every adapter so * it can codegen the worker entry. (Extends the bare `WatchCtx`/`DeployCtx` of * the spec with the fields a real codegen needs.) */ export interface DomainInfo { /** * The domain's addressing name — the graph slug it mounts under (e.g. * `'crm.acme.dev'`). NOT the cryptographic identity: the JWT `iss` is the * worker's serving URL, pinned by the kernel at install time. */ origin: string; /** Cross-domain deps by origin — verified at install (CLI/kernel), not here. */ requires: readonly string[]; /** Optional Astrale Path called by the kernel after install (as __SYSTEM__). */ postInstall?: string; /** * Whether the domain declares Views / standalone Functions — read from the * `defineDomain` definition, NOT probed from the filesystem. The adapter * codegen imports the corresponding module only when true. */ hasViews: boolean; hasFunctions: boolean; /** * Views whose binding is backed by a worker-relative SPA mount. This is domain * contract metadata (`defineView({ mount })`), not a frontend source folder: * adapters decide, per env, which client assets serve these mounts. */ mountedViews: Array<{ slug: string; mount: string; }>; /** * Whether the domain declares a `deps` mapper (`defineDomain({ deps })`). * When true the adapter codegen imports it from the domain's fixed `deps` * module and passes it to the worker entry; when false the worker passes the * raw env straight through as `ctx.deps`. Read from the definition, never * probed from the filesystem. */ hasDeps: boolean; } export interface WatchCtx { /** Absolute path to the domain project root. */ projectDir: string; /** Absolute path where the CLI writes the diagnostic `spec.json`. */ specPath: string; /** Flat secret map loaded from the env's `secrets` file — injected locally in dev. */ secrets: Record; /** Domain metadata for codegen. */ domain: DomainInfo; /** The env key being watched (e.g. 'dev'). */ env: string; /** Invoked by the adapter on every hot-reload so the CLI can re-log. */ onReload(): void; } export interface DeployCtx { projectDir: string; specPath: string; /** Flat secret map loaded from the env's `secrets` file (gitignored). */ secrets: Record; domain: DomainInfo; /** The env key being deployed (e.g. 'dev' | 'prod' | 'canary'). */ env: string; /** * Build the expected install-graph hash for a concrete serving URL from the * current domain definition. Adapters that must verify live drift during * deploy should use this instead of reading `.astrale/spec.json`, which is a * post-deploy diagnostic artifact and may be stale. */ schemaHashForUrl?(url: string): Promise; } /** A running local watch — exposes its URL and a stop handle. */ export interface WatchHandle { /** Local URL the worker is reachable at (e.g. http://localhost:8787). */ url: string; stop(): Promise; } /** A completed deploy — the authoritative public URL. */ export interface DeployResult { url: string; /** * Adapter-specific next-steps block printed INSTEAD of the CLI's default * "install on an instance" footer — managed deploys already installed the * domain, so the default hint is wrong there. Pre-indented plain lines. */ nextSteps?: string; } export interface DomainAdapter { /** 'astrale-host' | 'cloudflare' | 'node' | … */ name: string; /** Resolve an env key to this adapter's typed params. Throws on unknown key. */ params(env: string): Params; /** Local + hot-reload (watch) → controllable handle. Orthogonal to env. */ watch(params: Params, ctx: WatchCtx): Promise; /** * Optional: re-run codegen for an ALREADY-RUNNING `watch` after * `astrale.config.ts` changed — same shape as `watch` but it must NOT spawn * anything: it only rewrites the generated files, and the running dev server * (which watches them, e.g. `wrangler dev` on its `--config`) picks them up. * Adapters without it fall back to "restart to apply config changes". */ regenerate?(params: Params, ctx: WatchCtx): Promise; /** Build + bundle + ship (the adapter owns ITS build) → authoritative URL. */ deploy(params: Params, ctx: DeployCtx): Promise; /** * Optional: the path (relative to the project root) of the gitignored secrets * file for these params. The CLI loads it and passes the parsed map as * `ctx.secrets` — keeping secret-file loading generic while the path stays * provider-typed. Return `undefined` for "no secrets file". */ secretsFile?(params: Params): string | undefined; } /** * Spec passed to `defineAdapter` — identical to `DomainAdapter` minus the * `params(env)` resolver, which the helper attaches from `envs`. Custom adapter * authors use this so they never re-implement env→params resolution. */ export interface AdapterSpec { name: string; /** The provider-typed env map (`{ dev: {...}, prod: {...}, … }`). */ envs: Record; watch(params: Params, ctx: WatchCtx): Promise; regenerate?(params: Params, ctx: WatchCtx): Promise; deploy(params: Params, ctx: DeployCtx): Promise; secretsFile?(params: Params): string | undefined; } /** * Build a `DomainAdapter` from a spec + an env map, attaching a `params(env)` * resolver that throws a clear error on an unknown key (listing the valid ones). */ export declare function defineAdapter(spec: AdapterSpec): DomainAdapter; //# sourceMappingURL=adapter.d.ts.map