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",
},