/** * `domainWorkerEntry` — the one-call worker entry for a standalone domain. * * It folds the three steps every hand-rolled worker used to wire by hand — * compile the runtime domain (`defineRemoteDomain`), build the server * (`createRemoteServer`), and wrap it in the shared fetch plumbing * (`createWorkerEntry`) — into a single declaration. The author passes the raw * modules (`schema` / `methods` / `views` / `functions`) plus the identity and * deploy bits; the helper does the rest. This is what the cloudflare adapter's * codegen emits, and the recommended surface for a hand-rolled worker. * * Drop down to `createWorkerEntry` + `defineRemoteDomain` (from * `@astrale-os/sdk/domain`) only when the worker needs something this config * can't express — e.g. a serving-URL-dependent domain build (views stamped with * the live url) or a globally-injected signing key resolved per request. */ import type { Core, Schema } from '@astrale-os/kernel-dsl' import type { Hono } from 'hono' import type { DomainManifest } from '../config/define-domain.js' import type { AnyRemoteFunctionDef, ViewDef } from '../define/index.js' import type { SchemaMethodsImpl } from '../method/index.js' import type { RemoteServerConfig } from './config.js' import type { WorkerEntry, WorkerEntryConfig } from './worker-entry.js' import { defineRemoteDomain } from '../domain/index.js' import { createWorkerEntry } from './worker-entry.js' export interface DomainWorkerEntryConfig { /** The domain schema. */ schema: S /** Method implementations, typed against `schema` under `TDeps`. */ methods: SchemaMethodsImpl /** Optional Core override (extra genesis nodes / wiring). */ core?: Core /** Views (iframe-mountable UIs) keyed by slug. */ views?: Record> /** Standalone Functions (callables not bound to a class) keyed by slug. */ functions?: Record /** * The worker's signing key (its `iss` identity material). A static JWK, or a * resolver from `env` for keys injected as a secret / shared globally. */ privateKey: JsonWebKey | ((env: TEnv) => JsonWebKey) /** Cross-domain deps by origin — verified present at install. */ requires?: readonly string[] /** Typed colon-path the kernel calls once as __SYSTEM__ after install. */ postInstall?: string /** * Physical tree path for the Domain node (absolute, e.g. `/domains/acme`); * default `/domains/`. Rides in on the `...domain` spread from * `defineDomain`; declared here so it is captured (not silently dropped like a * spread prop absent from this type) and forwarded to `defineRemoteDomain`. */ path?: string /** Provenance stamped on `/meta`. */ meta?: RemoteServerConfig['meta'] /** Presentation metadata (logo / initial view) stamped on `/meta`. */ manifest?: DomainManifest /** * Map the worker `env` to the handler dependency container. Defaults to * passing `env` straight through (the common case where handlers read * bindings directly). */ deps?: (env: TEnv, url: string) => TDeps /** Optional pre-built host Hono app (CORS / logging / extra routes). */ app?: (env: TEnv) => Hono // ── createWorkerEntry plumbing (passed through verbatim) ────────────────── resolveUrl?: WorkerEntryConfig['resolveUrl'] selfBinding?: WorkerEntryConfig['selfBinding'] routeSubrequest?: WorkerEntryConfig['routeSubrequest'] before?: WorkerEntryConfig['before'] rewriteRequest?: WorkerEntryConfig['rewriteRequest'] } /** * Curried so `TDeps` can be fixed explicitly (it types `methods`/`views`) while * `S` is inferred from `schema` — mirroring `defineRemoteDomain`. The common * case `domainWorkerEntry()({ … })` leaves `TDeps = TEnv` (handlers read * the env directly); pass both — `domainWorkerEntry()` — when the * handler deps differ from the worker bindings and a `deps` mapper is supplied. */ export function domainWorkerEntry() { return function ( config: DomainWorkerEntryConfig, ): WorkerEntry { const domain = defineRemoteDomain()({ schema: config.schema, methods: config.methods, ...(config.core ? { core: config.core } : {}), ...(config.views ? { views: config.views } : {}), ...(config.functions ? { remoteFunctions: config.functions } : {}), ...(config.manifest ? { manifest: config.manifest } : {}), ...(config.path ? { path: config.path } : {}), }) return createWorkerEntry({ ...(config.resolveUrl ? { resolveUrl: config.resolveUrl } : {}), ...(config.selfBinding ? { selfBinding: config.selfBinding } : {}), ...(config.routeSubrequest ? { routeSubrequest: config.routeSubrequest } : {}), ...(config.before ? { before: config.before } : {}), ...(config.rewriteRequest ? { rewriteRequest: config.rewriteRequest } : {}), // `createWorkerEntry` conflates the worker env and the handler deps into a // single type param; we keep them distinct in the public config and bridge // here. The runtime deps (and the methods typed against them) are correct; // only this assembly is cast. build: (url, env) => ({ domain, deps: config.deps ? config.deps(env, url) : (env as unknown as TDeps), url, privateKey: typeof config.privateKey === 'function' ? config.privateKey(env) : config.privateKey, ...(config.requires && config.requires.length > 0 ? { requires: config.requires } : {}), ...(config.postInstall ? { postInstall: config.postInstall } : {}), ...(config.meta ? { meta: config.meta } : {}), ...(config.app ? { app: config.app(env) } : {}), }) as unknown as RemoteServerConfig, }) } }