alchemy 0.16.9 → 0.17.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/lib/ai/astro-file.d.ts +1 -1
- package/lib/ai/astro-file.d.ts.map +1 -1
- package/lib/ai/astro-file.js +1 -1
- package/lib/ai/astro-file.js.map +1 -1
- package/lib/ai/client.js +2 -2
- package/lib/ai/client.js.map +1 -1
- package/lib/ai/css-file.d.ts +1 -1
- package/lib/ai/css-file.d.ts.map +1 -1
- package/lib/ai/css-file.js +1 -1
- package/lib/ai/css-file.js.map +1 -1
- package/lib/ai/data.d.ts +1 -1
- package/lib/ai/data.d.ts.map +1 -1
- package/lib/ai/data.js +1 -1
- package/lib/ai/data.js.map +1 -1
- package/lib/ai/html-file.d.ts +1 -1
- package/lib/ai/html-file.d.ts.map +1 -1
- package/lib/ai/html-file.js +1 -1
- package/lib/ai/html-file.js.map +1 -1
- package/lib/ai/json-file.d.ts +1 -1
- package/lib/ai/json-file.d.ts.map +1 -1
- package/lib/ai/json-file.js +1 -1
- package/lib/ai/json-file.js.map +1 -1
- package/lib/ai/typescript-file.d.ts +1 -1
- package/lib/ai/typescript-file.d.ts.map +1 -1
- package/lib/ai/typescript-file.js +1 -1
- package/lib/ai/typescript-file.js.map +1 -1
- package/lib/ai/vue-file.d.ts +1 -1
- package/lib/ai/vue-file.d.ts.map +1 -1
- package/lib/ai/vue-file.js +1 -1
- package/lib/ai/vue-file.js.map +1 -1
- package/lib/ai/yaml-file.d.ts +1 -1
- package/lib/ai/yaml-file.d.ts.map +1 -1
- package/lib/ai/yaml-file.js +2 -2
- package/lib/ai/yaml-file.js.map +1 -1
- package/lib/alchemy.d.ts +4 -0
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js +14 -4
- package/lib/alchemy.js.map +1 -1
- package/lib/apply.d.ts +2 -0
- package/lib/apply.d.ts.map +1 -1
- package/lib/apply.js +17 -2
- package/lib/apply.js.map +1 -1
- package/lib/aws/bucket.d.ts +1 -1
- package/lib/aws/bucket.d.ts.map +1 -1
- package/lib/aws/bucket.js +1 -1
- package/lib/aws/bucket.js.map +1 -1
- package/lib/aws/function.d.ts +1 -1
- package/lib/aws/function.d.ts.map +1 -1
- package/lib/aws/function.js +2 -2
- package/lib/aws/function.js.map +1 -1
- package/lib/aws/oidc/oidc-provider.d.ts +1 -1
- package/lib/aws/oidc/oidc-provider.d.ts.map +1 -1
- package/lib/aws/oidc/oidc-provider.js +1 -1
- package/lib/aws/oidc/oidc-provider.js.map +1 -1
- package/lib/aws/policy-attachment.d.ts +1 -1
- package/lib/aws/policy-attachment.d.ts.map +1 -1
- package/lib/aws/policy-attachment.js +1 -1
- package/lib/aws/policy-attachment.js.map +1 -1
- package/lib/aws/policy.d.ts +1 -1
- package/lib/aws/policy.d.ts.map +1 -1
- package/lib/aws/policy.js +1 -1
- package/lib/aws/policy.js.map +1 -1
- package/lib/aws/queue.d.ts +1 -1
- package/lib/aws/queue.d.ts.map +1 -1
- package/lib/aws/queue.js +20 -25
- package/lib/aws/queue.js.map +1 -1
- package/lib/aws/role.d.ts +1 -1
- package/lib/aws/role.d.ts.map +1 -1
- package/lib/aws/role.js +1 -1
- package/lib/aws/role.js.map +1 -1
- package/lib/aws/ses.d.ts +1 -1
- package/lib/aws/ses.d.ts.map +1 -1
- package/lib/aws/ses.js +1 -1
- package/lib/aws/ses.js.map +1 -1
- package/lib/aws/table.d.ts +1 -1
- package/lib/aws/table.d.ts.map +1 -1
- package/lib/aws/table.js +1 -1
- package/lib/aws/table.js.map +1 -1
- package/lib/cloudflare/account-api-token.d.ts +1 -1
- package/lib/cloudflare/account-api-token.d.ts.map +1 -1
- package/lib/cloudflare/account-api-token.js +1 -1
- package/lib/cloudflare/account-api-token.js.map +1 -1
- package/lib/cloudflare/ai-gateway.d.ts +4 -3
- package/lib/cloudflare/ai-gateway.d.ts.map +1 -1
- package/lib/cloudflare/ai-gateway.js +13 -1
- package/lib/cloudflare/ai-gateway.js.map +1 -1
- package/lib/cloudflare/analytics-engine.d.ts +21 -0
- package/lib/cloudflare/analytics-engine.d.ts.map +1 -0
- package/lib/cloudflare/analytics-engine.js +17 -0
- package/lib/cloudflare/analytics-engine.js.map +1 -0
- package/lib/cloudflare/api-error.js +1 -1
- package/lib/cloudflare/api-error.js.map +1 -1
- package/lib/cloudflare/assets.js +2 -2
- package/lib/cloudflare/assets.js.map +1 -1
- package/lib/cloudflare/auth.js +1 -1
- package/lib/cloudflare/auth.js.map +1 -1
- package/lib/cloudflare/bindings.d.ts +18 -11
- package/lib/cloudflare/bindings.d.ts.map +1 -1
- package/lib/cloudflare/bindings.js +6 -0
- package/lib/cloudflare/bindings.js.map +1 -1
- package/lib/cloudflare/bound.d.ts +12 -10
- package/lib/cloudflare/bound.d.ts.map +1 -1
- package/lib/cloudflare/bucket.d.ts +6 -4
- package/lib/cloudflare/bucket.d.ts.map +1 -1
- package/lib/cloudflare/bucket.js +22 -2
- package/lib/cloudflare/bucket.js.map +1 -1
- package/lib/cloudflare/bundle/bundle-worker.d.ts +1 -0
- package/lib/cloudflare/bundle/bundle-worker.d.ts.map +1 -1
- package/lib/cloudflare/bundle/bundle-worker.js +4 -2
- package/lib/cloudflare/bundle/bundle-worker.js.map +1 -1
- package/lib/cloudflare/bundle/nodejs-compat-mode.d.ts +1 -1
- package/lib/cloudflare/bundle/nodejs-compat-mode.d.ts.map +1 -1
- package/lib/cloudflare/bundle/nodejs-compat-mode.js +2 -2
- package/lib/cloudflare/bundle/nodejs-compat-mode.js.map +1 -1
- package/lib/cloudflare/bundle/nodejs-compat.js +1 -1
- package/lib/cloudflare/bundle/nodejs-compat.js.map +1 -1
- package/lib/cloudflare/custom-domain.js +1 -1
- package/lib/cloudflare/custom-domain.js.map +1 -1
- package/lib/cloudflare/d1-database.d.ts +4 -62
- package/lib/cloudflare/d1-database.d.ts.map +1 -1
- package/lib/cloudflare/d1-database.js +27 -11
- package/lib/cloudflare/d1-database.js.map +1 -1
- package/lib/cloudflare/dns-records.d.ts +1 -1
- package/lib/cloudflare/dns-records.d.ts.map +1 -1
- package/lib/cloudflare/dns-records.js +2 -2
- package/lib/cloudflare/dns-records.js.map +1 -1
- package/lib/cloudflare/event-source.d.ts +3 -3
- package/lib/cloudflare/event-source.d.ts.map +1 -1
- package/lib/cloudflare/hyperdrive.d.ts +4 -3
- package/lib/cloudflare/hyperdrive.d.ts.map +1 -1
- package/lib/cloudflare/hyperdrive.js +9 -1
- package/lib/cloudflare/hyperdrive.js.map +1 -1
- package/lib/cloudflare/kv-namespace.d.ts +9 -5
- package/lib/cloudflare/kv-namespace.d.ts.map +1 -1
- package/lib/cloudflare/kv-namespace.js +26 -6
- package/lib/cloudflare/kv-namespace.js.map +1 -1
- package/lib/cloudflare/permission-groups.d.ts +1 -1
- package/lib/cloudflare/permission-groups.d.ts.map +1 -1
- package/lib/cloudflare/permission-groups.js +1 -1
- package/lib/cloudflare/permission-groups.js.map +1 -1
- package/lib/cloudflare/pipeline.d.ts +5 -3
- package/lib/cloudflare/pipeline.d.ts.map +1 -1
- package/lib/cloudflare/pipeline.js +16 -2
- package/lib/cloudflare/pipeline.js.map +1 -1
- package/lib/cloudflare/queue-consumer.d.ts +3 -3
- package/lib/cloudflare/queue-consumer.d.ts.map +1 -1
- package/lib/cloudflare/queue-consumer.js +1 -1
- package/lib/cloudflare/queue-consumer.js.map +1 -1
- package/lib/cloudflare/queue.d.ts +34 -22
- package/lib/cloudflare/queue.d.ts.map +1 -1
- package/lib/cloudflare/queue.js +66 -4
- package/lib/cloudflare/queue.js.map +1 -1
- package/lib/cloudflare/route.d.ts +1 -1
- package/lib/cloudflare/route.d.ts.map +1 -1
- package/lib/cloudflare/route.js +1 -1
- package/lib/cloudflare/route.js.map +1 -1
- package/lib/cloudflare/types.js +1 -1
- package/lib/cloudflare/types.js.map +1 -1
- package/lib/cloudflare/vectorize-index.d.ts +6 -4
- package/lib/cloudflare/vectorize-index.d.ts.map +1 -1
- package/lib/cloudflare/vectorize-index.js +20 -3
- package/lib/cloudflare/vectorize-index.js.map +1 -1
- package/lib/cloudflare/vectorize-metadata-index.d.ts +4 -3
- package/lib/cloudflare/vectorize-metadata-index.d.ts.map +1 -1
- package/lib/cloudflare/vectorize-metadata-index.js +5 -2
- package/lib/cloudflare/vectorize-metadata-index.js.map +1 -1
- package/lib/cloudflare/website.d.ts.map +1 -1
- package/lib/cloudflare/website.js +3 -0
- package/lib/cloudflare/website.js.map +1 -1
- package/lib/cloudflare/worker-assets.d.ts +32 -0
- package/lib/cloudflare/worker-assets.d.ts.map +1 -0
- package/lib/cloudflare/worker-assets.js +143 -0
- package/lib/cloudflare/worker-assets.js.map +1 -0
- package/lib/cloudflare/worker-metadata.d.ts +31 -0
- package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
- package/lib/cloudflare/worker-metadata.js +248 -0
- package/lib/cloudflare/worker-metadata.js.map +1 -1
- package/lib/cloudflare/worker-stub.d.ts +40 -0
- package/lib/cloudflare/worker-stub.d.ts.map +1 -0
- package/lib/cloudflare/worker-stub.js +86 -0
- package/lib/cloudflare/worker-stub.js.map +1 -0
- package/lib/cloudflare/worker.d.ts +57 -28
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +203 -472
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/wrangler.json.d.ts +29 -1
- package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
- package/lib/cloudflare/wrangler.json.js +50 -2
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/cloudflare/zone.d.ts +1 -1
- package/lib/cloudflare/zone.d.ts.map +1 -1
- package/lib/cloudflare/zone.js +1 -1
- package/lib/cloudflare/zone.js.map +1 -1
- package/lib/destroy.d.ts +1 -4
- package/lib/destroy.d.ts.map +1 -1
- package/lib/destroy.js +10 -21
- package/lib/destroy.js.map +1 -1
- package/lib/dns/import-dns.d.ts +1 -1
- package/lib/dns/import-dns.d.ts.map +1 -1
- package/lib/dns/import-dns.js +1 -1
- package/lib/dns/import-dns.js.map +1 -1
- package/lib/encrypt.d.ts.map +1 -1
- package/lib/encrypt.js +2 -1
- package/lib/encrypt.js.map +1 -1
- package/lib/env.js +14 -8
- package/lib/env.js.map +1 -1
- package/lib/esbuild/bundle.d.ts +2 -2
- package/lib/esbuild/bundle.d.ts.map +1 -1
- package/lib/esbuild/bundle.js +3 -3
- package/lib/esbuild/bundle.js.map +1 -1
- package/lib/fs/copy-file.d.ts +1 -1
- package/lib/fs/copy-file.d.ts.map +1 -1
- package/lib/fs/copy-file.js +1 -1
- package/lib/fs/copy-file.js.map +1 -1
- package/lib/github/client.js +1 -1
- package/lib/github/client.js.map +1 -1
- package/lib/github/repository-environment.d.ts +1 -1
- package/lib/github/repository-environment.d.ts.map +1 -1
- package/lib/github/repository-environment.js +2 -2
- package/lib/github/repository-environment.js.map +1 -1
- package/lib/github/secret.d.ts +1 -1
- package/lib/github/secret.d.ts.map +1 -1
- package/lib/github/secret.js +1 -1
- package/lib/github/secret.js.map +1 -1
- package/lib/internal/docs/providers.d.ts +1 -1
- package/lib/internal/docs/providers.d.ts.map +1 -1
- package/lib/internal/docs/providers.js +3 -1
- package/lib/internal/docs/providers.js.map +1 -1
- package/lib/neon/api-error.js +2 -2
- package/lib/neon/api-error.js.map +1 -1
- package/lib/os/exec.js +1 -1
- package/lib/os/exec.js.map +1 -1
- package/lib/resource.d.ts +13 -11
- package/lib/resource.d.ts.map +1 -1
- package/lib/resource.js +10 -5
- package/lib/resource.js.map +1 -1
- package/lib/runtime/bind.d.ts +25 -0
- package/lib/runtime/bind.d.ts.map +1 -0
- package/lib/runtime/bind.js +76 -0
- package/lib/runtime/bind.js.map +1 -0
- package/lib/runtime/global.d.ts +8 -0
- package/lib/runtime/global.d.ts.map +1 -0
- package/lib/runtime/global.js +3 -0
- package/lib/runtime/global.js.map +1 -0
- package/lib/runtime/plugin.d.ts +35 -0
- package/lib/runtime/plugin.d.ts.map +1 -0
- package/lib/runtime/plugin.js +133 -0
- package/lib/runtime/plugin.js.map +1 -0
- package/lib/runtime/shims.d.ts +6 -0
- package/lib/runtime/shims.d.ts.map +1 -0
- package/lib/runtime/shims.js +27 -0
- package/lib/runtime/shims.js.map +1 -0
- package/lib/runtime/state.d.ts +5 -0
- package/lib/runtime/state.d.ts.map +1 -0
- package/lib/runtime/state.js +4 -0
- package/lib/runtime/state.js.map +1 -0
- package/lib/scope.d.ts +16 -2
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +56 -9
- package/lib/scope.js.map +1 -1
- package/lib/secret.d.ts +7 -2
- package/lib/secret.d.ts.map +1 -1
- package/lib/secret.js +19 -4
- package/lib/secret.js.map +1 -1
- package/lib/sentry/client-key.d.ts +1 -1
- package/lib/sentry/client-key.d.ts.map +1 -1
- package/lib/sentry/client-key.js +1 -1
- package/lib/sentry/client-key.js.map +1 -1
- package/lib/sentry/project.d.ts +1 -1
- package/lib/sentry/project.d.ts.map +1 -1
- package/lib/sentry/project.js +1 -1
- package/lib/sentry/project.js.map +1 -1
- package/lib/sentry/team.d.ts +1 -1
- package/lib/sentry/team.d.ts.map +1 -1
- package/lib/sentry/team.js +1 -1
- package/lib/sentry/team.js.map +1 -1
- package/lib/serde.d.ts +26 -1
- package/lib/serde.d.ts.map +1 -1
- package/lib/serde.js +53 -8
- package/lib/serde.js.map +1 -1
- package/lib/stripe/meter.d.ts +1 -1
- package/lib/stripe/meter.d.ts.map +1 -1
- package/lib/stripe/meter.js +1 -1
- package/lib/stripe/meter.js.map +1 -1
- package/lib/stripe/price.d.ts +1 -1
- package/lib/stripe/price.d.ts.map +1 -1
- package/lib/stripe/price.js +1 -1
- package/lib/stripe/price.js.map +1 -1
- package/lib/stripe/product.d.ts +1 -1
- package/lib/stripe/product.d.ts.map +1 -1
- package/lib/stripe/product.js +1 -1
- package/lib/stripe/product.js.map +1 -1
- package/lib/stripe/webhook.d.ts +1 -1
- package/lib/stripe/webhook.d.ts.map +1 -1
- package/lib/stripe/webhook.js +1 -1
- package/lib/stripe/webhook.js.map +1 -1
- package/lib/test/bun.js +1 -1
- package/lib/test/bun.js.map +1 -1
- package/lib/test/prune.js +1 -1
- package/lib/test/prune.js.map +1 -1
- package/lib/upstash/redis.d.ts +1 -1
- package/lib/upstash/redis.d.ts.map +1 -1
- package/lib/upstash/redis.js +1 -1
- package/lib/upstash/redis.js.map +1 -1
- package/lib/util/assert-never.d.ts +2 -0
- package/lib/util/assert-never.d.ts.map +1 -0
- package/lib/util/assert-never.js +4 -0
- package/lib/util/assert-never.js.map +1 -0
- package/lib/util/content-type.d.ts +1 -1
- package/lib/util/content-type.d.ts.map +1 -1
- package/lib/util/content-type.js +1 -2
- package/lib/util/content-type.js.map +1 -1
- package/lib/util/retry.d.ts.map +1 -1
- package/lib/util/retry.js +1 -0
- package/lib/util/retry.js.map +1 -1
- package/lib/vercel/project-domain.d.ts +1 -1
- package/lib/vercel/project-domain.d.ts.map +1 -1
- package/lib/vercel/project-domain.js +1 -1
- package/lib/vercel/project-domain.js.map +1 -1
- package/lib/vercel/project.js +1 -1
- package/lib/vercel/project.js.map +1 -1
- package/lib/web/shadcn-component.d.ts +1 -1
- package/lib/web/shadcn-component.d.ts.map +1 -1
- package/lib/web/shadcn-component.js +1 -1
- package/lib/web/shadcn-component.js.map +1 -1
- package/lib/web/shadcn.d.ts +1 -1
- package/lib/web/shadcn.d.ts.map +1 -1
- package/lib/web/shadcn.js +1 -1
- package/lib/web/shadcn.js.map +1 -1
- package/lib/web/vitepress/dependencies.d.ts +1 -1
- package/lib/web/vitepress/dependencies.d.ts.map +1 -1
- package/lib/web/vitepress/dependencies.js +1 -1
- package/lib/web/vitepress/dependencies.js.map +1 -1
- package/lib/web/vitepress/vitepress.js +1 -1
- package/lib/web/vitepress/vitepress.js.map +1 -1
- package/package.json +2 -1
- package/src/ai/astro-file.ts +1 -1
- package/src/ai/client.ts +2 -2
- package/src/ai/css-file.ts +1 -1
- package/src/ai/data.ts +1 -1
- package/src/ai/html-file.ts +1 -1
- package/src/ai/json-file.ts +1 -1
- package/src/ai/typescript-file.ts +1 -1
- package/src/ai/vue-file.ts +1 -1
- package/src/ai/yaml-file.ts +2 -2
- package/src/alchemy.ts +18 -4
- package/src/apply.ts +27 -2
- package/src/aws/bucket.ts +1 -1
- package/src/aws/function.ts +2 -2
- package/src/aws/oidc/oidc-provider.ts +1 -1
- package/src/aws/policy-attachment.ts +1 -1
- package/src/aws/policy.ts +1 -1
- package/src/aws/queue.ts +28 -29
- package/src/aws/role.ts +1 -1
- package/src/aws/ses.ts +1 -1
- package/src/aws/table.ts +1 -1
- package/src/cloudflare/account-api-token.ts +1 -1
- package/src/cloudflare/ai-gateway.ts +23 -4
- package/src/cloudflare/analytics-engine.ts +26 -0
- package/src/cloudflare/api-error.ts +1 -1
- package/src/cloudflare/assets.ts +2 -2
- package/src/cloudflare/auth.ts +1 -1
- package/src/cloudflare/bindings.ts +35 -18
- package/src/cloudflare/bound.ts +27 -23
- package/src/cloudflare/bucket.ts +52 -24
- package/src/cloudflare/bundle/bundle-worker.ts +5 -2
- package/src/cloudflare/bundle/nodejs-compat-mode.ts +3 -3
- package/src/cloudflare/bundle/nodejs-compat.ts +1 -1
- package/src/cloudflare/custom-domain.ts +1 -1
- package/src/cloudflare/d1-database.ts +40 -19
- package/src/cloudflare/dns-records.ts +2 -2
- package/src/cloudflare/event-source.ts +3 -3
- package/src/cloudflare/hyperdrive.ts +19 -4
- package/src/cloudflare/kv-namespace.ts +46 -15
- package/src/cloudflare/permission-groups.ts +1 -1
- package/src/cloudflare/pipeline.ts +29 -6
- package/src/cloudflare/queue-consumer.ts +3 -3
- package/src/cloudflare/queue.ts +124 -23
- package/src/cloudflare/route.ts +1 -1
- package/src/cloudflare/types.ts +1 -1
- package/src/cloudflare/vectorize-index.ts +36 -8
- package/src/cloudflare/vectorize-metadata-index.ts +10 -4
- package/src/cloudflare/website.ts +3 -0
- package/src/cloudflare/worker-assets.ts +237 -0
- package/src/cloudflare/worker-metadata.ts +287 -0
- package/src/cloudflare/worker-stub.ts +153 -0
- package/src/cloudflare/worker.ts +386 -586
- package/src/cloudflare/wrangler.json.ts +75 -2
- package/src/cloudflare/zone.ts +1 -1
- package/src/destroy.ts +12 -23
- package/src/dns/import-dns.ts +1 -1
- package/src/encrypt.ts +2 -2
- package/src/env.ts +15 -8
- package/src/esbuild/bundle.ts +4 -3
- package/src/fs/copy-file.ts +1 -1
- package/src/github/client.ts +1 -1
- package/src/github/repository-environment.ts +2 -2
- package/src/github/secret.ts +1 -1
- package/src/internal/docs/providers.ts +1 -1
- package/src/neon/api-error.ts +2 -2
- package/src/os/exec.ts +1 -1
- package/src/resource.ts +22 -31
- package/src/runtime/bind.ts +95 -0
- package/src/runtime/global.ts +10 -0
- package/src/runtime/plugin.ts +162 -0
- package/src/runtime/shims.js +34 -0
- package/src/runtime/state.ts +9 -0
- package/src/scope.ts +72 -11
- package/src/secret.ts +29 -4
- package/src/sentry/client-key.ts +1 -1
- package/src/sentry/project.ts +1 -1
- package/src/sentry/team.ts +1 -1
- package/src/serde.ts +126 -10
- package/src/stripe/meter.ts +1 -1
- package/src/stripe/price.ts +1 -1
- package/src/stripe/product.ts +1 -1
- package/src/stripe/webhook.ts +1 -1
- package/src/test/bun.ts +1 -1
- package/src/test/prune.ts +1 -1
- package/src/upstash/redis.ts +1 -1
- package/src/util/assert-never.ts +3 -0
- package/src/util/content-type.ts +2 -3
- package/src/util/retry.ts +1 -0
- package/src/vercel/project-domain.ts +1 -1
- package/src/vercel/project.ts +1 -1
- package/src/web/shadcn-component.ts +1 -1
- package/src/web/shadcn.ts +1 -1
- package/src/web/vitepress/dependencies.ts +1 -1
- package/src/web/vitepress/vitepress.ts +1 -1
package/src/cloudflare/worker.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as fs from "node:fs/promises";
|
|
1
|
+
import path from "node:path";
|
|
3
2
|
import type { Context } from "../context.js";
|
|
4
3
|
import type { BundleProps } from "../esbuild/bundle.js";
|
|
5
|
-
import { Resource } from "../resource.js";
|
|
6
|
-
import {
|
|
4
|
+
import { InnerResourceScope, Resource, ResourceKind } from "../resource.js";
|
|
5
|
+
import { getBindKey, tryGetBinding } from "../runtime/bind.js";
|
|
6
|
+
import { isRuntime } from "../runtime/global.js";
|
|
7
|
+
import { bootstrapPlugin } from "../runtime/plugin.js";
|
|
8
|
+
import { Scope } from "../scope.js";
|
|
9
|
+
import { Secret, secret } from "../secret.js";
|
|
10
|
+
import { serializeScope } from "../serde.js";
|
|
7
11
|
import { withExponentialBackoff } from "../util/retry.js";
|
|
8
12
|
import { slugify } from "../util/slugify.js";
|
|
9
13
|
import { CloudflareApiError, handleApiError } from "./api-error.js";
|
|
@@ -13,19 +17,33 @@ import {
|
|
|
13
17
|
createCloudflareApi,
|
|
14
18
|
} from "./api.js";
|
|
15
19
|
import type { Assets } from "./assets.js";
|
|
16
|
-
import { type
|
|
20
|
+
import { type Binding, type Bindings, Json } from "./bindings.js";
|
|
17
21
|
import type { Bound } from "./bound.js";
|
|
22
|
+
import { isBucket } from "./bucket.js";
|
|
18
23
|
import { bundleWorkerScript } from "./bundle/bundle-worker.js";
|
|
19
|
-
import
|
|
20
|
-
import {
|
|
24
|
+
import { isD1Database } from "./d1-database.js";
|
|
25
|
+
import {
|
|
26
|
+
type EventSource,
|
|
27
|
+
type QueueEventSource,
|
|
28
|
+
isQueueEventSource,
|
|
29
|
+
} from "./event-source.js";
|
|
30
|
+
import { isKVNamespace } from "./kv-namespace.js";
|
|
31
|
+
import { isPipeline } from "./pipeline.js";
|
|
21
32
|
import {
|
|
22
33
|
QueueConsumer,
|
|
23
34
|
deleteQueueConsumer,
|
|
24
35
|
listQueueConsumers,
|
|
25
36
|
} from "./queue-consumer.js";
|
|
26
|
-
import { isQueue } from "./queue.js";
|
|
27
|
-
import
|
|
37
|
+
import { type QueueResource, isQueue } from "./queue.js";
|
|
38
|
+
import { isVectorizeIndex } from "./vectorize-index.js";
|
|
39
|
+
import { type AssetUploadResult, uploadAssets } from "./worker-assets.js";
|
|
40
|
+
import {
|
|
41
|
+
type WorkerMetadata,
|
|
42
|
+
type WorkerScriptMetadata,
|
|
43
|
+
prepareWorkerMetadata,
|
|
44
|
+
} from "./worker-metadata.js";
|
|
28
45
|
import type { SingleStepMigration } from "./worker-migration.js";
|
|
46
|
+
import { WorkerStub, isWorkerStub } from "./worker-stub.js";
|
|
29
47
|
import { type Workflow, upsertWorkflow } from "./workflow.js";
|
|
30
48
|
|
|
31
49
|
/**
|
|
@@ -72,40 +90,20 @@ export interface AssetsConfig {
|
|
|
72
90
|
serve_directly?: boolean;
|
|
73
91
|
}
|
|
74
92
|
|
|
75
|
-
|
|
76
|
-
* Properties for creating or updating a Worker
|
|
77
|
-
*/
|
|
78
|
-
export interface WorkerProps<B extends Bindings = Bindings>
|
|
93
|
+
export interface BaseWorkerProps<B extends Bindings = Bindings>
|
|
79
94
|
extends CloudflareApiOptions {
|
|
80
95
|
/**
|
|
81
|
-
*
|
|
82
|
-
* One of script, entryPoint, or bundle must be provided
|
|
83
|
-
*/
|
|
84
|
-
script?: string;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Path to the entry point file
|
|
88
|
-
*
|
|
89
|
-
* Will be bundled using esbuild
|
|
96
|
+
* Bundle options when using entryPoint
|
|
90
97
|
*
|
|
91
|
-
*
|
|
98
|
+
* Ignored if bundle is provided
|
|
92
99
|
*/
|
|
93
|
-
|
|
100
|
+
bundle?: Omit<BundleProps, "entryPoint">;
|
|
94
101
|
|
|
95
102
|
/**
|
|
96
|
-
* The
|
|
97
|
-
*
|
|
98
|
-
* @default process.cwd()
|
|
103
|
+
* The root directory of the project
|
|
99
104
|
*/
|
|
100
105
|
projectRoot?: string;
|
|
101
106
|
|
|
102
|
-
/**
|
|
103
|
-
* Bundle options when using entryPoint
|
|
104
|
-
*
|
|
105
|
-
* Ignored if bundle is provided
|
|
106
|
-
*/
|
|
107
|
-
bundle?: Omit<BundleProps, "entryPoint">;
|
|
108
|
-
|
|
109
107
|
/**
|
|
110
108
|
* Module format for the worker script
|
|
111
109
|
* - 'esm' - ECMAScript modules (default)
|
|
@@ -202,65 +200,128 @@ export interface WorkerProps<B extends Bindings = Bindings>
|
|
|
202
200
|
eventSources?: EventSource[];
|
|
203
201
|
}
|
|
204
202
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
Omit<WorkerProps<B>, "url" | "script"> {
|
|
211
|
-
type: "service";
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* The ID of the worker
|
|
215
|
-
*/
|
|
216
|
-
id: string;
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* The name of the worker
|
|
220
|
-
*/
|
|
221
|
-
name: string;
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Time at which the worker was created
|
|
225
|
-
*/
|
|
226
|
-
createdAt: number;
|
|
203
|
+
export interface InlineWorkerProps<B extends Bindings = Bindings>
|
|
204
|
+
extends BaseWorkerProps<B> {
|
|
205
|
+
script: string;
|
|
206
|
+
entrypoint?: undefined;
|
|
207
|
+
}
|
|
227
208
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
209
|
+
export interface EntrypointWorkerProps<B extends Bindings = Bindings>
|
|
210
|
+
extends BaseWorkerProps<B> {
|
|
211
|
+
entrypoint: string;
|
|
212
|
+
script?: undefined;
|
|
213
|
+
}
|
|
232
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Properties for creating or updating a Worker
|
|
217
|
+
*/
|
|
218
|
+
export type WorkerProps<B extends Bindings = Bindings> =
|
|
219
|
+
| InlineWorkerProps<B>
|
|
220
|
+
| EntrypointWorkerProps<B>;
|
|
221
|
+
|
|
222
|
+
export type FetchWorkerProps<
|
|
223
|
+
B extends Bindings = Bindings,
|
|
224
|
+
E extends EventSource[] = EventSource[],
|
|
225
|
+
> = Omit<WorkerProps<B>, "entrypoint" | "eventSources"> & {
|
|
233
226
|
/**
|
|
234
|
-
*
|
|
235
|
-
*
|
|
227
|
+
* A function that will be used to fetch the worker script.
|
|
228
|
+
*
|
|
229
|
+
* This is only used when using the fetch property.
|
|
236
230
|
*/
|
|
237
|
-
|
|
238
|
-
|
|
231
|
+
fetch?(
|
|
232
|
+
request: Request,
|
|
233
|
+
env: Bindings.Runtime<B>,
|
|
234
|
+
ctx: ExecutionContext,
|
|
235
|
+
): Promise<Response>;
|
|
239
236
|
/**
|
|
240
|
-
*
|
|
237
|
+
* Event sources that this worker will consume.
|
|
238
|
+
*
|
|
239
|
+
* Can include queues, streams, or other event sources.
|
|
241
240
|
*/
|
|
242
|
-
|
|
241
|
+
eventSources?: E;
|
|
243
242
|
|
|
244
243
|
/**
|
|
245
|
-
*
|
|
244
|
+
* A function that will be used to queue the worker script.
|
|
245
|
+
*
|
|
246
|
+
* This is only used when using the queue property.
|
|
246
247
|
*/
|
|
247
|
-
|
|
248
|
+
queue?(
|
|
249
|
+
batch: QueueBatch<E>,
|
|
250
|
+
env: Bindings.Runtime<B>,
|
|
251
|
+
ctx: ExecutionContext,
|
|
252
|
+
): Promise<void>;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
type QueueBatch<E extends EventSource[]> = E[number] extends QueueEventSource
|
|
256
|
+
? any
|
|
257
|
+
: E[number] extends QueueResource<infer Body>
|
|
258
|
+
? MessageBatch<Body>
|
|
259
|
+
: MessageBatch<unknown>;
|
|
260
|
+
|
|
261
|
+
export function isWorker(resource: Resource): resource is Worker<any> {
|
|
262
|
+
return resource[ResourceKind] === "cloudflare::Worker";
|
|
263
|
+
}
|
|
248
264
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
265
|
+
/**
|
|
266
|
+
* Output returned after Worker creation/update
|
|
267
|
+
*/
|
|
268
|
+
export type Worker<B extends Bindings = Bindings> =
|
|
269
|
+
Resource<"cloudflare::Worker"> &
|
|
270
|
+
Omit<WorkerProps<B>, "url" | "script"> &
|
|
271
|
+
globalThis.Service & {
|
|
272
|
+
type: "service";
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* The ID of the worker
|
|
276
|
+
*/
|
|
277
|
+
id: string;
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* The name of the worker
|
|
281
|
+
*/
|
|
282
|
+
name: string;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Time at which the worker was created
|
|
286
|
+
*/
|
|
287
|
+
createdAt: number;
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Time at which the worker was last updated
|
|
291
|
+
*/
|
|
292
|
+
updatedAt: number;
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* The worker's URL if enabled
|
|
296
|
+
* Format: {name}.{subdomain}.workers.dev
|
|
297
|
+
*/
|
|
298
|
+
url?: string;
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* The bindings that were created
|
|
302
|
+
*/
|
|
303
|
+
bindings: B | undefined;
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Configuration for static assets
|
|
307
|
+
*/
|
|
308
|
+
assets?: AssetsConfig;
|
|
309
|
+
|
|
310
|
+
// phantom property (for typeof myWorker.Env)
|
|
311
|
+
Env: {
|
|
312
|
+
[bindingName in keyof B]: Bound<B[bindingName]>;
|
|
313
|
+
};
|
|
253
314
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
315
|
+
/**
|
|
316
|
+
* The compatibility date for the worker
|
|
317
|
+
*/
|
|
318
|
+
compatibilityDate: string;
|
|
258
319
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
}
|
|
320
|
+
/**
|
|
321
|
+
* The compatibility flags for the worker
|
|
322
|
+
*/
|
|
323
|
+
compatibilityFlags: string[];
|
|
324
|
+
};
|
|
264
325
|
|
|
265
326
|
/**
|
|
266
327
|
* A Cloudflare Worker is a serverless function that can be deployed to the Cloudflare network.
|
|
@@ -354,7 +415,220 @@ export interface Worker<B extends Bindings = Bindings>
|
|
|
354
415
|
* @see
|
|
355
416
|
* https://developers.cloudflare.com/workers/
|
|
356
417
|
*/
|
|
357
|
-
export
|
|
418
|
+
export function Worker<const B extends Bindings>(
|
|
419
|
+
id: string,
|
|
420
|
+
props: WorkerProps<B>,
|
|
421
|
+
): Promise<Worker<B>>;
|
|
422
|
+
export function Worker<const B extends Bindings, const E extends EventSource[]>(
|
|
423
|
+
id: string,
|
|
424
|
+
meta: ImportMeta,
|
|
425
|
+
props: FetchWorkerProps<B, E>,
|
|
426
|
+
): Promise<Worker<B>> & globalThis.Service;
|
|
427
|
+
export function Worker<const B extends Bindings>(
|
|
428
|
+
...args:
|
|
429
|
+
| [id: string, props: WorkerProps<B>]
|
|
430
|
+
| [id: string, meta: ImportMeta, props: FetchWorkerProps<B>]
|
|
431
|
+
): Promise<Worker<B>> {
|
|
432
|
+
const [id, meta, props] =
|
|
433
|
+
args.length === 2 ? [args[0], undefined, args[1]] : args;
|
|
434
|
+
if (("fetch" in props && props.fetch) || ("queue" in props && props.queue)) {
|
|
435
|
+
const scope = Scope.current;
|
|
436
|
+
|
|
437
|
+
const workerName = props.name ?? id;
|
|
438
|
+
|
|
439
|
+
// we need to make sure the worker exists
|
|
440
|
+
const stub = WorkerStub(`${id}/stub`, {
|
|
441
|
+
name: workerName,
|
|
442
|
+
accountId: props.accountId,
|
|
443
|
+
apiKey: props.apiKey,
|
|
444
|
+
apiToken: props.apiToken,
|
|
445
|
+
baseUrl: props.baseUrl,
|
|
446
|
+
email: props.email,
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
async function collectResources(
|
|
450
|
+
scope: Scope | undefined,
|
|
451
|
+
): Promise<Resource[]> {
|
|
452
|
+
if (!scope) {
|
|
453
|
+
return [];
|
|
454
|
+
}
|
|
455
|
+
return (
|
|
456
|
+
await Promise.all(
|
|
457
|
+
Array.from(scope.resources.values()).map(async (resource) => [
|
|
458
|
+
(await resource) as Resource,
|
|
459
|
+
...(await collectResources(await resource[InnerResourceScope])),
|
|
460
|
+
]),
|
|
461
|
+
)
|
|
462
|
+
).flat();
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const deferred = scope.defer(async () => {
|
|
466
|
+
const autoBindings: Record<string, Binding> = {};
|
|
467
|
+
for (const resource of await collectResources(Scope.root)) {
|
|
468
|
+
if (
|
|
469
|
+
isQueue(resource) ||
|
|
470
|
+
isWorkerStub(resource) ||
|
|
471
|
+
isWorker(resource) ||
|
|
472
|
+
isD1Database(resource) ||
|
|
473
|
+
isBucket(resource) ||
|
|
474
|
+
isPipeline(resource) ||
|
|
475
|
+
isVectorizeIndex(resource) ||
|
|
476
|
+
isKVNamespace(resource)
|
|
477
|
+
) {
|
|
478
|
+
// TODO(sam): make this generic/pluggable
|
|
479
|
+
autoBindings[getBindKey(resource)] = resource;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// TODO(sam): prune to only needed secrets
|
|
484
|
+
for (const secret of Secret.all()) {
|
|
485
|
+
autoBindings[secret.name] = secret;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const bindings = {
|
|
489
|
+
...props.bindings,
|
|
490
|
+
__ALCHEMY_WORKER_NAME__: workerName,
|
|
491
|
+
__ALCHEMY_SERIALIZED_SCOPE__: Json(await serializeScope(scope)),
|
|
492
|
+
ALCHEMY_STAGE: scope.stage,
|
|
493
|
+
ALCHEMY_PASSWORD: secret(scope.password),
|
|
494
|
+
// TODO(sam): prune un-needed bindings
|
|
495
|
+
...autoBindings,
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
return _Worker(id, {
|
|
499
|
+
...(props as any),
|
|
500
|
+
url: true,
|
|
501
|
+
compatibilityFlags: [
|
|
502
|
+
"nodejs_compat",
|
|
503
|
+
...(props.compatibilityFlags ?? []),
|
|
504
|
+
],
|
|
505
|
+
entrypoint: meta!.filename,
|
|
506
|
+
name: workerName,
|
|
507
|
+
// adopt because the stub guarnatees that the worker exists
|
|
508
|
+
adopt: true,
|
|
509
|
+
bindings,
|
|
510
|
+
bundle: {
|
|
511
|
+
...props.bundle,
|
|
512
|
+
plugins: [bootstrapPlugin],
|
|
513
|
+
external: [
|
|
514
|
+
// for alchemy
|
|
515
|
+
"libsodium*",
|
|
516
|
+
"@swc/*",
|
|
517
|
+
"esbuild",
|
|
518
|
+
// TODO(sam): this is for fetch, why is it a package?
|
|
519
|
+
"undici",
|
|
520
|
+
// TODO(sam): no idea where this came from, feels dangerous to externalize it
|
|
521
|
+
"ws",
|
|
522
|
+
"miniflare",
|
|
523
|
+
],
|
|
524
|
+
banner: {
|
|
525
|
+
js: "var __ALCHEMY_RUNTIME__ = true;",
|
|
526
|
+
},
|
|
527
|
+
inject: [
|
|
528
|
+
...(props.bundle?.inject ?? []),
|
|
529
|
+
path.resolve(import.meta.dirname, "..", "runtime", "shims.js"),
|
|
530
|
+
],
|
|
531
|
+
},
|
|
532
|
+
});
|
|
533
|
+
}) as Promise<Worker<B>>;
|
|
534
|
+
|
|
535
|
+
// defer construction of this worker until the app is about to finaloze
|
|
536
|
+
// this ensures that the Worker's dependencies are instantiated before we bundle
|
|
537
|
+
// it is then safe to bundle and import the Worker to detect which resources need to be auto-bound
|
|
538
|
+
const promise = Promise.all([deferred, stub]).then(
|
|
539
|
+
([worker]) => worker,
|
|
540
|
+
) as Promise<Worker<B>> & {
|
|
541
|
+
fetch?: (...args: any[]) => Promise<Response>;
|
|
542
|
+
queue?: (
|
|
543
|
+
batch: QueueBatch<any>,
|
|
544
|
+
env: Bindings.Runtime<B>,
|
|
545
|
+
ctx: ExecutionContext,
|
|
546
|
+
) => Promise<void>;
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
if (isRuntime) {
|
|
550
|
+
if (props.fetch) {
|
|
551
|
+
promise.fetch = async (
|
|
552
|
+
request: Request,
|
|
553
|
+
env: Bindings.Runtime<B>,
|
|
554
|
+
ctx: ExecutionContext,
|
|
555
|
+
) => {
|
|
556
|
+
try {
|
|
557
|
+
return await props.fetch!(request, env as any, ctx);
|
|
558
|
+
} catch (err: any) {
|
|
559
|
+
return new Response(err.message + err.stack, {
|
|
560
|
+
status: 500,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
if (props.queue) {
|
|
566
|
+
promise.queue = async (
|
|
567
|
+
batch: QueueBatch<any>,
|
|
568
|
+
env: Bindings.Runtime<B>,
|
|
569
|
+
ctx: ExecutionContext,
|
|
570
|
+
) => {
|
|
571
|
+
return await props.queue!(batch, env, ctx);
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
} else {
|
|
575
|
+
promise.fetch = async (
|
|
576
|
+
request: string | URL | Request,
|
|
577
|
+
init?: RequestInit,
|
|
578
|
+
) => {
|
|
579
|
+
const worker = await promise;
|
|
580
|
+
if (!worker.url) {
|
|
581
|
+
throw new Error("Worker URL is not available in runtime");
|
|
582
|
+
}
|
|
583
|
+
if (request instanceof Request) {
|
|
584
|
+
const origin = new URL(worker.url);
|
|
585
|
+
const incoming = request.url.startsWith("/")
|
|
586
|
+
? new URL(`${worker.url}${request.url}`)
|
|
587
|
+
: new URL(request.url);
|
|
588
|
+
console.log(incoming);
|
|
589
|
+
const proxyURL = new URL(
|
|
590
|
+
`${incoming.pathname}${incoming.search}${incoming.hash}`,
|
|
591
|
+
origin,
|
|
592
|
+
);
|
|
593
|
+
|
|
594
|
+
const headers = new Headers(request.headers);
|
|
595
|
+
headers.set("host", origin.host);
|
|
596
|
+
|
|
597
|
+
try {
|
|
598
|
+
return await fetch(
|
|
599
|
+
new Request(proxyURL, {
|
|
600
|
+
method: request.method,
|
|
601
|
+
body: request.body,
|
|
602
|
+
headers,
|
|
603
|
+
// TODO(sam): do we need this? GPT added it ...
|
|
604
|
+
// redirect: "manual",
|
|
605
|
+
}),
|
|
606
|
+
);
|
|
607
|
+
} catch (err: any) {
|
|
608
|
+
return new Response(err.message ?? "proxy error", { status: 500 });
|
|
609
|
+
}
|
|
610
|
+
} else {
|
|
611
|
+
if (typeof request === "string" && request.startsWith("/")) {
|
|
612
|
+
request = new URL(`${worker.url}${request}`);
|
|
613
|
+
}
|
|
614
|
+
return await fetch(request, init);
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
return promise;
|
|
619
|
+
}
|
|
620
|
+
return _Worker(id, props as WorkerProps<B>).then(async (worker) => {
|
|
621
|
+
const binding = await tryGetBinding(worker);
|
|
622
|
+
if (binding) {
|
|
623
|
+
worker.fetch = (request: Request) => binding.fetch(request);
|
|
624
|
+
worker.connect = (address: SocketAddress, options: SocketOptions) =>
|
|
625
|
+
binding.connect(address, options);
|
|
626
|
+
}
|
|
627
|
+
return worker;
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
export const _Worker = Resource(
|
|
358
632
|
"cloudflare::Worker",
|
|
359
633
|
{
|
|
360
634
|
alwaysUpdate: true,
|
|
@@ -364,23 +638,18 @@ export const Worker = Resource(
|
|
|
364
638
|
id: string,
|
|
365
639
|
props: WorkerProps<B>,
|
|
366
640
|
): Promise<Worker<B>> {
|
|
367
|
-
// Validate input - we need either script, entryPoint, or bundle
|
|
368
|
-
if (!props.script && !props.entrypoint) {
|
|
369
|
-
throw new Error("One of script or entryPoint must be provided");
|
|
370
|
-
}
|
|
371
|
-
|
|
372
641
|
// Create Cloudflare API client with automatic account discovery
|
|
373
642
|
const api = await createCloudflareApi(props);
|
|
374
643
|
|
|
375
644
|
// Use the provided name
|
|
376
645
|
const workerName = props.name ?? id;
|
|
377
646
|
|
|
378
|
-
const oldBindings = await this.get<Bindings>("bindings");
|
|
379
|
-
|
|
380
647
|
const compatibilityDate = props.compatibilityDate ?? "2025-04-20";
|
|
381
648
|
const compatibilityFlags = props.compatibilityFlags ?? [];
|
|
382
649
|
|
|
383
650
|
const uploadWorkerScript = async (props: WorkerProps<B>) => {
|
|
651
|
+
const oldBindings = await this.get<Bindings>("bindings");
|
|
652
|
+
|
|
384
653
|
// Get the script content - either from props.script, or by bundling
|
|
385
654
|
const scriptContent =
|
|
386
655
|
props.script ??
|
|
@@ -437,6 +706,9 @@ export const Worker = Resource(
|
|
|
437
706
|
|
|
438
707
|
await putWorker(api, workerName, scriptContent, scriptMetadata);
|
|
439
708
|
|
|
709
|
+
// TODO: it is less than ideal that this can fail, resulting in state problem
|
|
710
|
+
await this.set("bindings", props.bindings);
|
|
711
|
+
|
|
440
712
|
for (const workflow of workflowsBindings) {
|
|
441
713
|
await upsertWorkflow(api, {
|
|
442
714
|
workflowName: workflow.workflowName,
|
|
@@ -464,9 +736,6 @@ export const Worker = Resource(
|
|
|
464
736
|
}) ?? [],
|
|
465
737
|
);
|
|
466
738
|
|
|
467
|
-
// TODO: it is less than ideal that this can fail, resulting in state problem
|
|
468
|
-
await this.set("bindings", props.bindings);
|
|
469
|
-
|
|
470
739
|
// Handle worker URL if requested
|
|
471
740
|
const workerUrl = await configureURL(
|
|
472
741
|
this,
|
|
@@ -495,23 +764,22 @@ export const Worker = Resource(
|
|
|
495
764
|
}
|
|
496
765
|
}
|
|
497
766
|
|
|
498
|
-
return { scriptMetadata, workerUrl, now };
|
|
767
|
+
return { scriptContent, scriptMetadata, workerUrl, now };
|
|
499
768
|
};
|
|
500
769
|
|
|
501
770
|
if (this.phase === "delete") {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
),
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
}
|
|
771
|
+
// Delete any queue consumers attached to this worker first
|
|
772
|
+
await deleteQueueConsumers(this, api, workerName);
|
|
773
|
+
|
|
774
|
+
await uploadWorkerScript({
|
|
775
|
+
...props,
|
|
776
|
+
entrypoint: undefined,
|
|
777
|
+
script:
|
|
778
|
+
props.format === "cjs"
|
|
779
|
+
? "addEventListener('fetch', event => { event.respondWith(new Response('hello world')); });"
|
|
780
|
+
: "export default { fetch(request) { return new Response('hello world'); } }",
|
|
781
|
+
bindings: {} as B,
|
|
782
|
+
});
|
|
515
783
|
|
|
516
784
|
await withExponentialBackoff(
|
|
517
785
|
() =>
|
|
@@ -532,6 +800,11 @@ export const Worker = Resource(
|
|
|
532
800
|
|
|
533
801
|
return this.destroy();
|
|
534
802
|
}
|
|
803
|
+
// Validate input - we need either script, entryPoint, or bundle
|
|
804
|
+
if (!props.script && !props.entrypoint) {
|
|
805
|
+
throw new Error("One of script or entrypoint must be provided");
|
|
806
|
+
}
|
|
807
|
+
|
|
535
808
|
if (this.phase === "create") {
|
|
536
809
|
if (!props.adopt) {
|
|
537
810
|
await assertWorkerDoesNotExist(this, api, workerName);
|
|
@@ -563,18 +836,16 @@ export const Worker = Resource(
|
|
|
563
836
|
crons: props.crons,
|
|
564
837
|
// phantom property
|
|
565
838
|
Env: undefined!,
|
|
566
|
-
});
|
|
839
|
+
} as unknown as Worker<B>);
|
|
567
840
|
},
|
|
568
841
|
);
|
|
569
842
|
|
|
570
|
-
async function deleteWorker<B extends Bindings>(
|
|
843
|
+
export async function deleteWorker<B extends Bindings>(
|
|
571
844
|
ctx: Context<Worker<B>>,
|
|
572
845
|
api: CloudflareApi,
|
|
573
846
|
props: WorkerProps<B> & { workerName: string },
|
|
574
847
|
) {
|
|
575
848
|
const workerName = props.workerName;
|
|
576
|
-
// Delete any queue consumers attached to this worker first
|
|
577
|
-
await deleteQueueConsumers(ctx, api, workerName);
|
|
578
849
|
|
|
579
850
|
// Delete worker
|
|
580
851
|
const deleteResponse = await api.delete(
|
|
@@ -605,7 +876,7 @@ async function deleteWorker<B extends Bindings>(
|
|
|
605
876
|
return;
|
|
606
877
|
}
|
|
607
878
|
|
|
608
|
-
async function putWorker(
|
|
879
|
+
export async function putWorker(
|
|
609
880
|
api: CloudflareApi,
|
|
610
881
|
workerName: string,
|
|
611
882
|
scriptContent: string,
|
|
@@ -667,299 +938,7 @@ async function putWorker(
|
|
|
667
938
|
);
|
|
668
939
|
}
|
|
669
940
|
|
|
670
|
-
|
|
671
|
-
compatibility_date: string;
|
|
672
|
-
compatibility_flags?: string[];
|
|
673
|
-
bindings: WorkerBindingSpec[];
|
|
674
|
-
observability: {
|
|
675
|
-
enabled: boolean;
|
|
676
|
-
};
|
|
677
|
-
migrations?: SingleStepMigration;
|
|
678
|
-
main_module?: string;
|
|
679
|
-
body_part?: string;
|
|
680
|
-
tags?: string[];
|
|
681
|
-
assets?: {
|
|
682
|
-
jwt?: string;
|
|
683
|
-
keep_assets?: boolean;
|
|
684
|
-
config?: AssetsConfig;
|
|
685
|
-
};
|
|
686
|
-
cron_triggers?: {
|
|
687
|
-
cron: string;
|
|
688
|
-
suspended: boolean;
|
|
689
|
-
}[];
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
interface AssetUploadResult {
|
|
693
|
-
completionToken: string;
|
|
694
|
-
assetConfig?: AssetsConfig;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
/**
|
|
698
|
-
* Creates asset configuration object from provided config or defaults
|
|
699
|
-
*/
|
|
700
|
-
function createAssetConfig(config?: AssetsConfig): AssetsConfig {
|
|
701
|
-
const assetConfig: AssetsConfig = {
|
|
702
|
-
html_handling: "auto-trailing-slash",
|
|
703
|
-
};
|
|
704
|
-
|
|
705
|
-
if (config) {
|
|
706
|
-
if (config._headers !== undefined) {
|
|
707
|
-
assetConfig._headers = config._headers;
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
if (config._redirects !== undefined) {
|
|
711
|
-
assetConfig._redirects = config._redirects;
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
if (config.html_handling !== undefined) {
|
|
715
|
-
assetConfig.html_handling = config.html_handling;
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
if (config.not_found_handling !== undefined) {
|
|
719
|
-
assetConfig.not_found_handling = config.not_found_handling;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
if (config.run_worker_first !== undefined) {
|
|
723
|
-
assetConfig.run_worker_first = config.run_worker_first;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
if (config.serve_directly !== undefined) {
|
|
727
|
-
assetConfig.serve_directly = config.serve_directly;
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
return assetConfig;
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
async function prepareWorkerMetadata<B extends Bindings>(
|
|
735
|
-
ctx: Context<Worker<B>>,
|
|
736
|
-
oldBindings: Bindings | undefined,
|
|
737
|
-
props: WorkerProps & {
|
|
738
|
-
compatibilityDate: string;
|
|
739
|
-
compatibilityFlags: string[];
|
|
740
|
-
workerName: string;
|
|
741
|
-
},
|
|
742
|
-
assetUploadResult?: AssetUploadResult,
|
|
743
|
-
): Promise<WorkerMetadata> {
|
|
744
|
-
// Prepare metadata with bindings
|
|
745
|
-
const meta: WorkerMetadata = {
|
|
746
|
-
compatibility_date: props.compatibilityDate,
|
|
747
|
-
compatibility_flags: props.compatibilityFlags,
|
|
748
|
-
bindings: [],
|
|
749
|
-
observability: {
|
|
750
|
-
enabled: props.observability?.enabled !== false,
|
|
751
|
-
},
|
|
752
|
-
// TODO(sam): base64 encode instead? 0 collision risk vs readability.
|
|
753
|
-
tags: [`alchemy:id:${slugify(ctx.fqn)}`],
|
|
754
|
-
migrations: {
|
|
755
|
-
new_classes: props.migrations?.new_classes ?? [],
|
|
756
|
-
deleted_classes: props.migrations?.deleted_classes ?? [],
|
|
757
|
-
renamed_classes: props.migrations?.renamed_classes ?? [],
|
|
758
|
-
transferred_classes: props.migrations?.transferred_classes ?? [],
|
|
759
|
-
new_sqlite_classes: props.migrations?.new_sqlite_classes ?? [],
|
|
760
|
-
},
|
|
761
|
-
};
|
|
762
|
-
|
|
763
|
-
// If we have asset upload results, add them to the metadata
|
|
764
|
-
if (assetUploadResult) {
|
|
765
|
-
meta.assets = {
|
|
766
|
-
jwt: assetUploadResult.completionToken,
|
|
767
|
-
};
|
|
768
|
-
|
|
769
|
-
// Initialize config from assetUploadResult if it exists
|
|
770
|
-
if (assetUploadResult.assetConfig) {
|
|
771
|
-
meta.assets.config = {
|
|
772
|
-
...assetUploadResult.assetConfig,
|
|
773
|
-
};
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
// If there's no config from assetUploadResult but we have props.assets,
|
|
777
|
-
// we need to create the config ourselves (this handles the case when no assets were uploaded)
|
|
778
|
-
if (!meta.assets.config && props.assets) {
|
|
779
|
-
meta.assets.config = createAssetConfig(props.assets);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
const bindings = (props.bindings ?? {}) as Bindings;
|
|
784
|
-
|
|
785
|
-
// Convert bindings to the format expected by the API
|
|
786
|
-
for (const [bindingName, binding] of Object.entries(bindings)) {
|
|
787
|
-
// Create a copy of the binding to avoid modifying the original
|
|
788
|
-
|
|
789
|
-
if (typeof binding === "string") {
|
|
790
|
-
meta.bindings.push({
|
|
791
|
-
type: "plain_text",
|
|
792
|
-
name: bindingName,
|
|
793
|
-
text: binding,
|
|
794
|
-
});
|
|
795
|
-
} else if (binding === Self) {
|
|
796
|
-
meta.bindings.push({
|
|
797
|
-
type: "service",
|
|
798
|
-
name: bindingName,
|
|
799
|
-
service: props.workerName,
|
|
800
|
-
});
|
|
801
|
-
} else if (binding.type === "d1") {
|
|
802
|
-
meta.bindings.push({
|
|
803
|
-
type: "d1",
|
|
804
|
-
name: bindingName,
|
|
805
|
-
id: binding.id,
|
|
806
|
-
});
|
|
807
|
-
} else if (binding.type === "kv_namespace") {
|
|
808
|
-
meta.bindings.push({
|
|
809
|
-
type: "kv_namespace",
|
|
810
|
-
name: bindingName,
|
|
811
|
-
namespace_id:
|
|
812
|
-
"namespaceId" in binding ? binding.namespaceId : binding.id,
|
|
813
|
-
});
|
|
814
|
-
} else if (binding.type === "service") {
|
|
815
|
-
meta.bindings.push({
|
|
816
|
-
type: "service",
|
|
817
|
-
name: bindingName,
|
|
818
|
-
service: binding.name,
|
|
819
|
-
});
|
|
820
|
-
} else if (binding.type === "durable_object_namespace") {
|
|
821
|
-
meta.bindings.push({
|
|
822
|
-
type: "durable_object_namespace",
|
|
823
|
-
name: bindingName,
|
|
824
|
-
class_name: binding.className,
|
|
825
|
-
script_name: binding.scriptName,
|
|
826
|
-
environment: binding.environment,
|
|
827
|
-
namespace_id: binding.namespaceId,
|
|
828
|
-
});
|
|
829
|
-
configureClassMigration(binding, binding.id, binding.className);
|
|
830
|
-
} else if (binding.type === "r2_bucket") {
|
|
831
|
-
meta.bindings.push({
|
|
832
|
-
type: "r2_bucket",
|
|
833
|
-
name: bindingName,
|
|
834
|
-
bucket_name: binding.name,
|
|
835
|
-
});
|
|
836
|
-
} else if (binding.type === "assets") {
|
|
837
|
-
meta.bindings.push({
|
|
838
|
-
type: "assets",
|
|
839
|
-
name: bindingName,
|
|
840
|
-
});
|
|
841
|
-
} else if (binding.type === "secret") {
|
|
842
|
-
meta.bindings.push({
|
|
843
|
-
type: "secret_text",
|
|
844
|
-
name: bindingName,
|
|
845
|
-
text: binding.unencrypted,
|
|
846
|
-
});
|
|
847
|
-
} else if (binding.type === "workflow") {
|
|
848
|
-
meta.bindings.push({
|
|
849
|
-
type: "workflow",
|
|
850
|
-
name: bindingName,
|
|
851
|
-
workflow_name: binding.workflowName,
|
|
852
|
-
class_name: binding.className,
|
|
853
|
-
// this should be set if the Workflow is in another script ...
|
|
854
|
-
// script_name: ??,
|
|
855
|
-
});
|
|
856
|
-
// it's unclear whether this is needed, but it works both ways
|
|
857
|
-
// configureClassMigration(binding, binding.id, binding.className);
|
|
858
|
-
} else if (binding.type === "queue") {
|
|
859
|
-
meta.bindings.push({
|
|
860
|
-
type: "queue",
|
|
861
|
-
name: bindingName,
|
|
862
|
-
queue_name: binding.name,
|
|
863
|
-
});
|
|
864
|
-
} else if (binding.type === "pipeline") {
|
|
865
|
-
meta.bindings.push({
|
|
866
|
-
type: "pipelines",
|
|
867
|
-
name: bindingName,
|
|
868
|
-
pipeline: binding.name,
|
|
869
|
-
});
|
|
870
|
-
} else if (binding.type === "vectorize") {
|
|
871
|
-
meta.bindings.push({
|
|
872
|
-
type: "vectorize",
|
|
873
|
-
name: bindingName,
|
|
874
|
-
index_name: binding.name,
|
|
875
|
-
});
|
|
876
|
-
} else if (binding.type === "ai_gateway") {
|
|
877
|
-
// AI Gateway binding - just needs the name property
|
|
878
|
-
meta.bindings.push({
|
|
879
|
-
type: "ai",
|
|
880
|
-
name: bindingName,
|
|
881
|
-
});
|
|
882
|
-
} else if (binding.type === "hyperdrive") {
|
|
883
|
-
// Hyperdrive binding
|
|
884
|
-
meta.bindings.push({
|
|
885
|
-
type: "hyperdrive",
|
|
886
|
-
name: bindingName,
|
|
887
|
-
id: binding.hyperdriveId,
|
|
888
|
-
});
|
|
889
|
-
} else if (binding.type === "browser") {
|
|
890
|
-
meta.bindings.push({
|
|
891
|
-
type: "browser",
|
|
892
|
-
name: bindingName,
|
|
893
|
-
});
|
|
894
|
-
} else if (binding.type === "ai") {
|
|
895
|
-
meta.bindings.push({
|
|
896
|
-
type: "ai",
|
|
897
|
-
name: bindingName,
|
|
898
|
-
});
|
|
899
|
-
} else {
|
|
900
|
-
// @ts-expect-error - we should never reach here
|
|
901
|
-
throw new Error(`Unsupported binding type: ${binding.type}`);
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
function configureClassMigration(
|
|
906
|
-
binding: DurableObjectNamespace | Workflow,
|
|
907
|
-
stableId: string,
|
|
908
|
-
className: string,
|
|
909
|
-
) {
|
|
910
|
-
const oldBinding: DurableObjectNamespace | Workflow | undefined =
|
|
911
|
-
Object.values(oldBindings ?? {})
|
|
912
|
-
?.filter(
|
|
913
|
-
(b) =>
|
|
914
|
-
typeof b === "object" &&
|
|
915
|
-
(b.type === "durable_object_namespace" || b.type === "workflow"),
|
|
916
|
-
)
|
|
917
|
-
?.find((b) => b.id === stableId);
|
|
918
|
-
|
|
919
|
-
if (!oldBinding) {
|
|
920
|
-
if (binding.type === "durable_object_namespace" && binding.sqlite) {
|
|
921
|
-
meta.migrations!.new_sqlite_classes!.push(className);
|
|
922
|
-
} else {
|
|
923
|
-
meta.migrations!.new_classes!.push(className);
|
|
924
|
-
}
|
|
925
|
-
} else if (oldBinding.className !== className) {
|
|
926
|
-
meta.migrations!.renamed_classes!.push({
|
|
927
|
-
from: oldBinding.className,
|
|
928
|
-
to: className,
|
|
929
|
-
});
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
// Convert env variables to plain_text bindings
|
|
934
|
-
// TODO(sam): remove Worker.env in favor of always bindings
|
|
935
|
-
if (props.env) {
|
|
936
|
-
for (const [key, value] of Object.entries(props.env)) {
|
|
937
|
-
meta.bindings.push({
|
|
938
|
-
name: key,
|
|
939
|
-
type: "plain_text",
|
|
940
|
-
text: value,
|
|
941
|
-
});
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
// Determine if we're using ESM or service worker format
|
|
946
|
-
const isEsModule = props.format !== "cjs"; // Default to ESM unless CJS is specified
|
|
947
|
-
const scriptName = isEsModule ? "worker.js" : "script";
|
|
948
|
-
|
|
949
|
-
if (isEsModule) {
|
|
950
|
-
// For ES modules format
|
|
951
|
-
meta.main_module = scriptName;
|
|
952
|
-
} else {
|
|
953
|
-
// For service worker format (CJS)
|
|
954
|
-
meta.body_part = scriptName;
|
|
955
|
-
}
|
|
956
|
-
if (process.env.DEBUG) {
|
|
957
|
-
console.log(meta);
|
|
958
|
-
}
|
|
959
|
-
return meta;
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
async function assertWorkerDoesNotExist<B extends Bindings>(
|
|
941
|
+
export async function assertWorkerDoesNotExist<B extends Bindings>(
|
|
963
942
|
ctx: Context<Worker<B>>,
|
|
964
943
|
api: CloudflareApi,
|
|
965
944
|
workerName: string,
|
|
@@ -996,7 +975,7 @@ async function assertWorkerDoesNotExist<B extends Bindings>(
|
|
|
996
975
|
);
|
|
997
976
|
}
|
|
998
977
|
|
|
999
|
-
async function configureURL<B extends Bindings>(
|
|
978
|
+
export async function configureURL<B extends Bindings>(
|
|
1000
979
|
ctx: Context<Worker<B>>,
|
|
1001
980
|
api: CloudflareApi,
|
|
1002
981
|
workerName: string,
|
|
@@ -1058,7 +1037,7 @@ async function configureURL<B extends Bindings>(
|
|
|
1058
1037
|
return workerUrl;
|
|
1059
1038
|
}
|
|
1060
1039
|
|
|
1061
|
-
async function getWorkerScriptMetadata(
|
|
1040
|
+
export async function getWorkerScriptMetadata(
|
|
1062
1041
|
api: CloudflareApi,
|
|
1063
1042
|
workerName: string,
|
|
1064
1043
|
): Promise<WorkerScriptMetadata | undefined> {
|
|
@@ -1076,7 +1055,7 @@ async function getWorkerScriptMetadata(
|
|
|
1076
1055
|
return ((await response.json()) as any).result as WorkerScriptMetadata;
|
|
1077
1056
|
}
|
|
1078
1057
|
|
|
1079
|
-
async function
|
|
1058
|
+
export async function _getWorkerBindings(
|
|
1080
1059
|
api: CloudflareApi,
|
|
1081
1060
|
workerName: string,
|
|
1082
1061
|
environment = "production",
|
|
@@ -1106,185 +1085,6 @@ async function getWorkerBindings(
|
|
|
1106
1085
|
return data.result;
|
|
1107
1086
|
}
|
|
1108
1087
|
|
|
1109
|
-
/**
|
|
1110
|
-
* Interface for a file's metadata to be uploaded
|
|
1111
|
-
*/
|
|
1112
|
-
interface FileMetadata {
|
|
1113
|
-
hash: string;
|
|
1114
|
-
size: number;
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
/**
|
|
1118
|
-
* Response from the assets upload session API
|
|
1119
|
-
*/
|
|
1120
|
-
interface UploadSessionResponse {
|
|
1121
|
-
result: {
|
|
1122
|
-
jwt: string;
|
|
1123
|
-
buckets: string[][];
|
|
1124
|
-
};
|
|
1125
|
-
success: boolean;
|
|
1126
|
-
errors: any[];
|
|
1127
|
-
messages: any[];
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
/**
|
|
1131
|
-
* Response from the file upload API
|
|
1132
|
-
*/
|
|
1133
|
-
interface UploadResponse {
|
|
1134
|
-
result: {
|
|
1135
|
-
jwt: string;
|
|
1136
|
-
buckets?: string[][];
|
|
1137
|
-
};
|
|
1138
|
-
success: boolean;
|
|
1139
|
-
errors: any[];
|
|
1140
|
-
messages: any[];
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
/**
|
|
1144
|
-
* Uploads assets to Cloudflare and returns a completion token
|
|
1145
|
-
*
|
|
1146
|
-
* @param api CloudflareApi instance
|
|
1147
|
-
* @param workerName Name of the worker
|
|
1148
|
-
* @param assets Assets resource containing files to upload
|
|
1149
|
-
* @param assetConfig Configuration for the assets
|
|
1150
|
-
* @returns Completion token for the assets upload
|
|
1151
|
-
*/
|
|
1152
|
-
async function uploadAssets(
|
|
1153
|
-
api: CloudflareApi,
|
|
1154
|
-
workerName: string,
|
|
1155
|
-
assets: Assets,
|
|
1156
|
-
assetConfig?: WorkerProps["assets"],
|
|
1157
|
-
): Promise<AssetUploadResult> {
|
|
1158
|
-
// Process the assets configuration once at the beginning
|
|
1159
|
-
const processedConfig = createAssetConfig(assetConfig);
|
|
1160
|
-
|
|
1161
|
-
// Generate the file manifest
|
|
1162
|
-
const fileMetadata: Record<string, FileMetadata> = {};
|
|
1163
|
-
|
|
1164
|
-
// Process each file in the assets
|
|
1165
|
-
for (const file of assets.files) {
|
|
1166
|
-
const { hash, size } = await calculateFileMetadata(file.filePath);
|
|
1167
|
-
// Use the relative path as the key, ensuring it starts with a slash
|
|
1168
|
-
const key = file.path.startsWith("/") ? file.path : `/${file.path}`;
|
|
1169
|
-
fileMetadata[key] = { hash, size };
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
// Start the upload session
|
|
1173
|
-
const uploadSessionUrl = `/accounts/${api.accountId}/workers/scripts/${workerName}/assets-upload-session`;
|
|
1174
|
-
const uploadSessionResponse = await api.post(
|
|
1175
|
-
uploadSessionUrl,
|
|
1176
|
-
JSON.stringify({ manifest: fileMetadata }),
|
|
1177
|
-
{
|
|
1178
|
-
headers: { "Content-Type": "application/json" },
|
|
1179
|
-
},
|
|
1180
|
-
);
|
|
1181
|
-
|
|
1182
|
-
if (!uploadSessionResponse.ok) {
|
|
1183
|
-
throw new Error(
|
|
1184
|
-
`Failed to start assets upload session: ${uploadSessionResponse.status} ${uploadSessionResponse.statusText}`,
|
|
1185
|
-
);
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
const sessionData =
|
|
1189
|
-
(await uploadSessionResponse.json()) as UploadSessionResponse;
|
|
1190
|
-
|
|
1191
|
-
// If there are no buckets, assets are already uploaded or empty
|
|
1192
|
-
if (!sessionData.result.buckets || sessionData.result.buckets.length === 0) {
|
|
1193
|
-
return {
|
|
1194
|
-
completionToken: sessionData.result.jwt,
|
|
1195
|
-
assetConfig: processedConfig,
|
|
1196
|
-
};
|
|
1197
|
-
}
|
|
1198
|
-
|
|
1199
|
-
// Upload the files in batches as specified by the API
|
|
1200
|
-
let completionToken = sessionData.result.jwt;
|
|
1201
|
-
const buckets = sessionData.result.buckets;
|
|
1202
|
-
|
|
1203
|
-
// Process each bucket of files
|
|
1204
|
-
for (const bucket of buckets) {
|
|
1205
|
-
const formData = new FormData();
|
|
1206
|
-
|
|
1207
|
-
let totalBytes = 0;
|
|
1208
|
-
|
|
1209
|
-
// Add each file in the bucket to the form
|
|
1210
|
-
for (const fileHash of bucket) {
|
|
1211
|
-
// Find the file with this hash
|
|
1212
|
-
const file = assets.files.find((f) => {
|
|
1213
|
-
const filePath = f.path.startsWith("/") ? f.path : `/${f.path}`;
|
|
1214
|
-
return fileMetadata[filePath]?.hash === fileHash;
|
|
1215
|
-
});
|
|
1216
|
-
|
|
1217
|
-
if (!file) {
|
|
1218
|
-
throw new Error(`Could not find file with hash ${fileHash}`);
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
// Read the file content
|
|
1222
|
-
const fileContent = await fs.readFile(file.filePath);
|
|
1223
|
-
|
|
1224
|
-
// Convert to base64 as required by the API when using base64=true
|
|
1225
|
-
const base64Content = fileContent.toString("base64");
|
|
1226
|
-
|
|
1227
|
-
// Add the file to the form with the hash as the key and set the correct content type
|
|
1228
|
-
const blob = new Blob([base64Content], {
|
|
1229
|
-
type: getContentType(file.filePath),
|
|
1230
|
-
});
|
|
1231
|
-
totalBytes += blob.size;
|
|
1232
|
-
formData.append(fileHash, blob, fileHash);
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1235
|
-
// Upload this batch of files
|
|
1236
|
-
const uploadResponse = await api.post(
|
|
1237
|
-
`/accounts/${api.accountId}/workers/assets/upload?base64=true`,
|
|
1238
|
-
formData,
|
|
1239
|
-
{
|
|
1240
|
-
headers: {
|
|
1241
|
-
Authorization: `Bearer ${completionToken}`,
|
|
1242
|
-
"Content-Type": "multipart/form-data",
|
|
1243
|
-
},
|
|
1244
|
-
},
|
|
1245
|
-
);
|
|
1246
|
-
|
|
1247
|
-
if (!uploadResponse.ok) {
|
|
1248
|
-
throw new Error(
|
|
1249
|
-
`Failed to upload asset files: ${uploadResponse.status} ${uploadResponse.statusText}`,
|
|
1250
|
-
);
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
const uploadData = (await uploadResponse.json()) as UploadResponse;
|
|
1254
|
-
// Update the completion token for the next batch
|
|
1255
|
-
if (uploadData.result.jwt) {
|
|
1256
|
-
completionToken = uploadData.result.jwt;
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
// Return the final completion token with asset configuration
|
|
1261
|
-
return {
|
|
1262
|
-
completionToken,
|
|
1263
|
-
assetConfig: processedConfig,
|
|
1264
|
-
};
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
/**
|
|
1268
|
-
* Calculate the SHA-256 hash and size of a file
|
|
1269
|
-
*
|
|
1270
|
-
* @param filePath Path to the file
|
|
1271
|
-
* @returns Hash (first 32 chars of SHA-256) and size of the file
|
|
1272
|
-
*/
|
|
1273
|
-
async function calculateFileMetadata(
|
|
1274
|
-
filePath: string,
|
|
1275
|
-
): Promise<{ hash: string; size: number }> {
|
|
1276
|
-
const hash = crypto.createHash("sha256");
|
|
1277
|
-
const fileContent = await fs.readFile(filePath);
|
|
1278
|
-
|
|
1279
|
-
hash.update(fileContent);
|
|
1280
|
-
const fileHash = hash.digest("hex").substring(0, 32); // First 32 chars of hash
|
|
1281
|
-
|
|
1282
|
-
return {
|
|
1283
|
-
hash: fileHash,
|
|
1284
|
-
size: fileContent.length,
|
|
1285
|
-
};
|
|
1286
|
-
}
|
|
1287
|
-
|
|
1288
1088
|
/**
|
|
1289
1089
|
* Lists and deletes all queue consumers for a specific worker
|
|
1290
1090
|
* @param ctx Worker context containing eventSources
|