alchemy 0.45.5 → 0.46.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/README.md +2 -2
- package/bin/alchemy.mjs +19285 -15137
- 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 +66 -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/auth-wrangler.d.ts +25 -0
- package/lib/cloudflare/auth-wrangler.d.ts.map +1 -0
- package/lib/cloudflare/auth-wrangler.js +224 -0
- package/lib/cloudflare/auth-wrangler.js.map +1 -0
- package/lib/cloudflare/auth.d.ts.map +1 -1
- package/lib/cloudflare/auth.js +7 -116
- 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 +6 -2
- package/lib/cloudflare/container.d.ts.map +1 -1
- package/lib/cloudflare/container.js +48 -4
- 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/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 +7 -21
- 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 +18 -8
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +32 -8
- 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 +2 -0
- package/lib/util/memoize.d.ts.map +1 -1
- package/lib/util/memoize.js +14 -7
- package/lib/util/memoize.js.map +1 -1
- package/lib/util/neverthrow.d.ts +9 -0
- package/lib/util/neverthrow.d.ts.map +1 -0
- package/lib/util/neverthrow.js +29 -0
- package/lib/util/neverthrow.js.map +1 -0
- package/package.json +20 -20
- 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/auth-wrangler.ts +314 -0
- package/src/cloudflare/auth.ts +8 -156
- 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 +77 -6
- 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/state.ts +35 -0
- package/src/cloudflare/user.ts +55 -70
- 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 +66 -20
- 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 +18 -7
- package/src/util/neverthrow.ts +36 -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
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
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";
|
|
8
|
+
|
|
9
|
+
const stateRootDir = path.join(process.cwd(), ".alchemy");
|
|
10
|
+
const ALCHEMY_SEPERATOR_CHAR = process.platform === "win32" ? "-" : ":";
|
|
11
|
+
|
|
12
|
+
export class FileSystemStateStore implements StateStore {
|
|
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
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { and, eq, getTableColumns, inArray } from "drizzle-orm";
|
|
2
|
+
import type { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
|
|
3
|
+
import type { State, StateStore } from "../state.ts";
|
|
4
|
+
import { assertNever } from "../util/assert-never.ts";
|
|
5
|
+
import type { StateStoreProxy } from "./proxy.ts";
|
|
6
|
+
import * as schema from "./schema.ts";
|
|
7
|
+
|
|
8
|
+
const { scope: _, ...columns } = getTableColumns(schema.resources);
|
|
9
|
+
|
|
10
|
+
type Database = BaseSQLiteDatabase<any, any, typeof schema>;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Represents the SQL operations for a SQLite-backed state store.
|
|
14
|
+
* DOES NOT include serialization/deserialization — that is handled by the `StateStoreProxy` class.
|
|
15
|
+
*/
|
|
16
|
+
export class SQLiteStateStoreOperations implements StateStore {
|
|
17
|
+
constructor(
|
|
18
|
+
private readonly db: Database,
|
|
19
|
+
private readonly context: { chain: string[] },
|
|
20
|
+
) {}
|
|
21
|
+
|
|
22
|
+
async dispatch<TMethod extends StateStoreProxy.Method>(
|
|
23
|
+
method: TMethod,
|
|
24
|
+
params: StateStoreProxy.API[TMethod]["params"],
|
|
25
|
+
): Promise<StateStoreProxy.API[TMethod]["result"]> {
|
|
26
|
+
switch (method) {
|
|
27
|
+
case "init":
|
|
28
|
+
return;
|
|
29
|
+
case "deinit":
|
|
30
|
+
return;
|
|
31
|
+
case "list":
|
|
32
|
+
return this.list();
|
|
33
|
+
case "count":
|
|
34
|
+
return this.count();
|
|
35
|
+
case "get": {
|
|
36
|
+
const [key] = params as StateStoreProxy.API["get"]["params"];
|
|
37
|
+
return this.get(key);
|
|
38
|
+
}
|
|
39
|
+
case "getBatch": {
|
|
40
|
+
const [keys] = params as StateStoreProxy.API["getBatch"]["params"];
|
|
41
|
+
return this.getBatch(keys);
|
|
42
|
+
}
|
|
43
|
+
case "all":
|
|
44
|
+
return this.all();
|
|
45
|
+
case "set": {
|
|
46
|
+
const [key, state] = params as StateStoreProxy.API["set"]["params"];
|
|
47
|
+
return this.set(key, state);
|
|
48
|
+
}
|
|
49
|
+
case "delete": {
|
|
50
|
+
const [key] = params as StateStoreProxy.API["delete"]["params"];
|
|
51
|
+
return this.delete(key);
|
|
52
|
+
}
|
|
53
|
+
default:
|
|
54
|
+
assertNever(method);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async list() {
|
|
59
|
+
const result = await this.db
|
|
60
|
+
.select({ id: schema.resources.id })
|
|
61
|
+
.from(schema.resources)
|
|
62
|
+
.where(eq(schema.resources.scope, this.context.chain));
|
|
63
|
+
return result.map((r) => r.id);
|
|
64
|
+
}
|
|
65
|
+
async count() {
|
|
66
|
+
const result = await this.db.$count(
|
|
67
|
+
this.db
|
|
68
|
+
.select()
|
|
69
|
+
.from(schema.resources)
|
|
70
|
+
.where(eq(schema.resources.scope, this.context.chain)),
|
|
71
|
+
);
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
async get(key: string) {
|
|
75
|
+
const [result] = await this.db
|
|
76
|
+
.select(columns)
|
|
77
|
+
.from(schema.resources)
|
|
78
|
+
.where(
|
|
79
|
+
and(
|
|
80
|
+
eq(schema.resources.scope, this.context.chain),
|
|
81
|
+
eq(schema.resources.id, key),
|
|
82
|
+
),
|
|
83
|
+
);
|
|
84
|
+
if (!result) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
...result,
|
|
89
|
+
props: result.props ?? undefined,
|
|
90
|
+
oldProps: result.oldProps ?? undefined,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
async all() {
|
|
94
|
+
const result = await this.db
|
|
95
|
+
.select(columns)
|
|
96
|
+
.from(schema.resources)
|
|
97
|
+
.where(eq(schema.resources.scope, this.context.chain));
|
|
98
|
+
const record: Record<string, State> = {};
|
|
99
|
+
for (const r of result) {
|
|
100
|
+
record[r.id] = {
|
|
101
|
+
...r,
|
|
102
|
+
props: r.props ?? undefined,
|
|
103
|
+
oldProps: r.oldProps ?? undefined,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return record;
|
|
107
|
+
}
|
|
108
|
+
async set(_key: string, state: State) {
|
|
109
|
+
await this.db
|
|
110
|
+
.insert(schema.resources)
|
|
111
|
+
.values({
|
|
112
|
+
...state,
|
|
113
|
+
scope: this.context.chain,
|
|
114
|
+
})
|
|
115
|
+
.onConflictDoUpdate({
|
|
116
|
+
target: [schema.resources.id, schema.resources.scope],
|
|
117
|
+
set: {
|
|
118
|
+
...state,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
async delete(key: string) {
|
|
123
|
+
await this.db
|
|
124
|
+
.delete(schema.resources)
|
|
125
|
+
.where(
|
|
126
|
+
and(
|
|
127
|
+
eq(schema.resources.scope, this.context.chain),
|
|
128
|
+
eq(schema.resources.id, key),
|
|
129
|
+
),
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
async getBatch(keys: string[]) {
|
|
133
|
+
const result = await this.db
|
|
134
|
+
.select(columns)
|
|
135
|
+
.from(schema.resources)
|
|
136
|
+
.where(
|
|
137
|
+
and(
|
|
138
|
+
eq(schema.resources.scope, this.context.chain),
|
|
139
|
+
inArray(schema.resources.id, keys),
|
|
140
|
+
),
|
|
141
|
+
);
|
|
142
|
+
const record: Record<string, State> = {};
|
|
143
|
+
for (const r of result) {
|
|
144
|
+
record[r.id] = {
|
|
145
|
+
...r,
|
|
146
|
+
props: r.props ?? undefined,
|
|
147
|
+
oldProps: r.oldProps ?? undefined,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return record;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { Scope } from "../scope.ts";
|
|
2
|
+
import type { State, StateStore } from "../state.ts";
|
|
3
|
+
import { withExponentialBackoff } from "../util/retry.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Wraps a local or remote state store implementation
|
|
7
|
+
* and handles serialization/deserialization.
|
|
8
|
+
*/
|
|
9
|
+
export abstract class StateStoreProxy implements StateStore {
|
|
10
|
+
private dispatch?: Promise<StateStoreProxy.Dispatch>;
|
|
11
|
+
|
|
12
|
+
constructor(readonly scope: Scope) {}
|
|
13
|
+
|
|
14
|
+
abstract provision(): Promise<StateStoreProxy.Dispatch>;
|
|
15
|
+
|
|
16
|
+
private async run<TMethod extends StateStoreProxy.Method>(
|
|
17
|
+
method: TMethod,
|
|
18
|
+
params: StateStoreProxy.API[TMethod]["params"],
|
|
19
|
+
): Promise<StateStoreProxy.API[TMethod]["result"]> {
|
|
20
|
+
this.dispatch ??= this.provision();
|
|
21
|
+
return this.dispatch.then(async (dispatch) => {
|
|
22
|
+
const result = await withExponentialBackoff(
|
|
23
|
+
() => dispatch(method, params),
|
|
24
|
+
() => true,
|
|
25
|
+
);
|
|
26
|
+
return result;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
init(): Promise<void> {
|
|
31
|
+
return this.run("init", []);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
deinit(): Promise<void> {
|
|
35
|
+
return this.run("deinit", []);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
list(): Promise<string[]> {
|
|
39
|
+
return this.run("list", []);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
count(): Promise<number> {
|
|
43
|
+
return this.run("count", []);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async get(key: string): Promise<State | undefined> {
|
|
47
|
+
const result = await this.run("get", [key]);
|
|
48
|
+
if (result === undefined) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
return await this.deserialize(result);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async getBatch(ids: string[]): Promise<Record<string, State>> {
|
|
55
|
+
return this.deserializeMany(await this.run("getBatch", [ids]));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async all(): Promise<Record<string, State>> {
|
|
59
|
+
return this.deserializeMany(await this.run("all", []));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async set(key: string, value: State): Promise<void> {
|
|
63
|
+
return this.run("set", [key, await this.serialize(value)]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async delete(key: string): Promise<void> {
|
|
67
|
+
return this.run("delete", [key]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private async deserialize(state: State): Promise<State> {
|
|
71
|
+
const { deserialize } = await import("../serde.ts"); // dynamic import to avoid circular dependency
|
|
72
|
+
return await deserialize(this.scope, state);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private async serialize(state: State) {
|
|
76
|
+
const { serialize } = await import("../serde.ts");
|
|
77
|
+
return await serialize(this.scope, state);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private async deserializeMany(states: Record<string, State>) {
|
|
81
|
+
return Object.fromEntries(
|
|
82
|
+
await Promise.all(
|
|
83
|
+
Object.entries(states).map(async ([key, value]) => [
|
|
84
|
+
key,
|
|
85
|
+
await this.deserialize(value),
|
|
86
|
+
]),
|
|
87
|
+
),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export declare namespace StateStoreProxy {
|
|
93
|
+
export type API = {
|
|
94
|
+
[K in keyof Required<StateStore>]: NonNullable<StateStore[K]> extends (
|
|
95
|
+
...args: infer Args
|
|
96
|
+
) => Promise<infer Return>
|
|
97
|
+
? {
|
|
98
|
+
method: K;
|
|
99
|
+
params: Args;
|
|
100
|
+
result: Return;
|
|
101
|
+
}
|
|
102
|
+
: never;
|
|
103
|
+
};
|
|
104
|
+
export type Method = keyof API;
|
|
105
|
+
|
|
106
|
+
export type Dispatch = <TMethod extends Method>(
|
|
107
|
+
method: TMethod,
|
|
108
|
+
params: API[TMethod]["params"],
|
|
109
|
+
) => Promise<API[TMethod]["result"]>;
|
|
110
|
+
|
|
111
|
+
export type Request<TMethod extends Method, TContext = unknown> = {
|
|
112
|
+
method: TMethod;
|
|
113
|
+
params: API[TMethod]["params"];
|
|
114
|
+
context: TContext;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export type SuccessResponse<TMethod extends Method> = {
|
|
118
|
+
success: true;
|
|
119
|
+
status: number;
|
|
120
|
+
result: API[TMethod]["result"];
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export type ErrorResponse = {
|
|
124
|
+
success: false;
|
|
125
|
+
status: number;
|
|
126
|
+
error: string;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export type Response<TMethod extends Method> =
|
|
130
|
+
| SuccessResponse<TMethod>
|
|
131
|
+
| ErrorResponse;
|
|
132
|
+
}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Scope } from "../scope.ts";
|
|
3
|
-
import { serialize, deserialize } from "../serde.ts";
|
|
4
|
-
import type { State, StateStore } from "../state.ts";
|
|
5
|
-
import { withExponentialBackoff } from "../util/retry.ts";
|
|
6
|
-
import { CloudflareApiError, handleApiError } from "./api-error.ts";
|
|
1
|
+
import { CloudflareApiError, handleApiError } from "../cloudflare/api-error.ts";
|
|
7
2
|
import {
|
|
8
3
|
type CloudflareApi,
|
|
9
4
|
type CloudflareApiOptions,
|
|
10
5
|
createCloudflareApi,
|
|
11
|
-
} from "
|
|
12
|
-
import {
|
|
6
|
+
} from "../cloudflare/api.ts";
|
|
7
|
+
import { ResourceScope } from "../resource.ts";
|
|
8
|
+
import type { Scope } from "../scope.ts";
|
|
9
|
+
import { deserialize, serialize } from "../serde.ts";
|
|
10
|
+
import type { State, StateStore } from "../state.ts";
|
|
11
|
+
import { withExponentialBackoff } from "../util/retry.ts";
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* Options for CloudflareR2StateStore
|
|
@@ -31,6 +30,8 @@ export interface CloudflareR2StateStoreOptions extends CloudflareApiOptions {
|
|
|
31
30
|
/**
|
|
32
31
|
* State store implementation using Cloudflare R2 API
|
|
33
32
|
* Uses R2 for immediate consistency compared to KV's eventual consistency
|
|
33
|
+
*
|
|
34
|
+
* @deprecated Use `CloudflareStateStore` from `alchemy/state` instead.
|
|
34
35
|
*/
|
|
35
36
|
export class R2RestStateStore implements StateStore {
|
|
36
37
|
private api: CloudflareApi;
|
|
@@ -66,6 +67,8 @@ export class R2RestStateStore implements StateStore {
|
|
|
66
67
|
async init(): Promise<void> {
|
|
67
68
|
if (this.initialized) return;
|
|
68
69
|
|
|
70
|
+
const { createBucket, getBucket } = await import("../cloudflare/bucket.ts");
|
|
71
|
+
|
|
69
72
|
// Create Cloudflare API client with automatic account discovery
|
|
70
73
|
this.api = await createCloudflareApi(this.options);
|
|
71
74
|
|
|
@@ -3,10 +3,9 @@ import fs from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import type { Scope } from "../scope.ts";
|
|
5
5
|
import { memoize } from "../util/memoize.ts";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "./base-sqlite-state-store.ts";
|
|
6
|
+
import { MIGRATIONS_DIRECTORY } from "./migrations.ts";
|
|
7
|
+
import { SQLiteStateStoreOperations } from "./operations.ts";
|
|
8
|
+
import { StateStoreProxy } from "./proxy.ts";
|
|
10
9
|
import * as schema from "./schema.ts";
|
|
11
10
|
|
|
12
11
|
interface BunSQLiteStateStoreOptions {
|
|
@@ -73,11 +72,20 @@ type SQLiteStateStoreOptions =
|
|
|
73
72
|
| LibSQLStateStoreOptions
|
|
74
73
|
| AutoSQLiteStateStoreOptions;
|
|
75
74
|
|
|
76
|
-
export class SQLiteStateStore extends
|
|
77
|
-
constructor(
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
export class SQLiteStateStore extends StateStoreProxy {
|
|
76
|
+
constructor(
|
|
77
|
+
scope: Scope,
|
|
78
|
+
private options?: SQLiteStateStoreOptions,
|
|
79
|
+
) {
|
|
80
|
+
super(scope);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async provision(): Promise<StateStoreProxy.Dispatch> {
|
|
84
|
+
const db = await createDatabase(this.options);
|
|
85
|
+
const operations = new SQLiteStateStoreOperations(db, {
|
|
86
|
+
chain: this.scope.chain,
|
|
80
87
|
});
|
|
88
|
+
return operations.dispatch.bind(operations);
|
|
81
89
|
}
|
|
82
90
|
}
|
|
83
91
|
|
|
@@ -132,7 +140,7 @@ async function createBunSQLiteDatabase(
|
|
|
132
140
|
const db = drizzle(client, {
|
|
133
141
|
schema,
|
|
134
142
|
});
|
|
135
|
-
migrate(db, { migrationsFolder:
|
|
143
|
+
migrate(db, { migrationsFolder: MIGRATIONS_DIRECTORY });
|
|
136
144
|
return db;
|
|
137
145
|
}
|
|
138
146
|
|
|
@@ -162,7 +170,7 @@ async function createLibSQLDatabase(
|
|
|
162
170
|
const db = drizzle(client, {
|
|
163
171
|
schema,
|
|
164
172
|
});
|
|
165
|
-
await migrate(db, { migrationsFolder:
|
|
173
|
+
await migrate(db, { migrationsFolder: MIGRATIONS_DIRECTORY });
|
|
166
174
|
return db;
|
|
167
175
|
}
|
|
168
176
|
|
package/src/test/vitest.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { afterAll, beforeAll, it } from "vitest";
|
|
3
3
|
import { alchemy } from "../alchemy.ts";
|
|
4
|
-
import { D1StateStore } from "../cloudflare/d1-state-store.ts";
|
|
5
|
-
import { DOStateStore } from "../cloudflare/do-state-store/index.ts";
|
|
6
|
-
import { FileSystemStateStore } from "../fs/file-system-state-store.ts";
|
|
7
4
|
import { Scope } from "../scope.ts";
|
|
8
|
-
import { SQLiteStateStore } from "../sqlite/sqlite-state-store.ts";
|
|
9
5
|
import type { StateStoreType } from "../state.ts";
|
|
6
|
+
import {
|
|
7
|
+
CloudflareStateStore,
|
|
8
|
+
D1StateStore,
|
|
9
|
+
FileSystemStateStore,
|
|
10
|
+
SQLiteStateStore,
|
|
11
|
+
} from "../state/index.ts";
|
|
10
12
|
import { NoopTelemetryClient } from "../util/telemetry/client.ts";
|
|
11
13
|
|
|
12
14
|
/**
|
|
@@ -129,8 +131,8 @@ export function test(
|
|
|
129
131
|
defaultOptions.stateStore ??= (scope) => {
|
|
130
132
|
const storeType = process.env.ALCHEMY_STATE_STORE;
|
|
131
133
|
switch (storeType) {
|
|
132
|
-
case "
|
|
133
|
-
return new
|
|
134
|
+
case "do":
|
|
135
|
+
return new CloudflareStateStore(scope);
|
|
134
136
|
case "fs":
|
|
135
137
|
return new FileSystemStateStore(scope);
|
|
136
138
|
case "d1":
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare var Deno: any;
|
|
2
|
+
declare var Bun: any;
|
|
3
|
+
|
|
4
|
+
export type Runtime = "bun" | "deno" | "node";
|
|
5
|
+
|
|
6
|
+
export function detectRuntime(): Runtime {
|
|
7
|
+
if (typeof Bun !== "undefined" && Bun !== null) return "bun";
|
|
8
|
+
if (typeof Deno !== "undefined" && Deno !== null) return "deno";
|
|
9
|
+
if (typeof process !== "undefined" && process.release?.name === "node")
|
|
10
|
+
return "node";
|
|
11
|
+
return "node";
|
|
12
|
+
}
|
|
@@ -1,18 +1,31 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { exists } from "./exists.ts";
|
|
2
2
|
|
|
3
|
-
export type PackageManager = "bun" | "pnpm" | "yarn" | "npm";
|
|
3
|
+
export type PackageManager = "bun" | "pnpm" | "yarn" | "npm" | "deno";
|
|
4
4
|
|
|
5
|
-
export function detectPackageManager(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (
|
|
5
|
+
export async function detectPackageManager(
|
|
6
|
+
path: string = process.cwd(),
|
|
7
|
+
): Promise<PackageManager> {
|
|
8
|
+
if (await exists(`${path}/deno.lock`)) return "deno";
|
|
9
|
+
if (
|
|
10
|
+
(await exists(`${path}/deno.json`)) ||
|
|
11
|
+
(await exists(`${path}/deno.jsonc`))
|
|
12
|
+
)
|
|
13
|
+
return "deno";
|
|
14
|
+
if (await exists(`${path}/bun.lockb`)) return "bun";
|
|
15
|
+
if (await exists(`${path}/pnpm-lock.yaml`)) return "pnpm";
|
|
16
|
+
if (await exists(`${path}/yarn.lock`)) return "yarn";
|
|
9
17
|
|
|
10
18
|
if (process.env.npm_execpath?.includes("bun")) {
|
|
11
19
|
return "bun";
|
|
12
20
|
}
|
|
13
21
|
|
|
22
|
+
if (process.env.DENO) {
|
|
23
|
+
return "deno";
|
|
24
|
+
}
|
|
25
|
+
|
|
14
26
|
const userAgent = process.env.npm_config_user_agent;
|
|
15
27
|
if (userAgent) {
|
|
28
|
+
if (userAgent.startsWith("deno")) return "deno";
|
|
16
29
|
if (userAgent.startsWith("bun")) return "bun";
|
|
17
30
|
if (userAgent.startsWith("pnpm")) return "pnpm";
|
|
18
31
|
if (userAgent.startsWith("yarn")) return "yarn";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import http from "node:http";
|
|
2
2
|
import type { AddressInfo } from "node:net";
|
|
3
3
|
import { Readable } from "node:stream";
|
|
4
|
-
import { promiseWithResolvers } from "
|
|
4
|
+
import { promiseWithResolvers } from "./promise-with-resolvers.ts";
|
|
5
5
|
|
|
6
6
|
export class HTTPServer {
|
|
7
7
|
server: http.Server;
|
package/src/util/memoize.ts
CHANGED
|
@@ -24,12 +24,23 @@ export function memoize<F extends (...args: any[]) => Promise<any>>(
|
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
args
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
export function memoizeSync<F extends (...args: any[]) => any>(
|
|
28
|
+
fn: F,
|
|
29
|
+
keyFn: (...args: Parameters<F>) => string = defaultKeyFn,
|
|
30
|
+
) {
|
|
31
|
+
const cache = new Map<string, ReturnType<F>>();
|
|
32
|
+
return (...args: Parameters<F>): ReturnType<F> => {
|
|
33
|
+
const key = keyFn(...args);
|
|
34
|
+
const cached = cache.get(key);
|
|
35
|
+
if (cached) {
|
|
36
|
+
return cached;
|
|
32
37
|
}
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
const result = fn(...args);
|
|
39
|
+
cache.set(key, result);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const defaultKeyFn = (...args: any[]) => {
|
|
45
|
+
return createHash("sha256").update(JSON.stringify(args)).digest("hex");
|
|
35
46
|
};
|