diff --git a/CHANGELOG.md b/CHANGELOG.md index afe2ad7db..e00970976 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## v0.37.2 + +###    🐞 Bug Fixes + +- **cloudflare**: Defensively resolve __dirname and worker.ts > worker.js in DOStateStore  -  by **Sam Goodwin** in https://github.com/sam-goodwin/alchemy/issues/452 [(c63fd)](https://github.com/sam-goodwin/alchemy/commit/c63fdd60) + +#####     [View changes on GitHub](https://github.com/sam-goodwin/alchemy/compare/v0.37.1...v0.37.2) + +--- + ## v0.37.1 ###    🚀 Features diff --git a/alchemy/package.json b/alchemy/package.json index dc313e887..321d4bfbe 100644 --- a/alchemy/package.json +++ b/alchemy/package.json @@ -1,6 +1,6 @@ { "name": "alchemy", - "version": "0.37.1", + "version": "0.37.2", "type": "module", "module": "./lib/index.js", "license": "Apache-2.0", diff --git a/alchemy/src/cloudflare/do-state-store/internal.ts b/alchemy/src/cloudflare/do-state-store/internal.ts index 68a4d3b66..194ca302a 100644 --- a/alchemy/src/cloudflare/do-state-store/internal.ts +++ b/alchemy/src/cloudflare/do-state-store/internal.ts @@ -1,5 +1,7 @@ import path from "node:path"; +import { fileURLToPath } from "node:url"; import { bundle } from "../../esbuild/index.ts"; +import { exists } from "../../util/exists.ts"; import { withExponentialBackoff } from "../../util/retry.ts"; import { handleApiError } from "../api-error.ts"; import type { CloudflareApi } from "../api.ts"; @@ -217,8 +219,15 @@ export async function getAccountSubdomain(api: CloudflareApi) { } async function bundleWorkerScript() { + const thisDir = + typeof __dirname !== "undefined" + ? __dirname + : path.dirname(fileURLToPath(import.meta.url)); + // we can be running from .ts or .js, so resolve it defensively + const workerTs = path.join(thisDir, "worker.ts"); + const workerJs = path.join(thisDir, "worker.js"); const result = await bundle({ - entryPoint: path.join(__dirname, "worker.ts"), + entryPoint: (await exists(workerTs)) ? workerTs : workerJs, bundle: true, format: "esm", target: "es2022", diff --git a/alchemy/src/util/exists.ts b/alchemy/src/util/exists.ts new file mode 100644 index 000000000..70b3f0f96 --- /dev/null +++ b/alchemy/src/util/exists.ts @@ -0,0 +1,10 @@ +import { access } from "node:fs/promises"; + +export async function exists(path: string): Promise { + try { + await access(path); + return true; + } catch { + return false; + } +} diff --git a/alchemy/test/cloudflare/ai.test.ts b/alchemy/test/cloudflare/ai.test.ts index 7010ef031..a6d82cd91 100644 --- a/alchemy/test/cloudflare/ai.test.ts +++ b/alchemy/test/cloudflare/ai.test.ts @@ -22,6 +22,7 @@ describe("AI Resource Binding", () => { // Create a worker with an AI binding worker = await Worker(workerName, { name: workerName, + adopt: true, script: ` export default { async fetch(request, env) { diff --git a/alchemy/test/cloudflare/browser-rendering.test.ts b/alchemy/test/cloudflare/browser-rendering.test.ts index e99f0ba4c..1164de90b 100644 --- a/alchemy/test/cloudflare/browser-rendering.test.ts +++ b/alchemy/test/cloudflare/browser-rendering.test.ts @@ -34,6 +34,7 @@ describe("Browser Rendering Resource", () => { // Create a worker with browser rendering binding worker = await Worker(workerName, { name: workerName, + adopt: true, entrypoint: path.join(import.meta.dirname, "browser-handler.ts"), format: "esm", compatibilityFlags: ["nodejs_compat"], // Required for puppeteer diff --git a/alchemy/test/cloudflare/bucket.test.ts b/alchemy/test/cloudflare/bucket.test.ts index 47110448c..6dc27de6c 100644 --- a/alchemy/test/cloudflare/bucket.test.ts +++ b/alchemy/test/cloudflare/bucket.test.ts @@ -202,6 +202,7 @@ describe("R2 Bucket Resource", async () => { // Create a worker with the R2 bucket binding worker = await Worker(workerName, { name: workerName, + adopt: true, script: ` export default { async fetch(request, env, ctx) { diff --git a/alchemy/test/cloudflare/d1-database.test.ts b/alchemy/test/cloudflare/d1-database.test.ts index edc0ed7f7..9dbcbb56d 100644 --- a/alchemy/test/cloudflare/d1-database.test.ts +++ b/alchemy/test/cloudflare/d1-database.test.ts @@ -384,6 +384,7 @@ describe("D1 Database Resource", async () => { // Create a worker with the D1 database binding worker = await Worker(workerName, { name: workerName, + adopt: true, script: ` export default { async fetch(request, env, ctx) { diff --git a/alchemy/test/cloudflare/dispatch-namespace.test.ts b/alchemy/test/cloudflare/dispatch-namespace.test.ts index cb8228ee8..75ccfc1c2 100644 --- a/alchemy/test/cloudflare/dispatch-namespace.test.ts +++ b/alchemy/test/cloudflare/dispatch-namespace.test.ts @@ -94,6 +94,7 @@ describe("Dispatch Namespace Resource", () => { // 2. Create a worker in the dispatch namespace targetWorker = await Worker(workerName, { name: workerName, + adopt: true, script: ` export default { async fetch(request, env, ctx) { @@ -107,6 +108,7 @@ describe("Dispatch Namespace Resource", () => { // 3. Create a worker bound to the namespace (dispatcher) dispatcherWorker = await Worker(dispatcherWorkerName, { name: dispatcherWorkerName, + adopt: true, script: ` export default { async fetch(request, env, ctx) { @@ -184,6 +186,7 @@ describe("Dispatch Namespace Resource", () => { // 4. Create a worker in the dispatch namespace with asset bindings assetWorker = await Worker(workerName, { name: workerName, + adopt: true, script: ` export default { async fetch(request, env, ctx) { @@ -201,6 +204,7 @@ describe("Dispatch Namespace Resource", () => { // 5. Create a dispatcher worker that routes to the asset worker dispatcherWorker = await Worker(dispatcherWorkerName, { name: dispatcherWorkerName, + adopt: true, script: ` export default { async fetch(request, env, ctx) { diff --git a/alchemy/test/cloudflare/durable-object.test.ts b/alchemy/test/cloudflare/durable-object.test.ts index 03009876e..9e039860a 100644 --- a/alchemy/test/cloudflare/durable-object.test.ts +++ b/alchemy/test/cloudflare/durable-object.test.ts @@ -68,6 +68,7 @@ describe("Durable Object Namespace", () => { // First create the worker without the DO binding worker = await Worker(workerName, { name: workerName, + adopt: true, script: durableObjectWorkerScript, format: "esm", // No bindings yet @@ -89,6 +90,7 @@ describe("Durable Object Namespace", () => { // Update the worker with the DO binding worker = await Worker(workerName, { name: workerName, + adopt: true, script: durableObjectWorkerScript, format: "esm", bindings: { diff --git a/alchemy/test/cloudflare/hyperdrive.test.ts b/alchemy/test/cloudflare/hyperdrive.test.ts index 4dd7afee2..8d3b17524 100644 --- a/alchemy/test/cloudflare/hyperdrive.test.ts +++ b/alchemy/test/cloudflare/hyperdrive.test.ts @@ -76,6 +76,7 @@ describe("Hyperdrive Resource", () => { const workerName = `${BRANCH_PREFIX}-hyperdrive-test-worker`; worker = await Worker(workerName, { name: workerName, + adopt: true, script: ` export default { async fetch(request, env, ctx) { diff --git a/alchemy/test/cloudflare/images.test.ts b/alchemy/test/cloudflare/images.test.ts index dfad5807b..6ff2573b1 100644 --- a/alchemy/test/cloudflare/images.test.ts +++ b/alchemy/test/cloudflare/images.test.ts @@ -21,6 +21,7 @@ describe("Images Binding", () => { try { worker = await Worker(workerName, { name: workerName, + adopt: true, entrypoint: path.join(import.meta.dirname, "images-handler.ts"), format: "esm", bindings: { diff --git a/alchemy/test/cloudflare/kv-namespace.test.ts b/alchemy/test/cloudflare/kv-namespace.test.ts index 5a3bf4be3..96a0d39fe 100644 --- a/alchemy/test/cloudflare/kv-namespace.test.ts +++ b/alchemy/test/cloudflare/kv-namespace.test.ts @@ -150,6 +150,7 @@ describe("KV Namespace Resource", () => { // Create a worker with the KV Namespace binding worker = await Worker(workerName, { name: workerName, + adopt: true, script: ` export default { async fetch(request, env, ctx) { diff --git a/alchemy/test/cloudflare/pipeline.test.ts b/alchemy/test/cloudflare/pipeline.test.ts index 9385a8466..1e6c13f6f 100644 --- a/alchemy/test/cloudflare/pipeline.test.ts +++ b/alchemy/test/cloudflare/pipeline.test.ts @@ -386,6 +386,7 @@ describe("Pipeline Resource", () => { // Create a worker with the pipeline binding worker = await Worker(workerName, { name: workerName, + adopt: true, script: pipelineWorkerScript, format: "esm", url: true, // Enable workers.dev URL to test the worker diff --git a/alchemy/test/cloudflare/secret-key.test.ts b/alchemy/test/cloudflare/secret-key.test.ts index 68cb942a4..d76f74c78 100644 --- a/alchemy/test/cloudflare/secret-key.test.ts +++ b/alchemy/test/cloudflare/secret-key.test.ts @@ -47,6 +47,7 @@ describe("SecretKey Binding", () => { // Create a worker that accesses the JWK SecretKey properties and can sign data worker = await Worker(workerName, { name: workerName, + adopt: true, format: "esm", url: true, bindings: { diff --git a/alchemy/test/cloudflare/secret.test.ts b/alchemy/test/cloudflare/secret.test.ts index f90794abb..8e67f1772 100644 --- a/alchemy/test/cloudflare/secret.test.ts +++ b/alchemy/test/cloudflare/secret.test.ts @@ -41,6 +41,7 @@ describe("Secret Resource", () => { // Create a worker that binds to the secret and returns the secret value worker = await Worker(workerName, { name: workerName, + adopt: true, script: ` export default { async fetch(request, env, ctx) { diff --git a/alchemy/test/cloudflare/unenv.test.ts b/alchemy/test/cloudflare/unenv.test.ts index 0e2413c88..fb4c6411e 100644 --- a/alchemy/test/cloudflare/unenv.test.ts +++ b/alchemy/test/cloudflare/unenv.test.ts @@ -20,6 +20,7 @@ describe("Worker Unenv Tests", () => { // Create a temporary directory for the files // Create the worker using the entrypoint file const worker = await Worker(`${BRANCH_PREFIX}-test-worker-unenv`, { + adopt: true, entrypoint: path.join(import.meta.dirname, "unenv-handler.ts"), format: "esm", url: true, // Enable workers.dev URL to test the worker diff --git a/alchemy/test/cloudflare/version-metadata.test.ts b/alchemy/test/cloudflare/version-metadata.test.ts index 2bcdd46bf..042434edd 100644 --- a/alchemy/test/cloudflare/version-metadata.test.ts +++ b/alchemy/test/cloudflare/version-metadata.test.ts @@ -22,6 +22,7 @@ describe("VersionMetadata Binding", () => { try { worker = await Worker(workerName, { name: workerName, + adopt: true, entrypoint: path.join( import.meta.dirname, "version-metadata-handler.ts", diff --git a/alchemy/test/cloudflare/worker-stub.test.ts b/alchemy/test/cloudflare/worker-stub.test.ts index 421fa9e22..0a01e71a1 100644 --- a/alchemy/test/cloudflare/worker-stub.test.ts +++ b/alchemy/test/cloudflare/worker-stub.test.ts @@ -15,6 +15,7 @@ test("worker-stub-types", () => { const workerA = await Worker("workerA", { entrypoint: "index.ts", name: "workerA", + adopt: true, bindings: { workerB: await WorkerStub("workerB", { name: "workerB", @@ -25,6 +26,7 @@ test("worker-stub-types", () => { const _workerB = await Worker("workerB", { entrypoint: "index.ts", name: "workerB", + adopt: true, bindings: { workerA, }, diff --git a/alchemy/test/cloudflare/worker.test.ts b/alchemy/test/cloudflare/worker.test.ts index de5adfaad..79cc3b6a9 100644 --- a/alchemy/test/cloudflare/worker.test.ts +++ b/alchemy/test/cloudflare/worker.test.ts @@ -53,6 +53,7 @@ describe("Worker Resource", () => { // Create a worker with an explicit name worker = await Worker(workerName, { name: workerName, + adopt: true, script: ` addEventListener('fetch', event => { event.respondWith(new Response('Hello world!', { status: 200 })); @@ -75,6 +76,7 @@ describe("Worker Resource", () => { worker = await Worker(workerName, { name: workerName, + adopt: true, script: updatedScript, format: "cjs", }); @@ -121,6 +123,7 @@ describe("Worker Resource", () => { worker = await Worker(workerName, { name: workerName, + adopt: true, script: updatedEsmScript, format: "esm", }); @@ -140,6 +143,7 @@ describe("Worker Resource", () => { // First create with ESM format worker = await Worker(workerName, { name: workerName, + adopt: true, script: ` export default { async fetch(request, env, ctx) { @@ -155,6 +159,7 @@ describe("Worker Resource", () => { // Update to CJS format worker = await Worker(workerName, { name: workerName, + adopt: true, script: ` addEventListener('fetch', event => { event.respondWith(new Response('Hello world!', { status: 200 })); @@ -272,6 +277,7 @@ describe("Worker Resource", () => { // Create a KV namespace const testKv = await KVNamespace("test-kv-namespace", { title: `${BRANCH_PREFIX} Test KV Namespace 1`, + adopt: true, values: [ { key: "testKey", @@ -288,6 +294,7 @@ describe("Worker Resource", () => { name: workerName, script: multiBindingsWorkerScript, format: "esm", + adopt: true, }); expect(worker.id).toBeTruthy(); @@ -303,6 +310,7 @@ describe("Worker Resource", () => { TEST_KV: testKv, API_KEY: "test-api-key-value", }, + adopt: true, }); expect(worker.id).toBeTruthy(); @@ -363,6 +371,7 @@ describe("Worker Resource", () => { APP_DEBUG: "true", }, url: true, // Enable workers.dev URL to test the worker + adopt: true, }); expect(worker.id).toBeTruthy(); @@ -399,6 +408,7 @@ describe("Worker Resource", () => { NEW_VAR: "new-value", }, url: true, + adopt: true, }); await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -497,6 +507,7 @@ describe("Worker Resource", () => { bindings: { ASSETS: assets, }, + adopt: true, }); await new Promise((resolve) => setTimeout(resolve, 1000)); diff --git a/alchemy/test/cloudflare/workflow.test.ts b/alchemy/test/cloudflare/workflow.test.ts index 8afe9a955..9ba70a16e 100644 --- a/alchemy/test/cloudflare/workflow.test.ts +++ b/alchemy/test/cloudflare/workflow.test.ts @@ -207,6 +207,7 @@ describe("Workflow", () => { // Create a worker with the workflow binding worker = await Worker(workerName, { name: workerName, + adopt: true, script: workflowWorkerScript, format: "esm", bindings: { @@ -250,6 +251,7 @@ describe("Workflow", () => { // Update the worker with multiple workflow bindings worker = await Worker(workerName, { name: workerName, + adopt: true, script: workflowWorkerScript, format: "esm", bindings: { @@ -317,6 +319,7 @@ describe("Workflow", () => { // First create the worker that defines the workflow with its own binding workflowProviderWorker = await Worker(workflowWorkerName, { name: workflowWorkerName, + adopt: true, script: workflowProviderWorkerScript, format: "esm", url: true, // Enable workers.dev URL @@ -339,6 +342,7 @@ describe("Workflow", () => { // Create the client worker with the cross-script workflow binding clientWorker = await Worker(clientWorkerName, { name: clientWorkerName, + adopt: true, script: clientWorkerScript, format: "esm", url: true, // Enable workers.dev URL @@ -434,6 +438,7 @@ describe("Workflow", () => { // First create the worker that defines the workflow with its own binding workflowProviderWorker = await Worker(workflowWorkerName, { name: workflowWorkerName, + adopt: true, script: workflowProviderWorkerScript, format: "esm", url: true, // Enable workers.dev URL @@ -463,6 +468,7 @@ describe("Workflow", () => { // Create the client worker with the cross-script workflow binding using re-exported syntax clientWorker = await Worker(clientWorkerName, { name: clientWorkerName, + adopt: true, script: clientWorkerScript, format: "esm", url: true, // Enable workers.dev URL diff --git a/bun.lock b/bun.lock index 4e1e0286c..417c4bd46 100644 --- a/bun.lock +++ b/bun.lock @@ -25,7 +25,7 @@ }, "alchemy": { "name": "alchemy", - "version": "0.37.1", + "version": "0.37.2", "bin": { "alchemy": "bin/alchemy.mjs", },