diff --git a/.changeset/nervous-jeans-obey.md b/.changeset/nervous-jeans-obey.md new file mode 100644 index 000000000000..4256c59b49b4 --- /dev/null +++ b/.changeset/nervous-jeans-obey.md @@ -0,0 +1,5 @@ +--- +"wrangler": patch +--- + +Fix to not require local connection string when using Hyperdrive and wrangler dev --remote diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 1da2472650f6..c33932498ba2 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -48,6 +48,7 @@ jobs: env: CLOUDFLARE_API_TOKEN: ${{ secrets.TEST_CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.TEST_CLOUDFLARE_ACCOUNT_ID }} + HYPERDRIVE_DATABASE_URL: ${{ secrets.TEST_HYPERDRIVE_DATABASE_URL}} WRANGLER: node --no-warnings ${{ github.workspace}}/packages/wrangler/bin/wrangler.js WRANGLER_IMPORT: ${{ github.workspace}}/packages/wrangler/wrangler-dist/cli.js NODE_OPTIONS: "--max_old_space_size=8192" diff --git a/packages/wrangler/e2e/dev-with-resources.test.ts b/packages/wrangler/e2e/dev-with-resources.test.ts index f464c54b9ab2..fc1a2ee04a20 100644 --- a/packages/wrangler/e2e/dev-with-resources.test.ts +++ b/packages/wrangler/e2e/dev-with-resources.test.ts @@ -580,6 +580,35 @@ describe.sequential.each(RUNTIMES)("Bindings: $flags", ({ runtime, flags }) => { ); }); + it("exposes Hyperdrive bindings", async () => { + const { id } = await helper.hyperdrive(false); + + await helper.seed({ + "wrangler.toml": dedent` + name = "${workerName}" + main = "src/index.ts" + compatibility_date = "2023-10-25" + + [[hyperdrive]] + binding = "HYPERDRIVE" + id = "${id}" + `, + "src/index.ts": dedent` + export default { + async fetch(request, env) { + if (request.url.includes("connect")) { + const conn = env.HYPERDRIVE.connect(); + } + return new Response(env.HYPERDRIVE?.connectionString ?? "no") + } + }`, + }); + + const worker = helper.runLongLived(`wrangler dev ${flags}`); + const { url } = await worker.waitForReady(); + await fetch(`${url}/connect`); + }); + it.skipIf(!isLocal).fails("exposes Pipelines bindings", async () => { await helper.seed({ "wrangler.toml": dedent` @@ -692,7 +721,6 @@ describe.sequential.each(RUNTIMES)("Bindings: $flags", ({ runtime, flags }) => { }); // TODO(soon): implement E2E tests for other bindings - it.todo("exposes hyperdrive bindings"); it.skipIf(isLocal).todo("exposes send email bindings"); it.skipIf(isLocal).todo("exposes browser bindings"); it.skipIf(isLocal).todo("exposes Workers AI bindings"); diff --git a/packages/wrangler/e2e/dev.test.ts b/packages/wrangler/e2e/dev.test.ts index 423ae226a8af..fbdd45e5b28d 100644 --- a/packages/wrangler/e2e/dev.test.ts +++ b/packages/wrangler/e2e/dev.test.ts @@ -653,6 +653,44 @@ describe("hyperdrive dev tests", () => { await socketMsgPromise; }); + it("does not require local connection string when running `wrangler dev --remote`", async () => { + const helper = new WranglerE2ETestHelper(); + const { id } = await helper.hyperdrive(false); + + await helper.seed({ + "wrangler.toml": dedent` + name = "${workerName}" + main = "src/index.ts" + compatibility_date = "2023-10-25" + + [[hyperdrive]] + binding = "HYPERDRIVE" + id = "${id}" + `, + "src/index.ts": dedent` + export default { + async fetch(request, env) { + if (request.url.includes("connect")) { + const conn = env.HYPERDRIVE.connect(); + } + return new Response(env.HYPERDRIVE?.connectionString ?? "no") + } + }`, + "package.json": dedent` + { + "name": "worker", + "version": "0.0.0", + "private": true + } + `, + }); + + const worker = helper.runLongLived("wrangler dev --remote"); + + const { url } = await worker.waitForReady(); + await fetch(`${url}/connect`); + }); + afterEach(() => { if (server.listening) { server.close(); diff --git a/packages/wrangler/e2e/helpers/e2e-wrangler-test.ts b/packages/wrangler/e2e/helpers/e2e-wrangler-test.ts index 293ff896b796..a12a8ea4f061 100644 --- a/packages/wrangler/e2e/helpers/e2e-wrangler-test.ts +++ b/packages/wrangler/e2e/helpers/e2e-wrangler-test.ts @@ -124,4 +124,27 @@ export class WranglerE2ETestHelper { return name; } + + async hyperdrive(isLocal: boolean): Promise<{ id: string; name: string }> { + const name = generateResourceName("hyperdrive"); + + if (isLocal) { + return { id: crypto.randomUUID(), name }; + } + + const result = await this.run( + `wrangler hyperdrive create ${name} --connection-string="${process.env.HYPERDRIVE_DATABASE_URL}"` + ); + const tomlMatch = /id = "([0-9a-f]{32})"/.exec(result.stdout); + const jsonMatch = /"id": "([0-9a-f]{32})"/.exec(result.stdout); + const match = jsonMatch ?? tomlMatch; + assert(match !== null, `Cannot find ID in ${JSON.stringify(result)}`); + const id = match[1]; + + onTestFinished(async () => { + await this.run(`wrangler hyperdrive delete ${name}`); + }); + + return { id, name }; + } } diff --git a/packages/wrangler/src/dev.ts b/packages/wrangler/src/dev.ts index 3d4a50aaa11f..0fae28516140 100644 --- a/packages/wrangler/src/dev.ts +++ b/packages/wrangler/src/dev.ts @@ -1020,7 +1020,12 @@ export function getBindings( process.env[ `WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_${hyperdrive.binding}` ]; - if (!connectionStringFromEnv && !hyperdrive.localConnectionString) { + // only require a local connection string in the wrangler file or the env if not using dev --remote + if ( + local && + !connectionStringFromEnv && + !hyperdrive.localConnectionString + ) { throw new UserError( `When developing locally, you should use a local Postgres connection string to emulate Hyperdrive functionality. Please setup Postgres locally and set the value of the 'WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_${hyperdrive.binding}' variable or "${hyperdrive.binding}"'s "localConnectionString" to the Postgres connection string.` ); diff --git a/packages/wrangler/turbo.json b/packages/wrangler/turbo.json index 4647f496f2e3..b4c4fc471697 100644 --- a/packages/wrangler/turbo.json +++ b/packages/wrangler/turbo.json @@ -59,7 +59,8 @@ "WRANGLER_DISABLE_EXPERIMENTAL_WARNING", "WRANGLER_DISABLE_REQUEST_BODY_DRAINING", "WRANGLER_WORKER_REGISTRY_PORT", - "WRANGLER_API_ENVIRONMENT" + "WRANGLER_API_ENVIRONMENT", + "HYPERDRIVE_DATABASE_URL" ] }, "test:ci": {