alchemy 0.45.6 → 0.46.1
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/README.md +2 -2
- package/bin/alchemy.mjs +19280 -15136
- package/bin/alchemy.ts +14 -56
- package/bin/commands/create.ts +307 -137
- package/bin/commands/deploy.ts +23 -0
- package/bin/commands/destroy.ts +19 -0
- package/bin/commands/dev.ts +21 -0
- package/bin/commands/login.ts +63 -0
- package/bin/commands/run.ts +29 -0
- package/bin/services/dependencies.ts +0 -5
- package/bin/services/execute-alchemy.ts +160 -0
- package/bin/services/git.ts +27 -0
- package/bin/services/github-workflow.ts +229 -0
- package/bin/services/package-manager.ts +51 -68
- package/bin/services/template-manager.ts +10 -21
- package/bin/trpc.ts +3 -0
- package/bin/types.ts +4 -2
- package/lib/apply.d.ts +2 -0
- package/lib/apply.d.ts.map +1 -1
- package/lib/apply.js +26 -8
- package/lib/apply.js.map +1 -1
- package/lib/build-date.d.ts +1 -1
- package/lib/build-date.js +1 -1
- package/lib/cloudflare/ai.d.ts +8 -4
- package/lib/cloudflare/ai.d.ts.map +1 -1
- package/lib/cloudflare/ai.js +6 -8
- package/lib/cloudflare/ai.js.map +1 -1
- package/lib/cloudflare/analytics-engine.d.ts +11 -7
- package/lib/cloudflare/analytics-engine.d.ts.map +1 -1
- package/lib/cloudflare/analytics-engine.js +11 -9
- package/lib/cloudflare/analytics-engine.js.map +1 -1
- package/lib/cloudflare/{types.d.ts → api-response.d.ts} +6 -1
- package/lib/cloudflare/api-response.d.ts.map +1 -0
- package/lib/cloudflare/api-response.js +38 -0
- package/lib/cloudflare/api-response.js.map +1 -0
- package/lib/cloudflare/api.d.ts +9 -5
- package/lib/cloudflare/api.d.ts.map +1 -1
- package/lib/cloudflare/api.js +6 -46
- package/lib/cloudflare/api.js.map +1 -1
- package/lib/cloudflare/auth.d.ts +16 -35
- package/lib/cloudflare/auth.d.ts.map +1 -1
- package/lib/cloudflare/auth.js +50 -129
- package/lib/cloudflare/auth.js.map +1 -1
- package/lib/cloudflare/browser-rendering.d.ts +12 -3
- package/lib/cloudflare/browser-rendering.d.ts.map +1 -1
- package/lib/cloudflare/browser-rendering.js +12 -2
- package/lib/cloudflare/browser-rendering.js.map +1 -1
- package/lib/cloudflare/bundle/fs.d.ts.map +1 -1
- package/lib/cloudflare/bundle/fs.js +3 -0
- package/lib/cloudflare/bundle/fs.js.map +1 -1
- package/lib/cloudflare/bundle/internal-worker-bundle.d.ts +6 -0
- package/lib/cloudflare/bundle/internal-worker-bundle.d.ts.map +1 -0
- package/lib/cloudflare/bundle/internal-worker-bundle.js +14 -0
- package/lib/cloudflare/bundle/internal-worker-bundle.js.map +1 -0
- package/lib/cloudflare/compatibility-presets.d.ts +22 -0
- package/lib/cloudflare/compatibility-presets.d.ts.map +1 -0
- package/lib/cloudflare/compatibility-presets.js +27 -0
- package/lib/cloudflare/compatibility-presets.js.map +1 -0
- package/lib/cloudflare/container.d.ts +5 -1
- package/lib/cloudflare/container.d.ts.map +1 -1
- package/lib/cloudflare/container.js +42 -2
- package/lib/cloudflare/container.js.map +1 -1
- package/lib/cloudflare/dispatch-namespace.d.ts +5 -0
- package/lib/cloudflare/dispatch-namespace.d.ts.map +1 -1
- package/lib/cloudflare/dispatch-namespace.js +8 -0
- package/lib/cloudflare/dispatch-namespace.js.map +1 -1
- package/lib/cloudflare/durable-object-namespace.d.ts +23 -15
- package/lib/cloudflare/durable-object-namespace.d.ts.map +1 -1
- package/lib/cloudflare/durable-object-namespace.js +22 -21
- package/lib/cloudflare/durable-object-namespace.js.map +1 -1
- package/lib/cloudflare/hyperdrive.d.ts +19 -5
- package/lib/cloudflare/hyperdrive.d.ts.map +1 -1
- package/lib/cloudflare/hyperdrive.js +14 -0
- package/lib/cloudflare/hyperdrive.js.map +1 -1
- package/lib/cloudflare/images.d.ts +27 -17
- package/lib/cloudflare/images.d.ts.map +1 -1
- package/lib/cloudflare/images.js +13 -8
- package/lib/cloudflare/images.js.map +1 -1
- package/lib/cloudflare/index.d.ts +1 -3
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +1 -3
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/miniflare/miniflare.d.ts +3 -3
- package/lib/cloudflare/miniflare/miniflare.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/miniflare.js +7 -7
- package/lib/cloudflare/miniflare/miniflare.js.map +1 -1
- package/lib/cloudflare/miniflare/{mixed-mode.d.ts → remote-binding-proxy.d.ts} +5 -5
- package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -0
- package/lib/cloudflare/miniflare/{mixed-mode.js → remote-binding-proxy.js} +16 -52
- package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -0
- package/lib/cloudflare/oauth.d.ts +22 -0
- package/lib/cloudflare/oauth.d.ts.map +1 -0
- package/lib/cloudflare/oauth.js +213 -0
- package/lib/cloudflare/oauth.js.map +1 -0
- package/lib/cloudflare/state.d.ts +26 -0
- package/lib/cloudflare/state.d.ts.map +1 -0
- package/lib/cloudflare/state.js +14 -0
- package/lib/cloudflare/state.js.map +1 -0
- package/lib/cloudflare/user.d.ts +2 -2
- package/lib/cloudflare/user.d.ts.map +1 -1
- package/lib/cloudflare/user.js +24 -47
- package/lib/cloudflare/user.js.map +1 -1
- package/lib/cloudflare/vectorize-index.d.ts.map +1 -1
- package/lib/cloudflare/vectorize-index.js +5 -2
- package/lib/cloudflare/vectorize-index.js.map +1 -1
- package/lib/cloudflare/version-metadata.d.ts +15 -3
- package/lib/cloudflare/version-metadata.d.ts.map +1 -1
- package/lib/cloudflare/version-metadata.js +11 -2
- package/lib/cloudflare/version-metadata.js.map +1 -1
- package/lib/cloudflare/vite.d.ts.map +1 -1
- package/lib/cloudflare/vite.js +2 -1
- package/lib/cloudflare/vite.js.map +1 -1
- package/lib/cloudflare/worker-metadata.d.ts +13 -2
- package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
- package/lib/cloudflare/worker-metadata.js +10 -15
- package/lib/cloudflare/worker-metadata.js.map +1 -1
- package/lib/cloudflare/worker-subdomain.d.ts +7 -0
- package/lib/cloudflare/worker-subdomain.d.ts.map +1 -1
- package/lib/cloudflare/worker-subdomain.js +17 -22
- package/lib/cloudflare/worker-subdomain.js.map +1 -1
- package/lib/cloudflare/{worker/tail.d.ts → worker-tail.d.ts} +2 -2
- package/lib/cloudflare/worker-tail.d.ts.map +1 -0
- package/lib/cloudflare/{worker/tail.js → worker-tail.js} +11 -9
- package/lib/cloudflare/worker-tail.js.map +1 -0
- package/lib/cloudflare/worker.d.ts +19 -8
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +35 -10
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/workflow.d.ts +22 -11
- package/lib/cloudflare/workflow.d.ts.map +1 -1
- package/lib/cloudflare/workflow.js +23 -18
- package/lib/cloudflare/workflow.js.map +1 -1
- package/lib/context.d.ts +2 -2
- package/lib/context.d.ts.map +1 -1
- package/lib/docker/api.d.ts.map +1 -1
- package/lib/docker/api.js +30 -8
- package/lib/docker/api.js.map +1 -1
- package/lib/fs/file-system-state-store.d.ts +5 -20
- package/lib/fs/file-system-state-store.d.ts.map +1 -1
- package/lib/fs/file-system-state-store.js +5 -121
- package/lib/fs/file-system-state-store.js.map +1 -1
- package/lib/fs/index.d.ts +0 -1
- package/lib/fs/index.d.ts.map +1 -1
- package/lib/fs/index.js +0 -1
- package/lib/fs/index.js.map +1 -1
- package/lib/llms.cloudflare.txt +6 -5
- package/lib/planetscale/password.js +1 -1
- package/lib/planetscale/password.js.map +1 -1
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +3 -6
- package/lib/scope.js.map +1 -1
- package/lib/state/cloudflare-state-store.d.ts +34 -0
- package/lib/state/cloudflare-state-store.d.ts.map +1 -0
- package/lib/state/cloudflare-state-store.js +116 -0
- package/lib/state/cloudflare-state-store.js.map +1 -0
- package/lib/state/d1-state-store.d.ts +15 -0
- package/lib/state/d1-state-store.d.ts.map +1 -0
- package/lib/{cloudflare → state}/d1-state-store.js +31 -27
- package/lib/state/d1-state-store.js.map +1 -0
- package/lib/{cloudflare/do-state-store/types.d.ts → state/dofs-state-store/api.d.ts} +1 -1
- package/lib/state/dofs-state-store/api.d.ts.map +1 -0
- package/lib/state/dofs-state-store/api.js +1 -0
- package/lib/state/dofs-state-store/api.js.map +1 -0
- package/lib/{cloudflare/do-state-store/store.d.ts → state/dofs-state-store/index.d.ts} +10 -5
- package/lib/state/dofs-state-store/index.d.ts.map +1 -0
- package/lib/{cloudflare/do-state-store/store.js → state/dofs-state-store/index.js} +15 -11
- package/lib/state/dofs-state-store/index.js.map +1 -0
- package/lib/{cloudflare/do-state-store/internal.d.ts → state/dofs-state-store/store.d.ts} +4 -5
- package/lib/state/dofs-state-store/store.d.ts.map +1 -0
- package/lib/{cloudflare/do-state-store/internal.js → state/dofs-state-store/store.js} +7 -22
- package/lib/state/dofs-state-store/store.js.map +1 -0
- package/lib/state/file-system-state-store.d.ts +21 -0
- package/lib/state/file-system-state-store.d.ts.map +1 -0
- package/lib/state/file-system-state-store.js +122 -0
- package/lib/state/file-system-state-store.js.map +1 -0
- package/lib/state/index.d.ts +7 -0
- package/lib/state/index.d.ts.map +1 -0
- package/lib/state/index.js +7 -0
- package/lib/state/index.js.map +1 -0
- package/lib/state/migrations.d.ts +2 -0
- package/lib/state/migrations.d.ts.map +1 -0
- package/lib/state/migrations.js +3 -0
- package/lib/state/migrations.js.map +1 -0
- package/lib/state/operations.d.ts +36 -0
- package/lib/state/operations.d.ts.map +1 -0
- package/lib/state/operations.js +126 -0
- package/lib/state/operations.js.map +1 -0
- package/lib/state/proxy.d.ts +53 -0
- package/lib/state/proxy.d.ts.map +1 -0
- package/lib/state/proxy.js +65 -0
- package/lib/state/proxy.js.map +1 -0
- package/lib/{cloudflare → state}/r2-rest-state-store.d.ts +3 -1
- package/lib/state/r2-rest-state-store.d.ts.map +1 -0
- package/lib/{cloudflare → state}/r2-rest-state-store.js +6 -4
- package/lib/state/r2-rest-state-store.js.map +1 -0
- package/lib/state/schema.d.ts.map +1 -0
- package/lib/state/schema.js.map +1 -0
- package/lib/{sqlite → state}/sqlite-state-store.d.ts +5 -3
- package/lib/state/sqlite-state-store.d.ts.map +1 -0
- package/lib/{sqlite → state}/sqlite-state-store.js +15 -6
- package/lib/state/sqlite-state-store.js.map +1 -0
- package/lib/test/vitest.d.ts.map +1 -1
- package/lib/test/vitest.js +3 -6
- package/lib/test/vitest.js.map +1 -1
- package/lib/util/detect-node-runtime.d.ts +3 -0
- package/lib/util/detect-node-runtime.d.ts.map +1 -0
- package/lib/util/detect-node-runtime.js +10 -0
- package/lib/util/detect-node-runtime.js.map +1 -0
- package/lib/util/detect-package-manager.d.ts +2 -2
- package/lib/util/detect-package-manager.d.ts.map +1 -1
- package/lib/util/detect-package-manager.js +15 -5
- package/lib/util/detect-package-manager.js.map +1 -1
- package/lib/util/http-server.d.ts.map +1 -0
- package/lib/{cloudflare/miniflare → util}/http-server.js +1 -1
- package/lib/util/http-server.js.map +1 -0
- package/lib/util/memoize.d.ts +1 -0
- package/lib/util/memoize.d.ts.map +1 -1
- package/lib/util/memoize.js +2 -8
- package/lib/util/memoize.js.map +1 -1
- package/lib/util/neverthrow.d.ts +16 -0
- package/lib/util/neverthrow.d.ts.map +1 -0
- package/lib/util/neverthrow.js +46 -0
- package/lib/util/neverthrow.js.map +1 -0
- package/package.json +18 -16
- package/src/apply.ts +31 -10
- package/src/build-date.ts +1 -1
- package/src/cloudflare/ai.ts +10 -5
- package/src/cloudflare/analytics-engine.ts +20 -11
- package/src/cloudflare/{types.ts → api-response.ts} +31 -0
- package/src/cloudflare/api.ts +18 -57
- package/src/cloudflare/auth.ts +79 -211
- package/src/cloudflare/browser-rendering.ts +16 -2
- package/src/cloudflare/bundle/fs.ts +5 -0
- package/src/cloudflare/bundle/internal-worker-bundle.ts +21 -0
- package/src/cloudflare/compatibility-presets.ts +34 -0
- package/src/cloudflare/container.ts +70 -3
- package/src/cloudflare/dispatch-namespace.ts +28 -0
- package/src/cloudflare/durable-object-namespace.ts +38 -27
- package/src/cloudflare/hyperdrive.ts +19 -5
- package/src/cloudflare/images.ts +32 -17
- package/src/cloudflare/index.ts +1 -3
- package/src/cloudflare/miniflare/miniflare.ts +10 -7
- package/src/cloudflare/miniflare/{mixed-mode.ts → remote-binding-proxy.ts} +25 -75
- package/src/cloudflare/oauth.ts +300 -0
- package/src/cloudflare/state.ts +35 -0
- package/src/cloudflare/user.ts +40 -73
- package/src/cloudflare/vectorize-index.ts +7 -2
- package/src/cloudflare/version-metadata.ts +19 -2
- package/src/cloudflare/vite.ts +2 -1
- package/src/cloudflare/worker-metadata.ts +18 -43
- package/src/cloudflare/worker-subdomain.ts +43 -37
- package/src/cloudflare/{worker/tail.ts → worker-tail.ts} +13 -10
- package/src/cloudflare/worker.ts +74 -23
- package/src/cloudflare/workflow.ts +38 -19
- package/src/context.ts +2 -2
- package/src/docker/api.ts +33 -8
- package/src/fs/file-system-state-store.ts +5 -148
- package/src/fs/index.ts +0 -1
- package/src/llms.cloudflare.txt +6 -5
- package/src/planetscale/password.ts +1 -1
- package/src/scope.ts +3 -6
- package/src/state/cloudflare-state-store.ts +170 -0
- package/src/state/d1-state-store.ts +102 -0
- package/src/{cloudflare/do-state-store/store.ts → state/dofs-state-store/index.ts} +20 -13
- package/src/{cloudflare/do-state-store/internal.ts → state/dofs-state-store/store.ts} +9 -27
- package/src/state/file-system-state-store.ts +149 -0
- package/src/state/index.ts +6 -0
- package/src/state/migrations.ts +9 -0
- package/src/state/operations.ts +152 -0
- package/src/state/proxy.ts +132 -0
- package/src/{cloudflare → state}/r2-rest-state-store.ts +11 -8
- package/src/{sqlite → state}/sqlite-state-store.ts +18 -10
- package/src/test/vitest.ts +8 -6
- package/src/util/detect-node-runtime.ts +12 -0
- package/src/util/detect-package-manager.ts +19 -6
- package/src/{cloudflare/miniflare → util}/http-server.ts +1 -1
- package/src/util/memoize.ts +2 -8
- package/src/util/neverthrow.ts +64 -0
- package/templates/astro/package.json +3 -3
- package/templates/nuxt/package.json +3 -3
- package/templates/react-router/package.json +3 -3
- package/templates/rwsdk/alchemy.run.ts +1 -1
- package/templates/rwsdk/package.json +3 -3
- package/templates/sveltekit/package.json +3 -3
- package/templates/tanstack-start/package.json +3 -3
- package/templates/typescript/package.json +3 -2
- package/templates/typescript/tsconfig.json +1 -0
- package/templates/vite/package.json +3 -3
- package/workers/cloudflare-state-store.js +5638 -0
- package/workers/cloudflare-state-store.ts +108 -0
- package/workers/{do-state-store.js → dofs-state-store.js} +4 -4
- package/workers/{do-state-store.ts → dofs-state-store.ts} +12 -8
- package/workers/{mixed-mode-proxy-worker.js → remote-binding-proxy.js} +3 -3
- package/workers/remote-binding-proxy.ts +45 -0
- package/lib/cloudflare/d1-state-store.d.ts +0 -10
- package/lib/cloudflare/d1-state-store.d.ts.map +0 -1
- package/lib/cloudflare/d1-state-store.js.map +0 -1
- package/lib/cloudflare/do-state-store/index.d.ts +0 -2
- package/lib/cloudflare/do-state-store/index.d.ts.map +0 -1
- package/lib/cloudflare/do-state-store/index.js +0 -2
- package/lib/cloudflare/do-state-store/index.js.map +0 -1
- package/lib/cloudflare/do-state-store/internal.d.ts.map +0 -1
- package/lib/cloudflare/do-state-store/internal.js.map +0 -1
- package/lib/cloudflare/do-state-store/store.d.ts.map +0 -1
- package/lib/cloudflare/do-state-store/store.js.map +0 -1
- package/lib/cloudflare/do-state-store/types.d.ts.map +0 -1
- package/lib/cloudflare/do-state-store/types.js +0 -1
- package/lib/cloudflare/do-state-store/types.js.map +0 -1
- package/lib/cloudflare/miniflare/http-server.d.ts.map +0 -1
- package/lib/cloudflare/miniflare/http-server.js.map +0 -1
- package/lib/cloudflare/miniflare/mixed-mode.d.ts.map +0 -1
- package/lib/cloudflare/miniflare/mixed-mode.js.map +0 -1
- package/lib/cloudflare/r2-rest-state-store.d.ts.map +0 -1
- package/lib/cloudflare/r2-rest-state-store.js.map +0 -1
- package/lib/cloudflare/types.d.ts.map +0 -1
- package/lib/cloudflare/types.js +0 -19
- package/lib/cloudflare/types.js.map +0 -1
- package/lib/cloudflare/worker/shared.d.ts +0 -4
- package/lib/cloudflare/worker/shared.d.ts.map +0 -1
- package/lib/cloudflare/worker/shared.js +0 -21
- package/lib/cloudflare/worker/shared.js.map +0 -1
- package/lib/cloudflare/worker/tail.d.ts.map +0 -1
- package/lib/cloudflare/worker/tail.js.map +0 -1
- package/lib/sqlite/base-sqlite-state-store.d.ts +0 -31
- package/lib/sqlite/base-sqlite-state-store.d.ts.map +0 -1
- package/lib/sqlite/base-sqlite-state-store.js +0 -124
- package/lib/sqlite/base-sqlite-state-store.js.map +0 -1
- package/lib/sqlite/index.d.ts +0 -2
- package/lib/sqlite/index.d.ts.map +0 -1
- package/lib/sqlite/index.js +0 -2
- package/lib/sqlite/index.js.map +0 -1
- package/lib/sqlite/schema.d.ts.map +0 -1
- package/lib/sqlite/schema.js.map +0 -1
- package/lib/sqlite/sqlite-state-store.d.ts.map +0 -1
- package/lib/sqlite/sqlite-state-store.js.map +0 -1
- package/src/cloudflare/d1-state-store.ts +0 -105
- package/src/cloudflare/do-state-store/index.ts +0 -1
- package/src/cloudflare/worker/shared.ts +0 -30
- package/src/sqlite/base-sqlite-state-store.ts +0 -199
- package/src/sqlite/index.ts +0 -1
- package/templates/typescript/src/worker.js +0 -5
- package/workers/mixed-mode-proxy-worker.ts +0 -46
- /package/drizzle/{0000_busy_mauler.sql → default/0000_busy_mauler.sql} +0 -0
- /package/drizzle/{0001_concerned_iceman.sql → default/0001_concerned_iceman.sql} +0 -0
- /package/drizzle/{meta → default/meta}/0000_snapshot.json +0 -0
- /package/drizzle/{meta → default/meta}/0001_snapshot.json +0 -0
- /package/drizzle/{meta → default/meta}/_journal.json +0 -0
- /package/lib/{sqlite → state}/schema.d.ts +0 -0
- /package/lib/{sqlite → state}/schema.js +0 -0
- /package/lib/{cloudflare/miniflare → util}/http-server.d.ts +0 -0
- /package/src/{cloudflare/do-state-store/types.ts → state/dofs-state-store/api.ts} +0 -0
- /package/src/{sqlite → state}/schema.ts +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Context } from "../context.ts";
|
|
2
2
|
import { Resource } from "../resource.ts";
|
|
3
|
+
import { memoize } from "../util/memoize.ts";
|
|
4
|
+
import { extractCloudflareResult } from "./api-response.ts";
|
|
3
5
|
import {
|
|
4
6
|
createCloudflareApi,
|
|
5
7
|
type CloudflareApi,
|
|
6
8
|
type CloudflareApiOptions,
|
|
7
9
|
} from "./api.ts";
|
|
8
|
-
import type { CloudflareApiResponse } from "./types.ts";
|
|
9
|
-
import { getAccountSubdomain } from "./worker/shared.ts";
|
|
10
10
|
|
|
11
11
|
interface WorkerSubdomainProps extends CloudflareApiOptions {
|
|
12
12
|
/**
|
|
@@ -49,16 +49,7 @@ export const WorkerSubdomain = Resource(
|
|
|
49
49
|
}
|
|
50
50
|
return this.destroy();
|
|
51
51
|
}
|
|
52
|
-
await
|
|
53
|
-
`enable subdomain for "${props.scriptName}"`,
|
|
54
|
-
api.post(
|
|
55
|
-
`/accounts/${api.accountId}/workers/scripts/${props.scriptName}/subdomain`,
|
|
56
|
-
{ enabled: true, previews_enabled: true },
|
|
57
|
-
{
|
|
58
|
-
headers: { "Content-Type": "application/json" },
|
|
59
|
-
},
|
|
60
|
-
),
|
|
61
|
-
);
|
|
52
|
+
await enableWorkerSubdomain(api, props.scriptName);
|
|
62
53
|
const subdomain = await getAccountSubdomain(api);
|
|
63
54
|
const base = `${subdomain}.workers.dev`;
|
|
64
55
|
let url: string;
|
|
@@ -77,7 +68,7 @@ export async function disableWorkerSubdomain(
|
|
|
77
68
|
api: CloudflareApi,
|
|
78
69
|
scriptName: string,
|
|
79
70
|
) {
|
|
80
|
-
await
|
|
71
|
+
await extractCloudflareResult<SubdomainResponse>(
|
|
81
72
|
`disable subdomain for "${scriptName}"`,
|
|
82
73
|
api.post(
|
|
83
74
|
`/accounts/${api.accountId}/workers/scripts/${scriptName}/subdomain`,
|
|
@@ -91,33 +82,48 @@ export async function disableWorkerSubdomain(
|
|
|
91
82
|
});
|
|
92
83
|
}
|
|
93
84
|
|
|
85
|
+
export async function enableWorkerSubdomain(
|
|
86
|
+
api: CloudflareApi,
|
|
87
|
+
scriptName: string,
|
|
88
|
+
) {
|
|
89
|
+
await extractCloudflareResult<SubdomainResponse>(
|
|
90
|
+
`enable subdomain for "${scriptName}"`,
|
|
91
|
+
api.post(
|
|
92
|
+
`/accounts/${api.accountId}/workers/scripts/${scriptName}/subdomain`,
|
|
93
|
+
{ enabled: true, previews_enabled: true },
|
|
94
|
+
),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function getWorkerSubdomain(
|
|
99
|
+
api: CloudflareApi,
|
|
100
|
+
scriptName: string,
|
|
101
|
+
) {
|
|
102
|
+
return await extractCloudflareResult<SubdomainResponse>(
|
|
103
|
+
`get subdomain for "${scriptName}"`,
|
|
104
|
+
api.get(
|
|
105
|
+
`/accounts/${api.accountId}/workers/scripts/${scriptName}/subdomain`,
|
|
106
|
+
),
|
|
107
|
+
).catch((error): SubdomainResponse => {
|
|
108
|
+
if (error.status === 404) {
|
|
109
|
+
return { enabled: false, previews_enabled: false };
|
|
110
|
+
}
|
|
111
|
+
throw error;
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
94
115
|
interface SubdomainResponse {
|
|
95
116
|
enabled: boolean;
|
|
96
117
|
previews_enabled: boolean;
|
|
97
118
|
}
|
|
98
119
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
throw new Error(`Failed to ${label}: Failed to fetch`);
|
|
105
|
-
});
|
|
106
|
-
const json = (await response.json().catch(() => {
|
|
107
|
-
throw new Error(
|
|
108
|
-
`Failed to ${label} (${response.status}): The API returned an invalid response`,
|
|
120
|
+
export const getAccountSubdomain = memoize(
|
|
121
|
+
async (api: CloudflareApi) => {
|
|
122
|
+
const result = await extractCloudflareResult<{ subdomain: string }>(
|
|
123
|
+
`get subdomain for account ${api.accountId}`,
|
|
124
|
+
api.get(`/accounts/${api.accountId}/workers/subdomain`),
|
|
109
125
|
);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const error = new Error(
|
|
115
|
-
`Failed to ${label} (${response.status}): ${json.errors.map((e) => `${e.code}: ${e.message}`).join(", ")}`,
|
|
116
|
-
);
|
|
117
|
-
Error.captureStackTrace(error, wrapFetch);
|
|
118
|
-
Object.assign(error, {
|
|
119
|
-
status: response.status,
|
|
120
|
-
});
|
|
121
|
-
throw error;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
126
|
+
return result.subdomain;
|
|
127
|
+
},
|
|
128
|
+
(api) => api.accountId,
|
|
129
|
+
);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import kleur from "kleur";
|
|
2
2
|
import { WebSocket } from "ws";
|
|
3
|
-
import { logger } from "
|
|
4
|
-
import type {
|
|
5
|
-
import type {
|
|
3
|
+
import { logger } from "../util/logger.ts";
|
|
4
|
+
import type { CloudflareApiResponse } from "./api-response.ts";
|
|
5
|
+
import type { CloudflareApi } from "./api.ts";
|
|
6
6
|
|
|
7
7
|
export const createTail = async (
|
|
8
8
|
api: CloudflareApi,
|
|
@@ -47,7 +47,12 @@ class TailClient {
|
|
|
47
47
|
}
|
|
48
48
|
const res = await this.api.post(
|
|
49
49
|
`/accounts/${this.api.accountId}/workers/scripts/${this.scriptName}/tails`,
|
|
50
|
-
{},
|
|
50
|
+
{ filters: [] },
|
|
51
|
+
{
|
|
52
|
+
headers: {
|
|
53
|
+
"Content-Type": "application/json",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
51
56
|
);
|
|
52
57
|
const json = (await res.json()) as CloudflareApiResponse<Tail>;
|
|
53
58
|
if (!json.success) {
|
|
@@ -72,11 +77,7 @@ class TailClient {
|
|
|
72
77
|
throw new Error(`Failed to connect to tail for ${this.scriptName}`);
|
|
73
78
|
}
|
|
74
79
|
const tail = await this.create();
|
|
75
|
-
const ws = new WebSocket(tail.url,
|
|
76
|
-
headers: {
|
|
77
|
-
"Sec-WebSocket-Protocol": "trace-v1",
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
+
const ws = new WebSocket(tail.url, "trace-v1");
|
|
80
81
|
ws.on("open", () => {
|
|
81
82
|
this.ping(ws);
|
|
82
83
|
if (DEBUG) {
|
|
@@ -92,7 +93,9 @@ class TailClient {
|
|
|
92
93
|
return;
|
|
93
94
|
}
|
|
94
95
|
logger.log(`reconnecting to tail for "${this.scriptName}"`);
|
|
95
|
-
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
this.connect(attempt + 1);
|
|
98
|
+
}, 1000);
|
|
96
99
|
});
|
|
97
100
|
ws.on("error", (event) => {
|
|
98
101
|
logger.error(`error on tail for "${this.scriptName}": ${event}`);
|
package/src/cloudflare/worker.ts
CHANGED
|
@@ -28,6 +28,7 @@ import { CloudflareApiError, handleApiError } from "./api-error.ts";
|
|
|
28
28
|
import {
|
|
29
29
|
type CloudflareApi,
|
|
30
30
|
type CloudflareApiOptions,
|
|
31
|
+
type InternalCloudflareApiOptions,
|
|
31
32
|
createCloudflareApi,
|
|
32
33
|
} from "./api.ts";
|
|
33
34
|
import type { Assets } from "./assets.ts";
|
|
@@ -48,6 +49,10 @@ import {
|
|
|
48
49
|
normalizeWorkerBundle,
|
|
49
50
|
} from "./bundle/index.ts";
|
|
50
51
|
import { wrap } from "./bundle/normalize.ts";
|
|
52
|
+
import {
|
|
53
|
+
type CompatibilityPreset,
|
|
54
|
+
unionCompatibilityFlags,
|
|
55
|
+
} from "./compatibility-presets.ts";
|
|
51
56
|
import { type Container, ContainerApplication } from "./container.ts";
|
|
52
57
|
import { CustomDomain } from "./custom-domain.ts";
|
|
53
58
|
import { isD1Database } from "./d1-database.ts";
|
|
@@ -81,9 +86,13 @@ import {
|
|
|
81
86
|
} from "./worker-metadata.ts";
|
|
82
87
|
import { WorkerStub, isWorkerStub } from "./worker-stub.ts";
|
|
83
88
|
import { WorkerSubdomain, disableWorkerSubdomain } from "./worker-subdomain.ts";
|
|
84
|
-
import { createTail } from "./worker
|
|
89
|
+
import { createTail } from "./worker-tail.ts";
|
|
85
90
|
import { Workflow, isWorkflow, upsertWorkflow } from "./workflow.ts";
|
|
86
91
|
|
|
92
|
+
// Previous versions of `Worker` used the `Bundle` resource.
|
|
93
|
+
// This import is here to avoid errors when destroying the `Bundle` resource.
|
|
94
|
+
import "../esbuild/bundle.ts";
|
|
95
|
+
|
|
87
96
|
/**
|
|
88
97
|
* Configuration options for static assets
|
|
89
98
|
*/
|
|
@@ -215,6 +224,15 @@ export interface BaseWorkerProps<
|
|
|
215
224
|
*/
|
|
216
225
|
compatibilityFlags?: string[];
|
|
217
226
|
|
|
227
|
+
/**
|
|
228
|
+
* Compatibility preset to automatically include common compatibility flags
|
|
229
|
+
*
|
|
230
|
+
* - "node": Includes nodejs_compat flag for Node.js compatibility
|
|
231
|
+
*
|
|
232
|
+
* @default undefined (no preset)
|
|
233
|
+
*/
|
|
234
|
+
compatibility?: CompatibilityPreset;
|
|
235
|
+
|
|
218
236
|
/**
|
|
219
237
|
* Configuration for static assets
|
|
220
238
|
*/
|
|
@@ -618,8 +636,8 @@ export function WorkerRef<
|
|
|
618
636
|
* @example
|
|
619
637
|
* // Create a real-time chat worker using Durable Objects
|
|
620
638
|
* // for state management:
|
|
621
|
-
* const chatRooms =
|
|
622
|
-
* const userStore =
|
|
639
|
+
* const chatRooms = DurableObjectNamespace("chat-rooms");
|
|
640
|
+
* const userStore = DurableObjectNamespace("user-store");
|
|
623
641
|
*
|
|
624
642
|
* const chat = await Worker("chat", {
|
|
625
643
|
* name: "chat-worker",
|
|
@@ -693,7 +711,7 @@ export function WorkerRef<
|
|
|
693
711
|
* entrypoint: "./src/data.ts",
|
|
694
712
|
* bindings: {
|
|
695
713
|
* // Bind to its own durable object
|
|
696
|
-
* STORAGE:
|
|
714
|
+
* STORAGE: DurableObjectNamespace("storage", {
|
|
697
715
|
* className: "DataStorage"
|
|
698
716
|
* })
|
|
699
717
|
* }
|
|
@@ -834,7 +852,13 @@ export function Worker<const B extends Bindings>(
|
|
|
834
852
|
...(props as any),
|
|
835
853
|
url: true,
|
|
836
854
|
compatibilityFlags: Array.from(
|
|
837
|
-
new Set([
|
|
855
|
+
new Set([
|
|
856
|
+
"nodejs_compat",
|
|
857
|
+
...unionCompatibilityFlags(
|
|
858
|
+
props.compatibility,
|
|
859
|
+
props.compatibilityFlags,
|
|
860
|
+
),
|
|
861
|
+
]),
|
|
838
862
|
),
|
|
839
863
|
entrypoint: meta!.filename,
|
|
840
864
|
name: workerName,
|
|
@@ -987,7 +1011,10 @@ export const _Worker = Resource(
|
|
|
987
1011
|
const workerName = props.name ?? id;
|
|
988
1012
|
const compatibilityDate =
|
|
989
1013
|
props.compatibilityDate ?? DEFAULT_COMPATIBILITY_DATE;
|
|
990
|
-
const compatibilityFlags =
|
|
1014
|
+
const compatibilityFlags = unionCompatibilityFlags(
|
|
1015
|
+
props.compatibility,
|
|
1016
|
+
props.compatibilityFlags,
|
|
1017
|
+
);
|
|
991
1018
|
const dispatchNamespace =
|
|
992
1019
|
typeof props.namespace === "string"
|
|
993
1020
|
? props.namespace
|
|
@@ -1085,6 +1112,26 @@ export const _Worker = Resource(
|
|
|
1085
1112
|
throw error;
|
|
1086
1113
|
}
|
|
1087
1114
|
|
|
1115
|
+
if (this.phase === "update") {
|
|
1116
|
+
const oldName = this.output.name ?? this.output.id;
|
|
1117
|
+
const newName = workerName;
|
|
1118
|
+
|
|
1119
|
+
if (oldName !== newName) {
|
|
1120
|
+
if (dispatchNamespace) {
|
|
1121
|
+
await this.replace(true);
|
|
1122
|
+
} else {
|
|
1123
|
+
const renameResponse = await api.patch(
|
|
1124
|
+
`/accounts/${api.accountId}/workers/services/${oldName}`,
|
|
1125
|
+
{ id: newName },
|
|
1126
|
+
);
|
|
1127
|
+
|
|
1128
|
+
if (!renameResponse.ok) {
|
|
1129
|
+
await handleApiError(renameResponse, "rename", "worker", oldName);
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1088
1135
|
let assetsBinding: Assets | undefined;
|
|
1089
1136
|
const workflowsBindings: Workflow[] = [];
|
|
1090
1137
|
const containersBindings: Container[] = [];
|
|
@@ -1219,8 +1266,13 @@ export const _Worker = Resource(
|
|
|
1219
1266
|
}),
|
|
1220
1267
|
);
|
|
1221
1268
|
putWorkerResult = await promise.value;
|
|
1222
|
-
|
|
1223
|
-
|
|
1269
|
+
await createTail(api, id, workerName)
|
|
1270
|
+
.then((tail) => {
|
|
1271
|
+
cleanups.push(() => tail.close());
|
|
1272
|
+
})
|
|
1273
|
+
.catch((error) => {
|
|
1274
|
+
logger.error(`Failed to create tail for ${workerName}`, error);
|
|
1275
|
+
});
|
|
1224
1276
|
} else {
|
|
1225
1277
|
putWorkerResult = await putWorkerWithAssets(props, await bundle.create());
|
|
1226
1278
|
}
|
|
@@ -1424,13 +1476,13 @@ const normalizeExportBindings = (
|
|
|
1424
1476
|
Object.entries(bindings).map(([bindingName, binding]) => [
|
|
1425
1477
|
bindingName,
|
|
1426
1478
|
isDurableObjectNamespace(binding) && binding.scriptName === undefined
|
|
1427
|
-
?
|
|
1479
|
+
? DurableObjectNamespace(binding.id, {
|
|
1428
1480
|
...binding,
|
|
1429
1481
|
// re-export this binding mapping to the host worker (this worker)
|
|
1430
1482
|
scriptName,
|
|
1431
1483
|
})
|
|
1432
1484
|
: isWorkflow(binding) && binding.scriptName === undefined
|
|
1433
|
-
?
|
|
1485
|
+
? Workflow(binding.id, {
|
|
1434
1486
|
...binding,
|
|
1435
1487
|
// re-export this binding mapping to the host worker (this worker)
|
|
1436
1488
|
scriptName,
|
|
@@ -1440,12 +1492,12 @@ const normalizeExportBindings = (
|
|
|
1440
1492
|
);
|
|
1441
1493
|
};
|
|
1442
1494
|
|
|
1443
|
-
const normalizeApiOptions = (
|
|
1495
|
+
const normalizeApiOptions = (
|
|
1496
|
+
api: CloudflareApi,
|
|
1497
|
+
): InternalCloudflareApiOptions => ({
|
|
1444
1498
|
accountId: api.accountId,
|
|
1445
|
-
apiKey: api.apiKey,
|
|
1446
|
-
apiToken: api.apiToken,
|
|
1447
|
-
email: api.email,
|
|
1448
1499
|
baseUrl: api.baseUrl,
|
|
1500
|
+
...api.authOptions,
|
|
1449
1501
|
});
|
|
1450
1502
|
|
|
1451
1503
|
async function provisionContainers(
|
|
@@ -1824,21 +1876,20 @@ function createDevCommand(props: {
|
|
|
1824
1876
|
}
|
|
1825
1877
|
}
|
|
1826
1878
|
|
|
1827
|
-
type PutWorkerOptions = WorkerProps & {
|
|
1879
|
+
type PutWorkerOptions = Omit<WorkerProps, "entrypoint"> & {
|
|
1828
1880
|
dispatchNamespace?: string;
|
|
1829
1881
|
migrationTag?: string;
|
|
1830
1882
|
workerName: string;
|
|
1831
1883
|
scriptBundle: WorkerBundle;
|
|
1832
|
-
version
|
|
1884
|
+
version?: string;
|
|
1833
1885
|
compatibilityDate: string;
|
|
1834
1886
|
compatibilityFlags: string[];
|
|
1835
|
-
assetUploadResult
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
| undefined;
|
|
1887
|
+
assetUploadResult?: {
|
|
1888
|
+
completionToken?: string;
|
|
1889
|
+
keepAssets?: boolean;
|
|
1890
|
+
assetConfig?: AssetsConfig;
|
|
1891
|
+
};
|
|
1892
|
+
tags?: string[];
|
|
1842
1893
|
unstable_cacheWorkerSettings?: boolean;
|
|
1843
1894
|
};
|
|
1844
1895
|
|
|
@@ -34,31 +34,50 @@ export interface WorkflowProps {
|
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export class Workflow<PARAMS = unknown> {
|
|
42
|
-
public readonly type = "workflow";
|
|
37
|
+
export type Workflow<PARAMS = unknown> = {
|
|
38
|
+
type: "workflow";
|
|
43
39
|
/**
|
|
44
40
|
* Phantom property to preserve workflow params at the type level.
|
|
45
|
-
*
|
|
46
41
|
* No value exists.
|
|
47
42
|
*/
|
|
48
|
-
|
|
43
|
+
_PARAMS: PARAMS;
|
|
44
|
+
id: string;
|
|
45
|
+
workflowName: string;
|
|
46
|
+
className: string;
|
|
47
|
+
scriptName?: string;
|
|
48
|
+
};
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
export function isWorkflow(binding: Binding): binding is Workflow {
|
|
51
|
+
return typeof binding === "object" && binding.type === "workflow";
|
|
52
|
+
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Creates a workflow binding for orchestrating and automating tasks.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* // Create a basic workflow
|
|
60
|
+
* const workflow = Workflow("my-workflow", {
|
|
61
|
+
* workflowName: "my-workflow",
|
|
62
|
+
* className: "MyWorkflow"
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export function Workflow<PARAMS = unknown>(
|
|
67
|
+
id: string,
|
|
68
|
+
props: WorkflowProps = {},
|
|
69
|
+
): Workflow<PARAMS> {
|
|
70
|
+
const workflowName = props.workflowName ?? props.className ?? id;
|
|
71
|
+
const className = props.className ?? workflowName;
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
type: "workflow",
|
|
75
|
+
_PARAMS: undefined!,
|
|
76
|
+
id,
|
|
77
|
+
workflowName,
|
|
78
|
+
className,
|
|
79
|
+
scriptName: props.scriptName,
|
|
80
|
+
};
|
|
62
81
|
}
|
|
63
82
|
|
|
64
83
|
export interface WorkflowMetadata {
|
package/src/context.ts
CHANGED
|
@@ -57,7 +57,7 @@ export interface BaseContext<Out extends Resource> {
|
|
|
57
57
|
* Indicate that this resource is being replaced.
|
|
58
58
|
* This will cause the resource to be deleted at the end of the stack's CREATE phase.
|
|
59
59
|
*/
|
|
60
|
-
replace(): never
|
|
60
|
+
replace(force?: boolean): Promise<never>;
|
|
61
61
|
/**
|
|
62
62
|
* Terminate the resource lifecycle handler and destroy the resource.
|
|
63
63
|
*
|
|
@@ -102,7 +102,7 @@ export function context<
|
|
|
102
102
|
seq: number;
|
|
103
103
|
props: Props;
|
|
104
104
|
state: State<Kind, Props, Out>;
|
|
105
|
-
replace: () => never
|
|
105
|
+
replace: (force?: boolean) => Promise<never>;
|
|
106
106
|
isReplacement?: boolean;
|
|
107
107
|
}): Context<Out> {
|
|
108
108
|
type InternalSymbols =
|
package/src/docker/api.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
1
2
|
import { Buffer } from "node:buffer";
|
|
2
3
|
import { spawn } from "node:child_process";
|
|
3
4
|
import fs from "node:fs/promises";
|
|
4
5
|
import path from "node:path";
|
|
5
|
-
import { exec } from "../os/exec.ts";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Options for Docker API requests
|
|
@@ -66,14 +66,39 @@ export class DockerApi {
|
|
|
66
66
|
? { ...process.env, DOCKER_CONFIG: this.configDir }
|
|
67
67
|
: process.env;
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
shell: true,
|
|
73
|
-
env,
|
|
74
|
-
})) as { stdout: string; stderr: string };
|
|
69
|
+
// Buffers to capture output
|
|
70
|
+
let stdout = "";
|
|
71
|
+
let stderr = "";
|
|
75
72
|
|
|
76
|
-
|
|
73
|
+
// Create the subprocess
|
|
74
|
+
const subprocess = execa(this.dockerPath, args, {
|
|
75
|
+
env: env,
|
|
76
|
+
// Don't buffer - we'll handle streams manually
|
|
77
|
+
buffer: false,
|
|
78
|
+
encoding: "utf8",
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Stream stdout in real-time
|
|
82
|
+
subprocess.stdout?.on("data", (chunk: string) => {
|
|
83
|
+
process.stdout.write(chunk);
|
|
84
|
+
stdout += chunk;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Stream stderr in real-time
|
|
88
|
+
subprocess.stderr?.on("data", (chunk: string) => {
|
|
89
|
+
process.stderr.write(chunk);
|
|
90
|
+
stderr += chunk;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Wait for the process to complete
|
|
94
|
+
try {
|
|
95
|
+
await subprocess;
|
|
96
|
+
} catch (error: any) {
|
|
97
|
+
// Process failed, but we still have the output
|
|
98
|
+
throw new Error(stderr || error.message || "Command failed");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return { stdout, stderr };
|
|
77
102
|
}
|
|
78
103
|
|
|
79
104
|
/**
|
|
@@ -1,149 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { ResourceScope } from "../resource.ts";
|
|
4
|
-
import type { Scope } from "../scope.ts";
|
|
5
|
-
import { deserialize, serialize } from "../serde.ts";
|
|
6
|
-
import type { State, StateStore } from "../state.ts";
|
|
7
|
-
import { ignore } from "../util/ignore.ts";
|
|
1
|
+
import * as state from "../state/file-system-state-store.ts";
|
|
8
2
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
public readonly dir: string;
|
|
14
|
-
private initialized = false;
|
|
15
|
-
constructor(
|
|
16
|
-
public readonly scope: Scope,
|
|
17
|
-
options?: {
|
|
18
|
-
rootDir?: string;
|
|
19
|
-
},
|
|
20
|
-
) {
|
|
21
|
-
this.dir = path.join(options?.rootDir ?? stateRootDir, ...scope.chain);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async init(): Promise<void> {
|
|
25
|
-
if (this.initialized) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
this.initialized = true;
|
|
29
|
-
await fs.promises.mkdir(this.dir, { recursive: true });
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async deinit(): Promise<void> {
|
|
33
|
-
await ignore("ENOENT", async () => {
|
|
34
|
-
const entries = await fs.promises.readdir(this.dir, {
|
|
35
|
-
withFileTypes: true,
|
|
36
|
-
});
|
|
37
|
-
const files = entries.filter((entry) => entry.isFile());
|
|
38
|
-
if (files.length > 0) {
|
|
39
|
-
throw new Error(
|
|
40
|
-
`Cannot deinit: directory "${this.dir}" contains files and cannot be deleted.`,
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
// Only folders (or empty), delete recursively
|
|
44
|
-
await fs.promises.rm(this.dir, { recursive: true, force: true });
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async count(): Promise<number> {
|
|
49
|
-
return Object.keys(await this.list()).length;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async list(): Promise<string[]> {
|
|
53
|
-
try {
|
|
54
|
-
const files = await fs.promises.readdir(this.dir, {
|
|
55
|
-
withFileTypes: true,
|
|
56
|
-
});
|
|
57
|
-
return files
|
|
58
|
-
.filter((dirent) => dirent.isFile() && dirent.name.endsWith(".json"))
|
|
59
|
-
.map((dirent) => dirent.name.replace(/\.json$/, ""))
|
|
60
|
-
.map((key) => key.replaceAll(":", "/"));
|
|
61
|
-
} catch (error: any) {
|
|
62
|
-
if (error.code === "ENOENT") {
|
|
63
|
-
return [];
|
|
64
|
-
}
|
|
65
|
-
throw error;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async get(key: string): Promise<State | undefined> {
|
|
70
|
-
try {
|
|
71
|
-
const content = await fs.promises.readFile(this.getPath(key), "utf8");
|
|
72
|
-
const state = (await deserialize(
|
|
73
|
-
this.scope,
|
|
74
|
-
JSON.parse(content),
|
|
75
|
-
)) as State;
|
|
76
|
-
if (state.output === undefined) {
|
|
77
|
-
state.output = {} as any;
|
|
78
|
-
}
|
|
79
|
-
state.output[ResourceScope] = this.scope;
|
|
80
|
-
return state;
|
|
81
|
-
} catch (error: any) {
|
|
82
|
-
if (error.code === "ENOENT") {
|
|
83
|
-
return undefined;
|
|
84
|
-
}
|
|
85
|
-
throw error;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async set(key: string, value: State): Promise<void> {
|
|
90
|
-
await this.init();
|
|
91
|
-
const file = this.getPath(key);
|
|
92
|
-
await fs.promises.mkdir(path.dirname(file), { recursive: true });
|
|
93
|
-
await fs.promises.writeFile(
|
|
94
|
-
file,
|
|
95
|
-
JSON.stringify(await serialize(this.scope, value), null, 2),
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async delete(key: string): Promise<void> {
|
|
100
|
-
try {
|
|
101
|
-
return await fs.promises.unlink(this.getPath(key));
|
|
102
|
-
} catch (error: any) {
|
|
103
|
-
if (error.code === "ENOENT") {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
throw error;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async all(): Promise<Record<string, State>> {
|
|
111
|
-
return this.getBatch(await this.list());
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async getBatch(ids: string[]): Promise<Record<string, State>> {
|
|
115
|
-
return Object.fromEntries(
|
|
116
|
-
(
|
|
117
|
-
await Promise.all(
|
|
118
|
-
Array.from(ids).flatMap(async (id) => {
|
|
119
|
-
const s = await this.get(id);
|
|
120
|
-
if (s === undefined) {
|
|
121
|
-
return [] as const;
|
|
122
|
-
}
|
|
123
|
-
return [[id, s]] as const;
|
|
124
|
-
}),
|
|
125
|
-
)
|
|
126
|
-
).flat(),
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private getPath(key: string): string {
|
|
131
|
-
if (key.includes(":")) {
|
|
132
|
-
throw new Error(`ID cannot include colons: ${key}`);
|
|
133
|
-
}
|
|
134
|
-
if (key.includes("/")) {
|
|
135
|
-
//todo(michael): remove this next time we do a breaking change
|
|
136
|
-
//* windows doesn't support ":" in file paths, but we already use ":"
|
|
137
|
-
//* so now we use both to prevent breaking changes
|
|
138
|
-
key = key.replaceAll("/", ALCHEMY_SEPERATOR_CHAR);
|
|
139
|
-
}
|
|
140
|
-
//todo(michael): remove this next time we do a breaking change
|
|
141
|
-
//* windows doesn't support "*" in file paths, but we already use "*"
|
|
142
|
-
//* when making cloudflare routes containing "*"
|
|
143
|
-
//* so now we use "+" on windows but "*" on mac/linux to prevent breaking changes
|
|
144
|
-
if (process.platform === "win32") {
|
|
145
|
-
key = key.replaceAll("*", "+");
|
|
146
|
-
}
|
|
147
|
-
return path.join(this.dir, `${key}.json`);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated Use `FileSystemStateStore` from `alchemy/state` instead.
|
|
5
|
+
*/
|
|
6
|
+
export const FileSystemStateStore = state.FileSystemStateStore;
|
package/src/fs/index.ts
CHANGED