wrangler 2.0.8 → 2.0.12
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/kv-asset-handler.js +1 -0
- package/package.json +3 -1
- package/src/__tests__/configuration.test.ts +255 -142
- package/src/__tests__/dev.test.tsx +88 -58
- package/src/__tests__/index.test.ts +2 -1
- package/src/__tests__/init.test.ts +3 -0
- package/src/__tests__/kv.test.ts +23 -2
- package/src/__tests__/pages.test.ts +98 -1
- package/src/__tests__/publish.test.ts +514 -162
- package/src/__tests__/whoami.test.tsx +34 -0
- package/src/bundle.ts +9 -5
- package/src/cfetch/internal.ts +6 -9
- package/src/config/config.ts +1 -1
- package/src/config/environment.ts +1 -1
- package/src/config/validation-helpers.ts +10 -1
- package/src/config/validation.ts +22 -13
- package/src/create-worker-preview.ts +15 -15
- package/src/dev/dev.tsx +32 -56
- package/src/dev/local.tsx +10 -7
- package/src/dev/remote.tsx +30 -17
- package/src/dev/use-esbuild.ts +1 -4
- package/src/index.tsx +239 -244
- package/src/kv.ts +1 -1
- package/src/pages.tsx +295 -229
- package/src/parse.ts +21 -1
- package/src/proxy.ts +19 -6
- package/src/publish.ts +154 -16
- package/src/sites.tsx +49 -18
- package/src/user.tsx +12 -1
- package/src/whoami.tsx +3 -2
- package/src/worker.ts +2 -1
- package/src/zones.ts +73 -0
- package/templates/static-asset-facade.js +1 -5
- package/wrangler-dist/cli.js +73693 -73458
- package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
- package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
- package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
- package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
- package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
- package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
- package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
- package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
- package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
- package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
- package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
- package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
- package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
- package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
- package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
- package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
- package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
- package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
- package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
- package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
- package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
- package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
- package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
- package/vendor/wrangler-mime/CHANGELOG.md +0 -289
- package/vendor/wrangler-mime/LICENSE +0 -21
- package/vendor/wrangler-mime/Mime.js +0 -97
- package/vendor/wrangler-mime/README.md +0 -187
- package/vendor/wrangler-mime/cli.js +0 -46
- package/vendor/wrangler-mime/index.js +0 -4
- package/vendor/wrangler-mime/lite.js +0 -4
- package/vendor/wrangler-mime/package.json +0 -52
- package/vendor/wrangler-mime/types/other.js +0 -1
- package/vendor/wrangler-mime/types/standard.js +0 -1
|
@@ -9,6 +9,8 @@ import { runInTempDir } from "./helpers/run-in-tmp";
|
|
|
9
9
|
import type { UserInfo } from "../whoami";
|
|
10
10
|
|
|
11
11
|
describe("getUserInfo()", () => {
|
|
12
|
+
const ENV_COPY = process.env;
|
|
13
|
+
|
|
12
14
|
runInTempDir({ homedir: "./home" });
|
|
13
15
|
const std = mockConsoleMethods();
|
|
14
16
|
const { setIsTTY } = useMockIsTTY();
|
|
@@ -17,6 +19,10 @@ describe("getUserInfo()", () => {
|
|
|
17
19
|
setIsTTY(true);
|
|
18
20
|
});
|
|
19
21
|
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
process.env = ENV_COPY;
|
|
24
|
+
});
|
|
25
|
+
|
|
20
26
|
it("should return undefined if there is no config file", async () => {
|
|
21
27
|
const userInfo = await getUserInfo();
|
|
22
28
|
expect(userInfo).toBeUndefined();
|
|
@@ -28,6 +34,34 @@ describe("getUserInfo()", () => {
|
|
|
28
34
|
expect(userInfo).toBeUndefined();
|
|
29
35
|
});
|
|
30
36
|
|
|
37
|
+
it("should say it's using an API token when one is set", async () => {
|
|
38
|
+
process.env = {
|
|
39
|
+
CLOUDFLARE_API_TOKEN: "123456789",
|
|
40
|
+
};
|
|
41
|
+
setMockResponse("/user", () => {
|
|
42
|
+
return { email: "user@example.com" };
|
|
43
|
+
});
|
|
44
|
+
setMockResponse("/accounts", () => {
|
|
45
|
+
return [
|
|
46
|
+
{ name: "Account One", id: "account-1" },
|
|
47
|
+
{ name: "Account Two", id: "account-2" },
|
|
48
|
+
{ name: "Account Three", id: "account-3" },
|
|
49
|
+
];
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const userInfo = await getUserInfo();
|
|
53
|
+
expect(userInfo).toEqual({
|
|
54
|
+
authType: "API",
|
|
55
|
+
apiToken: "123456789",
|
|
56
|
+
email: "user@example.com",
|
|
57
|
+
accounts: [
|
|
58
|
+
{ name: "Account One", id: "account-1" },
|
|
59
|
+
{ name: "Account Two", id: "account-2" },
|
|
60
|
+
{ name: "Account Three", id: "account-3" },
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
31
65
|
it("should return the user's email and accounts if authenticated via config token", async () => {
|
|
32
66
|
writeAuthConfigFile({ oauth_token: "some-oauth-token" });
|
|
33
67
|
|
package/src/bundle.ts
CHANGED
|
@@ -154,9 +154,7 @@ export async function bundleWorker(
|
|
|
154
154
|
};
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
type EntryPoint =
|
|
158
|
-
| { stdin: esbuild.StdinOptions; nodePaths: string[] }
|
|
159
|
-
| { entryPoints: string[] };
|
|
157
|
+
type EntryPoint = { stdin: esbuild.StdinOptions } | { entryPoints: string[] };
|
|
160
158
|
|
|
161
159
|
/**
|
|
162
160
|
* Create an object that describes the entry point for esbuild.
|
|
@@ -177,11 +175,17 @@ function getEntryPoint(
|
|
|
177
175
|
path.join(__dirname, "../templates/static-asset-facade.js"),
|
|
178
176
|
"utf8"
|
|
179
177
|
)
|
|
180
|
-
|
|
178
|
+
// on windows, escape backslashes in the path (`\`)
|
|
179
|
+
.replace("__ENTRY_POINT__", entryFile.replaceAll("\\", "\\\\"))
|
|
180
|
+
.replace(
|
|
181
|
+
"__KV_ASSET_HANDLER__",
|
|
182
|
+
path
|
|
183
|
+
.join(__dirname, "../kv-asset-handler.js")
|
|
184
|
+
.replaceAll("\\", "\\\\")
|
|
185
|
+
),
|
|
181
186
|
sourcefile: "static-asset-facade.js",
|
|
182
187
|
resolveDir: path.dirname(entryFile),
|
|
183
188
|
},
|
|
184
|
-
nodePaths: [path.join(__dirname, "../vendor")],
|
|
185
189
|
};
|
|
186
190
|
} else {
|
|
187
191
|
return { entryPoints: [entryFile] };
|
package/src/cfetch/internal.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
1
2
|
import { fetch, Headers } from "undici";
|
|
2
3
|
import { version as wranglerVersion } from "../../package.json";
|
|
3
4
|
import { getEnvironmentVariableFactory } from "../environment-variables";
|
|
4
5
|
import { ParseError, parseJSON } from "../parse";
|
|
5
|
-
import {
|
|
6
|
+
import { loginOrRefreshIfRequired, requireApiToken } from "../user";
|
|
6
7
|
import type { URLSearchParams } from "node:url";
|
|
7
8
|
import type { RequestInit, HeadersInit } from "undici";
|
|
8
9
|
|
|
@@ -30,6 +31,10 @@ export async function fetchInternal<ResponseType>(
|
|
|
30
31
|
queryParams?: URLSearchParams,
|
|
31
32
|
abortSignal?: AbortSignal
|
|
32
33
|
): Promise<ResponseType> {
|
|
34
|
+
assert(
|
|
35
|
+
resource.startsWith("/"),
|
|
36
|
+
`CF API fetch - resource path must start with a "/" but got "${resource}"`
|
|
37
|
+
);
|
|
33
38
|
await requireLoggedIn();
|
|
34
39
|
const apiToken = requireApiToken();
|
|
35
40
|
const headers = cloneHeaders(init.headers);
|
|
@@ -90,14 +95,6 @@ async function requireLoggedIn(): Promise<void> {
|
|
|
90
95
|
}
|
|
91
96
|
}
|
|
92
97
|
|
|
93
|
-
function requireApiToken(): string {
|
|
94
|
-
const authToken = getAPIToken();
|
|
95
|
-
if (!authToken) {
|
|
96
|
-
throw new Error("No API token found.");
|
|
97
|
-
}
|
|
98
|
-
return authToken;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
98
|
function addAuthorizationHeaderIfUnspecified(
|
|
102
99
|
headers: Record<string, string>,
|
|
103
100
|
apiToken: string
|
package/src/config/config.ts
CHANGED
|
@@ -175,7 +175,7 @@ interface EnvironmentInheritable {
|
|
|
175
175
|
/** The directory in which the command is executed. */
|
|
176
176
|
cwd?: string;
|
|
177
177
|
/** The directory to watch for changes while using wrangler dev, defaults to the current working directory */
|
|
178
|
-
watch_dir?: string;
|
|
178
|
+
watch_dir?: string | string[];
|
|
179
179
|
/**
|
|
180
180
|
* Deprecated field previously used to configure the build and upload of the script.
|
|
181
181
|
* @deprecated
|
|
@@ -277,12 +277,21 @@ export const isObjectWith =
|
|
|
277
277
|
!properties.every((prop) => prop in value))
|
|
278
278
|
) {
|
|
279
279
|
diagnostics.errors.push(
|
|
280
|
-
`Expected "${field}" to be of type object, containing properties ${properties}, but got ${JSON.stringify(
|
|
280
|
+
`Expected "${field}" to be of type object, containing only properties ${properties}, but got ${JSON.stringify(
|
|
281
281
|
value
|
|
282
282
|
)}.`
|
|
283
283
|
);
|
|
284
284
|
return false;
|
|
285
285
|
}
|
|
286
|
+
// it's an object with the field as desired,
|
|
287
|
+
// but let's also check for unexpected fields
|
|
288
|
+
if (value !== undefined) {
|
|
289
|
+
const restFields = Object.keys(value).filter(
|
|
290
|
+
(key) => !properties.includes(key)
|
|
291
|
+
);
|
|
292
|
+
validateAdditionalProperties(diagnostics, field, restFields, []);
|
|
293
|
+
}
|
|
294
|
+
|
|
286
295
|
return true;
|
|
287
296
|
};
|
|
288
297
|
|
package/src/config/validation.ts
CHANGED
|
@@ -227,19 +227,23 @@ function normalizeAndValidateBuild(
|
|
|
227
227
|
rawBuild: Config["build"],
|
|
228
228
|
configPath: string | undefined
|
|
229
229
|
): Config["build"] & { deprecatedUpload: DeprecatedUpload } {
|
|
230
|
-
const { command, cwd, watch_dir, upload, ...rest } = rawBuild;
|
|
230
|
+
const { command, cwd, watch_dir = "./src", upload, ...rest } = rawBuild;
|
|
231
231
|
const deprecatedUpload: DeprecatedUpload = { ...upload };
|
|
232
232
|
validateAdditionalProperties(diagnostics, "build", Object.keys(rest), []);
|
|
233
233
|
|
|
234
234
|
validateOptionalProperty(diagnostics, "build", "command", command, "string");
|
|
235
235
|
validateOptionalProperty(diagnostics, "build", "cwd", cwd, "string");
|
|
236
|
-
|
|
237
|
-
diagnostics,
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
236
|
+
if (Array.isArray(watch_dir)) {
|
|
237
|
+
validateTypedArray(diagnostics, "build.watch_dir", watch_dir, "string");
|
|
238
|
+
} else {
|
|
239
|
+
validateOptionalProperty(
|
|
240
|
+
diagnostics,
|
|
241
|
+
"build",
|
|
242
|
+
"watch_dir",
|
|
243
|
+
watch_dir,
|
|
244
|
+
"string"
|
|
245
|
+
);
|
|
246
|
+
}
|
|
243
247
|
|
|
244
248
|
deprecated(
|
|
245
249
|
diagnostics,
|
|
@@ -288,13 +292,18 @@ function normalizeAndValidateBuild(
|
|
|
288
292
|
// - `configPath` will always be defined since `build` can only
|
|
289
293
|
// be configured in `wrangler.toml`, but who knows, that may
|
|
290
294
|
// change in the future, so we do a check anyway
|
|
291
|
-
command
|
|
292
|
-
?
|
|
293
|
-
?
|
|
295
|
+
command && configPath
|
|
296
|
+
? Array.isArray(watch_dir)
|
|
297
|
+
? watch_dir.map((dir) =>
|
|
298
|
+
path.relative(
|
|
299
|
+
process.cwd(),
|
|
300
|
+
path.join(path.dirname(configPath), `${dir}`)
|
|
301
|
+
)
|
|
302
|
+
)
|
|
303
|
+
: path.relative(
|
|
294
304
|
process.cwd(),
|
|
295
|
-
path.join(path.dirname(configPath), watch_dir
|
|
305
|
+
path.join(path.dirname(configPath), `${watch_dir}`)
|
|
296
306
|
)
|
|
297
|
-
: watch_dir || "./src"
|
|
298
307
|
: watch_dir,
|
|
299
308
|
cwd,
|
|
300
309
|
deprecatedUpload,
|
|
@@ -63,7 +63,7 @@ async function sessionToken(
|
|
|
63
63
|
): Promise<CfPreviewToken> {
|
|
64
64
|
const { accountId } = account;
|
|
65
65
|
const initUrl = ctx.zone
|
|
66
|
-
? `/zones/${ctx.zone
|
|
66
|
+
? `/zones/${ctx.zone}/workers/edge-preview`
|
|
67
67
|
: `/accounts/${accountId}/workers/subdomain/edge-preview`;
|
|
68
68
|
|
|
69
69
|
const { exchange_url } = await fetchResult<{ exchange_url: string }>(
|
|
@@ -111,7 +111,7 @@ async function createPreviewToken(
|
|
|
111
111
|
);
|
|
112
112
|
|
|
113
113
|
const { accountId } = account;
|
|
114
|
-
const scriptId = ctx.zone ? randomId() :
|
|
114
|
+
const scriptId = worker.name || (ctx.zone ? randomId() : host.split(".")[0]);
|
|
115
115
|
const url =
|
|
116
116
|
ctx.env && !ctx.legacyEnv
|
|
117
117
|
? `/accounts/${accountId}/workers/services/${scriptId}/environments/${ctx.env}/edge-preview`
|
|
@@ -139,19 +139,19 @@ async function createPreviewToken(
|
|
|
139
139
|
|
|
140
140
|
return {
|
|
141
141
|
value: preview_token,
|
|
142
|
-
host:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
142
|
+
host:
|
|
143
|
+
ctx.host ??
|
|
144
|
+
(worker.name
|
|
145
|
+
? `${
|
|
146
|
+
worker.name
|
|
147
|
+
// TODO: this should also probably have the env prefix
|
|
148
|
+
// but it doesn't appear to work yet, instead giving us the
|
|
149
|
+
// "There is nothing here yet" screen
|
|
150
|
+
// ctx.env && !ctx.legacyEnv
|
|
151
|
+
// ? `${ctx.env}.${worker.name}`
|
|
152
|
+
// : worker.name
|
|
153
|
+
}.${host.split(".").slice(1).join(".")}`
|
|
154
|
+
: host),
|
|
155
155
|
|
|
156
156
|
inspectorUrl,
|
|
157
157
|
prewarmUrl,
|
package/src/dev/dev.tsx
CHANGED
|
@@ -13,7 +13,6 @@ import { runCustomBuild } from "../entry";
|
|
|
13
13
|
import { openInspector } from "../inspect";
|
|
14
14
|
import { logger } from "../logger";
|
|
15
15
|
import openInBrowser from "../open-in-browser";
|
|
16
|
-
import { getAPIToken } from "../user";
|
|
17
16
|
import { Local } from "./local";
|
|
18
17
|
import { Remote } from "./remote";
|
|
19
18
|
import { useEsbuild } from "./use-esbuild";
|
|
@@ -21,7 +20,6 @@ import type { Config } from "../config";
|
|
|
21
20
|
import type { Entry } from "../entry";
|
|
22
21
|
import type { AssetPaths } from "../sites";
|
|
23
22
|
import type { CfWorkerInit } from "../worker";
|
|
24
|
-
import type { EsbuildBundle } from "./use-esbuild";
|
|
25
23
|
|
|
26
24
|
export type DevProps = {
|
|
27
25
|
name?: string;
|
|
@@ -47,27 +45,14 @@ export type DevProps = {
|
|
|
47
45
|
usageModel: "bundled" | "unbound" | undefined;
|
|
48
46
|
minify: boolean | undefined;
|
|
49
47
|
nodeCompat: boolean | undefined;
|
|
50
|
-
build:
|
|
51
|
-
command?: string | undefined;
|
|
52
|
-
cwd?: string | undefined;
|
|
53
|
-
watch_dir?: string | undefined;
|
|
54
|
-
};
|
|
48
|
+
build: Config["build"];
|
|
55
49
|
env: string | undefined;
|
|
56
50
|
legacyEnv: boolean;
|
|
57
|
-
zone:
|
|
58
|
-
|
|
59
|
-
id: string;
|
|
60
|
-
host: string;
|
|
61
|
-
}
|
|
62
|
-
| undefined;
|
|
51
|
+
zone: string | undefined;
|
|
52
|
+
host: string | undefined;
|
|
63
53
|
};
|
|
64
54
|
|
|
65
55
|
export function DevImplementation(props: DevProps): JSX.Element {
|
|
66
|
-
const apiToken = props.initialMode === "remote" ? getAPIToken() : undefined;
|
|
67
|
-
const directory = useTmpDir();
|
|
68
|
-
|
|
69
|
-
useCustomBuild(props.entry, props.build);
|
|
70
|
-
|
|
71
56
|
if (props.public && props.entry.format === "service-worker") {
|
|
72
57
|
throw new Error(
|
|
73
58
|
"You cannot use the service-worker format with a `public` directory."
|
|
@@ -92,39 +77,16 @@ export function DevImplementation(props: DevProps): JSX.Element {
|
|
|
92
77
|
);
|
|
93
78
|
}
|
|
94
79
|
|
|
95
|
-
const bundle = useEsbuild({
|
|
96
|
-
entry: props.entry,
|
|
97
|
-
destination: directory,
|
|
98
|
-
staticRoot: props.public,
|
|
99
|
-
jsxFactory: props.jsxFactory,
|
|
100
|
-
rules: props.rules,
|
|
101
|
-
jsxFragment: props.jsxFragment,
|
|
102
|
-
serveAssetsFromWorker: !!props.public,
|
|
103
|
-
tsconfig: props.tsconfig,
|
|
104
|
-
minify: props.minify,
|
|
105
|
-
nodeCompat: props.nodeCompat,
|
|
106
|
-
});
|
|
107
|
-
|
|
108
80
|
// only load the UI if we're running in a supported environment
|
|
109
81
|
const { isRawModeSupported } = useStdin();
|
|
110
82
|
return isRawModeSupported ? (
|
|
111
|
-
<InteractiveDevSession {...props}
|
|
83
|
+
<InteractiveDevSession {...props} />
|
|
112
84
|
) : (
|
|
113
|
-
<DevSession
|
|
114
|
-
{...props}
|
|
115
|
-
bundle={bundle}
|
|
116
|
-
apiToken={apiToken}
|
|
117
|
-
local={props.initialMode === "local"}
|
|
118
|
-
/>
|
|
85
|
+
<DevSession {...props} local={props.initialMode === "local"} />
|
|
119
86
|
);
|
|
120
87
|
}
|
|
121
88
|
|
|
122
|
-
|
|
123
|
-
apiToken: string | undefined;
|
|
124
|
-
bundle: EsbuildBundle | undefined;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
function InteractiveDevSession(props: InteractiveDevSessionProps) {
|
|
89
|
+
function InteractiveDevSession(props: DevProps) {
|
|
128
90
|
const toggles = useHotkeys(
|
|
129
91
|
{
|
|
130
92
|
local: props.initialMode === "local",
|
|
@@ -157,15 +119,36 @@ function InteractiveDevSession(props: InteractiveDevSessionProps) {
|
|
|
157
119
|
);
|
|
158
120
|
}
|
|
159
121
|
|
|
160
|
-
type DevSessionProps =
|
|
122
|
+
type DevSessionProps = DevProps & {
|
|
123
|
+
local: boolean;
|
|
124
|
+
};
|
|
161
125
|
|
|
162
126
|
function DevSession(props: DevSessionProps) {
|
|
127
|
+
useCustomBuild(props.entry, props.build);
|
|
128
|
+
|
|
129
|
+
const directory = useTmpDir();
|
|
130
|
+
|
|
131
|
+
const bundle = useEsbuild({
|
|
132
|
+
entry: props.entry,
|
|
133
|
+
destination: directory,
|
|
134
|
+
staticRoot: props.public,
|
|
135
|
+
jsxFactory: props.jsxFactory,
|
|
136
|
+
rules: props.rules,
|
|
137
|
+
jsxFragment: props.jsxFragment,
|
|
138
|
+
// In dev for remote mode, we serve --experimental-assets from the local proxy before we send the request to the worker.
|
|
139
|
+
serveAssetsFromWorker: !!props.public && !!props.local,
|
|
140
|
+
tsconfig: props.tsconfig,
|
|
141
|
+
minify: props.minify,
|
|
142
|
+
nodeCompat: props.nodeCompat,
|
|
143
|
+
});
|
|
144
|
+
|
|
163
145
|
return props.local ? (
|
|
164
146
|
<Local
|
|
165
147
|
name={props.name}
|
|
166
|
-
bundle={
|
|
148
|
+
bundle={bundle}
|
|
167
149
|
format={props.entry.format}
|
|
168
150
|
compatibilityDate={props.compatibilityDate}
|
|
151
|
+
localProtocol={props.localProtocol}
|
|
169
152
|
compatibilityFlags={props.compatibilityFlags}
|
|
170
153
|
bindings={props.bindings}
|
|
171
154
|
assetPaths={props.assetPaths}
|
|
@@ -180,10 +163,9 @@ function DevSession(props: DevSessionProps) {
|
|
|
180
163
|
) : (
|
|
181
164
|
<Remote
|
|
182
165
|
name={props.name}
|
|
183
|
-
bundle={
|
|
166
|
+
bundle={bundle}
|
|
184
167
|
format={props.entry.format}
|
|
185
168
|
accountId={props.accountId}
|
|
186
|
-
apiToken={props.apiToken}
|
|
187
169
|
bindings={props.bindings}
|
|
188
170
|
assetPaths={props.assetPaths}
|
|
189
171
|
public={props.public}
|
|
@@ -197,6 +179,7 @@ function DevSession(props: DevSessionProps) {
|
|
|
197
179
|
env={props.env}
|
|
198
180
|
legacyEnv={props.legacyEnv}
|
|
199
181
|
zone={props.zone}
|
|
182
|
+
host={props.host}
|
|
200
183
|
/>
|
|
201
184
|
);
|
|
202
185
|
}
|
|
@@ -228,14 +211,7 @@ function useTmpDir(): string | undefined {
|
|
|
228
211
|
return directory?.name;
|
|
229
212
|
}
|
|
230
213
|
|
|
231
|
-
function useCustomBuild(
|
|
232
|
-
expectedEntry: Entry,
|
|
233
|
-
build: {
|
|
234
|
-
command?: string | undefined;
|
|
235
|
-
cwd?: string | undefined;
|
|
236
|
-
watch_dir?: string | undefined;
|
|
237
|
-
}
|
|
238
|
-
): void {
|
|
214
|
+
function useCustomBuild(expectedEntry: Entry, build: Config["build"]): void {
|
|
239
215
|
useEffect(() => {
|
|
240
216
|
if (!build.command) return;
|
|
241
217
|
let watcher: ReturnType<typeof watch> | undefined;
|
package/src/dev/local.tsx
CHANGED
|
@@ -21,6 +21,7 @@ interface LocalProps {
|
|
|
21
21
|
compatibilityDate: string;
|
|
22
22
|
compatibilityFlags: string[] | undefined;
|
|
23
23
|
bindings: CfWorkerInit["bindings"];
|
|
24
|
+
localProtocol: "http" | "https";
|
|
24
25
|
assetPaths: AssetPaths | undefined;
|
|
25
26
|
public: string | undefined;
|
|
26
27
|
port: number;
|
|
@@ -54,6 +55,7 @@ function useLocalWorker({
|
|
|
54
55
|
rules,
|
|
55
56
|
enableLocalPersistence,
|
|
56
57
|
ip,
|
|
58
|
+
localProtocol,
|
|
57
59
|
crons,
|
|
58
60
|
}: LocalProps) {
|
|
59
61
|
// TODO: pass vars via command line
|
|
@@ -82,11 +84,6 @@ function useLocalWorker({
|
|
|
82
84
|
abortSignal: abortController.signal,
|
|
83
85
|
});
|
|
84
86
|
|
|
85
|
-
if (publicDirectory) {
|
|
86
|
-
throw new Error(
|
|
87
|
-
'⎔ A "public" folder is not yet supported in local mode.'
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
87
|
if (bindings.services && bindings.services.length > 0) {
|
|
91
88
|
throw new Error(
|
|
92
89
|
"⎔ Service bindings are not yet supported in local mode."
|
|
@@ -164,6 +161,7 @@ function useLocalWorker({
|
|
|
164
161
|
name: workerName,
|
|
165
162
|
port,
|
|
166
163
|
scriptPath,
|
|
164
|
+
https: localProtocol === "https",
|
|
167
165
|
host: ip,
|
|
168
166
|
modules: format === "modules",
|
|
169
167
|
modulesRules: (rules || [])
|
|
@@ -251,12 +249,16 @@ function useLocalWorker({
|
|
|
251
249
|
process.stdout.write(data);
|
|
252
250
|
});
|
|
253
251
|
|
|
252
|
+
// parse the node inspector url (which may be received in chunks) from stderr
|
|
253
|
+
let stderrData = "";
|
|
254
254
|
local.current.stderr?.on("data", (data: Buffer) => {
|
|
255
|
+
stderrData += data.toString();
|
|
255
256
|
const matches =
|
|
256
|
-
/Debugger listening on (ws:\/\/127\.0\.0\.1:\d+\/[A-Za-z0-9-]+)/.exec(
|
|
257
|
-
|
|
257
|
+
/Debugger listening on (ws:\/\/127\.0\.0\.1:\d+\/[A-Za-z0-9-]+)[\r|\n]/.exec(
|
|
258
|
+
stderrData
|
|
258
259
|
);
|
|
259
260
|
if (matches) {
|
|
261
|
+
local.current?.stderr?.removeAllListeners("data");
|
|
260
262
|
setInspectorUrl(matches[1]);
|
|
261
263
|
}
|
|
262
264
|
});
|
|
@@ -298,6 +300,7 @@ function useLocalWorker({
|
|
|
298
300
|
workerName,
|
|
299
301
|
format,
|
|
300
302
|
port,
|
|
303
|
+
localProtocol,
|
|
301
304
|
ip,
|
|
302
305
|
bindings.durable_objects?.bindings,
|
|
303
306
|
bindings.kv_namespaces,
|
package/src/dev/remote.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import assert from "node:assert";
|
|
2
1
|
import { readFile } from "node:fs/promises";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { useState, useEffect, useRef } from "react";
|
|
@@ -7,6 +6,7 @@ import useInspector from "../inspect";
|
|
|
7
6
|
import { logger } from "../logger";
|
|
8
7
|
import { usePreviewServer } from "../proxy";
|
|
9
8
|
import { syncAssets } from "../sites";
|
|
9
|
+
import { requireApiToken, requireAuth } from "../user";
|
|
10
10
|
import type { CfPreviewToken } from "../create-worker-preview";
|
|
11
11
|
import type { AssetPaths } from "../sites";
|
|
12
12
|
import type { CfModule, CfWorkerInit, CfScriptFormat } from "../worker";
|
|
@@ -23,26 +23,24 @@ export function Remote(props: {
|
|
|
23
23
|
localProtocol: "https" | "http";
|
|
24
24
|
inspectorPort: number;
|
|
25
25
|
accountId: string | undefined;
|
|
26
|
-
apiToken: string | undefined;
|
|
27
26
|
bindings: CfWorkerInit["bindings"];
|
|
28
27
|
compatibilityDate: string;
|
|
29
28
|
compatibilityFlags: string[] | undefined;
|
|
30
29
|
usageModel: "bundled" | "unbound" | undefined;
|
|
31
30
|
env: string | undefined;
|
|
32
31
|
legacyEnv: boolean | undefined;
|
|
33
|
-
zone:
|
|
32
|
+
zone: string | undefined;
|
|
33
|
+
host: string | undefined;
|
|
34
34
|
}) {
|
|
35
|
-
assert(props.accountId, "accountId is required");
|
|
36
|
-
assert(props.apiToken, "apiToken is required");
|
|
37
35
|
const previewToken = useWorker({
|
|
38
36
|
name: props.name,
|
|
39
37
|
bundle: props.bundle,
|
|
40
38
|
format: props.format,
|
|
41
39
|
modules: props.bundle ? props.bundle.modules : [],
|
|
42
40
|
accountId: props.accountId,
|
|
43
|
-
apiToken: props.apiToken,
|
|
44
41
|
bindings: props.bindings,
|
|
45
42
|
assetPaths: props.assetPaths,
|
|
43
|
+
public: props.public,
|
|
46
44
|
port: props.port,
|
|
47
45
|
compatibilityDate: props.compatibilityDate,
|
|
48
46
|
compatibilityFlags: props.compatibilityFlags,
|
|
@@ -50,6 +48,7 @@ export function Remote(props: {
|
|
|
50
48
|
env: props.env,
|
|
51
49
|
legacyEnv: props.legacyEnv,
|
|
52
50
|
zone: props.zone,
|
|
51
|
+
host: props.host,
|
|
53
52
|
});
|
|
54
53
|
|
|
55
54
|
usePreviewServer({
|
|
@@ -73,17 +72,18 @@ export function useWorker(props: {
|
|
|
73
72
|
bundle: EsbuildBundle | undefined;
|
|
74
73
|
format: CfScriptFormat | undefined;
|
|
75
74
|
modules: CfModule[];
|
|
76
|
-
accountId: string;
|
|
77
|
-
apiToken: string;
|
|
75
|
+
accountId: string | undefined;
|
|
78
76
|
bindings: CfWorkerInit["bindings"];
|
|
79
77
|
assetPaths: AssetPaths | undefined;
|
|
78
|
+
public: string | undefined;
|
|
80
79
|
port: number;
|
|
81
80
|
compatibilityDate: string | undefined;
|
|
82
81
|
compatibilityFlags: string[] | undefined;
|
|
83
82
|
usageModel: "bundled" | "unbound" | undefined;
|
|
84
83
|
env: string | undefined;
|
|
85
84
|
legacyEnv: boolean | undefined;
|
|
86
|
-
zone:
|
|
85
|
+
zone: string | undefined;
|
|
86
|
+
host: string | undefined;
|
|
87
87
|
}): CfPreviewToken | undefined {
|
|
88
88
|
const {
|
|
89
89
|
name,
|
|
@@ -91,7 +91,6 @@ export function useWorker(props: {
|
|
|
91
91
|
format,
|
|
92
92
|
modules,
|
|
93
93
|
accountId,
|
|
94
|
-
apiToken,
|
|
95
94
|
bindings,
|
|
96
95
|
assetPaths,
|
|
97
96
|
compatibilityDate,
|
|
@@ -105,6 +104,9 @@ export function useWorker(props: {
|
|
|
105
104
|
// something's "happened" in our system; We make a ref and
|
|
106
105
|
// mark it once we log our initial message. Refs are vars!
|
|
107
106
|
const startedRef = useRef(false);
|
|
107
|
+
// This ref holds the actual accountId being used, the `accountId` prop could be undefined
|
|
108
|
+
// as it is only what is retrieved from the wrangler.toml config.
|
|
109
|
+
const accountIdRef = useRef(accountId);
|
|
108
110
|
|
|
109
111
|
useEffect(() => {
|
|
110
112
|
const abortController = new AbortController();
|
|
@@ -119,14 +121,19 @@ export function useWorker(props: {
|
|
|
119
121
|
logger.log("⎔ Detected changes, restarted server.");
|
|
120
122
|
}
|
|
121
123
|
|
|
124
|
+
// Ensure we have an account id, even if it means logging in here.
|
|
125
|
+
accountIdRef.current = await requireAuth({
|
|
126
|
+
account_id: accountIdRef.current,
|
|
127
|
+
});
|
|
128
|
+
|
|
122
129
|
const assets = await syncAssets(
|
|
123
|
-
|
|
130
|
+
accountIdRef.current,
|
|
124
131
|
// When we're using the newer service environments, we wouldn't
|
|
125
132
|
// have added the env name on to the script name. However, we must
|
|
126
133
|
// include it in the kv namespace name regardless (since there's no
|
|
127
134
|
// concept of service environments for kv namespaces yet).
|
|
128
135
|
name + (!props.legacyEnv && props.env ? `-${props.env}` : ""),
|
|
129
|
-
assetPaths,
|
|
136
|
+
props.public ? undefined : assetPaths,
|
|
130
137
|
true,
|
|
131
138
|
false
|
|
132
139
|
); // TODO: cancellable?
|
|
@@ -173,10 +180,15 @@ export function useWorker(props: {
|
|
|
173
180
|
await createWorkerPreview(
|
|
174
181
|
init,
|
|
175
182
|
{
|
|
176
|
-
accountId,
|
|
177
|
-
apiToken,
|
|
183
|
+
accountId: accountIdRef.current,
|
|
184
|
+
apiToken: requireApiToken(),
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
env: props.env,
|
|
188
|
+
legacyEnv: props.legacyEnv,
|
|
189
|
+
zone: props.zone,
|
|
190
|
+
host: props.host,
|
|
178
191
|
},
|
|
179
|
-
{ env: props.env, legacyEnv: props.legacyEnv, zone: props.zone },
|
|
180
192
|
abortController.signal
|
|
181
193
|
)
|
|
182
194
|
);
|
|
@@ -193,7 +205,7 @@ export function useWorker(props: {
|
|
|
193
205
|
"Error: You need to register a workers.dev subdomain before running the dev command in remote mode";
|
|
194
206
|
const solutionMessage =
|
|
195
207
|
"You can either enable local mode by pressing l, or register a workers.dev subdomain here:";
|
|
196
|
-
const onboardingLink = `https://dash.cloudflare.com/${
|
|
208
|
+
const onboardingLink = `https://dash.cloudflare.com/${accountIdRef.current}/workers/onboarding`;
|
|
197
209
|
logger.error(
|
|
198
210
|
`${errorMessage}\n${solutionMessage}\n${onboardingLink}`
|
|
199
211
|
);
|
|
@@ -211,9 +223,9 @@ export function useWorker(props: {
|
|
|
211
223
|
bundle,
|
|
212
224
|
format,
|
|
213
225
|
accountId,
|
|
214
|
-
apiToken,
|
|
215
226
|
port,
|
|
216
227
|
assetPaths,
|
|
228
|
+
props.public,
|
|
217
229
|
compatibilityDate,
|
|
218
230
|
compatibilityFlags,
|
|
219
231
|
usageModel,
|
|
@@ -222,6 +234,7 @@ export function useWorker(props: {
|
|
|
222
234
|
props.env,
|
|
223
235
|
props.legacyEnv,
|
|
224
236
|
props.zone,
|
|
237
|
+
props.host,
|
|
225
238
|
]);
|
|
226
239
|
return token;
|
|
227
240
|
}
|
package/src/dev/use-esbuild.ts
CHANGED
|
@@ -14,7 +14,6 @@ export type EsbuildBundle = {
|
|
|
14
14
|
entry: Entry;
|
|
15
15
|
type: "esm" | "commonjs";
|
|
16
16
|
modules: CfModule[];
|
|
17
|
-
serveAssetsFromWorker: boolean;
|
|
18
17
|
};
|
|
19
18
|
|
|
20
19
|
export function useEsbuild({
|
|
@@ -67,8 +66,7 @@ export function useEsbuild({
|
|
|
67
66
|
|
|
68
67
|
const { resolvedEntryPointPath, bundleType, modules, stop } =
|
|
69
68
|
await bundleWorker(entry, destination, {
|
|
70
|
-
|
|
71
|
-
serveAssetsFromWorker: false,
|
|
69
|
+
serveAssetsFromWorker,
|
|
72
70
|
jsxFactory,
|
|
73
71
|
jsxFragment,
|
|
74
72
|
rules,
|
|
@@ -87,7 +85,6 @@ export function useEsbuild({
|
|
|
87
85
|
path: resolvedEntryPointPath,
|
|
88
86
|
type: bundleType,
|
|
89
87
|
modules,
|
|
90
|
-
serveAssetsFromWorker,
|
|
91
88
|
});
|
|
92
89
|
}
|
|
93
90
|
|