Skip to content

Commit 45eba66

Browse files
fix: add warning about wrangler dev with remote Durable Objects
Durable Objects that are being bound by `script_name` will not be isolated from the live data during development with `wrangler dev`. This change simply warns the developer about this, so that they can back out before accidentally changing live data. Fixes #319
1 parent 62a89c6 commit 45eba66

File tree

3 files changed

+111
-10
lines changed

3 files changed

+111
-10
lines changed

.changeset/four-bags-admire.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
"wrangler": patch
3+
---
4+
5+
fix: add warning about `wrangler dev` with remote Durable Objects
6+
7+
Durable Objects that are being bound by `script_name` will not be isolated from the
8+
live data during development with `wrangler dev`.
9+
This change simply warns the developer about this, so that they can back out before
10+
accidentally changing live data.
11+
12+
Fixes #319

packages/wrangler/src/__tests__/dev.test.tsx

+67-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { runInTempDir } from "./helpers/run-in-tmp";
99
import { runWrangler } from "./helpers/run-wrangler";
1010
import writeWranglerToml from "./helpers/write-wrangler-toml";
1111

12-
describe("Dev component", () => {
12+
describe("wrangler dev", () => {
1313
mockAccountId();
1414
mockApiToken();
1515
runInTempDir();
@@ -480,6 +480,72 @@ describe("Dev component", () => {
480480
expect(std.err).toMatchInlineSnapshot(`""`);
481481
});
482482
});
483+
484+
describe("durable_objects", () => {
485+
it("should warn if there is one or more remote Durable Object", async () => {
486+
writeWranglerToml({
487+
main: "index.js",
488+
durable_objects: {
489+
bindings: [
490+
{ name: "NAME_1", class_name: "CLASS_1" },
491+
{
492+
name: "NAME_2",
493+
class_name: "CLASS_2",
494+
script_name: "SCRIPT_A",
495+
},
496+
{ name: "NAME_3", class_name: "CLASS_3" },
497+
{
498+
name: "NAME_4",
499+
class_name: "CLASS_4",
500+
script_name: "SCRIPT_B",
501+
},
502+
],
503+
},
504+
});
505+
fs.writeFileSync("index.js", `export default {};`);
506+
await runWrangler("dev");
507+
expect((Dev as jest.Mock).mock.calls[0][0].ip).toEqual("localhost");
508+
expect(std.out).toMatchInlineSnapshot(`""`);
509+
expect(std.warn).toMatchInlineSnapshot(`
510+
"WARNING: You have Durable Object bindings, which are not defined locally in the worker being developed.
511+
Be aware that changes to the data stored in these Durable Objects will be permanent and affect the live instances.
512+
Remote Durable Objects that are affected:
513+
- {\\"name\\":\\"NAME_2\\",\\"class_name\\":\\"CLASS_2\\",\\"script_name\\":\\"SCRIPT_A\\"}
514+
- {\\"name\\":\\"NAME_4\\",\\"class_name\\":\\"CLASS_4\\",\\"script_name\\":\\"SCRIPT_B\\"}"
515+
`);
516+
expect(std.err).toMatchInlineSnapshot(`""`);
517+
});
518+
519+
it("should use to `ip` from `wrangler.toml`, if available", async () => {
520+
writeWranglerToml({
521+
main: "index.js",
522+
dev: {
523+
ip: "0.0.0.0",
524+
},
525+
});
526+
fs.writeFileSync("index.js", `export default {};`);
527+
await runWrangler("dev");
528+
expect((Dev as jest.Mock).mock.calls[0][0].ip).toEqual("0.0.0.0");
529+
expect(std.out).toMatchInlineSnapshot(`""`);
530+
expect(std.warn).toMatchInlineSnapshot(`""`);
531+
expect(std.err).toMatchInlineSnapshot(`""`);
532+
});
533+
534+
it("should use --ip command line arg, if provided", async () => {
535+
writeWranglerToml({
536+
main: "index.js",
537+
dev: {
538+
ip: "1.1.1.1",
539+
},
540+
});
541+
fs.writeFileSync("index.js", `export default {};`);
542+
await runWrangler("dev --ip=0.0.0.0");
543+
expect((Dev as jest.Mock).mock.calls[0][0].ip).toEqual("0.0.0.0");
544+
expect(std.out).toMatchInlineSnapshot(`""`);
545+
expect(std.warn).toMatchInlineSnapshot(`""`);
546+
expect(std.err).toMatchInlineSnapshot(`""`);
547+
});
548+
});
483549
});
484550

485551
function mockGetZones(domain: string, zones: { id: string }[] = []) {

packages/wrangler/src/entry.ts

+32-9
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export type Entry = { file: string; directory: string; format: CfScriptFormat };
2020
export async function getEntry(
2121
args: { script?: string; format?: CfScriptFormat | undefined },
2222
config: Config,
23-
command: string
23+
command: "dev" | "publish"
2424
): Promise<Entry> {
2525
let file: string;
2626
let directory = process.cwd();
@@ -49,7 +49,19 @@ export async function getEntry(
4949
args.format ?? config.build?.upload?.format
5050
);
5151

52-
if (format === "service-worker" && hasDurableObjectImplementations(config)) {
52+
const { localBindings, remoteBindings } =
53+
partitionDurableObjectBindings(config);
54+
55+
if (command === "dev" && remoteBindings.length > 0) {
56+
console.warn(
57+
"WARNING: You have Durable Object bindings, which are not defined locally in the worker being developed.\n" +
58+
"Be aware that changes to the data stored in these Durable Objects will be permanent and affect the live instances.\n" +
59+
"Remote Durable Objects that are affected:\n" +
60+
remoteBindings.map((b) => `- ${JSON.stringify(b)}`).join("\n")
61+
);
62+
}
63+
64+
if (format === "service-worker" && localBindings.length > 0) {
5365
const errorMessage =
5466
"You seem to be trying to use Durable Objects in a Worker written with Service Worker syntax.";
5567
const addScriptName =
@@ -174,15 +186,26 @@ export function fileExists(filePath: string): boolean {
174186
return false;
175187
}
176188

189+
type DurableObjectBindings = Config["durable_objects"]["bindings"];
190+
177191
/**
178-
* Returns true if the given config contains Durable Object bindings that are implemented
179-
* in this worker instead of being implemented elsewhere, and bound via a `script_name`
180-
* property in wrangler.toml
192+
* Groups the durable object bindings into two lists:
193+
* those that are defined locally and those that refer to a durable object defined in another script.
181194
*/
182-
function hasDurableObjectImplementations(config: Config): boolean {
183-
return config.durable_objects.bindings.some(
184-
(binding) => binding.script_name === undefined
185-
);
195+
function partitionDurableObjectBindings(config: Config): {
196+
localBindings: DurableObjectBindings;
197+
remoteBindings: DurableObjectBindings;
198+
} {
199+
const localBindings: DurableObjectBindings = [];
200+
const remoteBindings: DurableObjectBindings = [];
201+
for (const binding of config.durable_objects.bindings) {
202+
if (binding.script_name === undefined) {
203+
localBindings.push(binding);
204+
} else {
205+
remoteBindings.push(binding);
206+
}
207+
}
208+
return { localBindings, remoteBindings };
186209
}
187210

188211
/**

0 commit comments

Comments
 (0)