alchemy 2.0.0-beta.2 → 2.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -119,6 +119,248 @@ export class DurableObjectNamespaceScope extends Context.Service<
119
119
  DurableObjectNamespace
120
120
  >()("Cloudflare.DurableObjectNamespace") {}
121
121
 
122
+ /**
123
+ * A Cloudflare Durable Object namespace that manages globally unique, stateful
124
+ * instances with WebSocket hibernation support.
125
+ *
126
+ * A Durable Object uses a two-phase pattern with two nested `Effect.gen`
127
+ * blocks. The outer Effect resolves shared dependencies (other DOs,
128
+ * containers, etc.). The inner Effect runs once per instance and returns
129
+ * the object's public methods and WebSocket handlers.
130
+ *
131
+ * ```typescript
132
+ * Effect.gen(function* () {
133
+ * // Phase 1: resolve shared dependencies
134
+ * const db = yield* Cloudflare.D1Connection.bind(MyDB);
135
+ *
136
+ * return Effect.gen(function* () {
137
+ * // Phase 2: per-instance setup and public API
138
+ * const state = yield* Cloudflare.DurableObjectState;
139
+ *
140
+ * return {
141
+ * save: (data: string) => db.exec("INSERT ..."),
142
+ * fetch: Effect.gen(function* () { ... }),
143
+ * webSocketMessage: Effect.fnUntraced(function* (ws, msg) { ... }),
144
+ * };
145
+ * });
146
+ * })
147
+ * ```
148
+ *
149
+ * There are two ways to define a Durable Object. See the
150
+ * {@link https://alchemy.run/concepts/platform | Platform concept} page
151
+ * for the full explanation.
152
+ *
153
+ * - **Inline** — Effect implementation passed directly, single file.
154
+ * - **Modular** — class and implementation in separate files for tree-shaking.
155
+ *
156
+ * @resource
157
+ *
158
+ * @section Inline Durable Objects
159
+ * Pass the Effect implementation as the second argument. This is the
160
+ * simplest approach — everything lives in one file. Convenient when
161
+ * the DO doesn't need to be referenced by other Workers or DOs that
162
+ * would pull in its runtime dependencies.
163
+ *
164
+ * @example Inline Durable Object
165
+ * ```typescript
166
+ * export default class Counter extends Cloudflare.DurableObjectNamespace<Counter>()(
167
+ * "Counter",
168
+ * Effect.gen(function* () {
169
+ * // init: bind resources
170
+ * const db = yield* Cloudflare.D1Connection.bind(MyDB);
171
+ *
172
+ * return Effect.gen(function* () {
173
+ * const state = yield* Cloudflare.DurableObjectState;
174
+ * const count = (yield* state.storage.get<number>("count")) ?? 0;
175
+ *
176
+ * return {
177
+ * // runtime: use them
178
+ * increment: () =>
179
+ * Effect.gen(function* () {
180
+ * const next = count + 1;
181
+ * yield* state.storage.put("count", next);
182
+ * return next;
183
+ * }),
184
+ * get: () => Effect.succeed(count),
185
+ * };
186
+ * });
187
+ * }),
188
+ * ) {}
189
+ * ```
190
+ *
191
+ * @section Modular Durable Objects
192
+ * When a Worker and a DO reference each other, or multiple Workers
193
+ * bind the same DO, define the class separately from its `.make()`
194
+ * call. The class is a lightweight identifier; `.make()` provides
195
+ * the runtime implementation as an `export default`. Rolldown treats
196
+ * `.make()` as pure, so the bundler tree-shakes it and all its
197
+ * runtime dependencies out of any consumer's bundle.
198
+ *
199
+ * The class and `.make()` can live in the same file. This is the
200
+ * same pattern used by `Worker` and `Container`.
201
+ *
202
+ * @example Modular Durable Object (class + .make() in one file)
203
+ * ```typescript
204
+ * // src/Counter.ts
205
+ * export default class Counter extends Cloudflare.DurableObjectNamespace<Counter>()(
206
+ * "Counter",
207
+ * ) {}
208
+ *
209
+ * export default Counter.make(
210
+ * Effect.gen(function* () {
211
+ * // init: bind resources
212
+ * const db = yield* Cloudflare.D1Connection.bind(MyDB);
213
+ *
214
+ * return Effect.gen(function* () {
215
+ * const state = yield* Cloudflare.DurableObjectState;
216
+ * const count = (yield* state.storage.get<number>("count")) ?? 0;
217
+ *
218
+ * return {
219
+ * // runtime: use them
220
+ * increment: () =>
221
+ * Effect.gen(function* () {
222
+ * const next = count + 1;
223
+ * yield* state.storage.put("count", next);
224
+ * yield* db.prepare("INSERT INTO logs (count) VALUES (?)").bind(next).run();
225
+ * return next;
226
+ * }),
227
+ * get: () => Effect.succeed(count),
228
+ * };
229
+ * });
230
+ * }),
231
+ * );
232
+ * ```
233
+ *
234
+ * @example Binding a modular DO from a Worker
235
+ * ```typescript
236
+ * // imports Counter; bundler tree-shakes .make()
237
+ * import Counter from "./Counter.ts";
238
+ *
239
+ * // init
240
+ * const counters = yield* Counter;
241
+ *
242
+ * return {
243
+ * fetch: Effect.gen(function* () {
244
+ * const counter = counters.getByName("user-123");
245
+ * return HttpServerResponse.text(String(yield* counter.get()));
246
+ * }),
247
+ * };
248
+ * ```
249
+ *
250
+ * @section RPC Methods
251
+ * Any function you return from the inner Effect becomes an RPC method
252
+ * that Workers can call through a stub. Methods must return an `Effect`.
253
+ * The caller gets a fully typed stub — if your DO returns `increment`
254
+ * and `get`, the stub exposes `counter.increment()` and `counter.get()`.
255
+ *
256
+ * @example Defining RPC methods
257
+ * ```typescript
258
+ * return {
259
+ * increment: () => Effect.succeed(++count),
260
+ * get: () => Effect.succeed(count),
261
+ * reset: () => Effect.sync(() => { count = 0; }),
262
+ * };
263
+ * ```
264
+ *
265
+ * @section Accessing Instance State
266
+ * Each Durable Object instance has its own transactional key-value
267
+ * storage via `Cloudflare.DurableObjectState`. Use `storage.get` and
268
+ * `storage.put` inside the inner Effect to persist data across requests
269
+ * and restarts.
270
+ *
271
+ * @example Reading and writing durable storage
272
+ * ```typescript
273
+ * const state = yield* Cloudflare.DurableObjectState;
274
+ *
275
+ * yield* state.storage.put("counter", 42);
276
+ * const value = yield* state.storage.get("counter");
277
+ * ```
278
+ *
279
+ * @section WebSocket Hibernation
280
+ * Durable Objects support WebSocket hibernation — the runtime can
281
+ * evict the object from memory while keeping connections open. Use
282
+ * `Cloudflare.upgrade()` to accept a connection, and return
283
+ * `webSocketMessage` / `webSocketClose` handlers to process events
284
+ * when the object wakes back up.
285
+ *
286
+ * @example Accepting a WebSocket connection
287
+ * ```typescript
288
+ * return {
289
+ * fetch: Effect.gen(function* () {
290
+ * const [response, socket] = yield* Cloudflare.upgrade();
291
+ * socket.serializeAttachment({ id: crypto.randomUUID() });
292
+ * return response;
293
+ * }),
294
+ * };
295
+ * ```
296
+ *
297
+ * @example Handling messages and close events
298
+ * ```typescript
299
+ * return {
300
+ * webSocketMessage: Effect.fnUntraced(function* (
301
+ * socket: Cloudflare.DurableWebSocket,
302
+ * message: string | Uint8Array,
303
+ * ) {
304
+ * const text = typeof message === "string"
305
+ * ? message
306
+ * : new TextDecoder().decode(message);
307
+ * // process the message
308
+ * }),
309
+ * webSocketClose: Effect.fnUntraced(function* (
310
+ * ws: Cloudflare.DurableWebSocket,
311
+ * code: number,
312
+ * reason: string,
313
+ * ) {
314
+ * yield* ws.close(code, reason);
315
+ * }),
316
+ * };
317
+ * ```
318
+ *
319
+ * @example Recovering sessions after hibernation
320
+ * ```typescript
321
+ * const state = yield* Cloudflare.DurableObjectState;
322
+ * const sockets = yield* state.getWebSockets();
323
+ *
324
+ * for (const socket of sockets) {
325
+ * const data = socket.deserializeAttachment<{ id: string }>();
326
+ * // re-populate your session map
327
+ * }
328
+ * ```
329
+ *
330
+ * @section Using from a Worker
331
+ * Yield the DO class in your Worker's init phase to get a namespace
332
+ * handle. Call `getByName` or `getById` to get a typed stub, then
333
+ * call any RPC method or forward an HTTP request with `fetch`.
334
+ *
335
+ * @example Calling RPC methods
336
+ * ```typescript
337
+ * // init
338
+ * const counters = yield* Counter;
339
+ *
340
+ * return {
341
+ * fetch: Effect.gen(function* () {
342
+ * const counter = counters.getByName("user-123");
343
+ * yield* counter.increment();
344
+ * const value = yield* counter.get();
345
+ * return HttpServerResponse.text(String(value));
346
+ * }),
347
+ * };
348
+ * ```
349
+ *
350
+ * @example Forwarding an HTTP request
351
+ * ```typescript
352
+ * // init
353
+ * const rooms = yield* Room;
354
+ *
355
+ * return {
356
+ * fetch: Effect.gen(function* () {
357
+ * const request = yield* HttpServerRequest;
358
+ * const room = rooms.getByName(roomId);
359
+ * return yield* room.fetch(request);
360
+ * }),
361
+ * };
362
+ * ```
363
+ */
122
364
  export const DurableObjectNamespace: DurableObjectNamespaceClass =
123
365
  taggedFunction(DurableObjectNamespaceScope, ((
124
366
  ...args:
@@ -70,16 +70,40 @@ export type DynamicWorkerLoader = {
70
70
  };
71
71
 
72
72
  /**
73
- * Declare a Dynamic Worker loader binding inside a Worker program.
73
+ * Load and run ephemeral Workers at runtime from inline JavaScript
74
+ * modules.
74
75
  *
75
- * At deploy time this registers a `worker_loader` binding on the parent
76
- * Worker. At runtime it exposes an Effect-wrapped interface for loading
77
- * and calling into dynamic workers.
76
+ * `DynamicWorkerLoader` registers a `worker_loader` binding on the
77
+ * parent Worker at deploy time. At runtime you call `.load()` with
78
+ * inline module source code and get back a fully typed Worker
79
+ * instance you can `fetch` or call RPC methods on. Each loaded
80
+ * Worker runs in its own isolate with full sandboxing.
78
81
  *
79
- * @example
82
+ * This is useful for evaluating user-provided code, running
83
+ * untrusted plugins, or dynamically generating Workers from
84
+ * templates.
85
+ *
86
+ * @resource
87
+ *
88
+ * @section Creating a Loader
89
+ * Yield `Cloudflare.DynamicWorkerLoader` in your Worker's init
90
+ * phase to register the binding. The string argument becomes the
91
+ * binding name on the deployed Worker.
92
+ *
93
+ * @example Registering a loader
80
94
  * ```typescript
81
- * const loader = yield* DynamicWorker("LOADER");
95
+ * // init
96
+ * const loader = yield* Cloudflare.DynamicWorkerLoader("Loader");
97
+ * ```
98
+ *
99
+ * @section Loading a Worker
100
+ * Call `loader.load()` with a compatibility date, a main module
101
+ * name, and a map of module names to source code strings. The
102
+ * returned instance exposes `.fetch()` for HTTP and RPC methods
103
+ * for named entrypoints.
82
104
  *
105
+ * @example Loading and calling a dynamic Worker
106
+ * ```typescript
83
107
  * const worker = loader.load({
84
108
  * compatibilityDate: "2026-01-28",
85
109
  * mainModule: "worker.js",
@@ -90,10 +114,45 @@ export type DynamicWorkerLoader = {
90
114
  * }
91
115
  * }`,
92
116
  * },
117
+ * });
118
+ *
119
+ * const response = yield* worker.fetch(
120
+ * HttpClientRequest.get("https://worker/"),
121
+ * );
122
+ * ```
123
+ *
124
+ * @section Sandboxing
125
+ * Set `globalOutbound` to `null` to block all outbound network
126
+ * access from the dynamic Worker, or pass an RPC stub to intercept
127
+ * and proxy outbound requests.
128
+ *
129
+ * @example Blocking outbound access
130
+ * ```typescript
131
+ * const worker = loader.load({
132
+ * compatibilityDate: "2026-01-28",
133
+ * mainModule: "worker.js",
134
+ * modules: {
135
+ * "worker.js": `export default {
136
+ * async fetch(req) {
137
+ * // fetch() calls from here will fail
138
+ * return new Response("sandboxed");
139
+ * }
140
+ * }`,
141
+ * },
93
142
  * globalOutbound: null,
94
143
  * });
144
+ * ```
95
145
  *
96
- * const response = yield* worker.fetch(request);
146
+ * @section Named Entrypoints
147
+ * If the dynamic Worker exports named entrypoints, use
148
+ * `.getEntrypoint(name)` to get a typed stub for calling its
149
+ * methods.
150
+ *
151
+ * @example Calling a named entrypoint
152
+ * ```typescript
153
+ * const worker = loader.load({ ... });
154
+ * const api = worker.getEntrypoint<{ greet: (name: string) => Effect.Effect<string> }>("api");
155
+ * const greeting = yield* api.greet("world");
97
156
  * ```
98
157
  */
99
158
  export const DynamicWorkerLoader = Effect.fnUntraced(function* (name: string) {
@@ -2,7 +2,7 @@ import type * as cf from "@cloudflare/workers-types";
2
2
  import * as Effect from "effect/Effect";
3
3
  import * as HttpBody from "effect/unstable/http/HttpBody";
4
4
  import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";
5
- import { DurableObjectState } from "./DurableObject.ts";
5
+ import { DurableObjectState } from "./DurableObjectNamespace.ts";
6
6
 
7
7
  export type RawWebSocket = cf.WebSocket;
8
8
 
@@ -50,7 +50,7 @@ import type { R2Bucket } from "../R2/R2Bucket.ts";
50
50
  import type { AssetsConfig, AssetsProps } from "./Assets.ts";
51
51
  import * as Assets from "./Assets.ts";
52
52
  import cloudflare_workers from "./cloudflare_workers.ts";
53
- import { isDurableObjectExport } from "./DurableObject.ts";
53
+ import { isDurableObjectExport } from "./DurableObjectNamespace.ts";
54
54
  import { workersHttpHandler } from "./HttpServer.ts";
55
55
  import { Request } from "./Request.ts";
56
56
  import { makeRpcStub } from "./Rpc.ts";
@@ -256,17 +256,322 @@ export type Worker<Bindings extends WorkerBindings = any> = Resource<
256
256
  * A Cloudflare Worker host with deploy-time binding support and runtime export
257
257
  * collection.
258
258
  *
259
- * `Worker` behaves like a resource during deploy, but it also carries a runtime
260
- * execution context so KV, R2, Durable Objects, assets, and service bindings
261
- * can be inferred from the worker program itself.
259
+ * A Worker follows a two-phase pattern. The outer `Effect.gen` runs at
260
+ * deploy time to bind resources (KV, R2, Durable Objects, etc.). It returns
261
+ * an object whose properties are the Worker's runtime handlers — `fetch` for
262
+ * HTTP requests and any additional RPC methods.
262
263
  *
263
- * @section Creating Workers
264
- * @example Basic Worker
265
264
  * ```typescript
266
- * const worker = yield* Worker("ApiWorker", {
265
+ * Effect.gen(function* () {
266
+ * // Phase 1: bind resources (runs at deploy time)
267
+ * const kv = yield* Cloudflare.KVNamespace.bind(MyKV);
268
+ *
269
+ * return {
270
+ * // Phase 2: runtime handlers (runs on each request)
271
+ * fetch: Effect.gen(function* () {
272
+ * const value = yield* kv.get("key");
273
+ * return HttpServerResponse.text(value ?? "not found");
274
+ * }),
275
+ * };
276
+ * })
277
+ * ```
278
+ *
279
+ * There are three ways to define a Worker, from simplest to most
280
+ * flexible. See the {@link https://alchemy.run/concepts/platform | Platform concept}
281
+ * page for the full explanation.
282
+ *
283
+ * - **Async** — plain `async fetch` handler, no Effect runtime in the bundle.
284
+ * - **Effect** — Effect implementation passed directly, single file.
285
+ * - **Layer** — class and `.make()` in a single file; Rolldown tree-shakes `.make()` from consumers.
286
+ *
287
+ * @section Async Workers
288
+ * You don't have to use Effect for your runtime code. If you create
289
+ * a Worker resource with `main` pointing at a file but provide no
290
+ * `Effect.gen` implementation, Alchemy bundles and deploys that file
291
+ * as-is. Your handler is a plain `async fetch` — no Effect runtime
292
+ * is included in the bundle.
293
+ *
294
+ * Use the `bindings` prop to declare which resources are available
295
+ * at runtime, and `Cloudflare.InferEnv` to extract a fully typed
296
+ * `env` object from those bindings.
297
+ *
298
+ * @example Defining an async Worker in your stack
299
+ * ```typescript
300
+ * // alchemy.run.ts
301
+ * const db = yield* Cloudflare.D1Database("DB");
302
+ * const bucket = yield* Cloudflare.R2Bucket("Bucket");
303
+ *
304
+ * export type WorkerEnv = Cloudflare.InferEnv<typeof Worker>;
305
+ *
306
+ * export const Worker = Cloudflare.Worker("Worker", {
267
307
  * main: "./src/worker.ts",
308
+ * bindings: { db, bucket },
309
+ * });
310
+ * ```
311
+ *
312
+ * @example Writing the async handler
313
+ * ```typescript
314
+ * // src/worker.ts
315
+ * import type { WorkerEnv } from "../alchemy.run.ts";
316
+ *
317
+ * export default {
318
+ * async fetch(request: Request, env: WorkerEnv) {
319
+ * if (request.method === "GET") {
320
+ * const object = await env.bucket.get("key");
321
+ * return new Response(object?.body ?? null);
322
+ * }
323
+ * return new Response("Not Found", { status: 404 });
324
+ * },
325
+ * };
326
+ * ```
327
+ *
328
+ * @section Effect Workers
329
+ * Pass the Effect implementation as the third argument. This is the
330
+ * simplest Effect-based approach — everything lives in one file.
331
+ * Convenient for standalone Workers that don't need to be referenced
332
+ * by other Workers.
333
+ *
334
+ * @example Worker Effect
335
+ * ```typescript
336
+ * export default class MyWorker extends Cloudflare.Worker<MyWorker>()(
337
+ * "MyWorker",
338
+ * { main: import.meta.path },
339
+ * Effect.gen(function* () {
340
+ * // init: bind resources
341
+ * const kv = yield* Cloudflare.KVNamespace.bind(MyKV);
342
+ *
343
+ * return {
344
+ * // runtime: use them
345
+ * fetch: Effect.gen(function* () {
346
+ * const value = yield* kv.get("key");
347
+ * return HttpServerResponse.text(value ?? "not found");
348
+ * }),
349
+ * };
350
+ * }),
351
+ * ) {}
352
+ * ```
353
+ *
354
+ * @section Worker Layer
355
+ * When two Workers need to reference each other (e.g. WorkerA calls
356
+ * WorkerB and vice versa), or you simply want optimal tree-shaking,
357
+ * define the Worker class separately from its `.make()` call. The
358
+ * class is a lightweight identifier; `.make()` provides the runtime
359
+ * implementation as an `export default`. Rolldown treats `.make()`
360
+ * as pure, so any Worker that imports the class to bind it will not
361
+ * pull in the `.make()` dependencies — the bundler tree-shakes
362
+ * them away entirely.
363
+ *
364
+ * The class and `.make()` can live in the same file. This is the
365
+ * same pattern used by `Container` and `DurableObjectNamespace`,
366
+ * and is recommended for any cross-Worker or cross-DO bindings.
367
+ *
368
+ * @example Worker Layer (class + .make() in one file)
369
+ * ```typescript
370
+ * // src/WorkerB.ts
371
+ * export default class WorkerB extends Cloudflare.Worker<WorkerB>()(
372
+ * "WorkerB",
373
+ * { main: import.meta.path },
374
+ * ) {}
375
+ *
376
+ * export default WorkerB.make(
377
+ * Effect.gen(function* () {
378
+ * // init: bind resources
379
+ * const kv = yield* Cloudflare.KVNamespace.bind(MyKV);
380
+ *
381
+ * return {
382
+ * // runtime: use them
383
+ * greet: (name: string) =>
384
+ * Effect.gen(function* () {
385
+ * yield* kv.put("last-greeted", name);
386
+ * return `Hello ${name}`;
387
+ * }),
388
+ * };
389
+ * }),
390
+ * );
391
+ * ```
392
+ *
393
+ * @example Binding a Worker Layer from another Worker
394
+ * ```typescript
395
+ * // src/WorkerA.ts — imports WorkerB; bundler tree-shakes .make()
396
+ * import WorkerB from "./WorkerB.ts";
397
+ *
398
+ * export default class WorkerA extends Cloudflare.Worker<WorkerA>()(
399
+ * "WorkerA",
400
+ * { main: import.meta.path },
401
+ * Effect.gen(function* () {
402
+ * const b = yield* Cloudflare.Worker.bind(WorkerB);
403
+ * return {
404
+ * fetch: Effect.gen(function* () {
405
+ * return yield* b.greet("world");
406
+ * }),
407
+ * };
408
+ * }),
409
+ * ) {}
410
+ * ```
411
+ *
412
+ * @section Configuration
413
+ * The props object controls compatibility flags, static assets, and
414
+ * build options. These are evaluated at deploy time.
415
+ *
416
+ * @example Enabling Node.js compatibility
417
+ * ```typescript
418
+ * {
419
+ * main: import.meta.path,
420
+ * compatibility: {
421
+ * flags: ["nodejs_compat"],
422
+ * date: "2026-03-17",
423
+ * },
424
+ * }
425
+ * ```
426
+ *
427
+ * @example Serving static assets
428
+ * ```typescript
429
+ * {
430
+ * main: import.meta.path,
431
+ * assets: "./public",
432
+ * }
433
+ * ```
434
+ *
435
+ * @section R2 Bucket
436
+ * Bind an R2 bucket in the init phase with `Cloudflare.R2Bucket.bind`.
437
+ * The returned handle exposes `get`, `put`, `delete`, and `list`
438
+ * methods you can call in your runtime handlers.
439
+ *
440
+ * @example Binding and using R2
441
+ * ```typescript
442
+ * // init
443
+ * const bucket = yield* Cloudflare.R2Bucket.bind(MyBucket);
444
+ *
445
+ * return {
446
+ * fetch: Effect.gen(function* () {
447
+ * const request = yield* HttpServerRequest;
448
+ * const key = request.url.split("/").pop()!;
449
+ *
450
+ * if (request.method === "GET") {
451
+ * const object = yield* bucket.get(key);
452
+ * return object
453
+ * ? HttpServerResponse.text(yield* object.text())
454
+ * : HttpServerResponse.empty({ status: 404 });
455
+ * }
456
+ *
457
+ * yield* bucket.put(key, request.stream);
458
+ * return HttpServerResponse.empty({ status: 201 });
459
+ * }),
460
+ * };
461
+ * ```
462
+ *
463
+ * @section KV Namespace
464
+ * Bind a KV namespace with `Cloudflare.KVNamespace.bind`. KV provides
465
+ * eventually-consistent, low-latency key-value reads replicated
466
+ * globally across Cloudflare's edge.
467
+ *
468
+ * @example Binding and using KV
469
+ * ```typescript
470
+ * // init
471
+ * const kv = yield* Cloudflare.KVNamespace.bind(MyKV);
472
+ *
473
+ * return {
474
+ * fetch: Effect.gen(function* () {
475
+ * const value = yield* kv.get("my-key");
476
+ * return HttpServerResponse.text(value ?? "not found");
477
+ * }),
478
+ * };
479
+ * ```
480
+ *
481
+ * @section D1 Database
482
+ * Bind a D1 database with `Cloudflare.D1Connection.bind`. D1 is a
483
+ * serverless SQLite database — use `prepare` to build parameterized
484
+ * queries and `all`, `first`, or `run` to execute them.
485
+ *
486
+ * @example Binding and querying D1
487
+ * ```typescript
488
+ * // init
489
+ * const db = yield* Cloudflare.D1Connection.bind(MyDB);
490
+ *
491
+ * return {
492
+ * fetch: Effect.gen(function* () {
493
+ * const results = yield* db
494
+ * .prepare("SELECT * FROM users WHERE id = ?")
495
+ * .bind(userId)
496
+ * .all();
497
+ * return yield* HttpServerResponse.json(results);
498
+ * }),
499
+ * };
500
+ * ```
501
+ *
502
+ * @section Durable Objects
503
+ * Yield a `DurableObjectNamespace` class in the init phase to get a
504
+ * namespace handle. Call `getByName` or `getById` to get a typed RPC
505
+ * stub, then call its methods from your runtime handlers.
506
+ *
507
+ * @example Using a Durable Object
508
+ * ```typescript
509
+ * // init
510
+ * const counters = yield* Counter;
511
+ *
512
+ * return {
513
+ * fetch: Effect.gen(function* () {
514
+ * const counter = counters.getByName("user-123");
515
+ * const value = yield* counter.increment();
516
+ * return HttpServerResponse.text(String(value));
517
+ * }),
518
+ * };
519
+ * ```
520
+ *
521
+ * @section Containers
522
+ * Containers run long-lived processes alongside Durable Objects. Bind
523
+ * one with `Cloudflare.Container.bind` and start it with
524
+ * `Cloudflare.start`. You can call typed methods on the running
525
+ * container or make HTTP requests to its exposed ports.
526
+ *
527
+ * @example Binding and starting a Container
528
+ * ```typescript
529
+ * // init (inside a DurableObjectNamespace)
530
+ * const sandbox = yield* Cloudflare.Container.bind(Sandbox);
531
+ *
532
+ * return Effect.gen(function* () {
533
+ * const container = yield* Cloudflare.start(sandbox);
534
+ *
535
+ * return {
536
+ * exec: (cmd: string) => container.exec(cmd),
537
+ * fetch: Effect.gen(function* () {
538
+ * const { fetch } = yield* container.getTcpPort(3000);
539
+ * const res = yield* fetch(HttpClientRequest.get("http://container/"));
540
+ * return HttpServerResponse.fromClientResponse(res);
541
+ * }),
542
+ * };
268
543
  * });
269
544
  * ```
545
+ *
546
+ * @section Dynamic Workers
547
+ * `DynamicWorkerLoader` lets you spin up ephemeral Workers at runtime
548
+ * from inline JavaScript modules. This is useful for sandboxing
549
+ * user-provided code or running untrusted scripts in isolation.
550
+ *
551
+ * @example Loading a dynamic Worker
552
+ * ```typescript
553
+ * // init
554
+ * const loader = yield* Cloudflare.DynamicWorkerLoader("Loader");
555
+ *
556
+ * return {
557
+ * fetch: Effect.gen(function* () {
558
+ * const worker = loader.load({
559
+ * compatibilityDate: "2026-01-28",
560
+ * mainModule: "worker.js",
561
+ * modules: {
562
+ * "worker.js": `export default {
563
+ * async fetch(req) { return new Response("sandboxed"); }
564
+ * }`,
565
+ * },
566
+ * });
567
+ *
568
+ * const res = yield* worker.fetch(
569
+ * HttpClientRequest.get("https://worker/"),
570
+ * );
571
+ * return HttpServerResponse.fromClientResponse(res);
572
+ * }),
573
+ * };
574
+ * ```
270
575
  */
271
576
  export const Worker: Platform<
272
577
  Worker,