Skip to content

Commit f6f1a18

Browse files
add remote option to initial bindings (#9183)
* add `remote` option to initial bindings * remove incorrect comment * make sure that service bindings also support remote * update pages-dev test snapshot * update service bindings messaging * remove incorrect `+`
1 parent 63a6504 commit f6f1a18

File tree

9 files changed

+328
-30
lines changed

9 files changed

+328
-30
lines changed

.changeset/orange-ads-judge.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"wrangler": patch
3+
---
4+
5+
add `remote` option to initial bindings
6+
7+
add the `remote` option (initial implementation
8+
gated behind `--x-mixed-mode`) for the following
9+
bindings: `service`, `kv`, `r2`, `d1`, `queue` and `workflow`

packages/wrangler/src/__tests__/config/configuration.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6273,6 +6273,82 @@ describe("normalizeAndValidateConfig()", () => {
62736273
});
62746274
});
62756275
});
6276+
6277+
describe("mixed mode", () => {
6278+
it("should ignore remote configs when specified without MIXED_MODE enabled", () => {
6279+
const rawConfig: RawConfig = {
6280+
name: "my-worker",
6281+
kv_namespaces: [
6282+
{
6283+
binding: "KV",
6284+
id: "xxxx-xxxx-xxxx-xxxx",
6285+
remote: true,
6286+
},
6287+
],
6288+
r2_buckets: [
6289+
{
6290+
binding: "R2",
6291+
bucket_name: "my-r2",
6292+
remote: 5 as unknown as boolean,
6293+
},
6294+
],
6295+
};
6296+
const { diagnostics } = run(
6297+
{
6298+
RESOURCES_PROVISION: false,
6299+
MULTIWORKER: false,
6300+
MIXED_MODE: false,
6301+
},
6302+
() =>
6303+
normalizeAndValidateConfig(rawConfig, undefined, undefined, {
6304+
env: undefined,
6305+
})
6306+
);
6307+
6308+
expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
6309+
"Processing wrangler configuration:
6310+
- Unexpected fields found in kv_namespaces[0] field: \\"remote\\"
6311+
- Unexpected fields found in r2_buckets[0] field: \\"remote\\""
6312+
`);
6313+
});
6314+
6315+
it("should error on non boolean remote values", () => {
6316+
const rawConfig: RawConfig = {
6317+
name: "my-worker",
6318+
kv_namespaces: [
6319+
{
6320+
binding: "KV",
6321+
id: "xxxx-xxxx-xxxx-xxxx",
6322+
remote: "hello" as unknown as boolean,
6323+
},
6324+
],
6325+
r2_buckets: [
6326+
{
6327+
binding: "R2",
6328+
bucket_name: "my-r2",
6329+
remote: 5 as unknown as boolean,
6330+
},
6331+
],
6332+
};
6333+
const { diagnostics } = run(
6334+
{
6335+
RESOURCES_PROVISION: false,
6336+
MULTIWORKER: false,
6337+
MIXED_MODE: true,
6338+
},
6339+
() =>
6340+
normalizeAndValidateConfig(rawConfig, undefined, undefined, {
6341+
env: undefined,
6342+
})
6343+
);
6344+
6345+
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
6346+
"Processing wrangler configuration:
6347+
- \\"kv_namespaces[0]\\" should, optionally, have a boolean \\"remote\\" field but got {\\"binding\\":\\"KV\\",\\"id\\":\\"xxxx-xxxx-xxxx-xxxx\\",\\"remote\\":\\"hello\\"}.
6348+
- \\"r2_buckets[0]\\" should, optionally, have a boolean \\"remote\\" field but got {\\"binding\\":\\"R2\\",\\"bucket_name\\":\\"my-r2\\",\\"remote\\":5}."
6349+
`);
6350+
});
6351+
});
62766352
});
62776353

62786354
describe("experimental_readRawConfig()", () => {

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

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,6 +1676,109 @@ describe.sequential("wrangler dev", () => {
16761676
`
16771677
);
16781678
});
1679+
1680+
describe("mixed mode", () => {
1681+
const wranglerConfigWithRemoteBindings = {
1682+
services: [{ binding: "WorkerA", service: "A", remote: true }],
1683+
kv_namespaces: [
1684+
{
1685+
binding: "KV",
1686+
id: "xxxx-xxxx-xxxx-xxxx",
1687+
remote: true,
1688+
},
1689+
],
1690+
r2_buckets: [
1691+
{
1692+
binding: "MY_R2",
1693+
bucket_name: "my-bucket",
1694+
remote: true,
1695+
},
1696+
],
1697+
queues: {
1698+
producers: [
1699+
{
1700+
binding: "MY_QUEUE_PRODUCES",
1701+
queue: "my-queue",
1702+
remote: true,
1703+
},
1704+
],
1705+
},
1706+
d1_databases: [
1707+
{
1708+
binding: "MY_D1",
1709+
database_id: "xxx",
1710+
remote: true,
1711+
},
1712+
],
1713+
workflows: [
1714+
{
1715+
binding: "MY_WORKFLOW",
1716+
name: "workflow-name",
1717+
class_name: "myClass",
1718+
remote: true,
1719+
},
1720+
],
1721+
};
1722+
1723+
it("should ignore remote true settings without the --x-mixed-mode flag (initial logs only test)", async () => {
1724+
writeWranglerConfig(wranglerConfigWithRemoteBindings);
1725+
fs.writeFileSync("index.js", `export default {};`);
1726+
await runWranglerUntilConfig("dev index.js");
1727+
expect(std.out).toMatchInlineSnapshot(`
1728+
"Your Worker and resources are simulated locally via Miniflare. For more information, see: https://developers.cloudflare.com/workers/testing/local-development.
1729+
1730+
Your Worker has access to the following bindings:
1731+
- Workflows:
1732+
- MY_WORKFLOW: myClass [simulated locally]
1733+
- KV Namespaces:
1734+
- KV: xxxx-xxxx-xxxx-xxxx [simulated locally]
1735+
- Queues:
1736+
- MY_QUEUE_PRODUCES: my-queue [simulated locally]
1737+
- D1 Databases:
1738+
- MY_D1: xxx [simulated locally]
1739+
- R2 Buckets:
1740+
- MY_R2: my-bucket [simulated locally]
1741+
- Services:
1742+
- WorkerA: A [not connected]
1743+
"
1744+
`);
1745+
expect(std.warn).toMatchInlineSnapshot(`
1746+
"▲ [WARNING] Processing wrangler.toml configuration:
1747+
1748+
- Unexpected fields found in kv_namespaces[0] field: \\"remote\\"
1749+
- Unexpected fields found in queues.producers[0] field: \\"remote\\"
1750+
- Unexpected fields found in r2_buckets[0] field: \\"remote\\"
1751+
- Unexpected fields found in d1_databases[0] field: \\"remote\\"
1752+
1753+
"
1754+
`);
1755+
});
1756+
1757+
it("should honor the remote true settings with the --x-mixed-mode flag (initial logs only test)", async () => {
1758+
writeWranglerConfig(wranglerConfigWithRemoteBindings);
1759+
fs.writeFileSync("index.js", `export default {};`);
1760+
await runWranglerUntilConfig("dev --x-mixed-mode index.js");
1761+
expect(std.out).toMatchInlineSnapshot(`
1762+
"Your Worker and resources are simulated locally via Miniflare. For more information, see: https://developers.cloudflare.com/workers/testing/local-development.
1763+
1764+
Your Worker has access to the following bindings:
1765+
- Workflows:
1766+
- MY_WORKFLOW: myClass [connected to remote resource]
1767+
- KV Namespaces:
1768+
- KV: xxxx-xxxx-xxxx-xxxx [connected to remote resource]
1769+
- Queues:
1770+
- MY_QUEUE_PRODUCES: my-queue [connected to remote resource]
1771+
- D1 Databases:
1772+
- MY_D1: xxx [connected to remote resource]
1773+
- R2 Buckets:
1774+
- MY_R2: my-bucket [connected to remote resource]
1775+
- Services:
1776+
- WorkerA: A [connected to remote resource]
1777+
"
1778+
`);
1779+
expect(std.warn).toMatchInlineSnapshot(`""`);
1780+
});
1781+
});
16791782
});
16801783

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

packages/wrangler/src/api/dev.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export interface Unstable_DevOptions {
3434
binding: string;
3535
id?: string;
3636
preview_id?: string;
37+
remote?: boolean;
3738
}[];
3839
durableObjects?: {
3940
name: string;
@@ -46,11 +47,13 @@ export interface Unstable_DevOptions {
4647
service: string;
4748
environment?: string | undefined;
4849
entrypoint?: string | undefined;
50+
remote?: boolean;
4951
}[];
5052
r2?: {
5153
binding: string;
5254
bucket_name?: string;
5355
preview_bucket_name?: string;
56+
remote?: boolean;
5457
}[];
5558
ai?: {
5659
binding: string;

packages/wrangler/src/config/environment.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,8 @@ export type WorkflowBinding = {
426426
class_name: string;
427427
/** The script where the Workflow is defined (if it's external to this Worker) */
428428
script_name?: string;
429+
/** Whether the Workflow should be remote or not (only available under `--x-mixed-mode`) */
430+
remote?: boolean;
429431
};
430432

431433
/**
@@ -523,6 +525,8 @@ export interface EnvironmentNonInheritable {
523525
id?: string;
524526
/** The ID of the KV namespace used during `wrangler dev` */
525527
preview_id?: string;
528+
/** Whether the KV namespace should be remote or not (only available under `--x-mixed-mode`) */
529+
remote?: boolean;
526530
}[];
527531

528532
/**
@@ -563,6 +567,9 @@ export interface EnvironmentNonInheritable {
563567

564568
/** The number of seconds to wait before delivering a message */
565569
delivery_delay?: number;
570+
571+
/** Whether the Queue producer should be remote or not (only available under `--x-mixed-mode`) */
572+
remote?: boolean;
566573
}[];
567574

568575
/** Consumer configuration */
@@ -614,6 +621,8 @@ export interface EnvironmentNonInheritable {
614621
preview_bucket_name?: string;
615622
/** The jurisdiction that the bucket exists in. Default if not present. */
616623
jurisdiction?: string;
624+
/** Whether the R2 bucket should be remote or not (only available under `--x-mixed-mode`) */
625+
remote?: boolean;
617626
}[];
618627

619628
/**
@@ -640,6 +649,8 @@ export interface EnvironmentNonInheritable {
640649
migrations_dir?: string;
641650
/** Internal use only. */
642651
database_internal_env?: string;
652+
/** Whether the D1 database should be remote or not (only available under `--x-mixed-mode`) */
653+
remote?: boolean;
643654
}[];
644655

645656
/**
@@ -697,6 +708,8 @@ export interface EnvironmentNonInheritable {
697708
entrypoint?: string;
698709
/** Optional properties that will be made available to the service via ctx.props. */
699710
props?: Record<string, unknown>;
711+
/** Whether the service binding should be remote or not (only available under `--x-mixed-mode`) */
712+
remote?: boolean;
700713
}[]
701714
| undefined;
702715

packages/wrangler/src/config/validation.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,6 +1891,10 @@ const validateDurableObjectBinding: ValidatorFn = (
18911891
isValid = false;
18921892
}
18931893

1894+
if (!isRemoteValid(value, field, diagnostics)) {
1895+
isValid = false;
1896+
}
1897+
18941898
validateAdditionalProperties(diagnostics, field, Object.keys(value), [
18951899
"class_name",
18961900
"environment",
@@ -2405,11 +2409,15 @@ const validateKVBinding: ValidatorFn = (diagnostics, field, value) => {
24052409
);
24062410
isValid = false;
24072411
}
2412+
if (!isRemoteValid(value, field, diagnostics)) {
2413+
isValid = false;
2414+
}
24082415

24092416
validateAdditionalProperties(diagnostics, field, Object.keys(value), [
24102417
"binding",
24112418
"id",
24122419
"preview_id",
2420+
...(getFlag("MIXED_MODE") ? ["remote"] : []),
24132421
]);
24142422

24152423
return isValid;
@@ -2483,6 +2491,7 @@ const validateQueueBinding: ValidatorFn = (diagnostics, field, value) => {
24832491
"binding",
24842492
"queue",
24852493
"delivery_delay",
2494+
...(getFlag("MIXED_MODE") ? ["remote"] : []),
24862495
])
24872496
) {
24882497
return false;
@@ -2526,6 +2535,10 @@ const validateQueueBinding: ValidatorFn = (diagnostics, field, value) => {
25262535
}
25272536
}
25282537

2538+
if (!isRemoteValid(value, field, diagnostics)) {
2539+
isValid = false;
2540+
}
2541+
25292542
return isValid;
25302543
};
25312544

@@ -2601,11 +2614,16 @@ const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
26012614
isValid = false;
26022615
}
26032616

2617+
if (!isRemoteValid(value, field, diagnostics)) {
2618+
isValid = false;
2619+
}
2620+
26042621
validateAdditionalProperties(diagnostics, field, Object.keys(value), [
26052622
"binding",
26062623
"bucket_name",
26072624
"preview_bucket_name",
26082625
"jurisdiction",
2626+
...(getFlag("MIXED_MODE") ? ["remote"] : []),
26092627
]);
26102628

26112629
return isValid;
@@ -2654,6 +2672,10 @@ const validateD1Binding: ValidatorFn = (diagnostics, field, value) => {
26542672
isValid = false;
26552673
}
26562674

2675+
if (!isRemoteValid(value, field, diagnostics)) {
2676+
isValid = false;
2677+
}
2678+
26572679
validateAdditionalProperties(diagnostics, field, Object.keys(value), [
26582680
"binding",
26592681
"database_id",
@@ -2662,6 +2684,7 @@ const validateD1Binding: ValidatorFn = (diagnostics, field, value) => {
26622684
"migrations_dir",
26632685
"migrations_table",
26642686
"preview_database_id",
2687+
...(getFlag("MIXED_MODE") ? ["remote"] : []),
26652688
]);
26662689

26672690
return isValid;
@@ -2879,6 +2902,9 @@ const validateServiceBinding: ValidatorFn = (diagnostics, field, value) => {
28792902
);
28802903
isValid = false;
28812904
}
2905+
if (!isRemoteValid(value, field, diagnostics)) {
2906+
isValid = false;
2907+
}
28822908
return isValid;
28832909
};
28842910

@@ -3566,3 +3592,26 @@ function warnIfDurableObjectsHaveNoMigrations(
35663592
}
35673593
}
35683594
}
3595+
3596+
function isRemoteValid(
3597+
targetObject: object,
3598+
fieldPath: string,
3599+
diagnostics: Diagnostics
3600+
) {
3601+
if (!getFlag("MIXED_MODE")) {
3602+
// the remote config only applies to mixed mode, if mixed mode
3603+
// is not enabled just return true and skip this validation
3604+
return true;
3605+
}
3606+
3607+
if (!isOptionalProperty(targetObject, "remote", "boolean")) {
3608+
diagnostics.errors.push(
3609+
`"${fieldPath}" should, optionally, have a boolean "remote" field but got ${JSON.stringify(
3610+
targetObject
3611+
)}.`
3612+
);
3613+
return false;
3614+
}
3615+
3616+
return true;
3617+
}

0 commit comments

Comments
 (0)