wrangler 2.0.21 → 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 +527 -5
- package/package.json +18 -5
- package/src/__tests__/configuration.test.ts +88 -16
- package/src/__tests__/dev.test.tsx +95 -4
- 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 +82 -61
- package/src/__tests__/metrics.test.ts +35 -0
- package/src/__tests__/publish.test.ts +573 -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__/version.test.ts +35 -0
- package/src/__tests__/whoami.test.tsx +60 -1
- package/src/api/dev.ts +43 -9
- package/src/bundle.ts +297 -37
- package/src/cfetch/internal.ts +34 -2
- package/src/config/config.ts +14 -2
- package/src/config/environment.ts +40 -8
- package/src/config/index.ts +13 -0
- package/src/config/validation.ts +110 -8
- package/src/create-worker-preview.ts +3 -1
- package/src/create-worker-upload-form.ts +25 -0
- package/src/dev/dev.tsx +135 -31
- package/src/dev/local.tsx +48 -20
- package/src/dev/remote.tsx +39 -12
- 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 +137 -65
- package/src/generate.ts +112 -14
- package/src/index.tsx +222 -7
- package/src/inspect.ts +93 -5
- package/src/metrics/index.ts +1 -0
- package/src/metrics/is-ci.ts +14 -0
- package/src/metrics/metrics-config.ts +19 -2
- 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/miniflare-cli/assets.ts +543 -0
- package/src/miniflare-cli/index.ts +36 -4
- 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 +85 -639
- package/src/pages/publish.tsx +1 -1
- package/src/pages/upload.tsx +32 -13
- package/src/publish.ts +139 -112
- package/src/r2.ts +68 -0
- package/src/user/choose-account.tsx +20 -11
- 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/pages-shim.ts +9 -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.d.ts +32 -3
- package/wrangler-dist/cli.js +45257 -25209
package/src/dev/local.tsx
CHANGED
|
@@ -4,11 +4,13 @@ import { writeFile } from "node:fs/promises";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { useState, useEffect, useRef } from "react";
|
|
6
6
|
import onExit from "signal-exit";
|
|
7
|
+
import { registerWorker } from "../dev-registry";
|
|
7
8
|
import useInspector from "../inspect";
|
|
8
9
|
import { logger } from "../logger";
|
|
9
10
|
import { DEFAULT_MODULE_RULES } from "../module-collection";
|
|
10
11
|
import { waitForPortToBeAvailable } from "../proxy";
|
|
11
12
|
import type { Config } from "../config";
|
|
13
|
+
import type { EnablePagesAssetsServiceBindingOptions } from "../miniflare-cli";
|
|
12
14
|
import type { AssetPaths } from "../sites";
|
|
13
15
|
import type { CfWorkerInit, CfScriptFormat } from "../worker";
|
|
14
16
|
import type { EsbuildBundle } from "./use-esbuild";
|
|
@@ -22,18 +24,20 @@ interface LocalProps {
|
|
|
22
24
|
compatibilityFlags: string[] | undefined;
|
|
23
25
|
bindings: CfWorkerInit["bindings"];
|
|
24
26
|
assetPaths: AssetPaths | undefined;
|
|
25
|
-
isWorkersSite: boolean;
|
|
26
27
|
port: number;
|
|
27
28
|
ip: string;
|
|
28
29
|
rules: Config["rules"];
|
|
29
30
|
inspectorPort: number;
|
|
30
31
|
enableLocalPersistence: boolean;
|
|
32
|
+
liveReload: boolean;
|
|
31
33
|
crons: Config["triggers"]["crons"];
|
|
32
34
|
localProtocol: "http" | "https";
|
|
33
35
|
localUpstream: string | undefined;
|
|
34
36
|
inspect: boolean;
|
|
35
37
|
onReady: (() => void) | undefined;
|
|
36
38
|
logLevel: "none" | "error" | "log" | "warn" | "debug" | undefined;
|
|
39
|
+
logPrefix?: string;
|
|
40
|
+
enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
export function Local(props: LocalProps) {
|
|
@@ -54,10 +58,11 @@ function useLocalWorker({
|
|
|
54
58
|
compatibilityFlags,
|
|
55
59
|
bindings,
|
|
56
60
|
assetPaths,
|
|
57
|
-
isWorkersSite,
|
|
58
61
|
port,
|
|
62
|
+
inspectorPort,
|
|
59
63
|
rules,
|
|
60
64
|
enableLocalPersistence,
|
|
65
|
+
liveReload,
|
|
61
66
|
ip,
|
|
62
67
|
crons,
|
|
63
68
|
localProtocol,
|
|
@@ -65,6 +70,8 @@ function useLocalWorker({
|
|
|
65
70
|
inspect,
|
|
66
71
|
onReady,
|
|
67
72
|
logLevel,
|
|
73
|
+
logPrefix,
|
|
74
|
+
enablePagesAssetsServiceBinding,
|
|
68
75
|
}: LocalProps) {
|
|
69
76
|
// TODO: pass vars via command line
|
|
70
77
|
const local = useRef<ChildProcess>();
|
|
@@ -80,6 +87,15 @@ function useLocalWorker({
|
|
|
80
87
|
// so that it's persisted in the temp dir across a dev session
|
|
81
88
|
// even when we change source and reload
|
|
82
89
|
null;
|
|
90
|
+
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
if (bindings.services && bindings.services.length > 0) {
|
|
93
|
+
logger.warn(
|
|
94
|
+
"⎔ Support for service bindings in local mode is experimental and may change."
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}, [bindings.services]);
|
|
98
|
+
|
|
83
99
|
useEffect(() => {
|
|
84
100
|
const abortController = new AbortController();
|
|
85
101
|
async function startLocalWorker() {
|
|
@@ -92,12 +108,6 @@ function useLocalWorker({
|
|
|
92
108
|
abortSignal: abortController.signal,
|
|
93
109
|
});
|
|
94
110
|
|
|
95
|
-
if (bindings.services && bindings.services.length > 0) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
"⎔ Service bindings are not yet supported in local mode."
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
111
|
// In local mode, we want to copy all referenced modules into
|
|
102
112
|
// the output bundle directory before starting up
|
|
103
113
|
for (const module of bundle.modules) {
|
|
@@ -212,6 +222,7 @@ function useLocalWorker({
|
|
|
212
222
|
r2Persist: true,
|
|
213
223
|
}),
|
|
214
224
|
|
|
225
|
+
liveReload,
|
|
215
226
|
sitePath: assetPaths?.assetDirectory
|
|
216
227
|
? path.join(assetPaths.baseDirectory, assetPaths.assetDirectory)
|
|
217
228
|
: undefined,
|
|
@@ -230,6 +241,7 @@ function useLocalWorker({
|
|
|
230
241
|
crons,
|
|
231
242
|
upstream,
|
|
232
243
|
disableLogs: logLevel === "none",
|
|
244
|
+
logOptions: logPrefix ? { prefix: logPrefix } : undefined,
|
|
233
245
|
};
|
|
234
246
|
|
|
235
247
|
// The path to the Miniflare CLI assumes that this file is being run from
|
|
@@ -248,19 +260,32 @@ function useLocalWorker({
|
|
|
248
260
|
// "--log=VERBOSE", // uncomment this to Miniflare to log "everything"!
|
|
249
261
|
];
|
|
250
262
|
if (inspect) {
|
|
251
|
-
nodeOptions.push("--inspect"); // start Miniflare listening for a debugger to attach
|
|
263
|
+
nodeOptions.push("--inspect=" + `${ip}:${inspectorPort}`); // start Miniflare listening for a debugger to attach
|
|
252
264
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
265
|
+
|
|
266
|
+
const forkOptions = [miniflareOptions];
|
|
267
|
+
|
|
268
|
+
if (enablePagesAssetsServiceBinding) {
|
|
269
|
+
forkOptions.push(JSON.stringify(enablePagesAssetsServiceBinding));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const child = (local.current = fork(miniflareCLIPath, forkOptions, {
|
|
273
|
+
cwd: path.dirname(scriptPath),
|
|
274
|
+
execArgv: nodeOptions,
|
|
275
|
+
stdio: "pipe",
|
|
276
|
+
}));
|
|
277
|
+
|
|
278
|
+
child.on("message", async (message) => {
|
|
263
279
|
if (message === "ready") {
|
|
280
|
+
// Let's register our presence in the dev registry
|
|
281
|
+
if (workerName) {
|
|
282
|
+
await registerWorker(workerName, {
|
|
283
|
+
protocol: localProtocol,
|
|
284
|
+
mode: "local",
|
|
285
|
+
port,
|
|
286
|
+
host: ip,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
264
289
|
onReady?.();
|
|
265
290
|
}
|
|
266
291
|
});
|
|
@@ -331,6 +356,7 @@ function useLocalWorker({
|
|
|
331
356
|
workerName,
|
|
332
357
|
format,
|
|
333
358
|
port,
|
|
359
|
+
inspectorPort,
|
|
334
360
|
ip,
|
|
335
361
|
bindings.durable_objects?.bindings,
|
|
336
362
|
bindings.kv_namespaces,
|
|
@@ -340,8 +366,8 @@ function useLocalWorker({
|
|
|
340
366
|
compatibilityDate,
|
|
341
367
|
compatibilityFlags,
|
|
342
368
|
localPersistencePath,
|
|
369
|
+
liveReload,
|
|
343
370
|
assetPaths,
|
|
344
|
-
isWorkersSite,
|
|
345
371
|
rules,
|
|
346
372
|
bindings.wasm_modules,
|
|
347
373
|
bindings.text_blobs,
|
|
@@ -351,7 +377,9 @@ function useLocalWorker({
|
|
|
351
377
|
localUpstream,
|
|
352
378
|
inspect,
|
|
353
379
|
logLevel,
|
|
380
|
+
logPrefix,
|
|
354
381
|
onReady,
|
|
382
|
+
enablePagesAssetsServiceBinding,
|
|
355
383
|
]);
|
|
356
384
|
return { inspectorUrl };
|
|
357
385
|
}
|
package/src/dev/remote.tsx
CHANGED
|
@@ -55,6 +55,8 @@ export function Remote(props: {
|
|
|
55
55
|
host: string | undefined;
|
|
56
56
|
routes: Route[] | undefined;
|
|
57
57
|
onReady?: (() => void) | undefined;
|
|
58
|
+
sourceMapPath: string | undefined;
|
|
59
|
+
sendMetrics: boolean | undefined;
|
|
58
60
|
}) {
|
|
59
61
|
const [accountId, setAccountId] = useState(props.accountId);
|
|
60
62
|
const accountChoicesRef = useRef<Promise<ChooseAccountItem[]>>();
|
|
@@ -69,7 +71,6 @@ export function Remote(props: {
|
|
|
69
71
|
bindings: props.bindings,
|
|
70
72
|
assetPaths: props.assetPaths,
|
|
71
73
|
isWorkersSite: props.isWorkersSite,
|
|
72
|
-
port: props.port,
|
|
73
74
|
compatibilityDate: props.compatibilityDate,
|
|
74
75
|
compatibilityFlags: props.compatibilityFlags,
|
|
75
76
|
usageModel: props.usageModel,
|
|
@@ -79,6 +80,7 @@ export function Remote(props: {
|
|
|
79
80
|
host: props.host,
|
|
80
81
|
routes: props.routes,
|
|
81
82
|
onReady: props.onReady,
|
|
83
|
+
sendMetrics: props.sendMetrics,
|
|
82
84
|
});
|
|
83
85
|
|
|
84
86
|
usePreviewServer({
|
|
@@ -98,6 +100,7 @@ export function Remote(props: {
|
|
|
98
100
|
: undefined,
|
|
99
101
|
port: props.inspectorPort,
|
|
100
102
|
logToTerminal: true,
|
|
103
|
+
sourceMapPath: props.sourceMapPath,
|
|
101
104
|
});
|
|
102
105
|
|
|
103
106
|
const errorHandler = useErrorHandler();
|
|
@@ -153,7 +156,6 @@ export function useWorker(props: {
|
|
|
153
156
|
bindings: CfWorkerInit["bindings"];
|
|
154
157
|
assetPaths: AssetPaths | undefined;
|
|
155
158
|
isWorkersSite: boolean;
|
|
156
|
-
port: number;
|
|
157
159
|
compatibilityDate: string | undefined;
|
|
158
160
|
compatibilityFlags: string[] | undefined;
|
|
159
161
|
usageModel: "bundled" | "unbound" | undefined;
|
|
@@ -163,6 +165,7 @@ export function useWorker(props: {
|
|
|
163
165
|
host: string | undefined;
|
|
164
166
|
routes: Route[] | undefined;
|
|
165
167
|
onReady: (() => void) | undefined;
|
|
168
|
+
sendMetrics: boolean | undefined;
|
|
166
169
|
}): CfPreviewToken | undefined {
|
|
167
170
|
const {
|
|
168
171
|
name,
|
|
@@ -175,7 +178,6 @@ export function useWorker(props: {
|
|
|
175
178
|
compatibilityDate,
|
|
176
179
|
compatibilityFlags,
|
|
177
180
|
usageModel,
|
|
178
|
-
port,
|
|
179
181
|
onReady,
|
|
180
182
|
} = props;
|
|
181
183
|
const [session, setSession] = useState<CfPreviewSession | undefined>();
|
|
@@ -205,6 +207,7 @@ export function useWorker(props: {
|
|
|
205
207
|
zone: props.zone,
|
|
206
208
|
host: props.host,
|
|
207
209
|
routes: props.routes,
|
|
210
|
+
sendMetrics: props.sendMetrics,
|
|
208
211
|
};
|
|
209
212
|
|
|
210
213
|
setSession(
|
|
@@ -233,6 +236,7 @@ export function useWorker(props: {
|
|
|
233
236
|
props.legacyEnv,
|
|
234
237
|
props.routes,
|
|
235
238
|
props.zone,
|
|
239
|
+
props.sendMetrics,
|
|
236
240
|
]);
|
|
237
241
|
|
|
238
242
|
// This effect uses the session to upload the worker and create a preview
|
|
@@ -323,17 +327,40 @@ export function useWorker(props: {
|
|
|
323
327
|
zone: props.zone,
|
|
324
328
|
host: props.host,
|
|
325
329
|
routes: props.routes,
|
|
330
|
+
sendMetrics: props.sendMetrics,
|
|
326
331
|
};
|
|
327
332
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
abortController.signal
|
|
335
|
-
)
|
|
333
|
+
const workerPreviewToken = await createWorkerPreview(
|
|
334
|
+
init,
|
|
335
|
+
workerAccount,
|
|
336
|
+
workerCtx,
|
|
337
|
+
session,
|
|
338
|
+
abortController.signal
|
|
336
339
|
);
|
|
340
|
+
|
|
341
|
+
setToken(workerPreviewToken);
|
|
342
|
+
|
|
343
|
+
// TODO: Once we get service bindings working in the
|
|
344
|
+
// edge preview server, we can define remote dev service bindings
|
|
345
|
+
// and you can uncomment this code.
|
|
346
|
+
// https://github.com/cloudflare/wrangler2/issues/1182
|
|
347
|
+
|
|
348
|
+
/*
|
|
349
|
+
if (name) {
|
|
350
|
+
await registerWorker(name, {
|
|
351
|
+
mode: "remote",
|
|
352
|
+
// upstream protocol is always https (https://github.com/cloudflare/wrangler2/issues/583)
|
|
353
|
+
protocol: "https",
|
|
354
|
+
port: undefined,
|
|
355
|
+
host: workerPreviewToken.host,
|
|
356
|
+
headers: {
|
|
357
|
+
"cf-workers-preview-token": workerPreviewToken.value,
|
|
358
|
+
host: workerPreviewToken.host,
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
*/
|
|
363
|
+
|
|
337
364
|
onReady?.();
|
|
338
365
|
}
|
|
339
366
|
start().catch((err) => {
|
|
@@ -366,7 +393,6 @@ export function useWorker(props: {
|
|
|
366
393
|
bundle,
|
|
367
394
|
format,
|
|
368
395
|
accountId,
|
|
369
|
-
port,
|
|
370
396
|
assetPaths,
|
|
371
397
|
props.isWorkersSite,
|
|
372
398
|
compatibilityDate,
|
|
@@ -381,6 +407,7 @@ export function useWorker(props: {
|
|
|
381
407
|
props.routes,
|
|
382
408
|
session,
|
|
383
409
|
onReady,
|
|
410
|
+
props.sendMetrics,
|
|
384
411
|
]);
|
|
385
412
|
return token;
|
|
386
413
|
}
|
package/src/dev/use-esbuild.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { useState, useEffect } from "react";
|
|
|
5
5
|
import { bundleWorker } from "../bundle";
|
|
6
6
|
import { logger } from "../logger";
|
|
7
7
|
import type { Config } from "../config";
|
|
8
|
+
import type { WorkerRegistry } from "../dev-registry";
|
|
8
9
|
import type { Entry } from "../entry";
|
|
9
10
|
import type { CfModule } from "../worker";
|
|
10
11
|
import type { WatchMode } from "esbuild";
|
|
@@ -15,6 +16,7 @@ export type EsbuildBundle = {
|
|
|
15
16
|
entry: Entry;
|
|
16
17
|
type: "esm" | "commonjs";
|
|
17
18
|
modules: CfModule[];
|
|
19
|
+
sourceMapPath: string | undefined;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
export function useEsbuild({
|
|
@@ -23,24 +25,32 @@ export function useEsbuild({
|
|
|
23
25
|
jsxFactory,
|
|
24
26
|
jsxFragment,
|
|
25
27
|
rules,
|
|
28
|
+
assets,
|
|
26
29
|
serveAssetsFromWorker,
|
|
27
30
|
tsconfig,
|
|
28
31
|
minify,
|
|
29
32
|
nodeCompat,
|
|
30
33
|
define,
|
|
31
34
|
noBundle,
|
|
35
|
+
workerDefinitions,
|
|
36
|
+
services,
|
|
37
|
+
firstPartyWorkerDevFacade,
|
|
32
38
|
}: {
|
|
33
39
|
entry: Entry;
|
|
34
40
|
destination: string | undefined;
|
|
35
41
|
jsxFactory: string | undefined;
|
|
36
42
|
jsxFragment: string | undefined;
|
|
37
43
|
rules: Config["rules"];
|
|
44
|
+
assets: Config["assets"];
|
|
38
45
|
define: Config["define"];
|
|
46
|
+
services: Config["services"];
|
|
39
47
|
serveAssetsFromWorker: boolean;
|
|
40
48
|
tsconfig: string | undefined;
|
|
41
49
|
minify: boolean | undefined;
|
|
42
50
|
nodeCompat: boolean | undefined;
|
|
43
51
|
noBundle: boolean;
|
|
52
|
+
workerDefinitions: WorkerRegistry;
|
|
53
|
+
firstPartyWorkerDevFacade: boolean | undefined;
|
|
44
54
|
}): EsbuildBundle | undefined {
|
|
45
55
|
const [bundle, setBundle] = useState<EsbuildBundle>();
|
|
46
56
|
const { exit } = useApp();
|
|
@@ -76,12 +86,14 @@ export function useEsbuild({
|
|
|
76
86
|
bundleType,
|
|
77
87
|
modules,
|
|
78
88
|
stop,
|
|
89
|
+
sourceMapPath,
|
|
79
90
|
}: Awaited<ReturnType<typeof bundleWorker>> = noBundle
|
|
80
91
|
? {
|
|
81
92
|
modules: [],
|
|
82
93
|
resolvedEntryPointPath: entry.file,
|
|
83
94
|
bundleType: entry.format === "modules" ? "esm" : "commonjs",
|
|
84
95
|
stop: undefined,
|
|
96
|
+
sourceMapPath: undefined,
|
|
85
97
|
}
|
|
86
98
|
: await bundleWorker(entry, destination, {
|
|
87
99
|
serveAssetsFromWorker,
|
|
@@ -94,6 +106,14 @@ export function useEsbuild({
|
|
|
94
106
|
nodeCompat,
|
|
95
107
|
define,
|
|
96
108
|
checkFetch: true,
|
|
109
|
+
assets: assets && {
|
|
110
|
+
...assets,
|
|
111
|
+
// disable the cache in dev
|
|
112
|
+
bypassCache: true,
|
|
113
|
+
},
|
|
114
|
+
workerDefinitions,
|
|
115
|
+
services,
|
|
116
|
+
firstPartyWorkerDevFacade,
|
|
97
117
|
});
|
|
98
118
|
|
|
99
119
|
// Capture the `stop()` method to use as the `useEffect()` destructor.
|
|
@@ -119,6 +139,7 @@ export function useEsbuild({
|
|
|
119
139
|
path: resolvedEntryPointPath,
|
|
120
140
|
type: bundleType,
|
|
121
141
|
modules,
|
|
142
|
+
sourceMapPath,
|
|
122
143
|
});
|
|
123
144
|
}
|
|
124
145
|
|
|
@@ -145,6 +166,10 @@ export function useEsbuild({
|
|
|
145
166
|
minify,
|
|
146
167
|
nodeCompat,
|
|
147
168
|
define,
|
|
169
|
+
assets,
|
|
170
|
+
services,
|
|
171
|
+
workerDefinitions,
|
|
172
|
+
firstPartyWorkerDevFacade,
|
|
148
173
|
]);
|
|
149
174
|
return bundle;
|
|
150
175
|
}
|
|
@@ -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
|
+
}
|