alchemy 2.0.0-beta.82 → 2.0.0-beta.83
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.
- package/lib/Cloudflare/Containers/Container.d.ts +128 -40
- package/lib/Cloudflare/Containers/Container.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/Container.js +124 -24
- package/lib/Cloudflare/Containers/Container.js.map +1 -1
- package/lib/Cloudflare/Containers/ContainerApplication.d.ts +59 -50
- package/lib/Cloudflare/Containers/ContainerApplication.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/ContainerApplication.js.map +1 -1
- package/lib/Cloudflare/Containers/ContainerClient.d.ts +20 -7
- package/lib/Cloudflare/Containers/ContainerClient.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/ContainerClient.js +22 -5
- package/lib/Cloudflare/Containers/ContainerClient.js.map +1 -1
- package/lib/Cloudflare/Containers/ContainerConfiguration.d.ts +132 -13
- package/lib/Cloudflare/Containers/ContainerConfiguration.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/ContainerConfiguration.js +219 -35
- package/lib/Cloudflare/Containers/ContainerConfiguration.js.map +1 -1
- package/lib/Cloudflare/Containers/ContainerPlatform.d.ts +1 -1
- package/lib/Cloudflare/Containers/ContainerPlatform.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/ContainerPlatform.js +21 -2
- package/lib/Cloudflare/Containers/ContainerPlatform.js.map +1 -1
- package/lib/Cloudflare/Containers/ContainerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/ContainerProvider.js +74 -177
- package/lib/Cloudflare/Containers/ContainerProvider.js.map +1 -1
- package/lib/Cloudflare/Containers/DurableObjectApplication.d.ts +84 -0
- package/lib/Cloudflare/Containers/DurableObjectApplication.d.ts.map +1 -0
- package/lib/Cloudflare/Containers/DurableObjectApplication.js +249 -0
- package/lib/Cloudflare/Containers/DurableObjectApplication.js.map +1 -0
- package/lib/Cloudflare/Containers/LocalContainerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/LocalContainerProvider.js +20 -41
- package/lib/Cloudflare/Containers/LocalContainerProvider.js.map +1 -1
- package/lib/Cloudflare/Containers/index.d.ts +2 -1
- package/lib/Cloudflare/Containers/index.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/index.js +2 -1
- package/lib/Cloudflare/Containers/index.js.map +1 -1
- package/lib/Cloudflare/Providers.d.ts.map +1 -1
- package/lib/Cloudflare/Providers.js +2 -1
- package/lib/Cloudflare/Providers.js.map +1 -1
- package/lib/Cloudflare/StateStore/Api.d.ts +3 -0
- package/lib/Cloudflare/Workers/DurableObject.d.ts +75 -1
- package/lib/Cloudflare/Workers/DurableObject.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/DurableObject.js +50 -0
- package/lib/Cloudflare/Workers/DurableObject.js.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js +29 -23
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js.map +1 -1
- package/lib/Cloudflare/Workers/Worker.d.ts +2 -0
- package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Worker.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.js +67 -4
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBinding.d.ts +6 -0
- package/lib/Cloudflare/Workers/WorkerBinding.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerProvider.js +54 -8
- package/lib/Cloudflare/Workers/WorkerProvider.js.map +1 -1
- package/lib/State/HttpStateApi.d.ts +13 -13
- package/package.json +6 -6
- package/src/Cloudflare/Containers/Container.ts +126 -56
- package/src/Cloudflare/Containers/ContainerApplication.ts +60 -53
- package/src/Cloudflare/Containers/ContainerClient.ts +47 -13
- package/src/Cloudflare/Containers/ContainerConfiguration.ts +316 -44
- package/src/Cloudflare/Containers/ContainerPlatform.ts +27 -3
- package/src/Cloudflare/Containers/ContainerProvider.ts +96 -256
- package/src/Cloudflare/Containers/DurableObjectApplication.ts +382 -0
- package/src/Cloudflare/Containers/LocalContainerProvider.ts +20 -48
- package/src/Cloudflare/Containers/index.ts +10 -0
- package/src/Cloudflare/Providers.ts +2 -0
- package/src/Cloudflare/Workers/DurableObject.ts +77 -1
- package/src/Cloudflare/Workers/LocalWorkerProvider.ts +32 -21
- package/src/Cloudflare/Workers/Worker.ts +2 -0
- package/src/Cloudflare/Workers/WorkerAsyncBindings.ts +95 -4
- package/src/Cloudflare/Workers/WorkerProvider.ts +78 -13
|
@@ -107,37 +107,37 @@ export declare const VersionResponse: Schema.Struct<{
|
|
|
107
107
|
export declare const GetVersion: HttpApiEndpoint.HttpApiEndpoint<"getVersion", "GET", "/version", never, never, never, never, Schema.toCodecJson<Schema.Struct<{
|
|
108
108
|
readonly version: Schema.Number;
|
|
109
109
|
}>>, never, never, never>;
|
|
110
|
-
declare const StateGroup_base: HttpApiGroup.HttpApiGroup<"state", HttpApiEndpoint.HttpApiEndpoint<"
|
|
111
|
-
readonly stack: Schema.String;
|
|
112
|
-
}>>, never, never, never, Schema.toCodecJson<Schema.$Array<Schema.String>>, never, StateAuth, BearerTokenValidator> | HttpApiEndpoint.HttpApiEndpoint<"deleteStack", "DELETE", "/state/stacks/:stack", Schema.toCodecStringTree<Schema.Struct<{
|
|
110
|
+
declare const StateGroup_base: HttpApiGroup.HttpApiGroup<"state", HttpApiEndpoint.HttpApiEndpoint<"deleteStack", "DELETE", "/state/stacks/:stack", Schema.toCodecStringTree<Schema.Struct<{
|
|
113
111
|
readonly stack: Schema.String;
|
|
114
112
|
}>>, Schema.toCodecStringTree<Schema.Struct<{
|
|
115
113
|
readonly stage: Schema.optional<Schema.String>;
|
|
116
|
-
}>>, never, never, Schema.toCodecJson<HttpApiSchema.NoContent>, never, StateAuth, BearerTokenValidator> | HttpApiEndpoint.HttpApiEndpoint<"
|
|
114
|
+
}>>, never, never, Schema.toCodecJson<HttpApiSchema.NoContent>, never, StateAuth, BearerTokenValidator> | HttpApiEndpoint.HttpApiEndpoint<"deleteState", "DELETE", "/state/stacks/:stack/stages/:stage/resources/:fqn", Schema.toCodecStringTree<Schema.Struct<{
|
|
117
115
|
readonly stack: Schema.String;
|
|
118
116
|
readonly stage: Schema.String;
|
|
119
|
-
|
|
117
|
+
readonly fqn: Schema.String;
|
|
118
|
+
}>>, never, never, never, Schema.toCodecJson<HttpApiSchema.NoContent>, never, StateAuth, BearerTokenValidator> | HttpApiEndpoint.HttpApiEndpoint<"getReplacedResources", "GET", "/state/stacks/:stack/stages/:stage/replaced-resources", Schema.toCodecStringTree<Schema.Struct<{
|
|
120
119
|
readonly stack: Schema.String;
|
|
121
120
|
readonly stage: Schema.String;
|
|
122
|
-
}>>, never, never, never, Schema.toCodecJson<Schema.$Array<Schema.
|
|
121
|
+
}>>, never, never, never, Schema.toCodecJson<Schema.$Array<Schema.Any>>, never, StateAuth, BearerTokenValidator> | HttpApiEndpoint.HttpApiEndpoint<"getStackOutput", "GET", "/state/stacks/:stack/stages/:stage/output", Schema.toCodecStringTree<Schema.Struct<{
|
|
123
122
|
readonly stack: Schema.String;
|
|
124
123
|
readonly stage: Schema.String;
|
|
125
|
-
}>>, never,
|
|
124
|
+
}>>, never, never, never, Schema.toCodecJson<Schema.UndefinedOr<Schema.Any>>, never, StateAuth, BearerTokenValidator> | HttpApiEndpoint.HttpApiEndpoint<"getState", "GET", "/state/stacks/:stack/stages/:stage/resources/:fqn", Schema.toCodecStringTree<Schema.Struct<{
|
|
126
125
|
readonly stack: Schema.String;
|
|
127
126
|
readonly stage: Schema.String;
|
|
128
|
-
|
|
127
|
+
readonly fqn: Schema.String;
|
|
128
|
+
}>>, never, never, never, Schema.toCodecJson<Schema.UndefinedOr<Schema.Any>>, never, StateAuth, BearerTokenValidator> | HttpApiEndpoint.HttpApiEndpoint<"listResources", "GET", "/state/stacks/:stack/stages/:stage/resources", Schema.toCodecStringTree<Schema.Struct<{
|
|
129
129
|
readonly stack: Schema.String;
|
|
130
130
|
readonly stage: Schema.String;
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
}>>, never, never, never, Schema.toCodecJson<Schema.$Array<Schema.String>>, never, StateAuth, BearerTokenValidator> | HttpApiEndpoint.HttpApiEndpoint<"listStacks", "GET", "/state/stacks", never, never, never, never, Schema.toCodecJson<Schema.$Array<Schema.String>>, never, StateAuth, BearerTokenValidator> | HttpApiEndpoint.HttpApiEndpoint<"listStages", "GET", "/state/stacks/:stack/stages", Schema.toCodecStringTree<Schema.Struct<{
|
|
132
|
+
readonly stack: Schema.String;
|
|
133
|
+
}>>, never, never, never, Schema.toCodecJson<Schema.$Array<Schema.String>>, never, StateAuth, BearerTokenValidator> | HttpApiEndpoint.HttpApiEndpoint<"setStackOutput", "PUT", "/state/stacks/:stack/stages/:stage/output", Schema.toCodecStringTree<Schema.Struct<{
|
|
133
134
|
readonly stack: Schema.String;
|
|
134
135
|
readonly stage: Schema.String;
|
|
135
|
-
|
|
136
|
-
}>>, never, never, never, Schema.toCodecJson<HttpApiSchema.NoContent>, never, StateAuth, BearerTokenValidator> | HttpApiEndpoint.HttpApiEndpoint<"getState", "GET", "/state/stacks/:stack/stages/:stage/resources/:fqn", Schema.toCodecStringTree<Schema.Struct<{
|
|
136
|
+
}>>, never, Schema.toCodecJson<Schema.Any>, never, Schema.toCodecJson<Schema.Any>, never, StateAuth, BearerTokenValidator> | HttpApiEndpoint.HttpApiEndpoint<"setState", "PUT", "/state/stacks/:stack/stages/:stage/resources/:fqn", Schema.toCodecStringTree<Schema.Struct<{
|
|
137
137
|
readonly stack: Schema.String;
|
|
138
138
|
readonly stage: Schema.String;
|
|
139
139
|
readonly fqn: Schema.String;
|
|
140
|
-
}>>, never,
|
|
140
|
+
}>>, never, Schema.toCodecJson<Schema.Any>, never, Schema.toCodecJson<Schema.Any>, never, StateAuth, BearerTokenValidator>, false>;
|
|
141
141
|
export declare class StateGroup extends StateGroup_base {
|
|
142
142
|
}
|
|
143
143
|
declare const VersionGroup_base: HttpApiGroup.HttpApiGroup<"version", HttpApiEndpoint.HttpApiEndpoint<"getVersion", "GET", "/version", never, never, never, never, Schema.toCodecJson<Schema.Struct<{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alchemy",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.83",
|
|
4
4
|
"description": "Infrastructure as Effects for TypeScript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"alchemy",
|
|
@@ -333,9 +333,9 @@
|
|
|
333
333
|
"access": "public"
|
|
334
334
|
},
|
|
335
335
|
"dependencies": {
|
|
336
|
-
"@alchemy.run/cloudflare-runtime": "2.0.0-beta.
|
|
337
|
-
"@alchemy.run/floci": "2.0.0-beta.
|
|
338
|
-
"@alchemy.run/node-utils": "2.0.0-beta.
|
|
336
|
+
"@alchemy.run/cloudflare-runtime": "2.0.0-beta.83",
|
|
337
|
+
"@alchemy.run/floci": "2.0.0-beta.83",
|
|
338
|
+
"@alchemy.run/node-utils": "2.0.0-beta.83",
|
|
339
339
|
"@alchemy.run/sigil": "0.1.0-alpha.1",
|
|
340
340
|
"@distilled.cloud/acme": "1.0.0-rc.15",
|
|
341
341
|
"@distilled.cloud/aws": "1.0.0-rc.15",
|
|
@@ -373,7 +373,7 @@
|
|
|
373
373
|
"yaml": "^2.9.0"
|
|
374
374
|
},
|
|
375
375
|
"devDependencies": {
|
|
376
|
-
"@alchemy.run/frontend-frameworks": "2.0.0-beta.
|
|
376
|
+
"@alchemy.run/frontend-frameworks": "2.0.0-beta.83",
|
|
377
377
|
"@aws/durable-execution-sdk-js": "^2.1.0",
|
|
378
378
|
"@cloudflare/containers": "^0.3.7",
|
|
379
379
|
"@cloudflare/puppeteer": "^1.1.0",
|
|
@@ -447,7 +447,7 @@
|
|
|
447
447
|
"ws": "^8.21.0"
|
|
448
448
|
},
|
|
449
449
|
"peerDependencies": {
|
|
450
|
-
"@alchemy.run/frontend-frameworks": "2.0.0-beta.
|
|
450
|
+
"@alchemy.run/frontend-frameworks": "2.0.0-beta.83",
|
|
451
451
|
"@aws/durable-execution-sdk-js": "^2.1.0",
|
|
452
452
|
"@effect/platform-bun": "^4.0.0",
|
|
453
453
|
"@effect/platform-node": "^4.0.0",
|
|
@@ -76,7 +76,6 @@ export class ContainerNotRunningError extends Data.TaggedError("ContainerNotRunn
|
|
|
76
76
|
export type ContainerStartupOptions = cf.ContainerStartupOptions;
|
|
77
77
|
|
|
78
78
|
import type {
|
|
79
|
-
ContainerImageProps,
|
|
80
79
|
DurableObjectContainerProps,
|
|
81
80
|
EffectfulContainerProps,
|
|
82
81
|
ExternalContainerProps,
|
|
@@ -129,24 +128,11 @@ export type ImageContainerProps<Req = never> =
|
|
|
129
128
|
Req
|
|
130
129
|
>;
|
|
131
130
|
|
|
132
|
-
/**
|
|
133
|
-
* Durable Object container props with statically known image names, so the
|
|
134
|
-
* native client can type `images.<name>` as present.
|
|
135
|
-
*/
|
|
136
|
-
type NamedImageProps<ImageName extends string> = Omit<DurableObjectContainerProps, "images"> & {
|
|
137
|
-
images: Record<ImageName, ContainerImageProps>;
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
type NamedImageContainerProps<ImageName extends string, Req> =
|
|
141
|
-
| InputProps<NamedImageProps<ImageName>>
|
|
142
|
-
| Effect.Effect<InputProps<NamedImageProps<ImageName>>, Config.ConfigError, Req>;
|
|
143
|
-
|
|
144
131
|
/**
|
|
145
132
|
* The handle `yield* MyContainer` returns inside a Durable Object. See
|
|
146
133
|
* {@link ContainerClient}.
|
|
147
134
|
*/
|
|
148
|
-
export type Container<Id extends string = string
|
|
149
|
-
ContainerClient<ImageName>;
|
|
135
|
+
export type Container<Id extends string = string> = Named<Id> & ContainerClient;
|
|
150
136
|
|
|
151
137
|
/** An RPC shape may not redeclare the container handle's own methods. */
|
|
152
138
|
type ContainerShape<Shape> = {
|
|
@@ -283,39 +269,37 @@ type ContainerShape<Shape> = {
|
|
|
283
269
|
* ```
|
|
284
270
|
*
|
|
285
271
|
* ### Native Durable Object Containers
|
|
286
|
-
* Use `schedulingPolicy: "durable_object"` to
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
* snapshot without publishing an image.
|
|
272
|
+
* Use `schedulingPolicy: "durable_object"` to let a Durable Object pick its
|
|
273
|
+
* image and instance size at runtime. One Container is one image: `image`
|
|
274
|
+
* copies a registry image, `context`/`dockerfile` builds one. Alchemy pins the
|
|
275
|
+
* image to a digest and prepares it before the Worker is uploaded.
|
|
291
276
|
*
|
|
292
|
-
* `yield*
|
|
293
|
-
* `
|
|
294
|
-
* an exit code, and an
|
|
277
|
+
* `yield* Node` returns the container's handle without starting it.
|
|
278
|
+
* `start()` starts the Container's own image. Its `exec` takes an argument
|
|
279
|
+
* vector and returns a scoped process with streams, an exit code, and an
|
|
280
|
+
* `output()` collector.
|
|
295
281
|
*
|
|
296
|
-
* **Example:** Execute a command in a
|
|
282
|
+
* **Example:** Execute a command in a Container's image
|
|
297
283
|
* ```typescript
|
|
298
|
-
* export class
|
|
284
|
+
* export class Node extends Cloudflare.Container<Node>()("Node", {
|
|
299
285
|
* schedulingPolicy: "durable_object",
|
|
300
|
-
*
|
|
286
|
+
* image: "node:24-slim",
|
|
301
287
|
* }) {}
|
|
302
288
|
*
|
|
303
289
|
* export class Agent extends Cloudflare.DurableObject<Agent>()(
|
|
304
290
|
* "Agent",
|
|
305
291
|
* Effect.gen(function* () {
|
|
306
|
-
* const
|
|
292
|
+
* const node = yield* Node;
|
|
307
293
|
* return Effect.succeed({
|
|
308
294
|
* exec: (args: string[]) =>
|
|
309
295
|
* Effect.gen(function* () {
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
* yield* sandbox.start({
|
|
313
|
-
* image: images.node,
|
|
296
|
+
* // Starts the Node image; a no-op when the container is running.
|
|
297
|
+
* yield* node.start({
|
|
314
298
|
* instance: "lite",
|
|
315
299
|
* entrypoint: ["sleep", "infinity"],
|
|
316
300
|
* enableInternet: false,
|
|
317
301
|
* });
|
|
318
|
-
* const process = yield*
|
|
302
|
+
* const process = yield* node.exec(args);
|
|
319
303
|
* const result = yield* process.output();
|
|
320
304
|
* return { text: new TextDecoder().decode(result.stdout), exitCode: result.exitCode };
|
|
321
305
|
* }).pipe(Effect.scoped),
|
|
@@ -324,13 +308,62 @@ type ContainerShape<Shape> = {
|
|
|
324
308
|
* ) {}
|
|
325
309
|
* ```
|
|
326
310
|
*
|
|
311
|
+
* ### Several Images in One Durable Object
|
|
312
|
+
* Cloudflare gives each Durable Object class one container application and
|
|
313
|
+
* each object one container instance. Bind several Containers to choose
|
|
314
|
+
* between their images. Every binding adds its image to the class's
|
|
315
|
+
* application under the Container's id. Each handle's `start()` starts its
|
|
316
|
+
* own image; start one at a time and `destroy()` before switching.
|
|
317
|
+
*
|
|
318
|
+
* **Example:** A Durable Object with Node and Python images
|
|
319
|
+
* ```typescript
|
|
320
|
+
* export class Node extends Cloudflare.Container<Node>()("Node", {
|
|
321
|
+
* schedulingPolicy: "durable_object",
|
|
322
|
+
* image: "node:24-slim",
|
|
323
|
+
* }) {}
|
|
324
|
+
*
|
|
325
|
+
* export class Python extends Cloudflare.Container<Python>()("Python", {
|
|
326
|
+
* schedulingPolicy: "durable_object",
|
|
327
|
+
* context: "./python",
|
|
328
|
+
* }) {}
|
|
329
|
+
*
|
|
330
|
+
* export class Agent extends Cloudflare.DurableObject<Agent>()(
|
|
331
|
+
* "Agent",
|
|
332
|
+
* Effect.gen(function* () {
|
|
333
|
+
* const node = yield* Node;
|
|
334
|
+
* const python = yield* Python;
|
|
335
|
+
* const run = (cmd: string[]) =>
|
|
336
|
+
* Effect.scoped(Effect.flatMap(node.exec(cmd), (process) => process.output()));
|
|
337
|
+
* return Effect.succeed({
|
|
338
|
+
* node: (cmd: string[]) =>
|
|
339
|
+
* node
|
|
340
|
+
* .start({ entrypoint: ["sleep", "infinity"], enableInternet: false })
|
|
341
|
+
* .pipe(Effect.andThen(run(cmd))),
|
|
342
|
+
* python: (cmd: string[]) =>
|
|
343
|
+
* Effect.gen(function* () {
|
|
344
|
+
* // Every handle controls the same instance: switch images explicitly.
|
|
345
|
+
* if (yield* node.running) yield* node.destroy();
|
|
346
|
+
* yield* python.start({ entrypoint: ["sleep", "infinity"], enableInternet: false });
|
|
347
|
+
* return yield* Effect.scoped(
|
|
348
|
+
* Effect.flatMap(python.exec(cmd), (process) => process.output()),
|
|
349
|
+
* );
|
|
350
|
+
* }),
|
|
351
|
+
* });
|
|
352
|
+
* }),
|
|
353
|
+
* ) {}
|
|
354
|
+
* ```
|
|
355
|
+
*
|
|
356
|
+
* Application-wide settings (`ssh`, `authorizedKeys`, `observability`) may be
|
|
357
|
+
* declared on any of the class's Containers. Two Containers declaring
|
|
358
|
+
* different values fail the deploy with `ContainerApplicationSettingsConflict`.
|
|
359
|
+
*
|
|
327
360
|
* **Example:** Save and restore the writable filesystem
|
|
328
361
|
* ```typescript
|
|
329
|
-
* const snapshot = yield*
|
|
362
|
+
* const snapshot = yield* node.snapshotContainer({ name: "workspace" });
|
|
330
363
|
* // Persist this handle in Durable Object storage before stopping the instance.
|
|
331
364
|
* yield* state.storage.put("snapshot", snapshot);
|
|
332
|
-
* yield*
|
|
333
|
-
* yield*
|
|
365
|
+
* yield* node.destroy();
|
|
366
|
+
* yield* node.start({
|
|
334
367
|
* containerSnapshot: snapshot,
|
|
335
368
|
* entrypoint: ["sleep", "infinity"],
|
|
336
369
|
* enableInternet: false,
|
|
@@ -344,9 +377,62 @@ type ContainerShape<Shape> = {
|
|
|
344
377
|
* when needed. Scope closure kills an unfinished exec process, but does not
|
|
345
378
|
* signal its descendants. Use an Effect timeout to bound a command's lifetime.
|
|
346
379
|
*
|
|
347
|
-
* Native
|
|
348
|
-
*
|
|
349
|
-
*
|
|
380
|
+
* ### Native Durable Objects on Async Workers
|
|
381
|
+
* A plain Durable Object class on an async Worker attaches its Containers
|
|
382
|
+
* through its Durable Object binding:
|
|
383
|
+
* `Cloudflare.DurableObject(className, { containers })`. Each Container adds
|
|
384
|
+
* its image to the class's application, and the class reads it from
|
|
385
|
+
* `ctx.container.images` under the Container's id. A Container may be listed
|
|
386
|
+
* by several classes; each class gets its own copy of the image key.
|
|
387
|
+
*
|
|
388
|
+
* **Example:** Two classes sharing the Node image
|
|
389
|
+
* ```typescript
|
|
390
|
+
* // alchemy.run.ts
|
|
391
|
+
* const Node = Cloudflare.Container("Node", {
|
|
392
|
+
* schedulingPolicy: "durable_object",
|
|
393
|
+
* image: "node:24-slim",
|
|
394
|
+
* });
|
|
395
|
+
* const Python = Cloudflare.Container("Python", {
|
|
396
|
+
* schedulingPolicy: "durable_object",
|
|
397
|
+
* image: "python:3.13-slim",
|
|
398
|
+
* });
|
|
399
|
+
* const Rust = Cloudflare.Container("Rust", {
|
|
400
|
+
* schedulingPolicy: "durable_object",
|
|
401
|
+
* image: "rust:1.90-slim",
|
|
402
|
+
* });
|
|
403
|
+
* export const Worker = Cloudflare.Worker("App", {
|
|
404
|
+
* main: "./src/worker.ts",
|
|
405
|
+
* env: {
|
|
406
|
+
* AGENT: Cloudflare.DurableObject("Agent", { containers: [Node, Python] }),
|
|
407
|
+
* REVIEWER: Cloudflare.DurableObject("Reviewer", { containers: [Node, Rust] }),
|
|
408
|
+
* },
|
|
409
|
+
* });
|
|
410
|
+
* ```
|
|
411
|
+
*
|
|
412
|
+
* A Durable Object-managed Container placed directly in `env` fails with
|
|
413
|
+
* `DurableObjectContainerBindingError`; only fleet Containers bind that way.
|
|
414
|
+
*
|
|
415
|
+
* **Example:** Starting an image from the class
|
|
416
|
+
* ```typescript
|
|
417
|
+
* // src/worker.ts
|
|
418
|
+
* import { DurableObject } from "cloudflare:workers";
|
|
419
|
+
*
|
|
420
|
+
* export class Agent extends DurableObject {
|
|
421
|
+
* async run(cmd: string[]) {
|
|
422
|
+
* const container = this.ctx.container!;
|
|
423
|
+
* if (!container.running) {
|
|
424
|
+
* container.start({
|
|
425
|
+
* image: container.images.Node,
|
|
426
|
+
* entrypoint: ["sleep", "infinity"],
|
|
427
|
+
* enableInternet: false,
|
|
428
|
+
* });
|
|
429
|
+
* }
|
|
430
|
+
* return (await container.exec(cmd)).output();
|
|
431
|
+
* }
|
|
432
|
+
* }
|
|
433
|
+
* ```
|
|
434
|
+
*
|
|
435
|
+
* Local development runs every image through workerd and Docker.
|
|
350
436
|
*
|
|
351
437
|
* Switching an existing application to this scheduling policy requires a new
|
|
352
438
|
* application and a new Durable Object class/namespace. Alchemy rejects an
|
|
@@ -683,7 +769,7 @@ type ContainerShape<Shape> = {
|
|
|
683
769
|
* ```
|
|
684
770
|
*
|
|
685
771
|
* A container's shape cannot declare a method the handle already has
|
|
686
|
-
* (`start`, `exec`, `
|
|
772
|
+
* (`start`, `exec`, `image`, `getTcpPort`, …); declaring one is a type
|
|
687
773
|
* error, because the handle's method would shadow the RPC call.
|
|
688
774
|
*
|
|
689
775
|
* ### Using a Container from a Layer
|
|
@@ -742,24 +828,11 @@ type ContainerShape<Shape> = {
|
|
|
742
828
|
*/
|
|
743
829
|
export const Container: ResourceClassLike<ContainerApplication> &
|
|
744
830
|
Pick<ResourceClass<ContainerApplication>, "ref"> & {
|
|
745
|
-
<
|
|
746
|
-
DOShape = unknown,
|
|
747
|
-
const Id extends string = string,
|
|
748
|
-
PropsReq = never,
|
|
749
|
-
ImageName extends string = string,
|
|
750
|
-
>(
|
|
751
|
-
id: Id,
|
|
752
|
-
props: NamedImageContainerProps<ImageName, PropsReq>,
|
|
753
|
-
): Container.Decl<Container<Id, ImageName>, {}, Id, PropsReq, DOShape, ImageName>;
|
|
754
831
|
<DOShape = unknown, const Id extends string = string, PropsReq = never>(
|
|
755
832
|
id: Id,
|
|
756
833
|
props: ImageContainerProps<PropsReq>,
|
|
757
834
|
): Container.Decl<Container<Id>, {}, Id, PropsReq, DOShape>;
|
|
758
835
|
<Self>(): {
|
|
759
|
-
<const Id extends string, ImageName extends string, PropsReq = never>(
|
|
760
|
-
id: Id,
|
|
761
|
-
props: NamedImageContainerProps<ImageName, PropsReq>,
|
|
762
|
-
): Container.Decl<Self, {}, Id, PropsReq, unknown, ImageName>;
|
|
763
836
|
<const Id extends string, PropsReq = never>(
|
|
764
837
|
id: Id,
|
|
765
838
|
props: ImageContainerProps<PropsReq>,
|
|
@@ -837,18 +910,15 @@ export declare namespace Container {
|
|
|
837
910
|
Id extends string = string,
|
|
838
911
|
Req = never,
|
|
839
912
|
DOShape = unknown,
|
|
840
|
-
ImageName extends string = string,
|
|
841
913
|
>
|
|
842
914
|
extends Effect.Effect<Self, never, Providers | Req>, Rpc<Shape>, Named<Id> {
|
|
843
|
-
new (): Container<Id
|
|
915
|
+
new (): Container<Id> & Shape;
|
|
844
916
|
/**
|
|
845
917
|
* @internal phantom — the Durable Object class type backing this
|
|
846
918
|
* container when it is bound on an async Worker's `env`. Drives
|
|
847
919
|
* `InferEnv` (`env.NAME` becomes `DurableObjectNamespace<DOShape>`).
|
|
848
920
|
*/
|
|
849
921
|
readonly "~alchemy/Container/Shape": DOShape;
|
|
850
|
-
/** @internal phantom — required image names available to the native client. */
|
|
851
|
-
readonly "~alchemy/Container/Images": ImageName;
|
|
852
922
|
/**
|
|
853
923
|
* @internal — the explicit `className` from props (`undefined` defaults
|
|
854
924
|
* to the binding name at bind time). Doubles as the runtime marker that
|
|
@@ -384,70 +384,73 @@ export interface ContainerSshConfiguration {
|
|
|
384
384
|
port?: number;
|
|
385
385
|
}
|
|
386
386
|
|
|
387
|
-
/**
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
/** Dockerfile path or inline content. Defaults to the context's Dockerfile. */
|
|
403
|
-
dockerfile?: string | InlineDockerfile;
|
|
404
|
-
}
|
|
405
|
-
);
|
|
387
|
+
/**
|
|
388
|
+
* Application-wide settings of a Durable Object class's container application.
|
|
389
|
+
* Every Container bound to the class may declare them; declarations must agree.
|
|
390
|
+
*/
|
|
391
|
+
export interface DurableObjectApplicationSettings {
|
|
392
|
+
/**
|
|
393
|
+
* SSH access to every instance of the application. Removing a previously
|
|
394
|
+
* declared value disables SSH.
|
|
395
|
+
*/
|
|
396
|
+
ssh?: ContainerSshConfiguration;
|
|
397
|
+
/** SSH public keys allowed to access instances. Removing this property clears previously managed keys. */
|
|
398
|
+
authorizedKeys?: Containers.UserSSHPublicKeyList;
|
|
399
|
+
/** Application-wide logging. Removing a previously declared value disables logs. Changes do not restart running containers. */
|
|
400
|
+
observability?: Containers.ContainerApplicationObservability;
|
|
401
|
+
}
|
|
406
402
|
|
|
407
403
|
/**
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
*
|
|
404
|
+
* One image a Durable Object starts with `ctx.container.start()`.
|
|
405
|
+
*
|
|
406
|
+
* Cloudflare allows one container application per Durable Object class. Every
|
|
407
|
+
* `durable_object` Container bound to the class adds its image to that
|
|
408
|
+
* application, under the Container's id. Bind several Containers to start
|
|
409
|
+
* different images from the same class, one at a time. One Container may be
|
|
410
|
+
* bound to several classes.
|
|
411
|
+
*
|
|
412
|
+
* An Effect-native Durable Object binds a Container with `yield*`. An async
|
|
413
|
+
* Worker attaches it to a class with
|
|
414
|
+
* `Cloudflare.DurableObject(className, { containers })`.
|
|
415
|
+
*
|
|
416
|
+
* The policy is immutable: migrating an existing fleet application requires a
|
|
417
|
+
* new application and Durable Object namespace.
|
|
411
418
|
*/
|
|
412
|
-
export interface DurableObjectContainerProps
|
|
413
|
-
|
|
414
|
-
name?: string;
|
|
415
|
-
/** Exported Durable Object class, when bound on an async Worker's env. */
|
|
416
|
-
className?: string;
|
|
419
|
+
export interface DurableObjectContainerProps
|
|
420
|
+
extends DurableObjectApplicationSettings, PlatformProps {
|
|
417
421
|
/** Select images and instance sizes in `ctx.container.start()`. */
|
|
418
422
|
schedulingPolicy: "durable_object";
|
|
419
423
|
/**
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
* `cloudflare/debian-trixie` image
|
|
424
|
-
* Supports up to 100 images, with names between 1 and 128 characters.
|
|
424
|
+
* Registry image to copy into Cloudflare's managed registry, e.g.
|
|
425
|
+
* `"node:24-slim"`. Exclusive with {@link context} and {@link dockerfile}.
|
|
426
|
+
* Omit every image source to contribute no image: `start()` then uses the
|
|
427
|
+
* managed `cloudflare/debian-trixie` image unless given another.
|
|
425
428
|
*/
|
|
426
|
-
|
|
429
|
+
image?: string;
|
|
430
|
+
/**
|
|
431
|
+
* Docker build context. Setting `context` or `dockerfile` builds the image;
|
|
432
|
+
* `context` defaults to the current directory.
|
|
433
|
+
*/
|
|
434
|
+
context?: string;
|
|
435
|
+
/** Dockerfile path or inline content. Defaults to the context's Dockerfile. */
|
|
436
|
+
dockerfile?: string | InlineDockerfile;
|
|
437
|
+
/** Image publication and build-cache configuration. */
|
|
438
|
+
publish?: ContainerApplicationPropsBase["publish"];
|
|
427
439
|
/**
|
|
428
|
-
* Maximum wait for Cloudflare to prepare
|
|
440
|
+
* Maximum wait for Cloudflare to prepare the published image, including API calls.
|
|
429
441
|
* Accepts an Effect duration such as "45 minutes". Must be finite and positive.
|
|
430
442
|
* Cancellation stops waiting; another deployment reuses the published registry image.
|
|
431
|
-
* Use an immutable source digest or change the image reference to refresh
|
|
443
|
+
* Use an immutable source digest or change the image reference to refresh the image.
|
|
432
444
|
* @default "30 minutes"
|
|
433
445
|
*/
|
|
434
446
|
imagePreparationTimeout?: Duration.Input;
|
|
435
|
-
/**
|
|
436
|
-
* SSH access to every instance of the application. Removing a previously
|
|
437
|
-
* declared value disables SSH.
|
|
438
|
-
*/
|
|
439
|
-
ssh?: ContainerSshConfiguration;
|
|
440
|
-
/** SSH public keys allowed to access instances. Removing this property clears previously managed keys. */
|
|
441
|
-
authorizedKeys?: Containers.UserSSHPublicKeyList;
|
|
442
|
-
/** Application-wide logging. Removing a previously declared value disables logs. Changes do not restart running containers. */
|
|
443
|
-
observability?: Containers.ContainerApplicationObservability;
|
|
444
447
|
}
|
|
445
448
|
|
|
446
449
|
/**
|
|
447
450
|
* Fleet-scheduled applications select a deployment image through `main`
|
|
448
451
|
* (bundled Effect program), `context`/`dockerfile`, or a pre-built `image`.
|
|
449
|
-
* Durable Object-managed
|
|
450
|
-
*
|
|
452
|
+
* A Durable Object-managed Container publishes one image that its Durable
|
|
453
|
+
* Object selects at runtime.
|
|
451
454
|
*/
|
|
452
455
|
export type ContainerApplicationProps =
|
|
453
456
|
| EffectfulContainerProps
|
|
@@ -468,7 +471,6 @@ export interface AnyContainerApplicationProps extends Omit<
|
|
|
468
471
|
schedulingPolicy?: ContainerApplication.SchedulingPolicy;
|
|
469
472
|
ssh?: ContainerSshConfiguration;
|
|
470
473
|
authorizedKeys?: Containers.UserSSHPublicKeyList;
|
|
471
|
-
images?: Record<string, ContainerImageProps>;
|
|
472
474
|
imagePreparationTimeout?: Duration.Input;
|
|
473
475
|
main?: string;
|
|
474
476
|
image?: string;
|
|
@@ -801,11 +803,15 @@ export interface ContainerApplication<Shape = unknown> extends Resource<
|
|
|
801
803
|
{
|
|
802
804
|
/**
|
|
803
805
|
* Cloudflare-assigned unique identifier of the container application.
|
|
806
|
+
* Empty for a Durable Object-managed Container: the application belongs
|
|
807
|
+
* to the Durable Object class that binds it.
|
|
804
808
|
*/
|
|
805
809
|
applicationId: string;
|
|
806
810
|
/**
|
|
807
811
|
* The resolved application name (either the provided `name` or the
|
|
808
812
|
* deterministic physical name derived from the stack, stage, and logical ID).
|
|
813
|
+
* For a Durable Object-managed Container, the name of its default image
|
|
814
|
+
* repository.
|
|
809
815
|
*/
|
|
810
816
|
applicationName: string;
|
|
811
817
|
/**
|
|
@@ -840,12 +846,14 @@ export interface ContainerApplication<Shape = unknown> extends Resource<
|
|
|
840
846
|
*/
|
|
841
847
|
configuration: Partial<ContainerApplication.Configuration> &
|
|
842
848
|
Containers.DurableObjectContainerConfiguration;
|
|
843
|
-
/** Application-wide logging
|
|
849
|
+
/** Application-wide logging declared by a Durable Object-managed Container. */
|
|
844
850
|
observability?: Containers.ContainerApplicationObservability;
|
|
845
|
-
/**
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
851
|
+
/**
|
|
852
|
+
* The prepared, digest-pinned image of a Durable Object-managed Container,
|
|
853
|
+
* or its local image key in `alchemy dev`. Unset when the Container
|
|
854
|
+
* declares no image source.
|
|
855
|
+
*/
|
|
856
|
+
image?: string;
|
|
849
857
|
/**
|
|
850
858
|
* The Durable Object namespace attached to the application, if it is bound
|
|
851
859
|
* to one.
|
|
@@ -872,7 +880,6 @@ export interface ContainerApplication<Shape = unknown> extends Resource<
|
|
|
872
880
|
image: string;
|
|
873
881
|
digest?: string;
|
|
874
882
|
configuration?: string;
|
|
875
|
-
images?: Record<string, string>;
|
|
876
883
|
};
|
|
877
884
|
dev: DevContainerImage | undefined;
|
|
878
885
|
},
|