/** * `defineDomain` — the WORKER-SAFE definition of a domain: what the domain *is* * (its `schema`, `methods`, `deps`, `views`, standalone `functions`) plus its * addressing identity (`origin`, `requires`, `postInstall`). It * deliberately carries NO deployment adapter — the adapter (`cloudflare(...)`, * `astrale(...)`) is node-only code (filesystem, wrangler) that must never enter * the worker bundle. The author wires this in a `domain.ts` the generated worker * imports directly, then attaches the adapter separately with `deploy(domain, * adapter)` in `astrale.config.ts` (see `./deploy`). * * The modules are wired EXPLICITLY here — imported and passed in — not * discovered from magic folder names. A renamed or mistyped module is a compile * error at this call site, never a silently-missing worker route. The adapter * reads this one definition for domain-side codegen; frontend source folders * live in adapter env config. `defineDomain` itself builds no server and boots * no kernel — it validates and packages the declaration. */ import type { Core, Schema } from '@astrale-os/kernel-dsl'; import type { AnyRemoteFunctionDef, ViewDef } from '../define/index.js'; import type { SchemaMethodsImpl } from '../method/index.js'; type AnyViewDef = ViewDef; type AnyFunctionDef = AnyRemoteFunctionDef; /** * Optional presentation metadata for the domain, served verbatim on the * worker's `/meta` endpoint (see `../deploy/meta`) so a host UI can brand a * freshly-installed domain. Both the block and every field are optional. */ export interface DomainManifest { /** Domain logo — an inline SVG string or a `data:` URL (no extra validation). */ logo?: string; /** * Slug of one of THIS domain's own views to open first — the domain's entry * surface. This is the SERVED form: a plain slug, stamped verbatim onto * `/meta`. Authors don't write the slug directly — they pass the view OBJECT * to `defineDomain` (see {@link DomainManifestConfig.entrypoint}), which * resolves it to this slug. Pinned at app install to the `View` node at * `//views/` via the app's `entrypoint` edge. */ entrypoint?: string; /** * The ROLES this domain declares — named capability identities a workspace * registers when an app for this domain is installed, then assigns to users * (`default: true` roles are auto-assigned to the installing user). The * domain itself grants each role its resource permissions (typically in its * `postInstall`); declaring a role here only names it. Slugs are validated * (lowercase slug charset, unique) at `defineDomain`. */ roles?: readonly DomainRoleDecl[]; } /** One declared role of the domain (see {@link DomainManifest.roles}). */ export interface DomainRoleDecl { /** Stable role slug, unique within the domain (e.g. `"editor"`). */ slug: string; /** Display name; defaults to the slug. */ name?: string; /** What holding this role means — shown in permission UIs. */ description?: string; /** Auto-assign this role to the user installing an app for this domain. */ default?: boolean; } /** * The author-facing manifest accepted by {@link defineDomain} — identical to the * served {@link DomainManifest} except `entrypoint` is the view OBJECT (a value * of the `views` map) rather than its slug. `defineDomain` resolves it to the * slug by identity, so a renamed or dropped view is a compile error at the * reference site, never a stale string (the same guarantee `postInstall` gives * for functions). */ export interface DomainManifestConfig extends Omit { /** * The view to open first — the domain's entry surface. Pass the view OBJECT * from this domain's own `views` map (e.g. `entrypoint: views.welcome`). * Resolved to its slug here and served as {@link DomainManifest.entrypoint}. */ entrypoint?: AnyViewDef; } export interface DefineDomainConfig { /** The domain schema (from `schema/`). Its `.domain` seeds the default origin. */ schema: S; /** * The domain's method implementations (from `methods/`), one per schema * method. Typed against `schema` — an unimplemented or misnamed method is a * compile error here. */ methods: SchemaMethodsImpl; /** Declarative genesis nodes and edges materialized with the domain at install time. */ core?: Core; /** * Map the worker `env` to the handler dependency container (`ctx.deps`). * Run ONCE per cold isolate per serving URL (the built app is cached), NOT * per request — so it's the place to construct ports/clients once instead of * re-deriving them in every handler. Its return type IS `TDeps`: type it the * shape your `methods` read (e.g. `(env) => ({ platform: buildPlatform(env) })`) * and the methods get the rich container, not raw env. The same value reaches * view/function handlers and the `install.authorize` hook. * * Omit for the common case: `env` is passed straight through (`TDeps = TEnv`), * so existing domains are unaffected. The function itself is imported by the * generated worker from a fixed `deps` module, mirroring `methods` — wire it * here so the type check binds `env → TDeps` and the adapter knows to emit it. */ deps?: (env: TEnv, url: string) => TDeps; /** * The domain's Views (iframe-mountable UIs), keyed by slug. Omit when the * domain has none. Each becomes a `View` node + a worker route. */ views?: Record; /** * The domain's standalone Functions (callables not bound to a class), keyed * by slug. Omit when the domain has none. */ functions?: Record; /** * Optional presentation metadata stamped onto `/meta`. When `manifest.entrypoint` * is set it MUST be a view from this domain's own `views` map — passed as the * OBJECT (`entrypoint: views.welcome`), resolved to its slug here. A view that * isn't in `views` is a compile error at the reference site, and the * resolution throws loudly if it's somehow absent — so a typo can never dangle * to a NOT_FOUND view path at install. */ manifest?: DomainManifestConfig; /** * The domain's **addressing name** (the graph slug it mounts under, e.g. * `'crm.acme.dev'`). Defaults to `schema.domain`. Must be a name, never a * URL. This is **NOT** the cryptographic identity: the `iss` is the worker's * **serving URL**, pinned by the kernel to the URL it fetched the domain at * during install (and verified against that URL's JWKS). `origin` is a free * addressing label, only required to be unique in the graph. */ origin?: string; /** Cross-domain deps, by origin. Verified present on the instance at install. */ requires?: readonly string[]; /** * Where the Domain node physically lives in the graph TREE — an absolute tree * path whose LAST segment is the origin (e.g. `'/domains/crm.acme.dev'`). * Optional; defaults to `/domains/`. This moves ONLY the physical * `has_parent` position: the domain's `installed_in` edge and EVERY typed * address (`/:`, `/::Class`, …) stay ROOT-mounted, so * addressing is unchanged. A platform domain that must stay top-level sets its * own origin path (e.g. `'/shell.astrale.ai'`). */ path?: string; /** * The function the kernel runs once after install, as __SYSTEM__ — where the * domain seeds itself / posts its own grants. Reference it from the `functions` * map: `postInstall: functions.seed`. The SDK derives its path by identity, so a * typo or a renamed key is a compile error here, never a stale string. It is * always a standalone function (a domain bootstrap belongs to the domain, not to * a class) under THIS domain — you never write the origin, and the kernel * resolves it relative to wherever the domain is installed. */ postInstall?: AnyFunctionDef; } export interface DomainDefinition { schema: Schema; methods: SchemaMethodsImpl; /** Declarative genesis nodes and edges, preserved through codegen and diagnostic builds. */ core?: Core; /** * env → deps mapper, when the author supplied one. Held loosely (the worker * imports the real function from its own `deps` module); the CLI reads only * its PRESENCE to set `DomainInfo.hasDeps`, the codegen signal. */ deps?: (env: any, url: string) => any; views?: Record; functions?: Record; /** Presentation metadata for `/meta`, validated at definition time. */ manifest?: DomainManifest; origin: string; requires: readonly string[]; postInstall?: string; /** Physical tree path for the Domain node; default `/domains/`. */ path?: string; } export declare function defineDomain(config: DefineDomainConfig): DomainDefinition; export {}; //# sourceMappingURL=define-domain.d.ts.map