wrangler 2.0.23 → 2.0.24
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/README.md +20 -2
- package/bin/wrangler.js +1 -1
- package/miniflare-dist/index.mjs +96 -34
- package/package.json +9 -4
- package/src/__tests__/configuration.test.ts +88 -16
- package/src/__tests__/dev.test.tsx +3 -0
- package/src/__tests__/generate.test.ts +93 -0
- package/src/__tests__/helpers/mock-cfetch.ts +54 -2
- package/src/__tests__/index.test.ts +10 -27
- package/src/__tests__/jest.setup.ts +31 -1
- package/src/__tests__/kv.test.ts +2 -2
- package/src/__tests__/metrics.test.ts +5 -0
- package/src/__tests__/publish.test.ts +497 -254
- package/src/__tests__/r2.test.ts +155 -71
- package/src/__tests__/user.test.ts +1 -0
- package/src/__tests__/validate-dev-props.test.ts +56 -0
- package/src/__tests__/whoami.test.tsx +60 -1
- package/src/bundle.ts +278 -44
- package/src/cfetch/internal.ts +34 -2
- package/src/config/config.ts +7 -2
- package/src/config/environment.ts +40 -8
- package/src/config/index.ts +13 -0
- package/src/config/validation.ts +101 -7
- package/src/create-worker-upload-form.ts +25 -0
- package/src/dev/dev.tsx +107 -28
- package/src/dev/local.tsx +20 -10
- package/src/dev/remote.tsx +39 -8
- package/src/dev/use-esbuild.ts +25 -0
- package/src/dev/validate-dev-props.ts +31 -0
- package/src/dev-registry.tsx +157 -0
- package/src/dev.tsx +93 -75
- package/src/generate.ts +112 -14
- package/src/index.tsx +182 -4
- package/src/inspect.ts +93 -5
- package/src/metrics/index.ts +1 -0
- package/src/metrics/metrics-dispatcher.ts +1 -0
- package/src/metrics/metrics-usage-headers.ts +24 -0
- package/src/metrics/send-event.ts +2 -2
- package/src/module-collection.ts +3 -3
- package/src/pages/constants.ts +1 -0
- package/src/pages/deployments.tsx +1 -1
- package/src/pages/dev.tsx +6 -1
- package/src/pages/publish.tsx +1 -1
- package/src/pages/upload.tsx +32 -13
- package/src/publish.ts +126 -112
- package/src/r2.ts +68 -0
- package/src/user/user.tsx +20 -2
- package/src/whoami.tsx +79 -1
- package/src/worker.ts +12 -0
- package/templates/first-party-worker-module-facade.ts +18 -0
- package/templates/format-dev-errors.ts +32 -0
- package/templates/{static-asset-facade.js → serve-static-assets.ts} +21 -7
- package/templates/service-bindings-module-facade.js +51 -0
- package/templates/service-bindings-sw-facade.js +39 -0
- package/wrangler-dist/cli.js +40192 -15265
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { DevProps } from "./dev";
|
|
2
|
+
|
|
3
|
+
export function validateDevProps(props: DevProps) {
|
|
4
|
+
if (
|
|
5
|
+
!props.isWorkersSite &&
|
|
6
|
+
props.assetPaths &&
|
|
7
|
+
props.entry.format === "service-worker"
|
|
8
|
+
) {
|
|
9
|
+
throw new Error(
|
|
10
|
+
"You cannot use the service-worker format with an `assets` directory yet. For information on how to migrate to the module-worker format, see: https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/"
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (props.bindings.wasm_modules && props.entry.format === "modules") {
|
|
15
|
+
throw new Error(
|
|
16
|
+
"You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code"
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (props.bindings.text_blobs && props.entry.format === "modules") {
|
|
21
|
+
throw new Error(
|
|
22
|
+
"You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[rules]` in your wrangler.toml"
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (props.bindings.data_blobs && props.entry.format === "modules") {
|
|
27
|
+
throw new Error(
|
|
28
|
+
"You cannot configure [data_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[rules]` in your wrangler.toml"
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import http from "http";
|
|
2
|
+
import net from "net";
|
|
3
|
+
import bodyParser from "body-parser";
|
|
4
|
+
import express from "express";
|
|
5
|
+
import { createHttpTerminator } from "http-terminator";
|
|
6
|
+
import { fetch } from "undici";
|
|
7
|
+
import { logger } from "./logger";
|
|
8
|
+
import type { Server } from "http";
|
|
9
|
+
import type { HttpTerminator } from "http-terminator";
|
|
10
|
+
|
|
11
|
+
const DEV_REGISTRY_PORT = "6284";
|
|
12
|
+
const DEV_REGISTRY_HOST = `http://localhost:${DEV_REGISTRY_PORT}`;
|
|
13
|
+
|
|
14
|
+
let server: Server;
|
|
15
|
+
let terminator: HttpTerminator;
|
|
16
|
+
|
|
17
|
+
export type WorkerRegistry = Record<string, WorkerDefinition>;
|
|
18
|
+
|
|
19
|
+
type WorkerDefinition = {
|
|
20
|
+
port: number | undefined;
|
|
21
|
+
protocol: "http" | "https" | undefined;
|
|
22
|
+
host: string | undefined;
|
|
23
|
+
mode: "local" | "remote";
|
|
24
|
+
headers?: Record<string, string>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A helper function to check whether our service registry is already running
|
|
29
|
+
*/
|
|
30
|
+
async function isPortAvailable() {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
const netServer = net
|
|
33
|
+
.createServer()
|
|
34
|
+
.once("error", (err) => {
|
|
35
|
+
netServer.close();
|
|
36
|
+
if ((err as unknown as { code: string }).code === "EADDRINUSE") {
|
|
37
|
+
resolve(false);
|
|
38
|
+
} else {
|
|
39
|
+
reject(err);
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
.once("listening", () => {
|
|
43
|
+
netServer.close();
|
|
44
|
+
resolve(true);
|
|
45
|
+
});
|
|
46
|
+
netServer.listen(DEV_REGISTRY_PORT);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const jsonBodyParser = bodyParser.json();
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Start the service registry. It's a simple server
|
|
54
|
+
* that exposes endpoints for registering and unregistering
|
|
55
|
+
* services, as well as getting the state of the registry.
|
|
56
|
+
*/
|
|
57
|
+
export async function startWorkerRegistry() {
|
|
58
|
+
if ((await isPortAvailable()) && !server) {
|
|
59
|
+
const app = express();
|
|
60
|
+
|
|
61
|
+
let workers: WorkerRegistry = {};
|
|
62
|
+
app
|
|
63
|
+
.get("/workers", async (req, res) => {
|
|
64
|
+
res.json(workers);
|
|
65
|
+
})
|
|
66
|
+
.post("/workers/:workerId", jsonBodyParser, async (req, res) => {
|
|
67
|
+
workers[req.params.workerId] = req.body;
|
|
68
|
+
res.json(null);
|
|
69
|
+
})
|
|
70
|
+
.delete(`/workers/:workerId`, async (req, res) => {
|
|
71
|
+
delete workers[req.params.workerId];
|
|
72
|
+
res.json(null);
|
|
73
|
+
})
|
|
74
|
+
.delete("/workers", async (req, res) => {
|
|
75
|
+
workers = {};
|
|
76
|
+
res.json(null);
|
|
77
|
+
});
|
|
78
|
+
server = http.createServer(app);
|
|
79
|
+
terminator = createHttpTerminator({ server });
|
|
80
|
+
server.listen(DEV_REGISTRY_PORT);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Stop the service registry.
|
|
86
|
+
*/
|
|
87
|
+
export async function stopWorkerRegistry() {
|
|
88
|
+
await terminator?.terminate();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Register a worker in the registry.
|
|
93
|
+
*/
|
|
94
|
+
export async function registerWorker(
|
|
95
|
+
name: string,
|
|
96
|
+
definition: WorkerDefinition
|
|
97
|
+
) {
|
|
98
|
+
try {
|
|
99
|
+
return await fetch(`${DEV_REGISTRY_HOST}/workers/${name}`, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: {
|
|
102
|
+
"Content-Type": "application/json",
|
|
103
|
+
},
|
|
104
|
+
body: JSON.stringify(definition),
|
|
105
|
+
});
|
|
106
|
+
} catch (e) {
|
|
107
|
+
if (
|
|
108
|
+
!["ECONNRESET", "ECONNREFUSED"].includes(
|
|
109
|
+
(e as unknown as { cause?: { code?: string } }).cause?.code || "___"
|
|
110
|
+
)
|
|
111
|
+
) {
|
|
112
|
+
logger.error("Failed to register worker in local service registry", e);
|
|
113
|
+
} else {
|
|
114
|
+
logger.debug("Failed to register worker in local service registry", e);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Unregister a worker from the registry.
|
|
121
|
+
*/
|
|
122
|
+
export async function unregisterWorker(name: string) {
|
|
123
|
+
try {
|
|
124
|
+
await fetch(`${DEV_REGISTRY_HOST}/workers/${name}`, {
|
|
125
|
+
method: "DELETE",
|
|
126
|
+
});
|
|
127
|
+
} catch (e) {
|
|
128
|
+
if (
|
|
129
|
+
!["ECONNRESET", "ECONNREFUSED"].includes(
|
|
130
|
+
(e as unknown as { cause?: { code?: string } }).cause?.code || "___"
|
|
131
|
+
)
|
|
132
|
+
) {
|
|
133
|
+
throw e;
|
|
134
|
+
// logger.error("failed to unregister worker", e);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Get the state of the service registry.
|
|
141
|
+
*/
|
|
142
|
+
export async function getRegisteredWorkers(): Promise<
|
|
143
|
+
WorkerRegistry | undefined
|
|
144
|
+
> {
|
|
145
|
+
try {
|
|
146
|
+
const response = await fetch(`${DEV_REGISTRY_HOST}/workers`);
|
|
147
|
+
return (await response.json()) as WorkerRegistry;
|
|
148
|
+
} catch (e) {
|
|
149
|
+
if (
|
|
150
|
+
!["ECONNRESET", "ECONNREFUSED"].includes(
|
|
151
|
+
(e as unknown as { cause?: { code?: string } }).cause?.code || "___"
|
|
152
|
+
)
|
|
153
|
+
) {
|
|
154
|
+
throw e;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
package/src/dev.tsx
CHANGED
|
@@ -260,9 +260,7 @@ export async function devHandler(args: ArgumentsCamelCase<DevArgs>) {
|
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
-
type
|
|
264
|
-
// These options can be passed in directly when called with the `wrangler.dev()` API.
|
|
265
|
-
// They aren't exposed as CLI arguments.
|
|
263
|
+
export type AdditionalDevProps = {
|
|
266
264
|
vars?: {
|
|
267
265
|
[key: string]: unknown;
|
|
268
266
|
};
|
|
@@ -277,9 +275,14 @@ type StartDevOptions = ArgumentsCamelCase<DevArgs> & {
|
|
|
277
275
|
script_name?: string | undefined;
|
|
278
276
|
environment?: string | undefined;
|
|
279
277
|
}[];
|
|
280
|
-
forceLocal?: boolean;
|
|
281
|
-
enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions;
|
|
282
278
|
};
|
|
279
|
+
type StartDevOptions = ArgumentsCamelCase<DevArgs> &
|
|
280
|
+
// These options can be passed in directly when called with the `wrangler.dev()` API.
|
|
281
|
+
// They aren't exposed as CLI arguments.
|
|
282
|
+
AdditionalDevProps & {
|
|
283
|
+
forceLocal?: boolean;
|
|
284
|
+
enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions;
|
|
285
|
+
};
|
|
283
286
|
|
|
284
287
|
export async function startDev(args: StartDevOptions) {
|
|
285
288
|
let watcher: ReturnType<typeof watch> | undefined;
|
|
@@ -296,11 +299,6 @@ export async function startDev(args: StartDevOptions) {
|
|
|
296
299
|
((args.script &&
|
|
297
300
|
findWranglerToml(path.dirname(args.script))) as ConfigPath);
|
|
298
301
|
let config = readConfig(configPath, args);
|
|
299
|
-
await metrics.sendMetricsEvent(
|
|
300
|
-
"run dev",
|
|
301
|
-
{ local: args.local },
|
|
302
|
-
{ sendMetrics: config.send_metrics, offline: args.local }
|
|
303
|
-
);
|
|
304
302
|
|
|
305
303
|
if (config.configPath) {
|
|
306
304
|
watcher = watch(config.configPath, {
|
|
@@ -322,6 +320,15 @@ export async function startDev(args: StartDevOptions) {
|
|
|
322
320
|
"dev"
|
|
323
321
|
);
|
|
324
322
|
|
|
323
|
+
await metrics.sendMetricsEvent(
|
|
324
|
+
"run dev",
|
|
325
|
+
{
|
|
326
|
+
local: args.local,
|
|
327
|
+
usesTypeScript: /\.tsx?$/.test(entry.file),
|
|
328
|
+
},
|
|
329
|
+
{ sendMetrics: config.send_metrics, offline: args.local }
|
|
330
|
+
);
|
|
331
|
+
|
|
325
332
|
if (config.services && config.services.length > 0) {
|
|
326
333
|
logger.warn(
|
|
327
334
|
`This worker is bound to live services: ${config.services
|
|
@@ -412,77 +419,18 @@ export async function startDev(args: StartDevOptions) {
|
|
|
412
419
|
);
|
|
413
420
|
}
|
|
414
421
|
|
|
415
|
-
// eslint-disable-next-line no-inner-declarations
|
|
416
|
-
async function getBindings(
|
|
417
|
-
configParam: Config
|
|
418
|
-
): Promise<CfWorkerInit["bindings"]> {
|
|
419
|
-
return {
|
|
420
|
-
kv_namespaces: [
|
|
421
|
-
...(configParam.kv_namespaces || []).map(
|
|
422
|
-
({ binding, preview_id, id: _id }) => {
|
|
423
|
-
// In `dev`, we make folks use a separate kv namespace called
|
|
424
|
-
// `preview_id` instead of `id` so that they don't
|
|
425
|
-
// break production data. So here we check that a `preview_id`
|
|
426
|
-
// has actually been configured.
|
|
427
|
-
// This whole block of code will be obsoleted in the future
|
|
428
|
-
// when we have copy-on-write for previews on edge workers.
|
|
429
|
-
if (!preview_id) {
|
|
430
|
-
// TODO: This error has to be a _lot_ better, ideally just asking
|
|
431
|
-
// to create a preview namespace for the user automatically
|
|
432
|
-
throw new Error(
|
|
433
|
-
`In development, you should use a separate kv namespace than the one you'd use in production. Please create a new kv namespace with "wrangler kv:namespace create <name> --preview" and add its id as preview_id to the kv_namespace "${binding}" in your wrangler.toml`
|
|
434
|
-
); // Ugh, I really don't like this message very much
|
|
435
|
-
}
|
|
436
|
-
return {
|
|
437
|
-
binding,
|
|
438
|
-
id: preview_id,
|
|
439
|
-
};
|
|
440
|
-
}
|
|
441
|
-
),
|
|
442
|
-
...(args.kv || []),
|
|
443
|
-
],
|
|
444
|
-
// Use a copy of combinedVars since we're modifying it later
|
|
445
|
-
vars: {
|
|
446
|
-
...getVarsForDev(configParam),
|
|
447
|
-
...args.vars,
|
|
448
|
-
},
|
|
449
|
-
wasm_modules: configParam.wasm_modules,
|
|
450
|
-
text_blobs: configParam.text_blobs,
|
|
451
|
-
data_blobs: configParam.data_blobs,
|
|
452
|
-
durable_objects: {
|
|
453
|
-
bindings: [
|
|
454
|
-
...(configParam.durable_objects || { bindings: [] }).bindings,
|
|
455
|
-
...(args.durableObjects || []),
|
|
456
|
-
],
|
|
457
|
-
},
|
|
458
|
-
r2_buckets: configParam.r2_buckets?.map(
|
|
459
|
-
({ binding, preview_bucket_name, bucket_name: _bucket_name }) => {
|
|
460
|
-
// same idea as kv namespace preview id,
|
|
461
|
-
// same copy-on-write TODO
|
|
462
|
-
if (!preview_bucket_name) {
|
|
463
|
-
throw new Error(
|
|
464
|
-
`In development, you should use a separate r2 bucket than the one you'd use in production. Please create a new r2 bucket with "wrangler r2 bucket create <name>" and add its name as preview_bucket_name to the r2_buckets "${binding}" in your wrangler.toml`
|
|
465
|
-
);
|
|
466
|
-
}
|
|
467
|
-
return {
|
|
468
|
-
binding,
|
|
469
|
-
bucket_name: preview_bucket_name,
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
),
|
|
473
|
-
worker_namespaces: configParam.worker_namespaces,
|
|
474
|
-
services: configParam.services,
|
|
475
|
-
unsafe: configParam.unsafe?.bindings,
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
|
|
479
422
|
const getLocalPort = memoizeGetPort(DEFAULT_LOCAL_PORT);
|
|
480
423
|
const getInspectorPort = memoizeGetPort(DEFAULT_INSPECTOR_PORT);
|
|
481
424
|
|
|
482
425
|
// eslint-disable-next-line no-inner-declarations
|
|
483
426
|
async function getDevReactElement(configParam: Config) {
|
|
484
427
|
// now log all available bindings into the terminal
|
|
485
|
-
const bindings = await getBindings(configParam
|
|
428
|
+
const bindings = await getBindings(configParam, {
|
|
429
|
+
kv: args.kv,
|
|
430
|
+
vars: args.vars,
|
|
431
|
+
durableObjects: args.durableObjects,
|
|
432
|
+
});
|
|
433
|
+
|
|
486
434
|
// mask anything that was overridden in .dev.vars
|
|
487
435
|
// so that we don't log potential secrets into the terminal
|
|
488
436
|
const maskedVars = { ...bindings.vars };
|
|
@@ -537,6 +485,7 @@ export async function startDev(args: StartDevOptions) {
|
|
|
537
485
|
liveReload={args.liveReload || false}
|
|
538
486
|
accountId={config.account_id || getAccountFromCache()?.id}
|
|
539
487
|
assetPaths={assetPaths}
|
|
488
|
+
assetsConfig={config.assets}
|
|
540
489
|
port={args.port || config.dev.port || (await getLocalPort())}
|
|
541
490
|
ip={args.ip || config.dev.ip}
|
|
542
491
|
inspectorPort={
|
|
@@ -562,6 +511,8 @@ export async function startDev(args: StartDevOptions) {
|
|
|
562
511
|
showInteractiveDevSession={args.showInteractiveDevSession}
|
|
563
512
|
forceLocal={args.forceLocal}
|
|
564
513
|
enablePagesAssetsServiceBinding={args.enablePagesAssetsServiceBinding}
|
|
514
|
+
firstPartyWorker={config.first_party_worker}
|
|
515
|
+
sendMetrics={config.send_metrics}
|
|
565
516
|
/>
|
|
566
517
|
);
|
|
567
518
|
}
|
|
@@ -596,3 +547,70 @@ function memoizeGetPort(defaultPort: number) {
|
|
|
596
547
|
return portValue || (portValue = await getPort({ port: defaultPort }));
|
|
597
548
|
};
|
|
598
549
|
}
|
|
550
|
+
|
|
551
|
+
async function getBindings(
|
|
552
|
+
configParam: Config,
|
|
553
|
+
args: AdditionalDevProps
|
|
554
|
+
): Promise<CfWorkerInit["bindings"]> {
|
|
555
|
+
const bindings = {
|
|
556
|
+
kv_namespaces: [
|
|
557
|
+
...(configParam.kv_namespaces || []).map(
|
|
558
|
+
({ binding, preview_id, id: _id }) => {
|
|
559
|
+
// In `dev`, we make folks use a separate kv namespace called
|
|
560
|
+
// `preview_id` instead of `id` so that they don't
|
|
561
|
+
// break production data. So here we check that a `preview_id`
|
|
562
|
+
// has actually been configured.
|
|
563
|
+
// This whole block of code will be obsoleted in the future
|
|
564
|
+
// when we have copy-on-write for previews on edge workers.
|
|
565
|
+
if (!preview_id) {
|
|
566
|
+
// TODO: This error has to be a _lot_ better, ideally just asking
|
|
567
|
+
// to create a preview namespace for the user automatically
|
|
568
|
+
throw new Error(
|
|
569
|
+
`In development, you should use a separate kv namespace than the one you'd use in production. Please create a new kv namespace with "wrangler kv:namespace create <name> --preview" and add its id as preview_id to the kv_namespace "${binding}" in your wrangler.toml`
|
|
570
|
+
); // Ugh, I really don't like this message very much
|
|
571
|
+
}
|
|
572
|
+
return {
|
|
573
|
+
binding,
|
|
574
|
+
id: preview_id,
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
),
|
|
578
|
+
...(args.kv || []),
|
|
579
|
+
],
|
|
580
|
+
// Use a copy of combinedVars since we're modifying it later
|
|
581
|
+
vars: {
|
|
582
|
+
...getVarsForDev(configParam),
|
|
583
|
+
...args.vars,
|
|
584
|
+
},
|
|
585
|
+
wasm_modules: configParam.wasm_modules,
|
|
586
|
+
text_blobs: configParam.text_blobs,
|
|
587
|
+
data_blobs: configParam.data_blobs,
|
|
588
|
+
durable_objects: {
|
|
589
|
+
bindings: [
|
|
590
|
+
...(configParam.durable_objects || { bindings: [] }).bindings,
|
|
591
|
+
...(args.durableObjects || []),
|
|
592
|
+
],
|
|
593
|
+
},
|
|
594
|
+
r2_buckets: configParam.r2_buckets?.map(
|
|
595
|
+
({ binding, preview_bucket_name, bucket_name: _bucket_name }) => {
|
|
596
|
+
// same idea as kv namespace preview id,
|
|
597
|
+
// same copy-on-write TODO
|
|
598
|
+
if (!preview_bucket_name) {
|
|
599
|
+
throw new Error(
|
|
600
|
+
`In development, you should use a separate r2 bucket than the one you'd use in production. Please create a new r2 bucket with "wrangler r2 bucket create <name>" and add its name as preview_bucket_name to the r2_buckets "${binding}" in your wrangler.toml`
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
return {
|
|
604
|
+
binding,
|
|
605
|
+
bucket_name: preview_bucket_name,
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
),
|
|
609
|
+
worker_namespaces: configParam.worker_namespaces,
|
|
610
|
+
services: configParam.services,
|
|
611
|
+
unsafe: configParam.unsafe?.bindings,
|
|
612
|
+
logfwdr: configParam.logfwdr,
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
return bindings;
|
|
616
|
+
}
|
package/src/generate.ts
CHANGED
|
@@ -1,33 +1,131 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { setup as createCloudflare } from "create-cloudflare";
|
|
4
|
+
import { initHandler } from "./init";
|
|
5
|
+
import { logger } from "./logger";
|
|
6
|
+
import { CommandLineArgsError, printWranglerBanner } from ".";
|
|
2
7
|
import type { Argv, ArgumentsCamelCase } from "yargs";
|
|
3
8
|
|
|
9
|
+
// https://github.com/cloudflare/wrangler/blob/master/src/cli/mod.rs#L106-L123
|
|
4
10
|
interface GenerateArgs {
|
|
5
|
-
name
|
|
6
|
-
template
|
|
11
|
+
name?: string;
|
|
12
|
+
template?: string;
|
|
13
|
+
type?: string;
|
|
14
|
+
site?: boolean;
|
|
7
15
|
}
|
|
8
16
|
|
|
9
17
|
export function generateOptions(yargs: Argv) {
|
|
10
18
|
return yargs
|
|
11
19
|
.positional("name", {
|
|
12
20
|
describe: "Name of the Workers project",
|
|
13
|
-
|
|
21
|
+
type: "string",
|
|
14
22
|
})
|
|
15
23
|
.positional("template", {
|
|
24
|
+
type: "string",
|
|
16
25
|
describe: "The URL of a GitHub template",
|
|
17
|
-
|
|
26
|
+
})
|
|
27
|
+
.option("type", {
|
|
28
|
+
alias: "t",
|
|
29
|
+
type: "string",
|
|
30
|
+
hidden: true,
|
|
31
|
+
deprecated: true,
|
|
32
|
+
})
|
|
33
|
+
.option("site", {
|
|
34
|
+
alias: "s",
|
|
35
|
+
type: "boolean",
|
|
36
|
+
hidden: true,
|
|
37
|
+
deprecated: true,
|
|
18
38
|
});
|
|
19
39
|
}
|
|
20
40
|
|
|
21
|
-
export function generateHandler(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
41
|
+
export async function generateHandler({
|
|
42
|
+
// somehow, `init` marks name as required but then also runs fine
|
|
43
|
+
// with the name omitted, and then substitutes it at runtime with ""
|
|
44
|
+
name = "",
|
|
45
|
+
template,
|
|
46
|
+
type,
|
|
47
|
+
site,
|
|
48
|
+
...args
|
|
49
|
+
}: ArgumentsCamelCase<GenerateArgs>) {
|
|
50
|
+
// delegate to `wrangler init` if no template is specified
|
|
51
|
+
if (template === undefined) {
|
|
52
|
+
return initHandler({ name, ...args });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// print down here cuz `init` prints it own its own
|
|
56
|
+
printWranglerBanner();
|
|
57
|
+
|
|
58
|
+
if (type) {
|
|
59
|
+
let message = "The --type option is no longer supported.";
|
|
60
|
+
if (args.type === "webpack") {
|
|
61
|
+
message +=
|
|
62
|
+
"\nIf you wish to use webpack then you will need to create a custom build.";
|
|
63
|
+
// TODO: Add a link to docs
|
|
64
|
+
}
|
|
65
|
+
throw new CommandLineArgsError(message);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const creationDirectory = generateWorkerDirectoryName(name);
|
|
69
|
+
|
|
70
|
+
if (site) {
|
|
71
|
+
const gitDirectory =
|
|
72
|
+
creationDirectory !== process.cwd()
|
|
73
|
+
? path.basename(creationDirectory)
|
|
74
|
+
: "my-site";
|
|
75
|
+
const message =
|
|
76
|
+
"The --site option is no longer supported.\n" +
|
|
77
|
+
"If you wish to create a brand new Worker Sites project then clone the `worker-sites-template` starter repository:\n\n" +
|
|
28
78
|
"```\n" +
|
|
29
|
-
`git clone ${
|
|
79
|
+
`git clone --depth=1 --branch=wrangler2 https://github.com/cloudflare/worker-sites-template ${gitDirectory}\n` +
|
|
80
|
+
`cd ${gitDirectory}\n` +
|
|
30
81
|
"```\n\n" +
|
|
31
|
-
"
|
|
82
|
+
"Find out more about how to create and maintain Sites projects at https://developers.cloudflare.com/workers/platform/sites.\n" +
|
|
83
|
+
"Have you considered using Cloudflare Pages instead? See https://pages.cloudflare.com/.";
|
|
84
|
+
throw new CommandLineArgsError(message);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
logger.log(
|
|
88
|
+
`Creating a worker in ${path.basename(creationDirectory)} from ${template}`
|
|
32
89
|
);
|
|
90
|
+
|
|
91
|
+
await createCloudflare(creationDirectory, template, {
|
|
92
|
+
init: true, // initialize a git repository
|
|
93
|
+
debug: logger.loggerLevel === "debug",
|
|
94
|
+
force: false, // do not overwrite an existing directory
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Creates a path based on the current working directory and a worker name.
|
|
100
|
+
* Automatically increments a counter when searching for an available directory.
|
|
101
|
+
*
|
|
102
|
+
* Running `wrangler generate worker https://some-git-repo` in a directory
|
|
103
|
+
* with the structure:
|
|
104
|
+
* ```
|
|
105
|
+
* - workers
|
|
106
|
+
* |
|
|
107
|
+
* | - worker
|
|
108
|
+
* | | - wrangler.toml
|
|
109
|
+
* | | ...
|
|
110
|
+
* |
|
|
111
|
+
* | - worker-1
|
|
112
|
+
* | | - wrangler.toml
|
|
113
|
+
* | | ...
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* will result in a new worker called `worker-2` being generated.
|
|
117
|
+
*
|
|
118
|
+
* @param workerName the name of the generated worker
|
|
119
|
+
* @returns an absolute path to the directory to generate the worker into
|
|
120
|
+
*/
|
|
121
|
+
function generateWorkerDirectoryName(workerName: string): string {
|
|
122
|
+
let workerDirectoryPath = path.resolve(process.cwd(), workerName);
|
|
123
|
+
let i = 1;
|
|
124
|
+
|
|
125
|
+
while (fs.existsSync(workerDirectoryPath)) {
|
|
126
|
+
workerDirectoryPath = path.resolve(process.cwd(), `${workerName}-${i}`);
|
|
127
|
+
i++;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return workerDirectoryPath;
|
|
33
131
|
}
|