1import type { HyperdriveOrigin } from "./bindings/hyperdrive/HyperdriveOrigin.shared.ts";
2import type { QueueConsumer } from "./bindings/queue/QueueOptions.shared.ts";
3import type { ContainerImage } from "./Docker.ts";
4import type { BindingHook } from "./PluginContext.ts";
5import type * as WorkerdConfig from "./workerd/Config.ts";
6import type { OutputSink, WorkerdExit } from "./workerd/Workerd.ts";
7
8export interface RuntimeWorker<B extends BindingHooks = BindingHooks> {
9 readonly name: string;
10 readonly proxySharedSecret?: string;
11 readonly compatibilityDate: string;
12 readonly compatibilityFlags: Array<string>;
13 readonly bindings: B;
14 readonly modules: ReadonlyArray<Module>;
15 readonly assets?: Assets;
16 readonly hyperdrives?: Record<string, HyperdriveOrigin>;
17 readonly durableObjectNamespaces?: ReadonlyArray<DurableObjectNamespace>;
18 /**
19 * Workflows whose `WorkflowEntrypoint` class is exported by this worker.
20 * Each entry hosts a local engine service (`workflows:<name>`) in this
21 * process and is published to the dev registry for cross-instance bindings.
22 */
23 readonly workflows?: ReadonlyArray<Workflow>;
24 /**
25 * Queues this worker consumes via its `queue()` handler. Each consumed
26 * queue gets an in-memory broker hosted in this worker's process; producers
27 * (local or in other dev instances) deliver to it.
28 */
29 readonly queueConsumers?: ReadonlyArray<QueueConsumer>;
30 /**
31 * Cron expressions (UTC) that trigger this worker's `scheduled()` handler.
32 * Each expression gets a Node-side timer that hits the entry socket's
33 * `/cdn-cgi/handler/scheduled` route at every match, so crons actually
34 * fire during local development. The route is also reachable manually
35 * (Miniflare-compatible: `?cron=<expr>&time=<epoch-millis>`).
36 */
37 readonly crons?: ReadonlyArray<string>;
38 /**
39 * Names of tail consumer workers (the deployed `tail_consumers` setting).
40 * workerd delivers this worker's trace events to each consumer's `tail()`
41 * handler. Consumers are resolved through the on-disk dev registry — the
42 * same path service bindings to other local workers take — so a consumer
43 * may run in a separate `cloudflare-runtime` or `wrangler dev` process and
44 * may (re)start at any time. Events produced while a consumer is not
45 * running are dropped with a warning, matching dev-registry semantics.
46 */
47 readonly tails?: ReadonlyArray<string>;
48 /**
49 * Names of streaming tail consumer workers (the deployed
50 * `streaming_tail_consumers` setting). The handler contract differs from
51 * plain `tails`: a plain tail consumer exports `tail(items)` and receives an
52 * array of completed `TraceItem`s after the producer's invocation has
53 * finished, while a streaming tail consumer exports `tailStream(event)`,
54 * which is invoked with the invocation's `onset` event as soon as the
55 * producer starts executing and returns a handler (a function, or an object
56 * keyed by event type) that receives every subsequent event (`spanOpen` /
57 * `spanClose`, `log`, `exception`, `diagnosticChannel`, `return`, …)
58 * streamed live during execution, ending with the terminal `outcome` event.
59 * Consumers are resolved through the on-disk dev registry exactly like
60 * `tails` — the registry proxy's `ExternalService` entrypoint forwards the
61 * `tailStream()` session to the consumer's process via the workerd debug
62 * port — so a consumer may run in a separate process and may (re)start at
63 * any time. Sessions started while a consumer is not running are dropped
64 * with a warning, matching dev-registry semantics.
65 */
66 readonly streamingTails?: ReadonlyArray<string>;
67 /**
68 * Whether the Cache API (`caches.default` / `caches.open()`) stores
69 * responses. Defaults to `true`; when `false` every cache operation is a
70 * no-op (matching production behaviour on `workers.dev` subdomains).
71 */
72 readonly cache?: boolean;
73 /**
74 * Per-worker `request.cf` blob. Merged the way Miniflare does — used
75 * verbatim unless the request carries an `MF-CF-Blob` header. Falls back
76 * to the runtime-wide `Cf` reference (a static placeholder by default).
77 */
78 readonly cf?: Record<string, unknown>;
79 /**
80 * Controls how output from the underlying `workerd` process is surfaced.
81 *
82 * By default, workerd does not log uncaught exceptions thrown by the
83 * worker — they surface as bare `500 Internal Server Error` responses with
84 * no output anywhere. Set `verbose: true` to have workerd log them
85 * (message + stack) to stderr, and optionally `onOutput` to capture the
86 * process output instead of inheriting the parent process's stdio.
87 */
88 readonly logging?: WorkerdLogging;
89 /**
90 * Called after the `workerd` process exited on its own (for example when
91 * V8 ran out of heap) and a replacement process is serving on the same
92 * ports again. The URL returned by `start` stays valid. Connections into
93 * the old process are gone, so a caller that keeps any (such as the Vite
94 * module runner sockets) reconnects here.
95 * Automatic recovery is limited to three restarts within a rolling minute,
96 * with backoff between attempts. A failed replacement stops recovery.
97 */
98 readonly onRestart?: (exit: WorkerdExit) => void;
99 readonly unsafe?: Partial<WorkerdConfig.Worker>;
100}
101
102export interface WorkerdLogging {
103 /**
104 * Pass `--verbose` to workerd. Enables INFO-level logging, which includes
105 * uncaught exceptions thrown by the worker (message + stack, written to
106 * stderr) — without it, those exceptions surface as bare
107 * `500 Internal Server Error` responses with no log output anywhere.
108 */
109 readonly verbose?: boolean;
110 /**
111 * Capture the workerd process's stdout/stderr output instead of piping it
112 * to the parent process's stdio. Output produced before the process
113 * finishes starting is not captured; startup failures surface as typed
114 * errors instead.
115 */
116 readonly onOutput?: OutputSink;
117}
118
119export type BindingHooks = ReadonlyArray<BindingHook<any>>;
120
121export type { HyperdriveOrigin } from "./bindings/hyperdrive/HyperdriveOrigin.shared.ts";
122export type { QueueConsumer } from "./bindings/queue/QueueOptions.shared.ts";
123
124export type Module =
125 | {
126 name: string;
127 type: "ESModule" | "CommonJsModule" | "Text" | "Json" | "PythonModule";
128 content: string;
129 }
130 | {
131 name: string;
132 type: "Data" | "Wasm";
133 content: Uint8Array;
134 };
135
136export interface Assets {
137 directory?: string;
138 headers?: string;
139 redirects?: string;
140 htmlHandling?:
141 | "auto-trailing-slash"
142 | "force-trailing-slash"
143 | "drop-trailing-slash"
144 | "none";
145 notFoundHandling?: "none" | "404-page" | "single-page-application";
146 runWorkerFirst?: Array<string> | boolean;
147 serveDirectly?: boolean;
148}
149
150export interface DurableObjectNamespace {
151 className: string;
152 sql: boolean;
153 uniqueKey?: string;
154 ephemeralLocal?: true;
155 /**
156 * Attach a container to every Durable Object in this namespace. workerd
157 * starts one per DO instance via the worker's `containerEngine` and exposes
158 * it as `ctx.container`.
159 */
160 container?: ContainerImage;
161}
162
163export interface Workflow {
164 /**
165 * Logical name of the workflow. Used as the engine identity
166 * (`workflows:<workflowName>`) and published to the dev registry.
167 */
168 workflowName: string;
169 /**
170 * Class name of the `WorkflowEntrypoint` exported by this worker.
171 */
172 className: string;
173 /**
174 * Optional step limit enforced by the local workflow engine.
175 */
176 stepLimit?: number;
177}