/** * Realm-ready handshake for internal `workflowExecutionMode: 'worker'` * Workers (WFT-28). * * An internal Worker realm sends a `ready` message — its own manifest, built * from exactly the workflow types its bootstrap script registered — before * it can receive a `run` turn. The host checks that every workflow type it * has registered appears in that manifest with a matching contract (a * subset check, not exact-set equality — a realm may legitimately advertise * more types than any one host dispatches to it, e.g. a shared worker pool * serving several engines). A missing or mismatched type means the realm's * bundle disagrees with the host about a workflow it needs (a stale build, a * bootstrap script that fell out of sync), and the realm is discarded before * it can ever execute a turn, rather than failing opaquely mid-dispatch. * * `ready` has no `workflowId` — it is a per-worker-lifetime handshake, not a * per-workflow-turn message — so it cannot fit {@link WorkerOutboundMessage}'s * shape (every variant there requires one) and is validated on its own path * instead of through {@link assertWorkerOutboundMessageShape}, the same way * `log` is handled outside the strict turn gate. * * @module core/worker-realm-readiness */ import type { WorkerManifest } from '../worker/manifest/types.ts'; import type { FailureCategory } from './types.ts'; /** Sent once by a Worker realm, before its first `run` turn. See {@link WorkerRealmReadiness}. */ export type WorkerRealmReadyMessage = Readonly<{ type: 'ready'; protocolVersion: number; realmGeneration: string; manifest: WorkerManifest; }>; /** Shallow type guard — deep field validation happens in {@link WorkerRealmReadiness.noteReadyMessage}. */ export declare function isWorkerRealmReadyMessage(message: unknown): message is WorkerRealmReadyMessage; export type RealmReadyOutcome = { ok: true; realmGeneration: string; manifestDigest: string; } | { ok: false; error: string; failureCategory: FailureCategory; }; export interface WorkerRealmReadinessDependencies { /** * Live accessor for the host's registered workflow types, called fresh on * every handshake rather than snapshotted at construction — the engine's * registrations map is still empty when the strategy is constructed (the * registration loop runs later in `Engine.create()`). */ getExpectedWorkflowTypes: () => readonly string[]; timeoutMs: number; maxProtocolMessageBytes: number | undefined; } /** * Tracks, per pooled `Worker` instance, whether its one-time ready handshake * has completed. A worker is validated at most once per lifetime — recycled * workers skip straight to {@link isReady}. */ export declare class WorkerRealmReadiness { #private; constructor(dependencies: WorkerRealmReadinessDependencies); isReady(worker: Worker): boolean; /** * Wait for `worker`'s ready handshake. Resolves immediately if the worker * already completed it. The caller must attach its message listener (which * routes into {@link noteReadyMessage}) before calling this, in the same * synchronous continuation — `acquireAndSend` does exactly that, so no * `ready` message can arrive before this registers its pending waiter. */ waitForReady(worker: Worker): Promise; /** Validate an inbound `ready` message and settle any pending {@link waitForReady} call. */ noteReadyMessage(worker: Worker, message: unknown): Promise; /** Drop a discarded worker's state, settling any pending waiter with a failure. */ forget(worker: Worker): void; /** Settle every pending waiter on strategy disposal so no wait hangs past teardown. */ clear(): void; }