alchemy 0.44.3 → 0.45.0
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/bin/alchemy.mjs +0 -13
- package/bin/commands/create.ts +1 -10
- package/bin/services/vibe-rules.ts +0 -14
- package/lib/alchemy.d.ts +3 -3
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js +5 -2
- package/lib/alchemy.js.map +1 -1
- package/lib/build-date.d.ts +1 -1
- package/lib/build-date.js +1 -1
- package/lib/cloudflare/auth.js +1 -1
- package/lib/cloudflare/auth.js.map +1 -1
- package/lib/cloudflare/bundle/esbuild.d.ts +16 -0
- package/lib/cloudflare/bundle/esbuild.d.ts.map +1 -0
- package/lib/cloudflare/bundle/esbuild.js +159 -0
- package/lib/cloudflare/bundle/esbuild.js.map +1 -0
- package/lib/cloudflare/bundle/fs.d.ts +18 -0
- package/lib/cloudflare/bundle/fs.d.ts.map +1 -0
- package/lib/cloudflare/bundle/fs.js +75 -0
- package/lib/cloudflare/bundle/fs.js.map +1 -0
- package/lib/cloudflare/bundle/index.d.ts +3 -0
- package/lib/cloudflare/bundle/index.d.ts.map +1 -0
- package/lib/cloudflare/bundle/index.js +2 -0
- package/lib/cloudflare/bundle/index.js.map +1 -0
- package/lib/cloudflare/bundle/inline.d.ts +12 -0
- package/lib/cloudflare/bundle/inline.d.ts.map +1 -0
- package/lib/cloudflare/bundle/inline.js +32 -0
- package/lib/cloudflare/bundle/inline.js.map +1 -0
- package/lib/cloudflare/bundle/normalize.d.ts +21 -0
- package/lib/cloudflare/bundle/normalize.d.ts.map +1 -0
- package/lib/cloudflare/bundle/normalize.js +49 -0
- package/lib/cloudflare/bundle/normalize.js.map +1 -0
- package/lib/cloudflare/bundle/{nodejs-import-warning-plugin.d.ts → plugin-compat-warning.d.ts} +2 -2
- package/lib/cloudflare/bundle/plugin-compat-warning.d.ts.map +1 -0
- package/lib/cloudflare/bundle/{nodejs-import-warning-plugin.js → plugin-compat-warning.js} +3 -4
- package/lib/cloudflare/bundle/plugin-compat-warning.js.map +1 -0
- package/lib/cloudflare/bundle/plugin-hot-reload.d.ts +8 -0
- package/lib/cloudflare/bundle/plugin-hot-reload.d.ts.map +1 -0
- package/lib/cloudflare/bundle/plugin-hot-reload.js +19 -0
- package/lib/cloudflare/bundle/plugin-hot-reload.js.map +1 -0
- package/lib/cloudflare/bundle/{nodejs-compat.d.ts → plugin-hybrid-node-compat.d.ts} +2 -2
- package/lib/cloudflare/bundle/plugin-hybrid-node-compat.d.ts.map +1 -0
- package/lib/cloudflare/bundle/{nodejs-compat.js → plugin-hybrid-node-compat.js} +10 -10
- package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js.map +1 -0
- package/lib/cloudflare/bundle/plugin-wasm.d.ts +3 -0
- package/lib/cloudflare/bundle/plugin-wasm.d.ts.map +1 -0
- package/lib/cloudflare/bundle/plugin-wasm.js +55 -0
- package/lib/cloudflare/bundle/plugin-wasm.js.map +1 -0
- package/lib/cloudflare/bundle/shared.d.ts +30 -0
- package/lib/cloudflare/bundle/shared.d.ts.map +1 -0
- package/lib/cloudflare/bundle/shared.js +34 -0
- package/lib/cloudflare/bundle/shared.js.map +1 -0
- package/lib/cloudflare/bundle/{nodejs-compat-mode.d.ts → validate-node-compat.d.ts} +8 -4
- package/lib/cloudflare/bundle/validate-node-compat.d.ts.map +1 -0
- package/lib/cloudflare/bundle/{nodejs-compat-mode.js → validate-node-compat.js} +27 -7
- package/lib/cloudflare/bundle/validate-node-compat.js.map +1 -0
- package/lib/cloudflare/container.d.ts +231 -0
- package/lib/cloudflare/container.d.ts.map +1 -1
- package/lib/cloudflare/container.js +7 -0
- package/lib/cloudflare/container.js.map +1 -1
- package/lib/cloudflare/d1-migrations.d.ts +1 -0
- package/lib/cloudflare/d1-migrations.d.ts.map +1 -1
- package/lib/cloudflare/d1-migrations.js +18 -6
- package/lib/cloudflare/d1-migrations.js.map +1 -1
- package/lib/cloudflare/d1-state-store.d.ts +10 -0
- package/lib/cloudflare/d1-state-store.d.ts.map +1 -0
- package/lib/cloudflare/d1-state-store.js +70 -0
- package/lib/cloudflare/d1-state-store.js.map +1 -0
- package/lib/cloudflare/do-state-store/internal.js +1 -1
- package/lib/cloudflare/do-state-store/internal.js.map +1 -1
- package/lib/cloudflare/do-state-store/store.js +1 -1
- package/lib/cloudflare/do-state-store/store.js.map +1 -1
- package/lib/cloudflare/index.d.ts +3 -2
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +3 -2
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/local-dev-cloudflare-shim.d.ts.map +1 -0
- package/lib/cloudflare/{bundle/local-dev-cloudflare-shim.js → local-dev-cloudflare-shim.js} +1 -1
- package/lib/cloudflare/local-dev-cloudflare-shim.js.map +1 -0
- package/lib/cloudflare/miniflare/http-server.d.ts.map +1 -0
- package/lib/cloudflare/miniflare/http-server.js.map +1 -0
- package/lib/cloudflare/{worker → miniflare}/miniflare-worker-options.d.ts +4 -3
- package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts.map +1 -0
- package/lib/cloudflare/{worker → miniflare}/miniflare-worker-options.js +6 -3
- package/lib/cloudflare/miniflare/miniflare-worker-options.js.map +1 -0
- package/lib/cloudflare/miniflare/miniflare.d.ts.map +1 -0
- package/lib/cloudflare/{worker → miniflare}/miniflare.js +1 -1
- package/lib/cloudflare/miniflare/miniflare.js.map +1 -0
- package/lib/cloudflare/miniflare/mixed-mode.d.ts.map +1 -0
- package/lib/cloudflare/{worker → miniflare}/mixed-mode.js +1 -2
- package/lib/cloudflare/miniflare/mixed-mode.js.map +1 -0
- package/lib/cloudflare/user.js +1 -1
- package/lib/cloudflare/user.js.map +1 -1
- package/lib/cloudflare/worker/shared.d.ts +4 -0
- package/lib/cloudflare/worker/shared.d.ts.map +1 -0
- package/lib/cloudflare/worker/{get-worker-template.js → shared.js} +10 -1
- package/lib/cloudflare/worker/shared.js.map +1 -0
- package/lib/cloudflare/worker/tail.d.ts +18 -0
- package/lib/cloudflare/worker/tail.d.ts.map +1 -0
- package/lib/cloudflare/worker/tail.js +140 -0
- package/lib/cloudflare/worker/tail.js.map +1 -0
- package/lib/cloudflare/worker-metadata.d.ts +6 -2
- package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
- package/lib/cloudflare/worker-metadata.js +7 -23
- package/lib/cloudflare/worker-metadata.js.map +1 -1
- package/lib/cloudflare/worker-stub.d.ts.map +1 -1
- package/lib/cloudflare/worker-stub.js +8 -4
- package/lib/cloudflare/worker-stub.js.map +1 -1
- package/lib/cloudflare/worker-subdomain.d.ts +31 -0
- package/lib/cloudflare/worker-subdomain.d.ts.map +1 -0
- package/lib/cloudflare/worker-subdomain.js +55 -0
- package/lib/cloudflare/worker-subdomain.js.map +1 -0
- package/lib/cloudflare/worker.d.ts +30 -28
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +641 -554
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/fs/file-system-state-store.js +1 -1
- package/lib/fs/file-system-state-store.js.map +1 -1
- package/lib/scope.d.ts +2 -2
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +23 -8
- package/lib/scope.js.map +1 -1
- package/lib/serde.d.ts +1 -1
- package/lib/serde.d.ts.map +1 -1
- package/lib/serde.js +4 -4
- package/lib/serde.js.map +1 -1
- package/lib/sqlite/base-sqlite-state-store.d.ts +31 -0
- package/lib/sqlite/base-sqlite-state-store.d.ts.map +1 -0
- package/lib/sqlite/base-sqlite-state-store.js +124 -0
- package/lib/sqlite/base-sqlite-state-store.js.map +1 -0
- package/lib/sqlite/index.d.ts +2 -0
- package/lib/sqlite/index.d.ts.map +1 -0
- package/lib/sqlite/index.js +2 -0
- package/lib/sqlite/index.js.map +1 -0
- package/lib/sqlite/schema.d.ts +198 -0
- package/lib/sqlite/schema.d.ts.map +1 -0
- package/lib/sqlite/schema.js +23 -0
- package/lib/sqlite/schema.js.map +1 -0
- package/lib/sqlite/sqlite-state-store.d.ts +60 -0
- package/lib/sqlite/sqlite-state-store.d.ts.map +1 -0
- package/lib/sqlite/sqlite-state-store.js +83 -0
- package/lib/sqlite/sqlite-state-store.js.map +1 -0
- package/lib/test/bun.d.ts.map +1 -1
- package/lib/test/bun.js +0 -6
- package/lib/test/bun.js.map +1 -1
- package/lib/test/vitest.d.ts.map +1 -1
- package/lib/test/vitest.js +19 -5
- package/lib/test/vitest.js.map +1 -1
- package/lib/util/memoize.d.ts +1 -1
- package/lib/util/memoize.d.ts.map +1 -1
- package/lib/util/memoize.js +11 -1
- package/lib/util/memoize.js.map +1 -1
- package/package.json +12 -3
- package/src/alchemy.ts +8 -6
- package/src/build-date.ts +1 -1
- package/src/cloudflare/auth.ts +1 -1
- package/src/cloudflare/bundle/esbuild.ts +194 -0
- package/src/cloudflare/bundle/fs.ts +98 -0
- package/src/cloudflare/bundle/index.ts +6 -0
- package/src/cloudflare/bundle/inline.ts +42 -0
- package/src/cloudflare/bundle/normalize.ts +76 -0
- package/src/cloudflare/bundle/{nodejs-import-warning-plugin.ts → plugin-compat-warning.ts} +4 -3
- package/src/cloudflare/bundle/plugin-hot-reload.ts +27 -0
- package/src/cloudflare/bundle/{nodejs-compat.ts → plugin-hybrid-node-compat.ts} +10 -10
- package/src/cloudflare/bundle/plugin-wasm.ts +62 -0
- package/src/cloudflare/bundle/shared.ts +73 -0
- package/src/cloudflare/bundle/{nodejs-compat-mode.ts → validate-node-compat.ts} +41 -16
- package/src/cloudflare/container.ts +296 -0
- package/src/cloudflare/d1-migrations.ts +29 -16
- package/src/cloudflare/d1-state-store.ts +105 -0
- package/src/cloudflare/do-state-store/internal.ts +1 -1
- package/src/cloudflare/do-state-store/store.ts +1 -1
- package/src/cloudflare/index.ts +3 -2
- package/src/cloudflare/{bundle/local-dev-cloudflare-shim.ts → local-dev-cloudflare-shim.ts} +1 -1
- package/src/cloudflare/{worker → miniflare}/miniflare-worker-options.ts +14 -6
- package/src/cloudflare/{worker → miniflare}/miniflare.ts +1 -1
- package/src/cloudflare/{worker → miniflare}/mixed-mode.ts +1 -2
- package/src/cloudflare/user.ts +1 -1
- package/src/cloudflare/worker/{subdomain.ts → shared.ts} +14 -0
- package/src/cloudflare/worker/tail.ts +287 -0
- package/src/cloudflare/worker-metadata.ts +18 -26
- package/src/cloudflare/worker-stub.ts +9 -4
- package/src/cloudflare/worker-subdomain.ts +123 -0
- package/src/cloudflare/worker.ts +863 -734
- package/src/fs/file-system-state-store.ts +1 -1
- package/src/scope.ts +30 -11
- package/src/serde.ts +4 -4
- package/src/sqlite/base-sqlite-state-store.ts +199 -0
- package/src/sqlite/index.ts +1 -0
- package/src/sqlite/schema.ts +37 -0
- package/src/sqlite/sqlite-state-store.ts +174 -0
- package/src/test/bun.ts +0 -8
- package/src/test/vitest.ts +19 -8
- package/src/util/memoize.ts +13 -1
- package/templates/astro/types/env.d.ts +1 -1
- package/templates/nuxt/types/env.d.ts +1 -1
- package/templates/react-router/types/env.d.ts +1 -1
- package/templates/rwsdk/types/env.d.ts +1 -1
- package/templates/sveltekit/types/env.d.ts +1 -1
- package/templates/tanstack-start/types/env.d.ts +1 -1
- package/templates/typescript/types/env.d.ts +1 -1
- package/templates/vite/types/env.d.ts +1 -1
- package/lib/cloudflare/bundle/alias-plugin.d.ts +0 -6
- package/lib/cloudflare/bundle/alias-plugin.d.ts.map +0 -1
- package/lib/cloudflare/bundle/alias-plugin.js +0 -36
- package/lib/cloudflare/bundle/alias-plugin.js.map +0 -1
- package/lib/cloudflare/bundle/build-failures.d.ts +0 -12
- package/lib/cloudflare/bundle/build-failures.d.ts.map +0 -1
- package/lib/cloudflare/bundle/build-failures.js +0 -45
- package/lib/cloudflare/bundle/build-failures.js.map +0 -1
- package/lib/cloudflare/bundle/bundle-worker-dev.d.ts +0 -26
- package/lib/cloudflare/bundle/bundle-worker-dev.d.ts.map +0 -1
- package/lib/cloudflare/bundle/bundle-worker-dev.js +0 -88
- package/lib/cloudflare/bundle/bundle-worker-dev.js.map +0 -1
- package/lib/cloudflare/bundle/bundle-worker.d.ts +0 -13
- package/lib/cloudflare/bundle/bundle-worker.d.ts.map +0 -1
- package/lib/cloudflare/bundle/bundle-worker.js +0 -98
- package/lib/cloudflare/bundle/bundle-worker.js.map +0 -1
- package/lib/cloudflare/bundle/external.d.ts +0 -4
- package/lib/cloudflare/bundle/external.d.ts.map +0 -1
- package/lib/cloudflare/bundle/external.js +0 -40
- package/lib/cloudflare/bundle/external.js.map +0 -1
- package/lib/cloudflare/bundle/local-dev-cloudflare-shim.d.ts.map +0 -1
- package/lib/cloudflare/bundle/local-dev-cloudflare-shim.js.map +0 -1
- package/lib/cloudflare/bundle/nodejs-compat-mode.d.ts.map +0 -1
- package/lib/cloudflare/bundle/nodejs-compat-mode.js.map +0 -1
- package/lib/cloudflare/bundle/nodejs-compat.d.ts.map +0 -1
- package/lib/cloudflare/bundle/nodejs-compat.js.map +0 -1
- package/lib/cloudflare/bundle/nodejs-import-warning-plugin.d.ts.map +0 -1
- package/lib/cloudflare/bundle/nodejs-import-warning-plugin.js.map +0 -1
- package/lib/cloudflare/bundle/wasm-plugin.d.ts +0 -3
- package/lib/cloudflare/bundle/wasm-plugin.d.ts.map +0 -1
- package/lib/cloudflare/bundle/wasm-plugin.js +0 -53
- package/lib/cloudflare/bundle/wasm-plugin.js.map +0 -1
- package/lib/cloudflare/worker/get-worker-template.d.ts +0 -2
- package/lib/cloudflare/worker/get-worker-template.d.ts.map +0 -1
- package/lib/cloudflare/worker/get-worker-template.js.map +0 -1
- package/lib/cloudflare/worker/http-server.d.ts.map +0 -1
- package/lib/cloudflare/worker/http-server.js.map +0 -1
- package/lib/cloudflare/worker/miniflare-worker-options.d.ts.map +0 -1
- package/lib/cloudflare/worker/miniflare-worker-options.js.map +0 -1
- package/lib/cloudflare/worker/miniflare.d.ts.map +0 -1
- package/lib/cloudflare/worker/miniflare.js.map +0 -1
- package/lib/cloudflare/worker/mixed-mode.d.ts.map +0 -1
- package/lib/cloudflare/worker/mixed-mode.js.map +0 -1
- package/lib/cloudflare/worker/subdomain.d.ts +0 -3
- package/lib/cloudflare/worker/subdomain.d.ts.map +0 -1
- package/lib/cloudflare/worker/subdomain.js +0 -10
- package/lib/cloudflare/worker/subdomain.js.map +0 -1
- package/src/cloudflare/bundle/alias-plugin.ts +0 -48
- package/src/cloudflare/bundle/build-failures.ts +0 -55
- package/src/cloudflare/bundle/bundle-worker-dev.ts +0 -129
- package/src/cloudflare/bundle/bundle-worker.ts +0 -150
- package/src/cloudflare/bundle/external.ts +0 -41
- package/src/cloudflare/bundle/wasm-plugin.ts +0 -57
- package/src/cloudflare/worker/get-worker-template.ts +0 -14
- /package/lib/cloudflare/{bundle/local-dev-cloudflare-shim.d.ts → local-dev-cloudflare-shim.d.ts} +0 -0
- /package/lib/cloudflare/{worker → miniflare}/http-server.d.ts +0 -0
- /package/lib/cloudflare/{worker → miniflare}/http-server.js +0 -0
- /package/lib/cloudflare/{worker → miniflare}/miniflare.d.ts +0 -0
- /package/lib/cloudflare/{worker → miniflare}/mixed-mode.d.ts +0 -0
- /package/src/cloudflare/{worker → miniflare}/http-server.ts +0 -0
package/lib/cloudflare/worker.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import kleur from "kleur";
|
|
1
2
|
import { spawn } from "node:child_process";
|
|
2
3
|
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
3
|
-
import
|
|
4
|
+
import { isDeepStrictEqual } from "node:util";
|
|
5
|
+
import path from "pathe";
|
|
4
6
|
import { BUILD_DATE } from "../build-date.js";
|
|
5
7
|
import { InnerResourceScope, Resource, ResourceKind } from "../resource.js";
|
|
6
8
|
import { getBindKey, tryGetBinding } from "../runtime/bind.js";
|
|
@@ -9,7 +11,6 @@ import { bootstrapPlugin } from "../runtime/plugin.js";
|
|
|
9
11
|
import { Scope } from "../scope.js";
|
|
10
12
|
import { Secret, secret } from "../secret.js";
|
|
11
13
|
import { serializeScope } from "../serde.js";
|
|
12
|
-
import { getContentType } from "../util/content-type.js";
|
|
13
14
|
import { DeferredPromise } from "../util/deferred-promise.js";
|
|
14
15
|
import { logger } from "../util/logger.js";
|
|
15
16
|
import { withExponentialBackoff } from "../util/retry.js";
|
|
@@ -17,14 +18,15 @@ import { CloudflareApiError, handleApiError } from "./api-error.js";
|
|
|
17
18
|
import { createCloudflareApi, } from "./api.js";
|
|
18
19
|
import { Json, } from "./bindings.js";
|
|
19
20
|
import { isBucket } from "./bucket.js";
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
21
|
+
import { normalizeWorkerBundle, } from "./bundle/index.js";
|
|
22
|
+
import { wrap } from "./bundle/normalize.js";
|
|
22
23
|
import { ContainerApplication } from "./container.js";
|
|
23
24
|
import { CustomDomain } from "./custom-domain.js";
|
|
24
25
|
import { isD1Database } from "./d1-database.js";
|
|
25
26
|
import { DurableObjectNamespace, isDurableObjectNamespace, } from "./durable-object-namespace.js";
|
|
26
27
|
import { isQueueEventSource, } from "./event-source.js";
|
|
27
28
|
import { isKVNamespace } from "./kv-namespace.js";
|
|
29
|
+
import { miniflareServer } from "./miniflare/miniflare.js";
|
|
28
30
|
import { isPipeline } from "./pipeline.js";
|
|
29
31
|
import { QueueConsumer, deleteQueueConsumer, listQueueConsumersForWorker, } from "./queue-consumer.js";
|
|
30
32
|
import { isQueue } from "./queue.js";
|
|
@@ -33,8 +35,8 @@ import { isVectorizeIndex } from "./vectorize-index.js";
|
|
|
33
35
|
import { uploadAssets } from "./worker-assets.js";
|
|
34
36
|
import { bumpMigrationTagVersion, prepareWorkerMetadata, } from "./worker-metadata.js";
|
|
35
37
|
import { WorkerStub, isWorkerStub } from "./worker-stub.js";
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
+
import { WorkerSubdomain, disableWorkerSubdomain } from "./worker-subdomain.js";
|
|
39
|
+
import { createTail } from "./worker/tail.js";
|
|
38
40
|
import { Workflow, isWorkflow, upsertWorkflow } from "./workflow.js";
|
|
39
41
|
export function isWorker(resource) {
|
|
40
42
|
return resource[ResourceKind] === "cloudflare::Worker";
|
|
@@ -224,174 +226,60 @@ export const DEFAULT_COMPATIBILITY_DATE = BUILD_DATE;
|
|
|
224
226
|
export const _Worker = Resource("cloudflare::Worker", {
|
|
225
227
|
alwaysUpdate: true,
|
|
226
228
|
}, async function (id, props) {
|
|
227
|
-
if (props.noBundle && !props.entrypoint) {
|
|
228
|
-
throw new Error("entrypoint must be provided when noBundle is true");
|
|
229
|
-
}
|
|
230
|
-
// Use the provided name
|
|
231
|
-
const workerName = props.name ?? id;
|
|
232
229
|
if (props.projectRoot) {
|
|
233
230
|
logger.warn("projectRoot is deprecated, use cwd instead");
|
|
234
231
|
props.cwd = props.projectRoot;
|
|
235
232
|
}
|
|
236
|
-
const cwd =
|
|
233
|
+
const cwd = path.resolve(props.cwd ?? process.cwd());
|
|
237
234
|
const relativeCwd = cwd === process.cwd() ? undefined : path.relative(process.cwd(), cwd);
|
|
235
|
+
const workerName = props.name ?? id;
|
|
238
236
|
const compatibilityDate = props.compatibilityDate ?? DEFAULT_COMPATIBILITY_DATE;
|
|
239
237
|
const compatibilityFlags = props.compatibilityFlags ?? [];
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
bindings: props.bindings ?? {},
|
|
260
|
-
env: props.env,
|
|
261
|
-
observability: props.observability,
|
|
262
|
-
createdAt: now,
|
|
263
|
-
updatedAt: now,
|
|
264
|
-
eventSources: props.eventSources,
|
|
265
|
-
url: props.dev.url,
|
|
266
|
-
dev: props.dev,
|
|
267
|
-
// Include assets configuration in the output
|
|
268
|
-
assets: props.assets,
|
|
269
|
-
// Include cron triggers in the output
|
|
270
|
-
crons: props.crons,
|
|
271
|
-
// phantom property
|
|
272
|
-
Env: undefined,
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
const sharedOptions = {
|
|
276
|
-
name: workerName,
|
|
277
|
-
compatibilityDate,
|
|
278
|
-
compatibilityFlags,
|
|
279
|
-
bindings: props.bindings ?? {},
|
|
280
|
-
port: typeof props.dev === "object" ? props.dev.port : undefined,
|
|
281
|
-
};
|
|
238
|
+
const dispatchNamespace = typeof props.namespace === "string"
|
|
239
|
+
? props.namespace
|
|
240
|
+
: props.namespace?.namespaceName;
|
|
241
|
+
const dev = normalizeDev(this, props.dev);
|
|
242
|
+
const [bundle, error] = wrap(() => normalizeWorkerBundle({
|
|
243
|
+
entrypoint: props.entrypoint,
|
|
244
|
+
script: props.script,
|
|
245
|
+
format: props.format,
|
|
246
|
+
noBundle: props.noBundle,
|
|
247
|
+
rules: "rules" in props ? props.rules : undefined,
|
|
248
|
+
bundle: props.bundle,
|
|
249
|
+
cwd,
|
|
250
|
+
compatibilityDate,
|
|
251
|
+
compatibilityFlags,
|
|
252
|
+
outdir: props.bundle?.outdir ??
|
|
253
|
+
path.join(process.cwd(), ".alchemy", ...this.scope.chain, id),
|
|
254
|
+
sourceMap: "sourceMap" in props ? props.sourceMap : undefined,
|
|
255
|
+
}));
|
|
256
|
+
if (dev.local) {
|
|
282
257
|
let url;
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const startPromise = new DeferredPromise();
|
|
286
|
-
await createWorkerDevContext(workerName, {
|
|
287
|
-
...props,
|
|
288
|
-
entrypoint: props.entrypoint,
|
|
289
|
-
cwd,
|
|
290
|
-
compatibilityDate,
|
|
291
|
-
compatibilityFlags,
|
|
292
|
-
}, {
|
|
293
|
-
onBuildStart: () => {
|
|
294
|
-
logger.task("miniflare-server", {
|
|
295
|
-
message: `${startPromise.status === "pending" ? "Building" : "Rebuilding"}`,
|
|
296
|
-
status: "pending",
|
|
297
|
-
resource: id,
|
|
298
|
-
prefix: "build",
|
|
299
|
-
prefixColor: "cyanBright",
|
|
300
|
-
});
|
|
301
|
-
},
|
|
302
|
-
onBuildEnd: async (newScript) => {
|
|
303
|
-
try {
|
|
304
|
-
// Hot reload callback - update the miniflare worker
|
|
305
|
-
const server = await miniflareServer.push({
|
|
306
|
-
...sharedOptions,
|
|
307
|
-
script: newScript,
|
|
308
|
-
});
|
|
309
|
-
if (startPromise.status === "pending") {
|
|
310
|
-
logger.task("miniflare-server", {
|
|
311
|
-
message: `Started Miniflare server at ${server.url}`,
|
|
312
|
-
status: "success",
|
|
313
|
-
resource: id,
|
|
314
|
-
prefix: "ready",
|
|
315
|
-
prefixColor: "cyanBright",
|
|
316
|
-
});
|
|
317
|
-
startPromise.resolve(server.url);
|
|
318
|
-
}
|
|
319
|
-
else {
|
|
320
|
-
logger.task("miniflare-server", {
|
|
321
|
-
message: `Updated Miniflare server at ${server.url}`,
|
|
322
|
-
status: "success",
|
|
323
|
-
resource: id,
|
|
324
|
-
prefix: "reload",
|
|
325
|
-
prefixColor: "cyanBright",
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
catch (error) {
|
|
330
|
-
if (startPromise.status === "pending") {
|
|
331
|
-
logger.error(error);
|
|
332
|
-
logger.task("miniflare-server", {
|
|
333
|
-
message: "Failed to start Miniflare server",
|
|
334
|
-
status: "failure",
|
|
335
|
-
resource: id,
|
|
336
|
-
prefix: "error",
|
|
337
|
-
prefixColor: "redBright",
|
|
338
|
-
});
|
|
339
|
-
startPromise.reject(new Error(`Failed to start Miniflare server for worker "${workerName}"`, { cause: error }));
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
342
|
-
logger.task("miniflare-server", {
|
|
343
|
-
message: "Failed to update Miniflare server",
|
|
344
|
-
status: "failure",
|
|
345
|
-
resource: id,
|
|
346
|
-
prefix: "error",
|
|
347
|
-
prefixColor: "redBright",
|
|
348
|
-
});
|
|
349
|
-
logger.error(error);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
},
|
|
353
|
-
onBuildError: (errors) => {
|
|
354
|
-
if (startPromise.status === "pending") {
|
|
355
|
-
logger.task("miniflare-server", {
|
|
356
|
-
message: "Failed to build worker",
|
|
357
|
-
status: "failure",
|
|
358
|
-
resource: id,
|
|
359
|
-
prefix: "error",
|
|
360
|
-
prefixColor: "redBright",
|
|
361
|
-
});
|
|
362
|
-
startPromise.reject(errors);
|
|
363
|
-
}
|
|
364
|
-
else {
|
|
365
|
-
logger.task("miniflare-server", {
|
|
366
|
-
message: "Failed to rebuild worker",
|
|
367
|
-
status: "failure",
|
|
368
|
-
resource: id,
|
|
369
|
-
prefix: "error",
|
|
370
|
-
prefixColor: "redBright",
|
|
371
|
-
});
|
|
372
|
-
logger.error(errors);
|
|
373
|
-
}
|
|
374
|
-
},
|
|
375
|
-
});
|
|
376
|
-
url = await startPromise.value;
|
|
258
|
+
if (error) {
|
|
259
|
+
throw error;
|
|
377
260
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
261
|
+
switch (dev.type) {
|
|
262
|
+
case "command":
|
|
263
|
+
createDevCommand({
|
|
264
|
+
id,
|
|
265
|
+
command: dev.command,
|
|
266
|
+
cwd: dev.cwd ?? process.cwd(),
|
|
267
|
+
env: props.env ?? {},
|
|
268
|
+
});
|
|
269
|
+
url = dev.url;
|
|
270
|
+
break;
|
|
271
|
+
case "miniflare": {
|
|
272
|
+
url = await createMiniflare({
|
|
273
|
+
id,
|
|
274
|
+
workerName,
|
|
385
275
|
compatibilityDate,
|
|
386
276
|
compatibilityFlags,
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
});
|
|
394
|
-
url = server.url;
|
|
277
|
+
bindings: props.bindings,
|
|
278
|
+
bundle,
|
|
279
|
+
port: dev.port,
|
|
280
|
+
});
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
395
283
|
}
|
|
396
284
|
return this({
|
|
397
285
|
type: "service",
|
|
@@ -402,11 +290,11 @@ export const _Worker = Resource("cloudflare::Worker", {
|
|
|
402
290
|
compatibilityDate,
|
|
403
291
|
compatibilityFlags,
|
|
404
292
|
format: props.format || "esm", // Include format in the output
|
|
405
|
-
bindings: props.bindings
|
|
293
|
+
bindings: normalizeExportBindings(workerName, props.bindings),
|
|
406
294
|
env: props.env,
|
|
407
295
|
observability: props.observability,
|
|
408
|
-
createdAt: now,
|
|
409
|
-
updatedAt: now,
|
|
296
|
+
createdAt: this.output?.createdAt ?? Date.now(),
|
|
297
|
+
updatedAt: Date.now(),
|
|
410
298
|
eventSources: props.eventSources,
|
|
411
299
|
url,
|
|
412
300
|
dev: props.dev,
|
|
@@ -418,59 +306,48 @@ export const _Worker = Resource("cloudflare::Worker", {
|
|
|
418
306
|
Env: undefined,
|
|
419
307
|
});
|
|
420
308
|
}
|
|
421
|
-
// Create Cloudflare API client with automatic account discovery
|
|
422
309
|
const api = await createCloudflareApi(props);
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
310
|
+
if (this.phase === "delete") {
|
|
311
|
+
await bundle?.delete?.();
|
|
312
|
+
if (!props.version) {
|
|
313
|
+
await deleteQueueConsumers(api, workerName);
|
|
314
|
+
await deleteWorker(api, {
|
|
315
|
+
scriptName: workerName,
|
|
316
|
+
dispatchNamespace,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
return this.destroy();
|
|
320
|
+
}
|
|
321
|
+
else if (error) {
|
|
322
|
+
throw error;
|
|
323
|
+
}
|
|
324
|
+
let assetsBinding;
|
|
325
|
+
const workflowsBindings = [];
|
|
326
|
+
const containersBindings = [];
|
|
327
|
+
for (const binding of Object.values(props.bindings ?? {})) {
|
|
328
|
+
if (typeof binding === "object") {
|
|
329
|
+
if (binding.type === "assets") {
|
|
330
|
+
assetsBinding = binding;
|
|
331
|
+
}
|
|
332
|
+
else if (binding.type === "workflow") {
|
|
333
|
+
workflowsBindings.push(binding);
|
|
334
|
+
}
|
|
335
|
+
else if (binding.type === "container") {
|
|
336
|
+
containersBindings.push(binding);
|
|
450
337
|
}
|
|
451
338
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
: props.namespace.namespace
|
|
457
|
-
: undefined;
|
|
458
|
-
// Upload any assets and get completion tokens
|
|
459
|
-
let assetUploadResult;
|
|
460
|
-
if (assetsBindings.length > 0) {
|
|
461
|
-
// We'll use the first asset binding for now
|
|
462
|
-
// In the future, we might want to support multiple asset bindings
|
|
463
|
-
const assetBinding = assetsBindings[0];
|
|
464
|
-
// Upload the assets and get the completion token
|
|
465
|
-
assetUploadResult = await uploadAssets(api, {
|
|
339
|
+
}
|
|
340
|
+
const putWorkerWithAssets = async (props, scriptBundle) => {
|
|
341
|
+
const assetUploadResult = assetsBinding
|
|
342
|
+
? await uploadAssets(api, {
|
|
466
343
|
workerName,
|
|
467
|
-
assets:
|
|
344
|
+
assets: assetsBinding,
|
|
468
345
|
assetConfig: props.assets,
|
|
469
346
|
namespace: dispatchNamespace,
|
|
470
|
-
})
|
|
471
|
-
|
|
347
|
+
})
|
|
348
|
+
: undefined;
|
|
472
349
|
// Deploy worker (either as version or live worker)
|
|
473
|
-
|
|
350
|
+
return await putWorker(api, {
|
|
474
351
|
...props,
|
|
475
352
|
workerName,
|
|
476
353
|
scriptBundle,
|
|
@@ -480,111 +357,14 @@ export const _Worker = Resource("cloudflare::Worker", {
|
|
|
480
357
|
compatibilityFlags,
|
|
481
358
|
assetUploadResult,
|
|
482
359
|
});
|
|
483
|
-
versionResult.versionId;
|
|
484
|
-
for (const workflow of workflowsBindings) {
|
|
485
|
-
if (workflow.scriptName === undefined ||
|
|
486
|
-
workflow.scriptName === workerName) {
|
|
487
|
-
await upsertWorkflow(api, {
|
|
488
|
-
workflowName: workflow.workflowName,
|
|
489
|
-
className: workflow.className,
|
|
490
|
-
scriptName: workflow.scriptName ?? workerName,
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
for (const container of containersBindings) {
|
|
495
|
-
async function findNamespaceId() {
|
|
496
|
-
const response = await api.get(`/accounts/${api.accountId}/workers/scripts/${workerName}/versions/${versionResult.deploymentId}`);
|
|
497
|
-
const result = (await response.json());
|
|
498
|
-
const namespaceId = result.result.resources.bindings.find((binding) => binding.type === "durable_object_namespace" &&
|
|
499
|
-
binding.class_name === container.className)?.namespace_id;
|
|
500
|
-
if (!namespaceId) {
|
|
501
|
-
throw new Error(`Namespace ID not found for container ${container.id}`);
|
|
502
|
-
}
|
|
503
|
-
return namespaceId;
|
|
504
|
-
}
|
|
505
|
-
await ContainerApplication(container.id, {
|
|
506
|
-
accountId: props.accountId,
|
|
507
|
-
apiKey: props.apiKey,
|
|
508
|
-
apiToken: props.apiToken,
|
|
509
|
-
baseUrl: props.baseUrl,
|
|
510
|
-
email: props.email,
|
|
511
|
-
image: container.image,
|
|
512
|
-
name: container.id,
|
|
513
|
-
instanceType: container.instanceType,
|
|
514
|
-
observability: container.observability,
|
|
515
|
-
durableObjects: {
|
|
516
|
-
namespaceId: await findNamespaceId(),
|
|
517
|
-
},
|
|
518
|
-
schedulingPolicy: container.schedulingPolicy,
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
await Promise.all(props.eventSources?.map((eventSource) => {
|
|
522
|
-
if (isQueue(eventSource) || isQueueEventSource(eventSource)) {
|
|
523
|
-
const queue = isQueue(eventSource)
|
|
524
|
-
? eventSource
|
|
525
|
-
: eventSource.queue;
|
|
526
|
-
return QueueConsumer(`${queue.id}-consumer`, {
|
|
527
|
-
queue,
|
|
528
|
-
scriptName: workerName,
|
|
529
|
-
accountId: api.accountId,
|
|
530
|
-
adopt: props.adopt,
|
|
531
|
-
settings: isQueueEventSource(eventSource)
|
|
532
|
-
? eventSource.settings
|
|
533
|
-
: queue.dlq
|
|
534
|
-
? { deadLetterQueue: queue.dlq }
|
|
535
|
-
: undefined,
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
throw new Error(`Unsupported event source type: ${eventSource}`);
|
|
539
|
-
}) ?? []);
|
|
540
|
-
// Handle worker URL if requested
|
|
541
|
-
let workerUrl;
|
|
542
|
-
if (props.version) {
|
|
543
|
-
// For versions, use the preview URL if available
|
|
544
|
-
workerUrl = versionResult?.previewUrl;
|
|
545
|
-
}
|
|
546
|
-
else if (!props.namespace) {
|
|
547
|
-
// namespaces don't support URLs
|
|
548
|
-
// For regular workers, use the normal URL configuration
|
|
549
|
-
workerUrl = await configureURL(this, api, workerName, props.url ?? true);
|
|
550
|
-
}
|
|
551
|
-
// Get current timestamp
|
|
552
|
-
const now = Date.now();
|
|
553
|
-
// Update cron triggers
|
|
554
|
-
if (props.crons) {
|
|
555
|
-
const res = await api.put(`/accounts/${api.accountId}/workers/scripts/${workerName}/schedules`, props.crons.map((cron) => ({ cron })));
|
|
556
|
-
if (!res.ok) {
|
|
557
|
-
await handleApiError(res, "updating cron triggers", "worker", workerName);
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
return { scriptBundle, workerUrl, now, versionResult };
|
|
561
360
|
};
|
|
562
|
-
if (this.phase === "delete") {
|
|
563
|
-
// only delete the worker if it's not a version
|
|
564
|
-
if (!props.version) {
|
|
565
|
-
// Delete any queue consumers attached to this worker first
|
|
566
|
-
await deleteQueueConsumers(api, workerName);
|
|
567
|
-
await withExponentialBackoff(() => deleteWorker(api, {
|
|
568
|
-
workerName,
|
|
569
|
-
namespace: typeof props.namespace === "string"
|
|
570
|
-
? props.namespace
|
|
571
|
-
: props.namespace?.namespaceId,
|
|
572
|
-
url: this.output.url,
|
|
573
|
-
}), (err) => (err.status === 400 &&
|
|
574
|
-
err.message.includes("is still referenced by service bindings in Workers")) ||
|
|
575
|
-
err.status === 500 ||
|
|
576
|
-
err.status === 503, 10, 100);
|
|
577
|
-
}
|
|
578
|
-
return this.destroy();
|
|
579
|
-
}
|
|
580
361
|
if (this.phase === "create") {
|
|
581
362
|
if (props.version) {
|
|
582
363
|
// When version is specified, we adopt existing workers or create them if they don't exist
|
|
583
|
-
|
|
584
|
-
if (!workerExists) {
|
|
364
|
+
if (!(await workerExists(api, workerName))) {
|
|
585
365
|
// Create the base worker first if it doesn't exist
|
|
586
366
|
const baseWorkerProps = { ...props, version: undefined };
|
|
587
|
-
await
|
|
367
|
+
await putWorkerWithAssets(baseWorkerProps, await bundle.create());
|
|
588
368
|
}
|
|
589
369
|
// We always "adopt" when publishing versions
|
|
590
370
|
}
|
|
@@ -592,73 +372,136 @@ export const _Worker = Resource("cloudflare::Worker", {
|
|
|
592
372
|
await assertWorkerDoesNotExist(api, workerName);
|
|
593
373
|
}
|
|
594
374
|
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
:
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
375
|
+
let putWorkerResult;
|
|
376
|
+
if (dev.type === "remote") {
|
|
377
|
+
// todo(john): clean this up and add log tail
|
|
378
|
+
const controller = new AbortController();
|
|
379
|
+
cleanups.push(() => controller.abort());
|
|
380
|
+
const watcher = await bundle.watch(controller.signal);
|
|
381
|
+
const promise = new DeferredPromise();
|
|
382
|
+
void watcher.pipeTo(new WritableStream({
|
|
383
|
+
async write(chunk) {
|
|
384
|
+
switch (chunk.type) {
|
|
385
|
+
case "start":
|
|
386
|
+
logger.task("", {
|
|
387
|
+
message: "start",
|
|
388
|
+
status: "pending",
|
|
389
|
+
resource: id,
|
|
390
|
+
prefix: "build",
|
|
391
|
+
prefixColor: "cyanBright",
|
|
392
|
+
});
|
|
393
|
+
break;
|
|
394
|
+
case "end": {
|
|
395
|
+
if (promise.status === "pending") {
|
|
396
|
+
await putWorkerWithAssets(props, chunk.result)
|
|
397
|
+
.then((result) => promise.resolve(result))
|
|
398
|
+
.catch((error) => {
|
|
399
|
+
controller.abort();
|
|
400
|
+
promise.reject(error);
|
|
401
|
+
});
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
logger.task("", {
|
|
405
|
+
message: "reload",
|
|
406
|
+
status: "success",
|
|
407
|
+
resource: id,
|
|
408
|
+
prefix: "build",
|
|
409
|
+
prefixColor: "cyanBright",
|
|
410
|
+
});
|
|
411
|
+
await putWorker(api, {
|
|
412
|
+
...props,
|
|
413
|
+
workerName,
|
|
414
|
+
scriptBundle: chunk.result,
|
|
415
|
+
dispatchNamespace,
|
|
416
|
+
version: props.version,
|
|
417
|
+
compatibilityDate,
|
|
418
|
+
compatibilityFlags,
|
|
419
|
+
assetUploadResult: assetsBinding
|
|
420
|
+
? {
|
|
421
|
+
keepAssets: true,
|
|
422
|
+
assetConfig: props.assets,
|
|
423
|
+
}
|
|
424
|
+
: undefined,
|
|
425
|
+
unstable_cacheWorkerSettings: true,
|
|
426
|
+
});
|
|
427
|
+
logger.task("", {
|
|
428
|
+
message: "updated",
|
|
429
|
+
status: "success",
|
|
430
|
+
resource: id,
|
|
431
|
+
prefix: "build",
|
|
432
|
+
prefixColor: "greenBright",
|
|
433
|
+
});
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
case "error":
|
|
437
|
+
logger.task("", {
|
|
438
|
+
message: "error",
|
|
439
|
+
status: "failure",
|
|
440
|
+
resource: id,
|
|
441
|
+
prefix: "build",
|
|
442
|
+
prefixColor: "redBright",
|
|
443
|
+
});
|
|
444
|
+
logger.error(chunk.errors);
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
},
|
|
619
448
|
}));
|
|
449
|
+
putWorkerResult = await promise.value;
|
|
450
|
+
const tail = await createTail(api, id, workerName);
|
|
451
|
+
cleanups.push(() => tail.close());
|
|
620
452
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
if (props.routes && props.routes.length > 0) {
|
|
624
|
-
ensureNoDuplicates("Route", props.routes.map((route) => typeof route === "string" ? route : route.pattern));
|
|
625
|
-
// Create Route resources for each route and capture their outputs
|
|
626
|
-
createdRoutes = await Promise.all(props.routes.map(async (routeConfig) => {
|
|
627
|
-
const pattern = typeof routeConfig === "string" ? routeConfig : routeConfig.pattern;
|
|
628
|
-
return await Route(pattern, {
|
|
629
|
-
pattern,
|
|
630
|
-
script: workerName,
|
|
631
|
-
zoneId: typeof routeConfig === "string" ? undefined : routeConfig.zoneId, // Route resource will handle inference if not provided
|
|
632
|
-
adopt: typeof routeConfig === "string"
|
|
633
|
-
? (props.adopt ?? false)
|
|
634
|
-
: (routeConfig.adopt ?? props.adopt),
|
|
635
|
-
accountId: props.accountId,
|
|
636
|
-
apiKey: props.apiKey,
|
|
637
|
-
apiToken: props.apiToken,
|
|
638
|
-
baseUrl: props.baseUrl,
|
|
639
|
-
email: props.email,
|
|
640
|
-
});
|
|
641
|
-
}));
|
|
453
|
+
else {
|
|
454
|
+
putWorkerResult = await putWorkerWithAssets(props, await bundle.create());
|
|
642
455
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
: isWorkflow(binding) && binding.scriptName === undefined
|
|
654
|
-
? new Workflow(binding.id, {
|
|
655
|
-
...binding,
|
|
656
|
-
// re-export this binding mapping to the host worker (this worker)
|
|
657
|
-
scriptName: workerName,
|
|
658
|
-
})
|
|
659
|
-
: binding,
|
|
660
|
-
]));
|
|
456
|
+
const tasks = [];
|
|
457
|
+
for (const workflow of workflowsBindings) {
|
|
458
|
+
if (workflow.scriptName === undefined ||
|
|
459
|
+
workflow.scriptName === workerName) {
|
|
460
|
+
tasks.push(upsertWorkflow(api, {
|
|
461
|
+
workflowName: workflow.workflowName,
|
|
462
|
+
className: workflow.className,
|
|
463
|
+
scriptName: workflow.scriptName ?? workerName,
|
|
464
|
+
}));
|
|
465
|
+
}
|
|
661
466
|
}
|
|
467
|
+
if (containersBindings.length > 0) {
|
|
468
|
+
tasks.push(getVersionMetadata(api, workerName, putWorkerResult.deployment_id).then((versionMetadata) => provisionContainers(api, {
|
|
469
|
+
scriptName: workerName,
|
|
470
|
+
containers: containersBindings,
|
|
471
|
+
bindings: versionMetadata.resources.bindings,
|
|
472
|
+
})));
|
|
473
|
+
}
|
|
474
|
+
if (!isDeepStrictEqual(props.crons, this.output?.crons)) {
|
|
475
|
+
tasks.push(api.put(`/accounts/${api.accountId}/workers/scripts/${workerName}/schedules`, props.crons?.map((cron) => ({ cron })) ?? []));
|
|
476
|
+
}
|
|
477
|
+
tasks.push(provisionEventSources(api, {
|
|
478
|
+
scriptName: workerName,
|
|
479
|
+
eventSources: props.eventSources,
|
|
480
|
+
}));
|
|
481
|
+
const [domains, routes, subdomain] = await Promise.all([
|
|
482
|
+
// TODO: can you provision domains and routes in parallel, or is there a dependency?
|
|
483
|
+
provisionDomains(api, {
|
|
484
|
+
scriptName: workerName,
|
|
485
|
+
adopt: props.adopt,
|
|
486
|
+
domains: props.domains,
|
|
487
|
+
}),
|
|
488
|
+
provisionRoutes(api, {
|
|
489
|
+
scriptName: workerName,
|
|
490
|
+
adopt: props.adopt,
|
|
491
|
+
routes: props.routes,
|
|
492
|
+
}),
|
|
493
|
+
provisionSubdomain(api, {
|
|
494
|
+
scriptName: workerName,
|
|
495
|
+
enable: props.url ?? dispatchNamespace === undefined,
|
|
496
|
+
previewVersionId: props.version && putWorkerResult.metadata.has_preview
|
|
497
|
+
? putWorkerResult.id
|
|
498
|
+
: undefined,
|
|
499
|
+
retain: !!props.version,
|
|
500
|
+
forceDelete: this.phase === "create" && !!props.adopt && props.url === false,
|
|
501
|
+
}),
|
|
502
|
+
...tasks,
|
|
503
|
+
]);
|
|
504
|
+
const now = Date.now();
|
|
662
505
|
// Construct the output
|
|
663
506
|
return this({
|
|
664
507
|
...props,
|
|
@@ -670,22 +513,22 @@ export const _Worker = Resource("cloudflare::Worker", {
|
|
|
670
513
|
compatibilityDate,
|
|
671
514
|
compatibilityFlags,
|
|
672
515
|
format: props.format || "esm", // Include format in the output
|
|
673
|
-
bindings:
|
|
516
|
+
bindings: normalizeExportBindings(workerName, props.bindings),
|
|
674
517
|
env: props.env,
|
|
675
518
|
observability: props.observability,
|
|
676
|
-
createdAt: now,
|
|
519
|
+
createdAt: this.output?.createdAt ?? now,
|
|
677
520
|
updatedAt: now,
|
|
678
521
|
eventSources: props.eventSources,
|
|
679
|
-
url:
|
|
522
|
+
url: subdomain?.url,
|
|
680
523
|
dev: props.dev,
|
|
681
524
|
// Include assets configuration in the output
|
|
682
525
|
assets: props.assets,
|
|
683
526
|
// Include cron triggers in the output
|
|
684
527
|
crons: props.crons,
|
|
685
528
|
// Include the created routes in the output
|
|
686
|
-
routes
|
|
529
|
+
routes,
|
|
687
530
|
// Include the created domains in the output
|
|
688
|
-
domains
|
|
531
|
+
domains,
|
|
689
532
|
// Include the dispatch namespace in the output
|
|
690
533
|
namespace: props.namespace,
|
|
691
534
|
// Include version information in the output
|
|
@@ -694,31 +537,324 @@ export const _Worker = Resource("cloudflare::Worker", {
|
|
|
694
537
|
Env: undefined,
|
|
695
538
|
});
|
|
696
539
|
});
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
540
|
+
const cleanups = [];
|
|
541
|
+
let exiting = false;
|
|
542
|
+
process.on("SIGINT", async () => {
|
|
543
|
+
if (cleanups.length > 0) {
|
|
544
|
+
if (!exiting) {
|
|
545
|
+
exiting = true;
|
|
546
|
+
logger.log(`\n${kleur.gray("Exiting...")}`);
|
|
547
|
+
}
|
|
548
|
+
// TODO: for some reason this runs twice...
|
|
549
|
+
// and this whole thing feels hacky anyway
|
|
550
|
+
await Promise.allSettled(cleanups.map((cleanup) => cleanup()));
|
|
551
|
+
}
|
|
552
|
+
process.exit(0);
|
|
553
|
+
});
|
|
554
|
+
const normalizeDev = (ctx, dev) => {
|
|
555
|
+
if (!ctx.scope.dev || ctx.phase === "delete" || dev === false) {
|
|
556
|
+
return {
|
|
557
|
+
type: "none",
|
|
558
|
+
local: false,
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
const devObj = dev === true ? {} : (dev ?? {});
|
|
562
|
+
if ("command" in devObj) {
|
|
563
|
+
// Commands are always local
|
|
564
|
+
return {
|
|
565
|
+
type: "command",
|
|
566
|
+
...devObj,
|
|
567
|
+
local: true,
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
if (devObj.remote === false || ctx.scope.dev === "prefer-local") {
|
|
571
|
+
return {
|
|
572
|
+
type: "miniflare",
|
|
573
|
+
port: devObj.port,
|
|
574
|
+
local: true,
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
return {
|
|
578
|
+
type: "remote",
|
|
579
|
+
local: false,
|
|
580
|
+
};
|
|
581
|
+
};
|
|
582
|
+
const assertUnique = (inputs, key, message) => {
|
|
583
|
+
const ids = inputs.map((input) => input[key]);
|
|
584
|
+
const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index);
|
|
585
|
+
if (duplicates.length > 0) {
|
|
586
|
+
throw new Error(`Duplicate ${message} found: ${duplicates.join(", ")}`);
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
const normalizeExportBindings = (scriptName, bindings = {}) => {
|
|
590
|
+
return Object.fromEntries(Object.entries(bindings).map(([bindingName, binding]) => [
|
|
591
|
+
bindingName,
|
|
592
|
+
isDurableObjectNamespace(binding) && binding.scriptName === undefined
|
|
593
|
+
? new DurableObjectNamespace(binding.id, {
|
|
594
|
+
...binding,
|
|
595
|
+
// re-export this binding mapping to the host worker (this worker)
|
|
596
|
+
scriptName,
|
|
597
|
+
})
|
|
598
|
+
: isWorkflow(binding) && binding.scriptName === undefined
|
|
599
|
+
? new Workflow(binding.id, {
|
|
600
|
+
...binding,
|
|
601
|
+
// re-export this binding mapping to the host worker (this worker)
|
|
602
|
+
scriptName,
|
|
603
|
+
})
|
|
604
|
+
: binding,
|
|
605
|
+
]));
|
|
606
|
+
};
|
|
607
|
+
const normalizeApiOptions = (api) => ({
|
|
608
|
+
accountId: api.accountId,
|
|
609
|
+
apiKey: api.apiKey,
|
|
610
|
+
apiToken: api.apiToken,
|
|
611
|
+
email: api.email,
|
|
612
|
+
baseUrl: api.baseUrl,
|
|
613
|
+
});
|
|
614
|
+
async function provisionContainers(api, props) {
|
|
615
|
+
if (!props.containers?.length) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
return await Promise.all(props.containers.map((container) => {
|
|
619
|
+
const namespaceId = props.bindings.find((binding) => binding.type === "durable_object_namespace" &&
|
|
620
|
+
binding.class_name === container.className)?.namespace_id;
|
|
621
|
+
if (!namespaceId) {
|
|
622
|
+
throw new Error(`Namespace ID not found for container ${container.id}`);
|
|
623
|
+
}
|
|
624
|
+
return ContainerApplication(container.id, {
|
|
625
|
+
image: container.image,
|
|
626
|
+
name: container.id,
|
|
627
|
+
instanceType: container.instanceType,
|
|
628
|
+
observability: container.observability,
|
|
629
|
+
durableObjects: {
|
|
630
|
+
namespaceId,
|
|
631
|
+
},
|
|
632
|
+
schedulingPolicy: container.schedulingPolicy,
|
|
633
|
+
adopt: container.adopt,
|
|
634
|
+
...normalizeApiOptions(api),
|
|
635
|
+
});
|
|
636
|
+
}));
|
|
637
|
+
}
|
|
638
|
+
async function provisionEventSources(api, props) {
|
|
639
|
+
if (!props.eventSources?.length) {
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
return await Promise.all(props.eventSources.map((eventSource) => {
|
|
643
|
+
if (isQueue(eventSource)) {
|
|
644
|
+
return QueueConsumer(`${eventSource.id}-consumer`, {
|
|
645
|
+
queue: eventSource,
|
|
646
|
+
scriptName: props.scriptName,
|
|
647
|
+
settings: eventSource.dlq
|
|
648
|
+
? { deadLetterQueue: eventSource.dlq }
|
|
649
|
+
: undefined,
|
|
650
|
+
...normalizeApiOptions(api),
|
|
712
651
|
});
|
|
713
652
|
}
|
|
714
|
-
|
|
715
|
-
|
|
653
|
+
if (isQueueEventSource(eventSource)) {
|
|
654
|
+
return QueueConsumer(`${eventSource.queue.id}-consumer`, {
|
|
655
|
+
queue: eventSource.queue,
|
|
656
|
+
scriptName: props.scriptName,
|
|
657
|
+
settings: eventSource.settings,
|
|
658
|
+
...normalizeApiOptions(api),
|
|
659
|
+
});
|
|
716
660
|
}
|
|
661
|
+
throw new Error(`Unsupported event source: ${eventSource}`);
|
|
662
|
+
}));
|
|
663
|
+
}
|
|
664
|
+
async function provisionDomains(api, props) {
|
|
665
|
+
if (!props.domains?.length) {
|
|
666
|
+
return;
|
|
717
667
|
}
|
|
718
|
-
|
|
719
|
-
|
|
668
|
+
const domains = props.domains.map((domain) => {
|
|
669
|
+
if (typeof domain === "string") {
|
|
670
|
+
return {
|
|
671
|
+
name: domain,
|
|
672
|
+
zoneId: undefined,
|
|
673
|
+
adopt: props.adopt,
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
return {
|
|
677
|
+
name: domain.domainName,
|
|
678
|
+
zoneId: domain.zoneId,
|
|
679
|
+
adopt: domain.adopt ?? props.adopt,
|
|
680
|
+
};
|
|
681
|
+
});
|
|
682
|
+
assertUnique(domains, "name", "Custom Domain");
|
|
683
|
+
return await Promise.all(domains.map(async (domain) => {
|
|
684
|
+
return await CustomDomain(domain.name, {
|
|
685
|
+
workerName: props.scriptName,
|
|
686
|
+
name: domain.name,
|
|
687
|
+
zoneId: domain.zoneId,
|
|
688
|
+
adopt: domain.adopt,
|
|
689
|
+
...normalizeApiOptions(api),
|
|
690
|
+
});
|
|
691
|
+
}));
|
|
692
|
+
}
|
|
693
|
+
async function provisionRoutes(api, props) {
|
|
694
|
+
if (!props.routes?.length) {
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
const routes = props.routes.map((route) => {
|
|
698
|
+
if (typeof route === "string") {
|
|
699
|
+
return {
|
|
700
|
+
pattern: route,
|
|
701
|
+
adopt: props.adopt,
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
return {
|
|
705
|
+
pattern: route.pattern,
|
|
706
|
+
zoneId: route.zoneId,
|
|
707
|
+
adopt: route.adopt ?? props.adopt,
|
|
708
|
+
};
|
|
709
|
+
});
|
|
710
|
+
assertUnique(routes, "pattern", "Route");
|
|
711
|
+
return await Promise.all(routes.map(async (route) => {
|
|
712
|
+
return await Route(route.pattern, {
|
|
713
|
+
pattern: route.pattern,
|
|
714
|
+
script: props.scriptName,
|
|
715
|
+
zoneId: route.zoneId,
|
|
716
|
+
adopt: route.adopt,
|
|
717
|
+
...normalizeApiOptions(api),
|
|
718
|
+
});
|
|
719
|
+
}));
|
|
720
720
|
}
|
|
721
|
-
function
|
|
721
|
+
async function provisionSubdomain(api, props) {
|
|
722
|
+
if (props.enable) {
|
|
723
|
+
return await WorkerSubdomain("url", {
|
|
724
|
+
scriptName: props.scriptName,
|
|
725
|
+
previewVersionId: props.previewVersionId,
|
|
726
|
+
retain: props.retain,
|
|
727
|
+
...normalizeApiOptions(api),
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
if (props.forceDelete) {
|
|
731
|
+
await disableWorkerSubdomain(api, props.scriptName);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
async function createMiniflare(props) {
|
|
735
|
+
const sharedOptions = {
|
|
736
|
+
name: props.workerName,
|
|
737
|
+
compatibilityDate: props.compatibilityDate,
|
|
738
|
+
compatibilityFlags: props.compatibilityFlags,
|
|
739
|
+
bindings: props.bindings,
|
|
740
|
+
port: props.port,
|
|
741
|
+
};
|
|
742
|
+
const startPromise = new DeferredPromise();
|
|
743
|
+
const controller = new AbortController();
|
|
744
|
+
cleanups.push(() => controller.abort());
|
|
745
|
+
(await props.bundle.watch(controller.signal))
|
|
746
|
+
.pipeThrough(new TransformStream({
|
|
747
|
+
async transform(chunk, controller) {
|
|
748
|
+
switch (chunk.type) {
|
|
749
|
+
case "start": {
|
|
750
|
+
controller.enqueue({ type: "build-start" });
|
|
751
|
+
break;
|
|
752
|
+
}
|
|
753
|
+
case "end": {
|
|
754
|
+
controller.enqueue({ type: "build-end" });
|
|
755
|
+
try {
|
|
756
|
+
const server = await miniflareServer.push({
|
|
757
|
+
...sharedOptions,
|
|
758
|
+
bundle: chunk.result,
|
|
759
|
+
});
|
|
760
|
+
controller.enqueue({
|
|
761
|
+
type: "miniflare-ready",
|
|
762
|
+
url: server.url,
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
catch (error) {
|
|
766
|
+
controller.enqueue({
|
|
767
|
+
type: "miniflare-error",
|
|
768
|
+
error: error,
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
break;
|
|
772
|
+
}
|
|
773
|
+
case "error": {
|
|
774
|
+
controller.enqueue({
|
|
775
|
+
type: "build-error",
|
|
776
|
+
errors: chunk.errors,
|
|
777
|
+
});
|
|
778
|
+
break;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
},
|
|
782
|
+
}))
|
|
783
|
+
.pipeTo(new WritableStream({
|
|
784
|
+
write: async (chunk) => {
|
|
785
|
+
switch (chunk.type) {
|
|
786
|
+
case "build-start": {
|
|
787
|
+
logger.task("", {
|
|
788
|
+
message: "start",
|
|
789
|
+
status: "pending",
|
|
790
|
+
resource: props.id,
|
|
791
|
+
prefix: "build",
|
|
792
|
+
prefixColor: "cyanBright",
|
|
793
|
+
});
|
|
794
|
+
break;
|
|
795
|
+
}
|
|
796
|
+
case "build-end": {
|
|
797
|
+
logger.task("", {
|
|
798
|
+
message: startPromise.status === "pending" ? "load" : "reload",
|
|
799
|
+
status: "success",
|
|
800
|
+
resource: props.id,
|
|
801
|
+
prefix: "build",
|
|
802
|
+
prefixColor: "greenBright",
|
|
803
|
+
});
|
|
804
|
+
break;
|
|
805
|
+
}
|
|
806
|
+
case "build-error": {
|
|
807
|
+
logger.task("", {
|
|
808
|
+
message: "error",
|
|
809
|
+
status: "failure",
|
|
810
|
+
resource: props.id,
|
|
811
|
+
prefix: "build",
|
|
812
|
+
prefixColor: "redBright",
|
|
813
|
+
});
|
|
814
|
+
if (startPromise.status === "pending") {
|
|
815
|
+
controller.abort();
|
|
816
|
+
startPromise.reject(chunk.errors);
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
logger.error(chunk.errors);
|
|
820
|
+
}
|
|
821
|
+
break;
|
|
822
|
+
}
|
|
823
|
+
case "miniflare-ready": {
|
|
824
|
+
logger.task("", {
|
|
825
|
+
message: `ready at ${chunk.url}`,
|
|
826
|
+
status: "success",
|
|
827
|
+
resource: props.id,
|
|
828
|
+
prefix: "miniflare",
|
|
829
|
+
prefixColor: "greenBright",
|
|
830
|
+
});
|
|
831
|
+
if (startPromise.status === "pending") {
|
|
832
|
+
startPromise.resolve(chunk.url);
|
|
833
|
+
}
|
|
834
|
+
break;
|
|
835
|
+
}
|
|
836
|
+
case "miniflare-error": {
|
|
837
|
+
logger.task("", {
|
|
838
|
+
message: "error",
|
|
839
|
+
status: "failure",
|
|
840
|
+
resource: props.id,
|
|
841
|
+
prefix: "miniflare",
|
|
842
|
+
prefixColor: "redBright",
|
|
843
|
+
});
|
|
844
|
+
if (startPromise.status === "pending") {
|
|
845
|
+
startPromise.reject(chunk.error);
|
|
846
|
+
}
|
|
847
|
+
else {
|
|
848
|
+
logger.error(chunk.error);
|
|
849
|
+
}
|
|
850
|
+
break;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
},
|
|
854
|
+
}));
|
|
855
|
+
return await startPromise.value;
|
|
856
|
+
}
|
|
857
|
+
function createDevCommand(props) {
|
|
722
858
|
const persistFile = path.join(process.cwd(), ".alchemy", `${props.id}.pid`);
|
|
723
859
|
if (existsSync(persistFile)) {
|
|
724
860
|
const pid = Number.parseInt(readFileSync(persistFile, "utf8"));
|
|
@@ -745,104 +881,92 @@ function upsertDevCommand(props) {
|
|
|
745
881
|
},
|
|
746
882
|
stdio: ["inherit", "inherit", "inherit"],
|
|
747
883
|
});
|
|
748
|
-
|
|
884
|
+
cleanups.push(() => {
|
|
749
885
|
try {
|
|
750
886
|
unlinkSync(persistFile);
|
|
751
887
|
}
|
|
752
888
|
catch {
|
|
753
889
|
// ignore
|
|
754
890
|
}
|
|
755
|
-
proc.kill(
|
|
756
|
-
process.exit(0);
|
|
891
|
+
proc.kill();
|
|
757
892
|
});
|
|
758
893
|
if (proc.pid) {
|
|
759
894
|
mkdirSync(path.dirname(persistFile), { recursive: true });
|
|
760
895
|
writeFileSync(persistFile, proc.pid.toString());
|
|
761
896
|
}
|
|
762
897
|
}
|
|
898
|
+
async function prepareWorkerUpload(api, props) {
|
|
899
|
+
const scriptMetadata = await prepareWorkerMetadata(api, props);
|
|
900
|
+
if (props.format === "cjs") {
|
|
901
|
+
scriptMetadata.body_part = props.scriptBundle.entrypoint;
|
|
902
|
+
}
|
|
903
|
+
else {
|
|
904
|
+
scriptMetadata.main_module = props.scriptBundle.entrypoint;
|
|
905
|
+
}
|
|
906
|
+
const body = new FormData();
|
|
907
|
+
for await (const file of props.scriptBundle.files) {
|
|
908
|
+
body.append(file.name, file);
|
|
909
|
+
}
|
|
910
|
+
// Prepare metadata - add version annotations if this is a version
|
|
911
|
+
const finalMetadata = props.version
|
|
912
|
+
? {
|
|
913
|
+
...scriptMetadata,
|
|
914
|
+
// Exclude migrations for worker versions - they're not allowed
|
|
915
|
+
migrations: undefined,
|
|
916
|
+
annotations: {
|
|
917
|
+
"workers/tag": props.version,
|
|
918
|
+
"workers/message": `Version ${props.version}`,
|
|
919
|
+
},
|
|
920
|
+
}
|
|
921
|
+
: {
|
|
922
|
+
...scriptMetadata,
|
|
923
|
+
migrations: scriptMetadata.migrations
|
|
924
|
+
? {
|
|
925
|
+
...scriptMetadata.migrations,
|
|
926
|
+
old_tag: props.migrationTag,
|
|
927
|
+
new_tag: bumpMigrationTagVersion(props.migrationTag),
|
|
928
|
+
}
|
|
929
|
+
: undefined,
|
|
930
|
+
};
|
|
931
|
+
body.append("metadata", new Blob([JSON.stringify(finalMetadata)], {
|
|
932
|
+
type: "application/json",
|
|
933
|
+
}));
|
|
934
|
+
let endpoint;
|
|
935
|
+
let method;
|
|
936
|
+
if (props.version) {
|
|
937
|
+
if (props.dispatchNamespace) {
|
|
938
|
+
throw new Error("Worker Preview Versions are not supported in Workers for Platforms");
|
|
939
|
+
}
|
|
940
|
+
// Upload worker version using the versions API
|
|
941
|
+
endpoint = `/accounts/${api.accountId}/workers/scripts/${props.workerName}/versions`;
|
|
942
|
+
method = "POST";
|
|
943
|
+
}
|
|
944
|
+
else {
|
|
945
|
+
// Upload worker script with bindings
|
|
946
|
+
endpoint = props.dispatchNamespace
|
|
947
|
+
? `/accounts/${api.accountId}/workers/dispatch/namespaces/${props.dispatchNamespace}/scripts/${props.workerName}`
|
|
948
|
+
: `/accounts/${api.accountId}/workers/scripts/${props.workerName}`;
|
|
949
|
+
method = "PUT";
|
|
950
|
+
}
|
|
951
|
+
return {
|
|
952
|
+
body,
|
|
953
|
+
endpoint,
|
|
954
|
+
method,
|
|
955
|
+
};
|
|
956
|
+
}
|
|
763
957
|
export async function putWorker(api, props) {
|
|
764
958
|
const {
|
|
765
959
|
//
|
|
766
|
-
|
|
767
|
-
const scriptMetadata = await prepareWorkerMetadata(api, props);
|
|
960
|
+
workerName, version, } = props;
|
|
768
961
|
return withExponentialBackoff(async () => {
|
|
769
|
-
const
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
? "application/javascript+module"
|
|
778
|
-
: contentType,
|
|
779
|
-
}), fileName);
|
|
780
|
-
}
|
|
781
|
-
if (typeof scriptBundle === "string") {
|
|
782
|
-
addFile(scriptName, scriptBundle);
|
|
783
|
-
}
|
|
784
|
-
else {
|
|
785
|
-
for (const [fileName, content] of Object.entries(scriptBundle)) {
|
|
786
|
-
addFile(fileName, content);
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
// Prepare metadata - add version annotations if this is a version
|
|
790
|
-
const finalMetadata = version
|
|
791
|
-
? {
|
|
792
|
-
...scriptMetadata,
|
|
793
|
-
// Exclude migrations for worker versions - they're not allowed
|
|
794
|
-
migrations: undefined,
|
|
795
|
-
annotations: {
|
|
796
|
-
"workers/tag": version,
|
|
797
|
-
"workers/message": `Version ${version}`,
|
|
798
|
-
},
|
|
799
|
-
}
|
|
800
|
-
: {
|
|
801
|
-
...scriptMetadata,
|
|
802
|
-
migrations: scriptMetadata.migrations
|
|
803
|
-
? {
|
|
804
|
-
...scriptMetadata.migrations,
|
|
805
|
-
old_tag: migrationTag,
|
|
806
|
-
new_tag: bumpMigrationTagVersion(migrationTag),
|
|
807
|
-
}
|
|
808
|
-
: undefined,
|
|
809
|
-
};
|
|
810
|
-
if (process.env.DEBUG) {
|
|
811
|
-
console.log(`metadata(${scriptName}):`, finalMetadata);
|
|
812
|
-
}
|
|
813
|
-
// Add metadata as JSON
|
|
814
|
-
formData.append("metadata", new Blob([JSON.stringify(finalMetadata)], {
|
|
815
|
-
type: "application/json",
|
|
816
|
-
}));
|
|
817
|
-
// Determine endpoint and HTTP method
|
|
818
|
-
let endpoint;
|
|
819
|
-
let method;
|
|
820
|
-
if (version) {
|
|
821
|
-
if (dispatchNamespace) {
|
|
822
|
-
throw new Error("Worker Preview Versions are not supported in Workers for Platforms");
|
|
823
|
-
}
|
|
824
|
-
// Upload worker version using the versions API
|
|
825
|
-
endpoint = `/accounts/${api.accountId}/workers/scripts/${workerName}/versions`;
|
|
826
|
-
method = "POST";
|
|
827
|
-
}
|
|
828
|
-
else {
|
|
829
|
-
// Upload worker script with bindings
|
|
830
|
-
endpoint = dispatchNamespace
|
|
831
|
-
? `/accounts/${api.accountId}/workers/dispatch/namespaces/${dispatchNamespace}/scripts/${workerName}`
|
|
832
|
-
: `/accounts/${api.accountId}/workers/scripts/${workerName}`;
|
|
833
|
-
method = "PUT";
|
|
834
|
-
}
|
|
835
|
-
const uploadResponse = method === "PUT"
|
|
836
|
-
? await api.put(endpoint, formData, {
|
|
837
|
-
headers: {
|
|
838
|
-
"Content-Type": "multipart/form-data",
|
|
839
|
-
},
|
|
840
|
-
})
|
|
841
|
-
: await api.post(endpoint, formData, {
|
|
842
|
-
headers: {
|
|
843
|
-
"Content-Type": "multipart/form-data",
|
|
844
|
-
},
|
|
845
|
-
});
|
|
962
|
+
const { body, endpoint, method } = await prepareWorkerUpload(api, props);
|
|
963
|
+
const uploadResponse = await api.fetch(endpoint, {
|
|
964
|
+
method,
|
|
965
|
+
headers: {
|
|
966
|
+
"Content-Type": "multipart/form-data",
|
|
967
|
+
},
|
|
968
|
+
body,
|
|
969
|
+
});
|
|
846
970
|
// Check if the upload was successful
|
|
847
971
|
if (!uploadResponse.ok) {
|
|
848
972
|
try {
|
|
@@ -876,33 +1000,7 @@ export async function putWorker(api, props) {
|
|
|
876
1000
|
}
|
|
877
1001
|
}
|
|
878
1002
|
const responseData = (await uploadResponse.json());
|
|
879
|
-
|
|
880
|
-
// Handle version response
|
|
881
|
-
if (props.version) {
|
|
882
|
-
// Get the account's workers.dev subdomain to construct preview URL
|
|
883
|
-
let previewUrl;
|
|
884
|
-
if (result.metadata?.has_preview) {
|
|
885
|
-
// Need to get the subdomain
|
|
886
|
-
const subdomainResponse = await api.get(`/accounts/${api.accountId}/workers/subdomain`);
|
|
887
|
-
if (subdomainResponse.ok) {
|
|
888
|
-
const subdomainData = await subdomainResponse.json();
|
|
889
|
-
const subdomain = subdomainData.result?.subdomain;
|
|
890
|
-
if (subdomain) {
|
|
891
|
-
// Preview URL format: <FIRST_8_CHARS_OF_VERSION_ID>-<WORKER_NAME>.<SUBDOMAIN>.workers.dev
|
|
892
|
-
const versionPrefix = result.id.substring(0, 8);
|
|
893
|
-
previewUrl = `https://${versionPrefix}-${workerName}.${subdomain}.workers.dev`;
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
return {
|
|
898
|
-
versionId: result.id,
|
|
899
|
-
previewUrl,
|
|
900
|
-
deploymentId: result.deployment_id,
|
|
901
|
-
};
|
|
902
|
-
}
|
|
903
|
-
return {
|
|
904
|
-
deploymentId: result.deployment_id,
|
|
905
|
-
};
|
|
1003
|
+
return responseData.result;
|
|
906
1004
|
}, (err) => err.status === 404 ||
|
|
907
1005
|
err.status === 500 ||
|
|
908
1006
|
err.status === 503 ||
|
|
@@ -911,68 +1009,57 @@ export async function putWorker(api, props) {
|
|
|
911
1009
|
err.status === 400 &&
|
|
912
1010
|
err.message.match(/binding.*failed to generate/)), 10, 100);
|
|
913
1011
|
}
|
|
914
|
-
|
|
915
|
-
const
|
|
916
|
-
return
|
|
1012
|
+
async function workerExists(api, scriptName) {
|
|
1013
|
+
const res = await api.get(`/accounts/${api.accountId}/workers/scripts/${scriptName}`);
|
|
1014
|
+
return res.status === 200;
|
|
917
1015
|
}
|
|
918
|
-
|
|
919
|
-
const response = await api.get(`/accounts/${api.accountId}/workers/scripts/${
|
|
1016
|
+
async function assertWorkerDoesNotExist(api, scriptName) {
|
|
1017
|
+
const response = await api.get(`/accounts/${api.accountId}/workers/scripts/${scriptName}`);
|
|
920
1018
|
if (response.status === 404) {
|
|
921
1019
|
return true;
|
|
922
1020
|
}
|
|
923
1021
|
if (response.status === 200) {
|
|
924
|
-
const metadata = await
|
|
1022
|
+
const metadata = await getScriptMetadata(api, scriptName);
|
|
925
1023
|
if (!metadata) {
|
|
926
1024
|
throw new Error(`Worker exists but failed to fetch metadata: ${response.status} ${response.statusText}`);
|
|
927
1025
|
}
|
|
928
|
-
throw new Error(`Worker with name '${
|
|
1026
|
+
throw new Error(`Worker with name '${scriptName}' already exists. Please use a unique name.`);
|
|
929
1027
|
}
|
|
930
1028
|
throw new Error(`Error checking if worker exists: ${response.status} ${response.statusText} ${await response.text()}`);
|
|
931
1029
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
if (
|
|
935
|
-
|
|
936
|
-
await api.post(`/accounts/${api.accountId}/workers/scripts/${workerName}/subdomain`, { enabled: true, previews_enabled: true }, {
|
|
937
|
-
headers: { "Content-Type": "application/json" },
|
|
938
|
-
});
|
|
939
|
-
// Get the account's workers.dev subdomain
|
|
940
|
-
const subdomain = await getAccountSubdomain(api);
|
|
941
|
-
if (subdomain) {
|
|
942
|
-
workerUrl = `https://${workerName}.${subdomain}.workers.dev`;
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
else if (url === false && ctx.output?.url) {
|
|
946
|
-
// Explicitly disable URL if it was previously enabled
|
|
947
|
-
const response = await api.post(`/accounts/${api.accountId}/workers/scripts/${workerName}/subdomain`, JSON.stringify({ enabled: false }), {
|
|
948
|
-
headers: { "Content-Type": "application/json" },
|
|
949
|
-
});
|
|
950
|
-
if (!response.ok) {
|
|
951
|
-
throw new Error(`Failed to disable worker URL: ${response.status} ${response.statusText}`);
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
return workerUrl;
|
|
955
|
-
}
|
|
956
|
-
export async function getWorkerScriptMetadata(api, workerName) {
|
|
957
|
-
const response = await api.get(`/accounts/${api.accountId}/workers/services/${workerName}`);
|
|
958
|
-
if (response.status === 404) {
|
|
959
|
-
return undefined;
|
|
1030
|
+
async function getScriptMetadata(api, scriptName) {
|
|
1031
|
+
const res = await api.get(`/accounts/${api.accountId}/workers/services/${scriptName}`);
|
|
1032
|
+
if (res.status === 404) {
|
|
1033
|
+
return;
|
|
960
1034
|
}
|
|
961
|
-
if (!
|
|
962
|
-
throw new Error(`Error getting worker script metadata: ${
|
|
1035
|
+
if (!res.ok) {
|
|
1036
|
+
throw new Error(`Error getting worker script metadata: ${res.status} ${res.statusText}`);
|
|
963
1037
|
}
|
|
964
|
-
|
|
1038
|
+
const json = (await res.json());
|
|
1039
|
+
return json.result;
|
|
965
1040
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
* @param ctx Worker context containing eventSources
|
|
969
|
-
* @param api CloudflareApi instance
|
|
970
|
-
* @param workerName Name of the worker script
|
|
971
|
-
*/
|
|
972
|
-
async function deleteQueueConsumers(api, workerName) {
|
|
973
|
-
const consumers = await listQueueConsumersForWorker(api, workerName);
|
|
1041
|
+
async function deleteQueueConsumers(api, scriptName) {
|
|
1042
|
+
const consumers = await listQueueConsumersForWorker(api, scriptName);
|
|
974
1043
|
await Promise.all(consumers.map(async (consumer) => {
|
|
975
1044
|
await deleteQueueConsumer(api, consumer.queueId, consumer.consumerId);
|
|
976
1045
|
}));
|
|
977
1046
|
}
|
|
1047
|
+
export async function deleteWorker(api, props) {
|
|
1048
|
+
await withExponentialBackoff(async () => {
|
|
1049
|
+
const deleteResponse = await api.delete(props.dispatchNamespace
|
|
1050
|
+
? `/accounts/${api.accountId}/workers/dispatch/namespaces/${props.dispatchNamespace}/scripts/${props.scriptName}?force=true`
|
|
1051
|
+
: `/accounts/${api.accountId}/workers/scripts/${props.scriptName}?force=true`);
|
|
1052
|
+
if (!deleteResponse.ok && deleteResponse.status !== 404) {
|
|
1053
|
+
await handleApiError(deleteResponse, "delete", "worker", props.scriptName);
|
|
1054
|
+
}
|
|
1055
|
+
}, (err) => (err.status === 400 &&
|
|
1056
|
+
err.message.includes("is still referenced by service bindings in Workers")) ||
|
|
1057
|
+
err.status === 500 ||
|
|
1058
|
+
err.status === 503, 10, 100);
|
|
1059
|
+
}
|
|
1060
|
+
async function getVersionMetadata(api, scriptName, deploymentId) {
|
|
1061
|
+
const response = await api.get(`/accounts/${api.accountId}/workers/scripts/${scriptName}/versions/${deploymentId}`);
|
|
1062
|
+
const result = (await response.json());
|
|
1063
|
+
return result.result;
|
|
1064
|
+
}
|
|
978
1065
|
//# sourceMappingURL=worker.js.map
|