wrangler 2.3.2 → 2.4.1
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 +2 -2
- package/src/__tests__/dev.test.tsx +27 -0
- package/src/__tests__/index.test.ts +2 -0
- package/src/__tests__/metrics.test.ts +1 -1
- package/src/__tests__/pages.test.ts +55 -1
- package/src/api/dev.ts +2 -0
- package/src/bundle.ts +0 -7
- package/src/dev/dev.tsx +3 -1
- package/src/dev/local.tsx +165 -27
- package/src/dev/start-server.ts +20 -8
- package/src/dev/use-esbuild.ts +0 -4
- package/src/dev.tsx +41 -4
- package/src/dialogs.tsx +1 -2
- package/src/index.tsx +1 -2
- package/src/metrics/metrics-config.ts +2 -2
- package/src/pages/publish.tsx +20 -0
- package/src/publish/publish.ts +0 -1
- package/wrangler-dist/cli.d.ts +2 -0
- package/wrangler-dist/cli.js +4803 -4693
- package/templates/experimental-local-cache-stubs.js +0 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wrangler",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "Command-line interface for all things Cloudflare Workers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wrangler",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"@databases/sql": "^3.2.0",
|
|
120
120
|
"@iarna/toml": "^3.0.0",
|
|
121
121
|
"@microsoft/api-extractor": "^7.28.3",
|
|
122
|
-
"@miniflare/tre": "^3.0.0-next.
|
|
122
|
+
"@miniflare/tre": "^3.0.0-next.7",
|
|
123
123
|
"@types/better-sqlite3": "^7.6.0",
|
|
124
124
|
"@types/busboy": "^1.5.0",
|
|
125
125
|
"@types/command-exists": "^1.2.0",
|
|
@@ -830,6 +830,31 @@ describe("wrangler dev", () => {
|
|
|
830
830
|
});
|
|
831
831
|
|
|
832
832
|
describe("inspector port", () => {
|
|
833
|
+
it("should connect WebSocket server with --experimental-local", async () => {
|
|
834
|
+
writeWranglerToml({
|
|
835
|
+
main: "./index.js",
|
|
836
|
+
});
|
|
837
|
+
fs.writeFileSync(
|
|
838
|
+
"index.js",
|
|
839
|
+
`export default {
|
|
840
|
+
async fetch(request, env, ctx ){
|
|
841
|
+
console.log('Hello World LOGGING');
|
|
842
|
+
},
|
|
843
|
+
};`
|
|
844
|
+
);
|
|
845
|
+
await runWrangler("dev --experimental-local");
|
|
846
|
+
|
|
847
|
+
expect((Dev as jest.Mock).mock.calls[0][0].inspectorPort).toEqual(9229);
|
|
848
|
+
expect(std).toMatchInlineSnapshot(`
|
|
849
|
+
Object {
|
|
850
|
+
"debug": "",
|
|
851
|
+
"err": "",
|
|
852
|
+
"out": "",
|
|
853
|
+
"warn": "",
|
|
854
|
+
}
|
|
855
|
+
`);
|
|
856
|
+
});
|
|
857
|
+
|
|
833
858
|
it("should use 9229 as the default port", async () => {
|
|
834
859
|
writeWranglerToml({
|
|
835
860
|
main: "index.js",
|
|
@@ -1178,10 +1203,12 @@ describe("wrangler dev", () => {
|
|
|
1178
1203
|
--tsconfig Path to a custom tsconfig.json file [string]
|
|
1179
1204
|
-l, --local Run on my machine [boolean] [default: false]
|
|
1180
1205
|
--experimental-local Run on my machine using the Cloudflare Workers runtime [boolean] [default: false]
|
|
1206
|
+
--experimental-local-remote-kv Read/write KV data from/to real namespaces on the Cloudflare network [boolean] [default: false]
|
|
1181
1207
|
--minify Minify the script [boolean]
|
|
1182
1208
|
--node-compat Enable node.js compatibility [boolean]
|
|
1183
1209
|
--persist Enable persistence for local mode, using default path: .wrangler/state [boolean]
|
|
1184
1210
|
--persist-to Specify directory to use for local persistence (implies --persist) [string]
|
|
1211
|
+
--live-reload Auto reload HTML pages when change is detected in local mode [boolean]
|
|
1185
1212
|
--test-scheduled Test scheduled events by visiting /__scheduled in browser [boolean] [default: false]
|
|
1186
1213
|
--log-level Specify logging level [choices: \\"debug\\", \\"info\\", \\"log\\", \\"warn\\", \\"error\\", \\"none\\"] [default: \\"log\\"]",
|
|
1187
1214
|
"warn": "",
|
|
@@ -51,6 +51,7 @@ describe("wrangler", () => {
|
|
|
51
51
|
wrangler logout 🚪 Logout from Cloudflare
|
|
52
52
|
wrangler whoami 🕵️ Retrieve your user info and test your auth config
|
|
53
53
|
wrangler types 📝 Generate types from bindings & module rules in config
|
|
54
|
+
wrangler deployments 🚢 Displays the 10 most recent deployments for a worker
|
|
54
55
|
|
|
55
56
|
Flags:
|
|
56
57
|
-c, --config Path to .toml configuration file [string]
|
|
@@ -96,6 +97,7 @@ describe("wrangler", () => {
|
|
|
96
97
|
wrangler logout 🚪 Logout from Cloudflare
|
|
97
98
|
wrangler whoami 🕵️ Retrieve your user info and test your auth config
|
|
98
99
|
wrangler types 📝 Generate types from bindings & module rules in config
|
|
100
|
+
wrangler deployments 🚢 Displays the 10 most recent deployments for a worker
|
|
99
101
|
|
|
100
102
|
Flags:
|
|
101
103
|
-c, --config Path to .toml configuration file [string]
|
|
@@ -364,7 +364,7 @@ describe("metrics", () => {
|
|
|
364
364
|
|
|
365
365
|
expect(std.out).toMatchInlineSnapshot(`
|
|
366
366
|
"Usage metrics tracking has changed since you last granted permission.
|
|
367
|
-
Your choice has been saved in the following file:
|
|
367
|
+
Your choice has been saved in the following file: test-xdg-config/metrics.json.
|
|
368
368
|
|
|
369
369
|
You can override the user level setting for a project in \`wrangler.toml\`:
|
|
370
370
|
|
|
@@ -1165,16 +1165,21 @@ describe("pages", () => {
|
|
|
1165
1165
|
const body = init.body as FormData;
|
|
1166
1166
|
const manifest = JSON.parse(body.get("manifest") as string);
|
|
1167
1167
|
|
|
1168
|
-
// for Functions projects, we auto-generate a `_worker.js
|
|
1168
|
+
// for Functions projects, we auto-generate a `_worker.js`,
|
|
1169
|
+
// `functions-filepath-routing-config.json`, and `_routes.json`
|
|
1169
1170
|
// file, based on the contents of `/functions`
|
|
1170
1171
|
const generatedWorkerJS = body.get("_worker.js") as Blob;
|
|
1171
1172
|
const generatedRoutesJSON = await (
|
|
1172
1173
|
body.get("_routes.json") as Blob
|
|
1173
1174
|
).text();
|
|
1175
|
+
const generatedFilepathRoutingConfig = await (
|
|
1176
|
+
body.get("functions-filepath-routing-config.json") as Blob
|
|
1177
|
+
).text();
|
|
1174
1178
|
|
|
1175
1179
|
// make sure this is all we uploaded
|
|
1176
1180
|
expect([...body.keys()]).toEqual([
|
|
1177
1181
|
"manifest",
|
|
1182
|
+
"functions-filepath-routing-config.json",
|
|
1178
1183
|
"_worker.js",
|
|
1179
1184
|
"_routes.json",
|
|
1180
1185
|
]);
|
|
@@ -1202,6 +1207,25 @@ describe("pages", () => {
|
|
|
1202
1207
|
include: ["/hello"],
|
|
1203
1208
|
exclude: [],
|
|
1204
1209
|
});
|
|
1210
|
+
|
|
1211
|
+
// Make sure the routing config is valid json
|
|
1212
|
+
const parsedFilepathRoutingConfig = JSON.parse(
|
|
1213
|
+
generatedFilepathRoutingConfig
|
|
1214
|
+
);
|
|
1215
|
+
// The actual shape doesn't matter that much since this
|
|
1216
|
+
// is only used for display in Dash, but it's still useful for
|
|
1217
|
+
// tracking unexpected changes to this config.
|
|
1218
|
+
expect(parsedFilepathRoutingConfig).toStrictEqual({
|
|
1219
|
+
routes: [
|
|
1220
|
+
{
|
|
1221
|
+
routePath: "/hello",
|
|
1222
|
+
mountPath: "/",
|
|
1223
|
+
method: "",
|
|
1224
|
+
module: ["hello.js:onRequest"],
|
|
1225
|
+
},
|
|
1226
|
+
],
|
|
1227
|
+
baseURL: "/",
|
|
1228
|
+
});
|
|
1205
1229
|
});
|
|
1206
1230
|
|
|
1207
1231
|
return {
|
|
@@ -1456,10 +1480,14 @@ describe("pages", () => {
|
|
|
1456
1480
|
const customRoutesJSON = await (
|
|
1457
1481
|
body.get("_routes.json") as Blob
|
|
1458
1482
|
).text();
|
|
1483
|
+
const generatedFilepathRoutingConfig = await (
|
|
1484
|
+
body.get("functions-filepath-routing-config.json") as Blob
|
|
1485
|
+
).text();
|
|
1459
1486
|
|
|
1460
1487
|
// make sure this is all we uploaded
|
|
1461
1488
|
expect([...body.keys()]).toEqual([
|
|
1462
1489
|
"manifest",
|
|
1490
|
+
"functions-filepath-routing-config.json",
|
|
1463
1491
|
"_worker.js",
|
|
1464
1492
|
"_routes.json",
|
|
1465
1493
|
]);
|
|
@@ -1481,6 +1509,32 @@ describe("pages", () => {
|
|
|
1481
1509
|
include: ["/hello"],
|
|
1482
1510
|
exclude: [],
|
|
1483
1511
|
});
|
|
1512
|
+
|
|
1513
|
+
// Make sure the routing config is valid json
|
|
1514
|
+
const parsedFilepathRoutingConfig = JSON.parse(
|
|
1515
|
+
generatedFilepathRoutingConfig
|
|
1516
|
+
);
|
|
1517
|
+
// The actual shape doesn't matter that much since this
|
|
1518
|
+
// is only used for display in Dash, but it's still useful for
|
|
1519
|
+
// tracking unexpected changes to this config.
|
|
1520
|
+
console.log(generatedFilepathRoutingConfig);
|
|
1521
|
+
expect(parsedFilepathRoutingConfig).toStrictEqual({
|
|
1522
|
+
routes: [
|
|
1523
|
+
{
|
|
1524
|
+
routePath: "/goodbye",
|
|
1525
|
+
mountPath: "/",
|
|
1526
|
+
method: "",
|
|
1527
|
+
module: ["goodbye.ts:onRequest"],
|
|
1528
|
+
},
|
|
1529
|
+
{
|
|
1530
|
+
routePath: "/hello",
|
|
1531
|
+
mountPath: "/",
|
|
1532
|
+
method: "",
|
|
1533
|
+
module: ["hello.js:onRequest"],
|
|
1534
|
+
},
|
|
1535
|
+
],
|
|
1536
|
+
baseURL: "/",
|
|
1537
|
+
});
|
|
1484
1538
|
});
|
|
1485
1539
|
|
|
1486
1540
|
return {
|
package/src/api/dev.ts
CHANGED
package/src/bundle.ts
CHANGED
|
@@ -97,7 +97,6 @@ export async function bundleWorker(
|
|
|
97
97
|
targetConsumer: "dev" | "publish";
|
|
98
98
|
local: boolean;
|
|
99
99
|
testScheduled?: boolean;
|
|
100
|
-
experimentalLocalStubCache?: boolean;
|
|
101
100
|
inject?: string[];
|
|
102
101
|
loader?: Record<string, string>;
|
|
103
102
|
sourcemap?: esbuild.CommonOptions["sourcemap"];
|
|
@@ -125,7 +124,6 @@ export async function bundleWorker(
|
|
|
125
124
|
firstPartyWorkerDevFacade,
|
|
126
125
|
targetConsumer,
|
|
127
126
|
testScheduled,
|
|
128
|
-
experimentalLocalStubCache,
|
|
129
127
|
inject: injectOption,
|
|
130
128
|
loader,
|
|
131
129
|
sourcemap,
|
|
@@ -277,11 +275,6 @@ export async function bundleWorker(
|
|
|
277
275
|
|
|
278
276
|
const inject: string[] = injectOption ?? [];
|
|
279
277
|
if (checkFetch) inject.push(checkedFetchFileToInject);
|
|
280
|
-
if (experimentalLocalStubCache) {
|
|
281
|
-
inject.push(
|
|
282
|
-
path.resolve(getBasePath(), "templates/experimental-local-cache-stubs.js")
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
278
|
|
|
286
279
|
const buildOptions: esbuild.BuildOptions & { metafile: true } = {
|
|
287
280
|
entryPoints: [inputEntry.file],
|
package/src/dev/dev.tsx
CHANGED
|
@@ -155,6 +155,7 @@ export type DevProps = {
|
|
|
155
155
|
sendMetrics: boolean | undefined;
|
|
156
156
|
testScheduled: boolean | undefined;
|
|
157
157
|
experimentalLocal: boolean | undefined;
|
|
158
|
+
experimentalLocalRemoteKv: boolean | undefined;
|
|
158
159
|
};
|
|
159
160
|
|
|
160
161
|
export function DevImplementation(props: DevProps): JSX.Element {
|
|
@@ -287,7 +288,6 @@ function DevSession(props: DevSessionProps) {
|
|
|
287
288
|
// Enable the bundling to know whether we are using dev or publish
|
|
288
289
|
targetConsumer: "dev",
|
|
289
290
|
testScheduled: props.testScheduled ?? false,
|
|
290
|
-
experimentalLocalStubCache: props.local && props.experimentalLocal,
|
|
291
291
|
});
|
|
292
292
|
|
|
293
293
|
// TODO(queues) support remote wrangler dev
|
|
@@ -326,6 +326,8 @@ function DevSession(props: DevSessionProps) {
|
|
|
326
326
|
onReady={props.onReady}
|
|
327
327
|
enablePagesAssetsServiceBinding={props.enablePagesAssetsServiceBinding}
|
|
328
328
|
experimentalLocal={props.experimentalLocal}
|
|
329
|
+
accountId={props.accountId}
|
|
330
|
+
experimentalLocalRemoteKv={props.experimentalLocalRemoteKv}
|
|
329
331
|
/>
|
|
330
332
|
) : (
|
|
331
333
|
<Remote
|
package/src/dev/local.tsx
CHANGED
|
@@ -4,10 +4,10 @@ import { realpathSync } from "node:fs";
|
|
|
4
4
|
import { readFile, writeFile } from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import chalk from "chalk";
|
|
7
|
-
import getPort from "get-port";
|
|
8
7
|
import { npxImport } from "npx-import";
|
|
9
8
|
import { useState, useEffect, useRef } from "react";
|
|
10
9
|
import onExit from "signal-exit";
|
|
10
|
+
import { performApiFetch } from "../cfetch/internal";
|
|
11
11
|
import { registerWorker } from "../dev-registry";
|
|
12
12
|
import useInspector from "../inspect";
|
|
13
13
|
import { logger } from "../logger";
|
|
@@ -17,8 +17,10 @@ import {
|
|
|
17
17
|
} from "../module-collection";
|
|
18
18
|
import { getBasePath } from "../paths";
|
|
19
19
|
import { waitForPortToBeAvailable } from "../proxy";
|
|
20
|
+
import { requireAuth } from "../user";
|
|
20
21
|
import type { Config } from "../config";
|
|
21
22
|
import type { WorkerRegistry } from "../dev-registry";
|
|
23
|
+
import type { LoggerLevel } from "../logger";
|
|
22
24
|
import type { EnablePagesAssetsServiceBindingOptions } from "../miniflare-cli";
|
|
23
25
|
import type { AssetPaths } from "../sites";
|
|
24
26
|
import type {
|
|
@@ -38,9 +40,12 @@ import type { EsbuildBundle } from "./use-esbuild";
|
|
|
38
40
|
import type {
|
|
39
41
|
Miniflare as Miniflare3Type,
|
|
40
42
|
MiniflareOptions as Miniflare3Options,
|
|
43
|
+
Log as Miniflare3LogType,
|
|
44
|
+
CloudflareFetch,
|
|
41
45
|
} from "@miniflare/tre";
|
|
42
46
|
import type { MiniflareOptions } from "miniflare";
|
|
43
47
|
import type { ChildProcess } from "node:child_process";
|
|
48
|
+
import type { RequestInit } from "undici";
|
|
44
49
|
|
|
45
50
|
export interface LocalProps {
|
|
46
51
|
name: string | undefined;
|
|
@@ -67,15 +72,29 @@ export interface LocalProps {
|
|
|
67
72
|
logPrefix?: string;
|
|
68
73
|
enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions;
|
|
69
74
|
testScheduled?: boolean;
|
|
70
|
-
experimentalLocal
|
|
75
|
+
experimentalLocal: boolean | undefined;
|
|
76
|
+
accountId: string | undefined; // Account ID? In local mode??? :exploding_head:
|
|
77
|
+
experimentalLocalRemoteKv: boolean | undefined;
|
|
71
78
|
}
|
|
72
79
|
|
|
80
|
+
type InspectorJSON = {
|
|
81
|
+
id: string;
|
|
82
|
+
title: string;
|
|
83
|
+
type: "node";
|
|
84
|
+
description: string;
|
|
85
|
+
webSocketDebuggerUrl: string;
|
|
86
|
+
devtoolsFrontendUrl: string;
|
|
87
|
+
devtoolsFrontendUrlCompat: string;
|
|
88
|
+
faviconUrl: string;
|
|
89
|
+
url: string;
|
|
90
|
+
}[];
|
|
91
|
+
|
|
73
92
|
export function Local(props: LocalProps) {
|
|
74
93
|
const { inspectorUrl } = useLocalWorker(props);
|
|
75
94
|
useInspector({
|
|
76
95
|
inspectorUrl,
|
|
77
96
|
port: props.inspectorPort,
|
|
78
|
-
logToTerminal: false,
|
|
97
|
+
logToTerminal: props.experimentalLocal ?? false,
|
|
79
98
|
});
|
|
80
99
|
return null;
|
|
81
100
|
}
|
|
@@ -105,6 +124,8 @@ function useLocalWorker({
|
|
|
105
124
|
logPrefix,
|
|
106
125
|
enablePagesAssetsServiceBinding,
|
|
107
126
|
experimentalLocal,
|
|
127
|
+
accountId,
|
|
128
|
+
experimentalLocalRemoteKv,
|
|
108
129
|
}: LocalProps) {
|
|
109
130
|
// TODO: pass vars via command line
|
|
110
131
|
const local = useRef<ChildProcess>();
|
|
@@ -209,11 +230,24 @@ function useLocalWorker({
|
|
|
209
230
|
});
|
|
210
231
|
|
|
211
232
|
if (experimentalLocal) {
|
|
212
|
-
const
|
|
233
|
+
const log = await buildMiniflare3Logger(logPrefix);
|
|
234
|
+
const mf3Options = await transformMf2OptionsToMf3Options({
|
|
235
|
+
miniflare2Options: options,
|
|
236
|
+
format,
|
|
237
|
+
bundle,
|
|
238
|
+
log,
|
|
239
|
+
kvNamespaces: bindings?.kv_namespaces,
|
|
240
|
+
r2Buckets: bindings?.r2_buckets,
|
|
241
|
+
authenticatedAccountId: accountId,
|
|
242
|
+
kvRemote: experimentalLocalRemoteKv,
|
|
243
|
+
inspectorPort,
|
|
244
|
+
});
|
|
245
|
+
|
|
213
246
|
const current = experimentalLocalRef.current;
|
|
247
|
+
|
|
214
248
|
if (current === undefined) {
|
|
215
249
|
// If we don't have an active Miniflare instance, create a new one
|
|
216
|
-
const Miniflare = await
|
|
250
|
+
const { Miniflare } = await getMiniflare3();
|
|
217
251
|
if (abortController.signal.aborted) return;
|
|
218
252
|
const mf = new Miniflare(mf3Options);
|
|
219
253
|
experimentalLocalRef.current = mf;
|
|
@@ -230,6 +264,34 @@ function useLocalWorker({
|
|
|
230
264
|
logger.log("⎔ Reloading experimental local server.");
|
|
231
265
|
await current.setOptions(mf3Options);
|
|
232
266
|
}
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
// fetch the inspector JSON response from the DevTools Inspector protocol
|
|
270
|
+
const inspectorJSONArr = (await (
|
|
271
|
+
await fetch(`http://127.0.0.1:${inspectorPort}/json`)
|
|
272
|
+
).json()) as InspectorJSON;
|
|
273
|
+
|
|
274
|
+
const foundInspectorURL = inspectorJSONArr?.find((inspectorJSON) =>
|
|
275
|
+
inspectorJSON.id.startsWith("core:user")
|
|
276
|
+
)?.webSocketDebuggerUrl;
|
|
277
|
+
if (foundInspectorURL === undefined) {
|
|
278
|
+
setInspectorUrl(undefined);
|
|
279
|
+
} else {
|
|
280
|
+
const url = new URL(foundInspectorURL);
|
|
281
|
+
// Force inspector URL to be different on each reload so `useEffect`
|
|
282
|
+
// in `useInspector` is re-run to connect to newly restarted
|
|
283
|
+
// `workerd` server when updating options. Can't use a query param
|
|
284
|
+
// here as that seems to cause an infinite connection loop, can't
|
|
285
|
+
// use a hash as those are forbidden by `ws`, so username it is.
|
|
286
|
+
url.username = `${Date.now()}-${Math.floor(
|
|
287
|
+
Math.random() * Number.MAX_SAFE_INTEGER
|
|
288
|
+
)}`;
|
|
289
|
+
setInspectorUrl(url.toString());
|
|
290
|
+
}
|
|
291
|
+
} catch (error: unknown) {
|
|
292
|
+
logger.error("Error attempting to retrieve Debugger URL:", error);
|
|
293
|
+
}
|
|
294
|
+
|
|
233
295
|
return;
|
|
234
296
|
}
|
|
235
297
|
|
|
@@ -367,6 +429,8 @@ function useLocalWorker({
|
|
|
367
429
|
onReady,
|
|
368
430
|
enablePagesAssetsServiceBinding,
|
|
369
431
|
experimentalLocal,
|
|
432
|
+
accountId,
|
|
433
|
+
experimentalLocalRemoteKv,
|
|
370
434
|
]);
|
|
371
435
|
|
|
372
436
|
// Rather than disposing the Miniflare instance on every reload, only dispose
|
|
@@ -683,24 +747,86 @@ export function setupNodeOptions({
|
|
|
683
747
|
return nodeOptions;
|
|
684
748
|
}
|
|
685
749
|
|
|
686
|
-
|
|
687
|
-
|
|
750
|
+
export interface SetupMiniflare3Options {
|
|
751
|
+
// Regular Miniflare 2 options to transform
|
|
752
|
+
miniflare2Options: MiniflareOptions;
|
|
753
|
+
// Miniflare 3 requires all modules to be manually specified
|
|
754
|
+
format: CfScriptFormat;
|
|
755
|
+
bundle: EsbuildBundle;
|
|
756
|
+
|
|
757
|
+
// Miniflare's logger
|
|
758
|
+
log: Miniflare3LogType;
|
|
759
|
+
|
|
760
|
+
// Miniflare 3 accepts namespace/bucket names in addition to binding names.
|
|
761
|
+
// This means multiple workers persisting to the same location can have
|
|
762
|
+
// different binding names for the same namespace/bucket. Therefore, we need
|
|
763
|
+
// the full KV/R2 arrays. This is also required for remote KV storage, as
|
|
764
|
+
// we need actual namespace IDs to connect to.
|
|
765
|
+
kvNamespaces: CfKvNamespace[] | undefined;
|
|
766
|
+
r2Buckets: CfR2Bucket[] | undefined;
|
|
767
|
+
|
|
768
|
+
// Account ID to use for authenticated Cloudflare fetch. If true, prompt
|
|
769
|
+
// user for ID if multiple available.
|
|
770
|
+
authenticatedAccountId: string | true | undefined;
|
|
771
|
+
// Whether to read/write from/to real KV namespaces
|
|
772
|
+
kvRemote: boolean | undefined;
|
|
773
|
+
|
|
774
|
+
// Port to start DevTools inspector server on
|
|
775
|
+
inspectorPort: number;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
export async function buildMiniflare3Logger(
|
|
779
|
+
logPrefix?: string
|
|
780
|
+
): Promise<Miniflare3LogType> {
|
|
781
|
+
const { Log, NoOpLog, LogLevel } = await getMiniflare3();
|
|
782
|
+
|
|
783
|
+
let level = logger.loggerLevel.toUpperCase() as Uppercase<LoggerLevel>;
|
|
784
|
+
if (level === "LOG") level = "INFO";
|
|
785
|
+
const logLevel = LogLevel[level];
|
|
786
|
+
|
|
787
|
+
return logLevel === LogLevel.NONE
|
|
788
|
+
? new NoOpLog()
|
|
789
|
+
: new Log(logLevel, { prefix: logPrefix });
|
|
688
790
|
}
|
|
689
791
|
|
|
690
|
-
export async function
|
|
691
|
-
|
|
692
|
-
format
|
|
693
|
-
bundle
|
|
694
|
-
|
|
792
|
+
export async function transformMf2OptionsToMf3Options({
|
|
793
|
+
miniflare2Options,
|
|
794
|
+
format,
|
|
795
|
+
bundle,
|
|
796
|
+
log,
|
|
797
|
+
kvNamespaces,
|
|
798
|
+
r2Buckets,
|
|
799
|
+
authenticatedAccountId,
|
|
800
|
+
kvRemote,
|
|
801
|
+
inspectorPort,
|
|
802
|
+
}: SetupMiniflare3Options): Promise<Miniflare3Options> {
|
|
803
|
+
// Build authenticated Cloudflare API fetch function if required
|
|
804
|
+
let cloudflareFetch: CloudflareFetch | undefined;
|
|
805
|
+
if (kvRemote && authenticatedAccountId !== undefined) {
|
|
806
|
+
const preferredAccountId =
|
|
807
|
+
authenticatedAccountId === true ? undefined : authenticatedAccountId;
|
|
808
|
+
const accountId = await requireAuth({ account_id: preferredAccountId });
|
|
809
|
+
cloudflareFetch = (resource, searchParams, init) => {
|
|
810
|
+
resource = `/accounts/${accountId}/${resource}`;
|
|
811
|
+
// Miniflare and Wrangler's `undici` versions may be slightly different,
|
|
812
|
+
// but their `RequestInit` types *should* be compatible
|
|
813
|
+
return performApiFetch(resource, init as RequestInit, searchParams);
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
|
|
695
817
|
const options: Miniflare3Options = {
|
|
696
|
-
...
|
|
818
|
+
...miniflare2Options,
|
|
697
819
|
// Miniflare 3 distinguishes between binding name and namespace/bucket IDs.
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
r2Buckets:
|
|
702
|
-
|
|
820
|
+
kvNamespaces: Object.fromEntries(
|
|
821
|
+
kvNamespaces?.map(({ binding, id }) => [binding, id]) ?? []
|
|
822
|
+
),
|
|
823
|
+
r2Buckets: Object.fromEntries(
|
|
824
|
+
r2Buckets?.map(({ binding, bucket_name }) => [binding, bucket_name]) ?? []
|
|
825
|
+
),
|
|
826
|
+
inspectorPort,
|
|
703
827
|
verbose: true,
|
|
828
|
+
cloudflareFetch,
|
|
829
|
+
log,
|
|
704
830
|
};
|
|
705
831
|
|
|
706
832
|
if (format === "modules") {
|
|
@@ -729,18 +855,30 @@ export async function transformLocalOptions(
|
|
|
729
855
|
];
|
|
730
856
|
}
|
|
731
857
|
|
|
858
|
+
if (kvRemote) {
|
|
859
|
+
// `kvPersist` is always assigned a truthy value in `setupMiniflareOptions`
|
|
860
|
+
assert(options.kvPersist);
|
|
861
|
+
const kvRemoteCache =
|
|
862
|
+
options.kvPersist === true
|
|
863
|
+
? // If storing in temporary directory, find this path from the bundle
|
|
864
|
+
// output path
|
|
865
|
+
path.join(path.dirname(bundle.path), ".mf", "kv-remote")
|
|
866
|
+
: // Otherwise, `kvPersist` looks like `.../kv`, so rewrite it to
|
|
867
|
+
// `kv-remote` since the expected metadata format for remote storage
|
|
868
|
+
// is different to local
|
|
869
|
+
path.join(path.dirname(options.kvPersist), "kv-remote");
|
|
870
|
+
options.kvPersist = `remote:?cache=${encodeURIComponent(kvRemoteCache)}`;
|
|
871
|
+
}
|
|
872
|
+
|
|
732
873
|
return options;
|
|
733
874
|
}
|
|
734
875
|
|
|
735
876
|
// Caching of the `npx-import`ed `@miniflare/tre` package
|
|
736
877
|
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
737
|
-
let
|
|
738
|
-
export async function
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
>("@miniflare/tre@3.0.0-next.5"));
|
|
744
|
-
}
|
|
745
|
-
return Miniflare;
|
|
878
|
+
let miniflare3Module: typeof import("@miniflare/tre");
|
|
879
|
+
export async function getMiniflare3(): Promise<
|
|
880
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
881
|
+
typeof import("@miniflare/tre")
|
|
882
|
+
> {
|
|
883
|
+
return (miniflare3Module ??= await npxImport("@miniflare/tre@3.0.0-next.7"));
|
|
746
884
|
}
|
package/src/dev/start-server.ts
CHANGED
|
@@ -17,10 +17,11 @@ import { logger } from "../logger";
|
|
|
17
17
|
import { waitForPortToBeAvailable } from "../proxy";
|
|
18
18
|
import {
|
|
19
19
|
setupBindings,
|
|
20
|
-
|
|
20
|
+
getMiniflare3,
|
|
21
|
+
buildMiniflare3Logger,
|
|
21
22
|
setupMiniflareOptions,
|
|
22
23
|
setupNodeOptions,
|
|
23
|
-
|
|
24
|
+
transformMf2OptionsToMf3Options,
|
|
24
25
|
} from "./local";
|
|
25
26
|
import { startRemoteServer } from "./remote";
|
|
26
27
|
import { validateDevProps } from "./validate-dev-props";
|
|
@@ -98,7 +99,6 @@ export async function startDevServer(
|
|
|
98
99
|
services: props.bindings.services,
|
|
99
100
|
firstPartyWorkerDevFacade: props.firstPartyWorker,
|
|
100
101
|
testScheduled: props.testScheduled,
|
|
101
|
-
experimentalLocalStubCache: props.experimentalLocal,
|
|
102
102
|
});
|
|
103
103
|
|
|
104
104
|
if (props.local) {
|
|
@@ -127,6 +127,8 @@ export async function startDevServer(
|
|
|
127
127
|
usageModel: props.usageModel,
|
|
128
128
|
workerDefinitions,
|
|
129
129
|
experimentalLocal: props.experimentalLocal,
|
|
130
|
+
accountId: props.accountId,
|
|
131
|
+
experimentalLocalRemoteKv: props.experimentalLocalRemoteKv,
|
|
130
132
|
});
|
|
131
133
|
|
|
132
134
|
return {
|
|
@@ -204,7 +206,6 @@ async function runEsbuild({
|
|
|
204
206
|
services,
|
|
205
207
|
firstPartyWorkerDevFacade,
|
|
206
208
|
testScheduled,
|
|
207
|
-
experimentalLocalStubCache,
|
|
208
209
|
}: {
|
|
209
210
|
entry: Entry;
|
|
210
211
|
destination: string | undefined;
|
|
@@ -223,7 +224,6 @@ async function runEsbuild({
|
|
|
223
224
|
workerDefinitions: WorkerRegistry;
|
|
224
225
|
firstPartyWorkerDevFacade: boolean | undefined;
|
|
225
226
|
testScheduled?: boolean;
|
|
226
|
-
experimentalLocalStubCache: boolean | undefined;
|
|
227
227
|
}): Promise<EsbuildBundle | undefined> {
|
|
228
228
|
if (!destination) return;
|
|
229
229
|
|
|
@@ -264,7 +264,6 @@ async function runEsbuild({
|
|
|
264
264
|
targetConsumer: "dev", // We are starting a dev server
|
|
265
265
|
local: true,
|
|
266
266
|
testScheduled,
|
|
267
|
-
experimentalLocalStubCache,
|
|
268
267
|
});
|
|
269
268
|
|
|
270
269
|
return {
|
|
@@ -303,6 +302,8 @@ export async function startLocalServer({
|
|
|
303
302
|
logPrefix,
|
|
304
303
|
enablePagesAssetsServiceBinding,
|
|
305
304
|
experimentalLocal,
|
|
305
|
+
accountId,
|
|
306
|
+
experimentalLocalRemoteKv,
|
|
306
307
|
}: LocalProps) {
|
|
307
308
|
let local: ChildProcess | undefined;
|
|
308
309
|
let experimentalLocalRef: Miniflare3Type | undefined;
|
|
@@ -396,8 +397,19 @@ export async function startLocalServer({
|
|
|
396
397
|
});
|
|
397
398
|
|
|
398
399
|
if (experimentalLocal) {
|
|
399
|
-
const
|
|
400
|
-
const
|
|
400
|
+
const log = await buildMiniflare3Logger(logPrefix);
|
|
401
|
+
const mf3Options = await transformMf2OptionsToMf3Options({
|
|
402
|
+
miniflare2Options: options,
|
|
403
|
+
format,
|
|
404
|
+
bundle,
|
|
405
|
+
log,
|
|
406
|
+
kvNamespaces: bindings?.kv_namespaces,
|
|
407
|
+
r2Buckets: bindings?.r2_buckets,
|
|
408
|
+
authenticatedAccountId: accountId,
|
|
409
|
+
kvRemote: experimentalLocalRemoteKv,
|
|
410
|
+
inspectorPort,
|
|
411
|
+
});
|
|
412
|
+
const { Miniflare } = await getMiniflare3();
|
|
401
413
|
const mf = new Miniflare(mf3Options);
|
|
402
414
|
const runtimeURL = await mf.ready;
|
|
403
415
|
experimentalLocalRef = mf;
|
package/src/dev/use-esbuild.ts
CHANGED
|
@@ -41,7 +41,6 @@ export function useEsbuild({
|
|
|
41
41
|
local,
|
|
42
42
|
targetConsumer,
|
|
43
43
|
testScheduled,
|
|
44
|
-
experimentalLocalStubCache,
|
|
45
44
|
}: {
|
|
46
45
|
entry: Entry;
|
|
47
46
|
destination: string | undefined;
|
|
@@ -63,7 +62,6 @@ export function useEsbuild({
|
|
|
63
62
|
local: boolean;
|
|
64
63
|
targetConsumer: "dev" | "publish";
|
|
65
64
|
testScheduled: boolean;
|
|
66
|
-
experimentalLocalStubCache: boolean | undefined;
|
|
67
65
|
}): EsbuildBundle | undefined {
|
|
68
66
|
const [bundle, setBundle] = useState<EsbuildBundle>();
|
|
69
67
|
const { exit } = useApp();
|
|
@@ -136,7 +134,6 @@ export function useEsbuild({
|
|
|
136
134
|
local,
|
|
137
135
|
targetConsumer,
|
|
138
136
|
testScheduled,
|
|
139
|
-
experimentalLocalStubCache,
|
|
140
137
|
});
|
|
141
138
|
|
|
142
139
|
// Capture the `stop()` method to use as the `useEffect()` destructor.
|
|
@@ -198,7 +195,6 @@ export function useEsbuild({
|
|
|
198
195
|
local,
|
|
199
196
|
targetConsumer,
|
|
200
197
|
testScheduled,
|
|
201
|
-
experimentalLocalStubCache,
|
|
202
198
|
]);
|
|
203
199
|
return bundle;
|
|
204
200
|
}
|