wrangler 2.0.5 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/__tests__/configuration.test.ts +204 -27
- package/src/__tests__/dev.test.tsx +60 -7
- package/src/__tests__/index.test.ts +5 -6
- package/src/__tests__/kv.test.ts +85 -85
- package/src/__tests__/pages.test.ts +28 -5
- package/src/__tests__/publish.test.ts +306 -7
- package/src/__tests__/r2.test.ts +47 -24
- package/src/__tests__/secret.test.ts +35 -0
- package/src/bundle.ts +32 -1
- package/src/config/environment.ts +40 -14
- package/src/config/validation.ts +102 -35
- package/src/create-worker-upload-form.ts +22 -8
- package/src/dev/local.tsx +6 -0
- package/src/index.tsx +45 -20
- package/src/kv.ts +18 -3
- package/src/pages.tsx +3 -4
- package/src/publish.ts +210 -21
- package/src/sites.tsx +3 -1
- package/src/worker.ts +8 -0
- package/wrangler-dist/cli.js +432 -234
|
@@ -8,6 +8,24 @@ export interface Environment
|
|
|
8
8
|
extends EnvironmentInheritable,
|
|
9
9
|
EnvironmentNonInheritable {}
|
|
10
10
|
|
|
11
|
+
export type SimpleRoute = string;
|
|
12
|
+
export type ZoneIdRoute = {
|
|
13
|
+
pattern: string;
|
|
14
|
+
zone_id: string;
|
|
15
|
+
custom_domain?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export type ZoneNameRoute = {
|
|
18
|
+
pattern: string;
|
|
19
|
+
zone_name: string;
|
|
20
|
+
custom_domain?: boolean;
|
|
21
|
+
};
|
|
22
|
+
export type CustomDomainRoute = { pattern: string; custom_domain: boolean };
|
|
23
|
+
export type Route =
|
|
24
|
+
| SimpleRoute
|
|
25
|
+
| ZoneIdRoute
|
|
26
|
+
| ZoneNameRoute
|
|
27
|
+
| CustomDomainRoute;
|
|
28
|
+
|
|
11
29
|
/**
|
|
12
30
|
* The `EnvironmentInheritable` interface declares all the configuration fields for an environment
|
|
13
31
|
* that can be inherited (and overridden) from the top-level environment.
|
|
@@ -74,13 +92,7 @@ interface EnvironmentInheritable {
|
|
|
74
92
|
*
|
|
75
93
|
* @inheritable
|
|
76
94
|
*/
|
|
77
|
-
routes:
|
|
78
|
-
| (
|
|
79
|
-
| string
|
|
80
|
-
| { pattern: string; zone_id: string }
|
|
81
|
-
| { pattern: string; zone_name: string }
|
|
82
|
-
)[]
|
|
83
|
-
| undefined;
|
|
95
|
+
routes: Route[] | undefined;
|
|
84
96
|
|
|
85
97
|
/**
|
|
86
98
|
* A route that your worker should be published to. Literally
|
|
@@ -91,13 +103,7 @@ interface EnvironmentInheritable {
|
|
|
91
103
|
*
|
|
92
104
|
* @inheritable
|
|
93
105
|
*/
|
|
94
|
-
route:
|
|
95
|
-
| (
|
|
96
|
-
| string
|
|
97
|
-
| { pattern: string; zone_id: string }
|
|
98
|
-
| { pattern: string; zone_name: string }
|
|
99
|
-
)
|
|
100
|
-
| undefined;
|
|
106
|
+
route: Route | undefined;
|
|
101
107
|
|
|
102
108
|
/**
|
|
103
109
|
* Path to a custom tsconfig
|
|
@@ -236,6 +242,8 @@ interface EnvironmentNonInheritable {
|
|
|
236
242
|
class_name: string;
|
|
237
243
|
/** The script where the Durable Object is defined (if it's external to this worker) */
|
|
238
244
|
script_name?: string;
|
|
245
|
+
/** The service environment of the script_name to bind to */
|
|
246
|
+
environment?: string;
|
|
239
247
|
}[];
|
|
240
248
|
};
|
|
241
249
|
|
|
@@ -279,6 +287,24 @@ interface EnvironmentNonInheritable {
|
|
|
279
287
|
preview_bucket_name?: string;
|
|
280
288
|
}[];
|
|
281
289
|
|
|
290
|
+
/**
|
|
291
|
+
* Specifies service bindings (worker-to-worker) that are bound to this Worker environment.
|
|
292
|
+
*
|
|
293
|
+
* NOTE: This field is not automatically inherited from the top level environment,
|
|
294
|
+
* and so must be specified in every named environment.
|
|
295
|
+
*
|
|
296
|
+
* @default `[]`
|
|
297
|
+
* @nonInheritable
|
|
298
|
+
*/
|
|
299
|
+
services: {
|
|
300
|
+
/** The binding name used to refer to the bound service. */
|
|
301
|
+
binding: string;
|
|
302
|
+
/** The name of the service. */
|
|
303
|
+
service: string;
|
|
304
|
+
/** The environment of the service (e.g. production, staging, etc). */
|
|
305
|
+
environment?: string;
|
|
306
|
+
}[];
|
|
307
|
+
|
|
282
308
|
/**
|
|
283
309
|
* "Unsafe" tables for features that aren't directly supported by wrangler.
|
|
284
310
|
*
|
package/src/config/validation.ts
CHANGED
|
@@ -562,19 +562,37 @@ function normalizeAndValidateModulePaths(
|
|
|
562
562
|
* or an object that looks like {pattern: string, zone_id: string }
|
|
563
563
|
*/
|
|
564
564
|
function isValidRouteValue(item: unknown): boolean {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
565
|
+
if (!item) {
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
if (typeof item === "string") {
|
|
569
|
+
return true;
|
|
570
|
+
}
|
|
571
|
+
if (typeof item === "object") {
|
|
572
|
+
if (!hasProperty(item, "pattern") || typeof item.pattern !== "string") {
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const otherKeys = Object.keys(item).length - 1; // minus one to subtract "pattern"
|
|
577
|
+
|
|
578
|
+
const hasZoneId =
|
|
579
|
+
hasProperty(item, "zone_id") && typeof item.zone_id === "string";
|
|
580
|
+
const hasZoneName =
|
|
581
|
+
hasProperty(item, "zone_name") && typeof item.zone_name === "string";
|
|
582
|
+
const hasCustomDomainFlag =
|
|
583
|
+
hasProperty(item, "custom_domain") &&
|
|
584
|
+
typeof item.custom_domain === "boolean";
|
|
585
|
+
|
|
586
|
+
if (otherKeys === 2 && hasCustomDomainFlag && (hasZoneId || hasZoneName)) {
|
|
587
|
+
return true;
|
|
588
|
+
} else if (
|
|
589
|
+
otherKeys === 1 &&
|
|
590
|
+
(hasZoneId || hasZoneName || hasCustomDomainFlag)
|
|
591
|
+
) {
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return false;
|
|
578
596
|
}
|
|
579
597
|
|
|
580
598
|
/**
|
|
@@ -583,7 +601,7 @@ function isValidRouteValue(item: unknown): boolean {
|
|
|
583
601
|
const isRoute: ValidatorFn = (diagnostics, field, value) => {
|
|
584
602
|
if (value !== undefined && !isValidRouteValue(value)) {
|
|
585
603
|
diagnostics.errors.push(
|
|
586
|
-
`Expected "${field}" to be either a string, or an object with shape { pattern, zone_id | zone_name }, but got ${JSON.stringify(
|
|
604
|
+
`Expected "${field}" to be either a string, or an object with shape { pattern, custom_domain, zone_id | zone_name }, but got ${JSON.stringify(
|
|
587
605
|
value
|
|
588
606
|
)}.`
|
|
589
607
|
);
|
|
@@ -613,7 +631,7 @@ const isRouteArray: ValidatorFn = (diagnostics, field, value) => {
|
|
|
613
631
|
}
|
|
614
632
|
if (invalidRoutes.length > 0) {
|
|
615
633
|
diagnostics.errors.push(
|
|
616
|
-
`Expected "${field}" to be an array of either strings or objects with the shape { pattern, zone_id | zone_name }, but these weren't valid: ${JSON.stringify(
|
|
634
|
+
`Expected "${field}" to be an array of either strings or objects with the shape { pattern, custom_domain, zone_id | zone_name }, but these weren't valid: ${JSON.stringify(
|
|
617
635
|
invalidRoutes,
|
|
618
636
|
null,
|
|
619
637
|
2
|
|
@@ -696,27 +714,12 @@ function normalizeAndValidateEnvironment(
|
|
|
696
714
|
diagnostics,
|
|
697
715
|
rawEnv,
|
|
698
716
|
"experimental_services",
|
|
699
|
-
`The "experimental_services" field is no longer supported.
|
|
700
|
-
"```\n" +
|
|
701
|
-
TOML.stringify({
|
|
702
|
-
unsafe: {
|
|
703
|
-
bindings: (rawEnv?.experimental_services || []).map(
|
|
704
|
-
(serviceDefinition) => {
|
|
705
|
-
return {
|
|
706
|
-
name: serviceDefinition.name,
|
|
707
|
-
type: "service",
|
|
708
|
-
service: serviceDefinition.service,
|
|
709
|
-
environment: serviceDefinition.environment,
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
),
|
|
713
|
-
},
|
|
714
|
-
}) +
|
|
715
|
-
"```",
|
|
717
|
+
`The "experimental_services" field is no longer supported. Simply rename the [experimental_services] field to [services].`,
|
|
716
718
|
true
|
|
717
719
|
);
|
|
718
720
|
|
|
719
721
|
experimental(diagnostics, rawEnv, "unsafe");
|
|
722
|
+
experimental(diagnostics, rawEnv, "services");
|
|
720
723
|
|
|
721
724
|
const route = validateRoute(diagnostics, topLevelEnv, rawEnv);
|
|
722
725
|
|
|
@@ -880,6 +883,16 @@ function normalizeAndValidateEnvironment(
|
|
|
880
883
|
validateBindingArray(envName, validateR2Binding),
|
|
881
884
|
[]
|
|
882
885
|
),
|
|
886
|
+
services: notInheritable(
|
|
887
|
+
diagnostics,
|
|
888
|
+
topLevelEnv,
|
|
889
|
+
rawConfig,
|
|
890
|
+
rawEnv,
|
|
891
|
+
envName,
|
|
892
|
+
"services",
|
|
893
|
+
validateBindingArray(envName, validateServiceBinding),
|
|
894
|
+
[]
|
|
895
|
+
),
|
|
883
896
|
unsafe: notInheritable(
|
|
884
897
|
diagnostics,
|
|
885
898
|
topLevelEnv,
|
|
@@ -1014,7 +1027,7 @@ const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
|
1014
1027
|
|
|
1015
1028
|
if (!isOptionalProperty(rule, "fallthrough", "boolean")) {
|
|
1016
1029
|
diagnostics.errors.push(
|
|
1017
|
-
`
|
|
1030
|
+
`the field "fallthrough", when present, should be a boolean.`
|
|
1018
1031
|
);
|
|
1019
1032
|
isValid = false;
|
|
1020
1033
|
}
|
|
@@ -1135,7 +1148,7 @@ const validateDurableObjectBinding: ValidatorFn = (
|
|
|
1135
1148
|
return false;
|
|
1136
1149
|
}
|
|
1137
1150
|
|
|
1138
|
-
// Durable Object bindings must have a name and class_name, and optionally a script_name.
|
|
1151
|
+
// Durable Object bindings must have a name and class_name, and optionally a script_name and an environment.
|
|
1139
1152
|
let isValid = true;
|
|
1140
1153
|
if (!isRequiredProperty(value, "name", "string")) {
|
|
1141
1154
|
diagnostics.errors.push(`binding should have a string "name" field.`);
|
|
@@ -1147,7 +1160,21 @@ const validateDurableObjectBinding: ValidatorFn = (
|
|
|
1147
1160
|
}
|
|
1148
1161
|
if (!isOptionalProperty(value, "script_name", "string")) {
|
|
1149
1162
|
diagnostics.errors.push(
|
|
1150
|
-
`
|
|
1163
|
+
`the field "script_name", when present, should be a string.`
|
|
1164
|
+
);
|
|
1165
|
+
isValid = false;
|
|
1166
|
+
}
|
|
1167
|
+
// environment requires a script_name
|
|
1168
|
+
if (!isOptionalProperty(value, "environment", "string")) {
|
|
1169
|
+
diagnostics.errors.push(
|
|
1170
|
+
`the field "environment", when present, should be a string.`
|
|
1171
|
+
);
|
|
1172
|
+
isValid = false;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
if ("environment" in value && !("script_name" in value)) {
|
|
1176
|
+
diagnostics.errors.push(
|
|
1177
|
+
`binding should have a "script_name" field if "environment" is present.`
|
|
1151
1178
|
);
|
|
1152
1179
|
isValid = false;
|
|
1153
1180
|
}
|
|
@@ -1178,8 +1205,13 @@ const validateUnsafeBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
1178
1205
|
const safeBindings = [
|
|
1179
1206
|
"plain_text",
|
|
1180
1207
|
"json",
|
|
1208
|
+
"wasm_module",
|
|
1209
|
+
"data_blob",
|
|
1210
|
+
"text_blob",
|
|
1181
1211
|
"kv_namespace",
|
|
1182
1212
|
"durable_object_namespace",
|
|
1213
|
+
"r2_bucket",
|
|
1214
|
+
"service",
|
|
1183
1215
|
];
|
|
1184
1216
|
|
|
1185
1217
|
if (safeBindings.includes(value.type)) {
|
|
@@ -1422,3 +1454,38 @@ const validateBindingsHaveUniqueNames = (
|
|
|
1422
1454
|
|
|
1423
1455
|
return !hasDuplicates;
|
|
1424
1456
|
};
|
|
1457
|
+
const validateServiceBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
1458
|
+
if (typeof value !== "object" || value === null) {
|
|
1459
|
+
diagnostics.errors.push(
|
|
1460
|
+
`"services" bindings should be objects, but got ${JSON.stringify(value)}`
|
|
1461
|
+
);
|
|
1462
|
+
return false;
|
|
1463
|
+
}
|
|
1464
|
+
let isValid = true;
|
|
1465
|
+
// Service bindings must have a binding, service, and environment.
|
|
1466
|
+
if (!isRequiredProperty(value, "binding", "string")) {
|
|
1467
|
+
diagnostics.errors.push(
|
|
1468
|
+
`"${field}" bindings should have a string "binding" field but got ${JSON.stringify(
|
|
1469
|
+
value
|
|
1470
|
+
)}.`
|
|
1471
|
+
);
|
|
1472
|
+
isValid = false;
|
|
1473
|
+
}
|
|
1474
|
+
if (!isRequiredProperty(value, "service", "string")) {
|
|
1475
|
+
diagnostics.errors.push(
|
|
1476
|
+
`"${field}" bindings should have a string "service" field but got ${JSON.stringify(
|
|
1477
|
+
value
|
|
1478
|
+
)}.`
|
|
1479
|
+
);
|
|
1480
|
+
isValid = false;
|
|
1481
|
+
}
|
|
1482
|
+
if (!isOptionalProperty(value, "environment", "string")) {
|
|
1483
|
+
diagnostics.errors.push(
|
|
1484
|
+
`"${field}" bindings should have a string "environment" field but got ${JSON.stringify(
|
|
1485
|
+
value
|
|
1486
|
+
)}.`
|
|
1487
|
+
);
|
|
1488
|
+
isValid = false;
|
|
1489
|
+
}
|
|
1490
|
+
return isValid;
|
|
1491
|
+
};
|
|
@@ -32,20 +32,24 @@ export interface WorkerMetadata {
|
|
|
32
32
|
compatibility_flags?: string[];
|
|
33
33
|
usage_model?: "bundled" | "unbound";
|
|
34
34
|
migrations?: CfDurableObjectMigrations;
|
|
35
|
+
// If you add any new binding types here, also add it to safeBindings
|
|
36
|
+
// under validateUnsafeBinding in config/validation.ts
|
|
35
37
|
bindings: (
|
|
36
|
-
| { type: "kv_namespace"; name: string; namespace_id: string }
|
|
37
38
|
| { type: "plain_text"; name: string; text: string }
|
|
38
39
|
| { type: "json"; name: string; json: unknown }
|
|
39
40
|
| { type: "wasm_module"; name: string; part: string }
|
|
40
41
|
| { type: "text_blob"; name: string; part: string }
|
|
41
42
|
| { type: "data_blob"; name: string; part: string }
|
|
43
|
+
| { type: "kv_namespace"; name: string; namespace_id: string }
|
|
42
44
|
| {
|
|
43
45
|
type: "durable_object_namespace";
|
|
44
46
|
name: string;
|
|
45
47
|
class_name: string;
|
|
46
48
|
script_name?: string;
|
|
49
|
+
environment?: string;
|
|
47
50
|
}
|
|
48
51
|
| { type: "r2_bucket"; name: string; bucket_name: string }
|
|
52
|
+
| { type: "service"; name: string; service: string; environment?: string }
|
|
49
53
|
)[];
|
|
50
54
|
}
|
|
51
55
|
|
|
@@ -67,6 +71,14 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
|
|
|
67
71
|
|
|
68
72
|
const metadataBindings: WorkerMetadata["bindings"] = [];
|
|
69
73
|
|
|
74
|
+
Object.entries(bindings.vars || {})?.forEach(([key, value]) => {
|
|
75
|
+
if (typeof value === "string") {
|
|
76
|
+
metadataBindings.push({ name: key, type: "plain_text", text: value });
|
|
77
|
+
} else {
|
|
78
|
+
metadataBindings.push({ name: key, type: "json", json: value });
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
70
82
|
bindings.kv_namespaces?.forEach(({ id, binding }) => {
|
|
71
83
|
metadataBindings.push({
|
|
72
84
|
name: binding,
|
|
@@ -76,12 +88,13 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
|
|
|
76
88
|
});
|
|
77
89
|
|
|
78
90
|
bindings.durable_objects?.bindings.forEach(
|
|
79
|
-
({ name, class_name, script_name }) => {
|
|
91
|
+
({ name, class_name, script_name, environment }) => {
|
|
80
92
|
metadataBindings.push({
|
|
81
93
|
name,
|
|
82
94
|
type: "durable_object_namespace",
|
|
83
95
|
class_name: class_name,
|
|
84
96
|
...(script_name && { script_name }),
|
|
97
|
+
...(environment && { environment }),
|
|
85
98
|
});
|
|
86
99
|
}
|
|
87
100
|
);
|
|
@@ -94,12 +107,13 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
|
|
|
94
107
|
});
|
|
95
108
|
});
|
|
96
109
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
bindings.services?.forEach(({ binding, service, environment }) => {
|
|
111
|
+
metadataBindings.push({
|
|
112
|
+
name: binding,
|
|
113
|
+
type: "service",
|
|
114
|
+
service,
|
|
115
|
+
...(environment && { environment }),
|
|
116
|
+
});
|
|
103
117
|
});
|
|
104
118
|
|
|
105
119
|
for (const [name, filePath] of Object.entries(bindings.wasm_modules || {})) {
|
package/src/dev/local.tsx
CHANGED
|
@@ -87,6 +87,11 @@ function useLocalWorker({
|
|
|
87
87
|
'⎔ A "public" folder is not yet supported in local mode.'
|
|
88
88
|
);
|
|
89
89
|
}
|
|
90
|
+
if (bindings.services && bindings.services.length > 0) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
"⎔ Service bindings are not yet supported in local mode."
|
|
93
|
+
);
|
|
94
|
+
}
|
|
90
95
|
|
|
91
96
|
// In local mode, we want to copy all referenced modules into
|
|
92
97
|
// the output bundle directory before starting up
|
|
@@ -297,6 +302,7 @@ function useLocalWorker({
|
|
|
297
302
|
bindings.durable_objects?.bindings,
|
|
298
303
|
bindings.kv_namespaces,
|
|
299
304
|
bindings.vars,
|
|
305
|
+
bindings.services,
|
|
300
306
|
compatibilityDate,
|
|
301
307
|
compatibilityFlags,
|
|
302
308
|
localPersistencePath,
|
package/src/index.tsx
CHANGED
|
@@ -206,9 +206,17 @@ function demandOneOfOption(...options: string[]) {
|
|
|
206
206
|
};
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Remove trailing white space from inputs.
|
|
211
|
+
* Matching Wrangler legacy behavior with handling inputs
|
|
212
|
+
*/
|
|
213
|
+
function trimTrailingWhitespace(str: string) {
|
|
214
|
+
return str.trimEnd();
|
|
215
|
+
}
|
|
216
|
+
|
|
209
217
|
class CommandLineArgsError extends Error {}
|
|
210
218
|
|
|
211
|
-
|
|
219
|
+
function createCLIParser(argv: string[]) {
|
|
212
220
|
const wrangler = makeCLI(argv)
|
|
213
221
|
.strict()
|
|
214
222
|
// We handle errors ourselves in a try-catch around `yargs.parse`.
|
|
@@ -413,12 +421,7 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
413
421
|
try {
|
|
414
422
|
isGitInstalled = (await execa("git", ["--version"])).exitCode === 0;
|
|
415
423
|
} catch (err) {
|
|
416
|
-
|
|
417
|
-
// only throw if the error is not because git is not installed
|
|
418
|
-
throw err;
|
|
419
|
-
} else {
|
|
420
|
-
isGitInstalled = false;
|
|
421
|
-
}
|
|
424
|
+
isGitInstalled = false;
|
|
422
425
|
}
|
|
423
426
|
if (!isInsideGitProject && isGitInstalled) {
|
|
424
427
|
const shouldInitGit =
|
|
@@ -897,6 +900,19 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
897
900
|
const config = readConfig(configPath, args);
|
|
898
901
|
const entry = await getEntry(args, config, "dev");
|
|
899
902
|
|
|
903
|
+
if (config.services && config.services.length > 0) {
|
|
904
|
+
logger.warn(
|
|
905
|
+
`This worker is bound to live services: ${config.services
|
|
906
|
+
.map(
|
|
907
|
+
(service) =>
|
|
908
|
+
`${service.binding} (${service.service}${
|
|
909
|
+
service.environment ? `@${service.environment}` : ""
|
|
910
|
+
})`
|
|
911
|
+
)
|
|
912
|
+
.join(", ")}`
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
|
|
900
916
|
if (args.inspect) {
|
|
901
917
|
logger.warn(
|
|
902
918
|
"Passing --inspect is unnecessary, now you can always connect to devtools."
|
|
@@ -934,6 +950,9 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
934
950
|
* try to extract a host from it
|
|
935
951
|
*/
|
|
936
952
|
function getHost(urlLike: string): string | undefined {
|
|
953
|
+
// strip leading * / *.
|
|
954
|
+
urlLike = urlLike.replace(/^\*(\.)?/g, "");
|
|
955
|
+
|
|
937
956
|
if (
|
|
938
957
|
!(urlLike.startsWith("http://") || urlLike.startsWith("https://"))
|
|
939
958
|
) {
|
|
@@ -1104,6 +1123,7 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1104
1123
|
};
|
|
1105
1124
|
}
|
|
1106
1125
|
),
|
|
1126
|
+
services: config.services,
|
|
1107
1127
|
unsafe: config.unsafe?.bindings,
|
|
1108
1128
|
}}
|
|
1109
1129
|
crons={config.triggers.crons}
|
|
@@ -1258,7 +1278,7 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1258
1278
|
);
|
|
1259
1279
|
}
|
|
1260
1280
|
|
|
1261
|
-
const accountId = await requireAuth(config);
|
|
1281
|
+
const accountId = args.dryRun ? undefined : await requireAuth(config);
|
|
1262
1282
|
|
|
1263
1283
|
const assetPaths = getAssetPaths(
|
|
1264
1284
|
config,
|
|
@@ -1556,6 +1576,7 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1556
1576
|
};
|
|
1557
1577
|
}
|
|
1558
1578
|
),
|
|
1579
|
+
services: config.services,
|
|
1559
1580
|
unsafe: config.unsafe?.bindings,
|
|
1560
1581
|
}}
|
|
1561
1582
|
crons={config.triggers.crons}
|
|
@@ -1706,9 +1727,11 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1706
1727
|
const accountId = await requireAuth(config);
|
|
1707
1728
|
|
|
1708
1729
|
const isInteractive = process.stdin.isTTY;
|
|
1709
|
-
const secretValue =
|
|
1710
|
-
|
|
1711
|
-
|
|
1730
|
+
const secretValue = trimTrailingWhitespace(
|
|
1731
|
+
isInteractive
|
|
1732
|
+
? await prompt("Enter a secret value:", "password")
|
|
1733
|
+
: await readFromStdin()
|
|
1734
|
+
);
|
|
1712
1735
|
|
|
1713
1736
|
logger.log(
|
|
1714
1737
|
`🌀 Creating the secret for script ${scriptName} ${
|
|
@@ -1753,6 +1776,7 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
1753
1776
|
vars: {},
|
|
1754
1777
|
durable_objects: { bindings: [] },
|
|
1755
1778
|
r2_buckets: [],
|
|
1779
|
+
services: [],
|
|
1756
1780
|
wasm_modules: {},
|
|
1757
1781
|
text_blobs: {},
|
|
1758
1782
|
data_blobs: {},
|
|
@@ -2334,13 +2358,7 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
2334
2358
|
const warnings: string[] = [];
|
|
2335
2359
|
for (let i = 0; i < content.length; i++) {
|
|
2336
2360
|
const keyValue = content[i];
|
|
2337
|
-
if (
|
|
2338
|
-
errors.push(
|
|
2339
|
-
`The item at index ${i} is type: "${typeof keyValue}" - ${JSON.stringify(
|
|
2340
|
-
keyValue
|
|
2341
|
-
)}`
|
|
2342
|
-
);
|
|
2343
|
-
} else if (!isKVKeyValue(keyValue)) {
|
|
2361
|
+
if (!isKVKeyValue(keyValue)) {
|
|
2344
2362
|
errors.push(
|
|
2345
2363
|
`The item at index ${i} is ${JSON.stringify(keyValue)}`
|
|
2346
2364
|
);
|
|
@@ -2647,14 +2665,21 @@ export async function main(argv: string[]): Promise<void> {
|
|
|
2647
2665
|
wrangler.version(wranglerVersion).alias("v", "version");
|
|
2648
2666
|
wrangler.exitProcess(false);
|
|
2649
2667
|
|
|
2668
|
+
return wrangler;
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
export async function main(argv: string[]): Promise<void> {
|
|
2672
|
+
const wrangler = createCLIParser(argv);
|
|
2650
2673
|
try {
|
|
2651
2674
|
await wrangler.parse();
|
|
2652
2675
|
} catch (e) {
|
|
2653
2676
|
logger.log(""); // Just adds a bit of space
|
|
2654
2677
|
if (e instanceof CommandLineArgsError) {
|
|
2655
|
-
wrangler.showHelp("error");
|
|
2656
|
-
logger.log(""); // Add a bit of space.
|
|
2657
2678
|
logger.error(e.message);
|
|
2679
|
+
// We are not able to ask the `wrangler` CLI parser to show help for a subcommand programmatically.
|
|
2680
|
+
// The workaround is to re-run the parsing with an additional `--help` flag, which will result in the correct help message being displayed.
|
|
2681
|
+
// The `wrangler` object is "frozen"; we cannot reuse that with different args, so we must create a new CLI parser to generate the help message.
|
|
2682
|
+
await createCLIParser([...argv, "--help"]).parse();
|
|
2658
2683
|
} else if (e instanceof ParseError) {
|
|
2659
2684
|
e.notes.push({
|
|
2660
2685
|
text: "\nIf you think this is a bug, please open an issue at: https://github.com/cloudflare/wrangler2/issues/new",
|
package/src/kv.ts
CHANGED
|
@@ -129,9 +129,24 @@ const KeyValueKeys = new Set([
|
|
|
129
129
|
/**
|
|
130
130
|
* Is the given object a valid `KeyValue` type?
|
|
131
131
|
*/
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
133
|
+
export function isKVKeyValue(keyValue: any): keyValue is KeyValue {
|
|
134
|
+
// (keyValue could indeed be any-thing)
|
|
135
|
+
if (
|
|
136
|
+
typeof keyValue !== "object" ||
|
|
137
|
+
typeof keyValue.key !== "string" ||
|
|
138
|
+
typeof keyValue.value !== "string" ||
|
|
139
|
+
!(
|
|
140
|
+
keyValue.expiration === undefined ||
|
|
141
|
+
typeof keyValue.expiration === "number"
|
|
142
|
+
) ||
|
|
143
|
+
!(
|
|
144
|
+
keyValue.expiration_ttl === undefined ||
|
|
145
|
+
typeof keyValue.expiration_ttl === "number"
|
|
146
|
+
) ||
|
|
147
|
+
!(keyValue.base64 === undefined || typeof keyValue.base64 === "boolean") ||
|
|
148
|
+
!(keyValue.metadata === undefined || typeof keyValue.metadata === "object")
|
|
149
|
+
) {
|
|
135
150
|
return false;
|
|
136
151
|
}
|
|
137
152
|
return true;
|
package/src/pages.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import { execSync, spawn } from "node:child_process";
|
|
|
4
4
|
import { existsSync, lstatSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { readdir, readFile, stat } from "node:fs/promises";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
|
-
import { dirname, join, sep } from "node:path";
|
|
7
|
+
import { dirname, join, sep, extname, basename } from "node:path";
|
|
8
8
|
import { cwd } from "node:process";
|
|
9
9
|
import { URL } from "node:url";
|
|
10
10
|
import { hash } from "blake3-wasm";
|
|
@@ -1079,8 +1079,7 @@ const createDeployment: CommandModule<
|
|
|
1079
1079
|
const fileContent = await readFile(filepath);
|
|
1080
1080
|
|
|
1081
1081
|
const base64Content = fileContent.toString("base64");
|
|
1082
|
-
const extension =
|
|
1083
|
-
name.split(".").length > 1 ? name.split(".").at(-1) || "" : "";
|
|
1082
|
+
const extension = extname(basename(name)).substring(1);
|
|
1084
1083
|
|
|
1085
1084
|
const content = base64Content + extension;
|
|
1086
1085
|
|
|
@@ -1244,7 +1243,7 @@ const createDeployment: CommandModule<
|
|
|
1244
1243
|
export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
1245
1244
|
return yargs
|
|
1246
1245
|
.command(
|
|
1247
|
-
"dev [directory] [-- command]",
|
|
1246
|
+
"dev [directory] [-- command..]",
|
|
1248
1247
|
"🧑💻 Develop your full-stack Pages application locally",
|
|
1249
1248
|
(yargs) => {
|
|
1250
1249
|
return yargs
|