wrangler 2.1.13 → 2.1.14
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 +0 -4
- package/miniflare-dist/index.mjs +11 -7
- package/package.json +1 -1
- package/src/__tests__/delete.test.ts +114 -0
- package/src/__tests__/deployments.test.ts +91 -0
- package/src/__tests__/helpers/msw/handlers/deployments.ts +80 -0
- package/src/__tests__/helpers/msw/index.ts +4 -2
- package/src/__tests__/index.test.ts +4 -2
- package/src/__tests__/init.test.ts +1 -1
- package/src/__tests__/tail.test.ts +2 -2
- package/src/__tests__/type-generation.test.ts +217 -0
- package/src/delete.ts +26 -1
- package/src/dev/local.tsx +5 -0
- package/src/entry.ts +1 -1
- package/src/index.tsx +88 -2
- package/src/init.ts +1 -1
- package/src/logger.ts +2 -2
- package/src/miniflare-cli/index.ts +13 -8
- package/src/pages/dev.tsx +4 -0
- package/src/sites.tsx +1 -1
- package/src/type-generation.ts +159 -0
- package/templates/__tests__/pages-dev-util.test.ts +128 -0
- package/templates/pages-dev-pipeline.ts +5 -12
- package/templates/pages-dev-util.ts +52 -0
- package/templates/tsconfig.json +2 -1
- package/wrangler-dist/cli.js +7042 -6822
package/src/delete.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import assert from "assert";
|
|
1
2
|
import path from "path";
|
|
2
3
|
import { fetchResult } from "./cfetch";
|
|
3
4
|
import { findWranglerToml, readConfig } from "./config";
|
|
4
5
|
import { confirm } from "./dialogs";
|
|
5
6
|
import { CI } from "./is-ci";
|
|
6
7
|
import isInteractive from "./is-interactive";
|
|
8
|
+
import { deleteKVNamespace, listKVNamespaces } from "./kv/helpers";
|
|
7
9
|
import { logger } from "./logger";
|
|
8
10
|
import * as metrics from "./metrics";
|
|
9
11
|
import { requireAuth } from "./user";
|
|
@@ -60,11 +62,18 @@ export async function deleteHandler(args: ArgumentsCamelCase<DeleteArgs>) {
|
|
|
60
62
|
|
|
61
63
|
const scriptName = getScriptName(args, config);
|
|
62
64
|
|
|
65
|
+
assert(
|
|
66
|
+
scriptName,
|
|
67
|
+
"A worker name must be defined, either via --name, or in wrangler.toml"
|
|
68
|
+
);
|
|
69
|
+
|
|
63
70
|
if (args.dryRun) {
|
|
64
71
|
logger.log(`--dry-run: exiting now.`);
|
|
65
72
|
return;
|
|
66
73
|
}
|
|
67
74
|
|
|
75
|
+
assert(accountId, "Missing accountId");
|
|
76
|
+
|
|
68
77
|
let confirmed = true;
|
|
69
78
|
if (isInteractive() || !CI.isCI()) {
|
|
70
79
|
confirmed = await confirm(
|
|
@@ -79,8 +88,24 @@ export async function deleteHandler(args: ArgumentsCamelCase<DeleteArgs>) {
|
|
|
79
88
|
new URLSearchParams({ force: "true" })
|
|
80
89
|
);
|
|
81
90
|
|
|
91
|
+
await deleteSiteNamespaceIfExisting(scriptName, accountId);
|
|
92
|
+
|
|
82
93
|
logger.log("Successfully deleted", scriptName);
|
|
83
94
|
}
|
|
95
|
+
}
|
|
84
96
|
|
|
85
|
-
|
|
97
|
+
async function deleteSiteNamespaceIfExisting(
|
|
98
|
+
scriptName: string,
|
|
99
|
+
accountId: string
|
|
100
|
+
): Promise<void> {
|
|
101
|
+
const title = `__${scriptName}-workers_sites_assets`;
|
|
102
|
+
const previewTitle = `__${scriptName}-workers_sites_assets_preview`;
|
|
103
|
+
const allNamespaces = await listKVNamespaces(accountId);
|
|
104
|
+
const namespacesToDelete = allNamespaces.filter(
|
|
105
|
+
(ns) => ns.title === title || ns.title === previewTitle
|
|
106
|
+
);
|
|
107
|
+
for (const ns of namespacesToDelete) {
|
|
108
|
+
await deleteKVNamespace(accountId, ns.id);
|
|
109
|
+
logger.log(`🌀 Deleted asset namespace for Workers Site "${ns.title}"`);
|
|
110
|
+
}
|
|
86
111
|
}
|
package/src/dev/local.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import { fork } from "node:child_process";
|
|
|
3
3
|
import { realpathSync } from "node:fs";
|
|
4
4
|
import { readFile, writeFile } from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
|
+
import chalk from "chalk";
|
|
6
7
|
import { npxImport } from "npx-import";
|
|
7
8
|
import { useState, useEffect, useRef } from "react";
|
|
8
9
|
import onExit from "signal-exit";
|
|
@@ -221,6 +222,10 @@ function useLocalWorker({
|
|
|
221
222
|
cwd: path.dirname(scriptPath),
|
|
222
223
|
execArgv: nodeOptions,
|
|
223
224
|
stdio: "pipe",
|
|
225
|
+
env: {
|
|
226
|
+
...process.env,
|
|
227
|
+
FORCE_COLOR: chalk.supportsColor.hasBasic ? "1" : undefined,
|
|
228
|
+
},
|
|
224
229
|
}));
|
|
225
230
|
|
|
226
231
|
child.on("message", async (messageString) => {
|
package/src/entry.ts
CHANGED
package/src/index.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import supportsColor from "supports-color";
|
|
|
5
5
|
import { ProxyAgent, setGlobalDispatcher } from "undici";
|
|
6
6
|
import makeCLI from "yargs";
|
|
7
7
|
import { version as wranglerVersion } from "../package.json";
|
|
8
|
+
import { fetchResult } from "./cfetch";
|
|
8
9
|
import { readConfig } from "./config";
|
|
9
10
|
import { d1 } from "./d1";
|
|
10
11
|
import { deleteHandler, deleteOptions } from "./delete";
|
|
@@ -35,11 +36,22 @@ import { pubSubCommands } from "./pubsub/pubsub-commands";
|
|
|
35
36
|
import { r2 } from "./r2";
|
|
36
37
|
import { secret, secretBulkHandler, secretBulkOptions } from "./secret";
|
|
37
38
|
import { tailOptions, tailHandler } from "./tail";
|
|
39
|
+
import { generateTypes } from "./type-generation";
|
|
38
40
|
import { updateCheck } from "./update-check";
|
|
39
|
-
import {
|
|
41
|
+
import {
|
|
42
|
+
listScopes,
|
|
43
|
+
login,
|
|
44
|
+
logout,
|
|
45
|
+
requireAuth,
|
|
46
|
+
validateScopeKeys,
|
|
47
|
+
} from "./user";
|
|
40
48
|
import { whoami } from "./whoami";
|
|
41
49
|
|
|
50
|
+
import type { DeploymentListRes } from "./__tests__/helpers/msw/handlers/deployments";
|
|
42
51
|
import type { Config } from "./config";
|
|
52
|
+
import type { ServiceMetadataRes } from "./init";
|
|
53
|
+
import type { PartialConfigToDTS } from "./type-generation";
|
|
54
|
+
import type { ArgumentsCamelCase } from "yargs";
|
|
43
55
|
import type Yargs from "yargs";
|
|
44
56
|
|
|
45
57
|
export type ConfigPath = string | undefined;
|
|
@@ -262,7 +274,7 @@ export function createCLIParser(argv: string[]) {
|
|
|
262
274
|
// delete
|
|
263
275
|
wrangler.command(
|
|
264
276
|
"delete [script]",
|
|
265
|
-
"🗑
|
|
277
|
+
"🗑 Delete your Worker from Cloudflare.",
|
|
266
278
|
deleteOptions,
|
|
267
279
|
deleteHandler
|
|
268
280
|
);
|
|
@@ -467,6 +479,80 @@ export function createCLIParser(argv: string[]) {
|
|
|
467
479
|
}
|
|
468
480
|
);
|
|
469
481
|
|
|
482
|
+
// type generation
|
|
483
|
+
wrangler.command(
|
|
484
|
+
"types",
|
|
485
|
+
"📝 Generate types from bindings & module rules in config",
|
|
486
|
+
() => {},
|
|
487
|
+
async () => {
|
|
488
|
+
await printWranglerBanner();
|
|
489
|
+
const config = readConfig(undefined, {});
|
|
490
|
+
|
|
491
|
+
const configBindings: PartialConfigToDTS = {
|
|
492
|
+
kv_namespaces: config.kv_namespaces ?? [],
|
|
493
|
+
vars: { ...config.vars },
|
|
494
|
+
wasm_modules: config.wasm_modules,
|
|
495
|
+
text_blobs: {
|
|
496
|
+
...config.text_blobs,
|
|
497
|
+
},
|
|
498
|
+
data_blobs: config.data_blobs,
|
|
499
|
+
durable_objects: config.durable_objects,
|
|
500
|
+
r2_buckets: config.r2_buckets,
|
|
501
|
+
// @ts-expect-error - We don't want the type generated to inlcude the Beta prefix
|
|
502
|
+
d1_databases: config.d1_databases,
|
|
503
|
+
services: config.services,
|
|
504
|
+
dispatch_namespaces: config.dispatch_namespaces,
|
|
505
|
+
logfwdr: config.logfwdr,
|
|
506
|
+
unsafe: config.unsafe?.bindings,
|
|
507
|
+
rules: config.rules,
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
await generateTypes(configBindings, config);
|
|
511
|
+
}
|
|
512
|
+
);
|
|
513
|
+
|
|
514
|
+
wrangler.command(
|
|
515
|
+
"deployments",
|
|
516
|
+
false,
|
|
517
|
+
// "🚢 Logs the 10 most recent deployments with 'Version ID', 'Version number','Author email', 'Created on' and 'Latest deploy'",
|
|
518
|
+
(yargs) => {
|
|
519
|
+
yargs.option("name", {
|
|
520
|
+
describe: "The name of your worker",
|
|
521
|
+
type: "string",
|
|
522
|
+
});
|
|
523
|
+
},
|
|
524
|
+
async (deploymentsYargs: ArgumentsCamelCase<{ name: string }>) => {
|
|
525
|
+
await printWranglerBanner();
|
|
526
|
+
const config = readConfig(
|
|
527
|
+
deploymentsYargs.config as ConfigPath,
|
|
528
|
+
deploymentsYargs
|
|
529
|
+
);
|
|
530
|
+
const accountId = await requireAuth(config);
|
|
531
|
+
const scriptName = getScriptName(
|
|
532
|
+
{ name: deploymentsYargs.name, env: undefined },
|
|
533
|
+
config
|
|
534
|
+
);
|
|
535
|
+
const scriptMetadata = await fetchResult<ServiceMetadataRes>(
|
|
536
|
+
`/accounts/${accountId}/workers/services/${scriptName}`
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
const scriptTag = scriptMetadata.default_environment.script.tag;
|
|
540
|
+
const deployments = await fetchResult<DeploymentListRes>(
|
|
541
|
+
`/accounts/${accountId}/workers/versions/by-script/${scriptTag}`
|
|
542
|
+
);
|
|
543
|
+
|
|
544
|
+
const versionMessages = deployments.versions.map(
|
|
545
|
+
(versions, index) =>
|
|
546
|
+
`\nVersion ID: ${versions.version_id}\nVersion number: ${
|
|
547
|
+
versions.version_number
|
|
548
|
+
}\nCreated on: ${versions.metadata.created_on}\nAuthor email: ${
|
|
549
|
+
versions.metadata.author_email
|
|
550
|
+
}\nLatest deploy: ${index === 0}\n`
|
|
551
|
+
);
|
|
552
|
+
logger.log(...versionMessages);
|
|
553
|
+
}
|
|
554
|
+
);
|
|
555
|
+
|
|
470
556
|
// This set to false to allow overwrite of default behaviour
|
|
471
557
|
wrangler.version(false);
|
|
472
558
|
|
package/src/init.ts
CHANGED
|
@@ -16,8 +16,8 @@ import { parsePackageJSON, parseTOML, readFileSync } from "./parse";
|
|
|
16
16
|
import { getBasePath } from "./paths";
|
|
17
17
|
import { requireAuth } from "./user";
|
|
18
18
|
import { CommandLineArgsError, printWranglerBanner } from "./index";
|
|
19
|
-
import type { RawConfig } from "./config";
|
|
20
19
|
|
|
20
|
+
import type { RawConfig } from "./config";
|
|
21
21
|
import type { Route, SimpleRoute } from "./config/environment";
|
|
22
22
|
import type { WorkerMetadata } from "./create-worker-upload-form";
|
|
23
23
|
import type { ConfigPath } from "./index";
|
package/src/logger.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { format } from "node:util";
|
|
|
2
2
|
import { formatMessagesSync } from "esbuild";
|
|
3
3
|
import { getEnvironmentVariableFactory } from "./environment-variables";
|
|
4
4
|
|
|
5
|
-
const LOGGER_LEVELS = {
|
|
5
|
+
export const LOGGER_LEVELS = {
|
|
6
6
|
none: -1,
|
|
7
7
|
error: 0,
|
|
8
8
|
warn: 1,
|
|
@@ -11,7 +11,7 @@ const LOGGER_LEVELS = {
|
|
|
11
11
|
debug: 4,
|
|
12
12
|
} as const;
|
|
13
13
|
|
|
14
|
-
type LoggerLevel = keyof typeof LOGGER_LEVELS;
|
|
14
|
+
export type LoggerLevel = keyof typeof LOGGER_LEVELS;
|
|
15
15
|
|
|
16
16
|
/** A map from LOGGER_LEVEL to the error `kind` needed by `formatMessagesSync()`. */
|
|
17
17
|
const LOGGER_LEVEL_FORMAT_TYPE_MAP = {
|
|
@@ -4,16 +4,18 @@ import {
|
|
|
4
4
|
DurableObjectStub,
|
|
5
5
|
} from "@miniflare/durable-objects";
|
|
6
6
|
import {
|
|
7
|
-
Log,
|
|
7
|
+
Log as MiniflareLog,
|
|
8
|
+
LogLevel as MiniflareLogLevel,
|
|
8
9
|
Miniflare,
|
|
9
|
-
Response as MiniflareResponse,
|
|
10
10
|
Request as MiniflareRequest,
|
|
11
|
+
Response as MiniflareResponse,
|
|
11
12
|
} from "miniflare";
|
|
12
13
|
import yargs from "yargs";
|
|
13
14
|
import { hideBin } from "yargs/helpers";
|
|
14
15
|
import { FatalError } from "../errors";
|
|
15
16
|
import generateASSETSBinding from "./assets";
|
|
16
17
|
import { getRequestContextCheckOptions } from "./request-context";
|
|
18
|
+
import type { LoggerLevel } from "../logger";
|
|
17
19
|
import type { Options } from "./assets";
|
|
18
20
|
import type { AddressInfo } from "net";
|
|
19
21
|
|
|
@@ -24,7 +26,7 @@ export interface EnablePagesAssetsServiceBindingOptions {
|
|
|
24
26
|
|
|
25
27
|
// miniflare defines this but importing it throws:
|
|
26
28
|
// Dynamic require of "path" is not supported
|
|
27
|
-
class
|
|
29
|
+
class MiniflareNoOpLog extends MiniflareLog {
|
|
28
30
|
log(): void {}
|
|
29
31
|
|
|
30
32
|
error(message: Error): void {
|
|
@@ -41,14 +43,17 @@ async function main() {
|
|
|
41
43
|
...JSON.parse((args._[0] as string) ?? "{}"),
|
|
42
44
|
...requestContextCheckOptions,
|
|
43
45
|
};
|
|
44
|
-
|
|
46
|
+
|
|
47
|
+
let logLevelString: Uppercase<LoggerLevel> = config.logLevel.toUpperCase();
|
|
48
|
+
if (logLevelString === "LOG") logLevelString = "INFO";
|
|
49
|
+
const logLevel = MiniflareLogLevel[logLevelString];
|
|
45
50
|
|
|
46
51
|
config.log =
|
|
47
|
-
|
|
48
|
-
? new
|
|
49
|
-
: new
|
|
52
|
+
logLevel === MiniflareLogLevel.NONE
|
|
53
|
+
? new MiniflareNoOpLog()
|
|
54
|
+
: new MiniflareLog(logLevel, config.logOptions);
|
|
50
55
|
|
|
51
|
-
if (logLevel ===
|
|
56
|
+
if (logLevel === MiniflareLogLevel.DEBUG) {
|
|
52
57
|
console.log("MINIFLARE OPTIONS:\n", JSON.stringify(config, null, 2));
|
|
53
58
|
}
|
|
54
59
|
|
package/src/pages/dev.tsx
CHANGED
package/src/sites.tsx
CHANGED
|
@@ -77,7 +77,7 @@ async function createKVNamespaceIfNotAlreadyExisting(
|
|
|
77
77
|
// check if it already exists
|
|
78
78
|
// TODO: this is super inefficient, should be made better
|
|
79
79
|
const namespaces = await listKVNamespaces(accountId);
|
|
80
|
-
const found = namespaces.find((
|
|
80
|
+
const found = namespaces.find((ns) => ns.title === title);
|
|
81
81
|
if (found) {
|
|
82
82
|
return { created: false, id: found.id };
|
|
83
83
|
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import { findUpSync } from "find-up";
|
|
3
|
+
import { getEntry } from "./entry";
|
|
4
|
+
import { logger } from "./logger";
|
|
5
|
+
import type { Config } from "./config";
|
|
6
|
+
import type { CfWorkerInit } from "./worker";
|
|
7
|
+
|
|
8
|
+
// Currently includes bindings & rules for declaring modules
|
|
9
|
+
export type PartialConfigToDTS = CfWorkerInit["bindings"] & {
|
|
10
|
+
rules: Config["rules"];
|
|
11
|
+
};
|
|
12
|
+
export async function generateTypes(
|
|
13
|
+
configToDTS: PartialConfigToDTS,
|
|
14
|
+
config: Config
|
|
15
|
+
) {
|
|
16
|
+
const entry = await getEntry({}, config, "types");
|
|
17
|
+
const envTypeStructure: string[] = [];
|
|
18
|
+
|
|
19
|
+
if (configToDTS.kv_namespaces) {
|
|
20
|
+
for (const kvNamespace of configToDTS.kv_namespaces) {
|
|
21
|
+
envTypeStructure.push(` ${kvNamespace.binding}: KVNamespace;`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (configToDTS.vars) {
|
|
26
|
+
for (const varName in configToDTS.vars) {
|
|
27
|
+
const varValue = configToDTS.vars[varName];
|
|
28
|
+
if (
|
|
29
|
+
typeof varValue === "string" ||
|
|
30
|
+
typeof varValue === "number" ||
|
|
31
|
+
typeof varValue === "boolean"
|
|
32
|
+
) {
|
|
33
|
+
envTypeStructure.push(` ${varName}: ${varValue};`);
|
|
34
|
+
}
|
|
35
|
+
if (typeof varValue === "object" && varValue !== null) {
|
|
36
|
+
envTypeStructure.push(` ${varName}: ${JSON.stringify(varValue)};`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (configToDTS.durable_objects?.bindings) {
|
|
42
|
+
for (const durableObject of configToDTS.durable_objects.bindings) {
|
|
43
|
+
envTypeStructure.push(` ${durableObject.name}: DurableObjectNamespace;`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (configToDTS.r2_buckets) {
|
|
48
|
+
for (const R2Bucket of configToDTS.r2_buckets) {
|
|
49
|
+
envTypeStructure.push(` ${R2Bucket.binding}: R2Bucket;`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (configToDTS.d1_databases) {
|
|
54
|
+
for (const d1 of configToDTS.d1_databases) {
|
|
55
|
+
envTypeStructure.push(` ${d1.binding}: D1Database;`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (configToDTS.services) {
|
|
60
|
+
for (const service of configToDTS.services) {
|
|
61
|
+
envTypeStructure.push(` ${service.binding}: Fetcher;`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (configToDTS.dispatch_namespaces) {
|
|
66
|
+
for (const namespace of configToDTS.dispatch_namespaces) {
|
|
67
|
+
envTypeStructure.push(` ${namespace.binding}: any;`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (configToDTS.logfwdr?.schema) {
|
|
72
|
+
envTypeStructure.push(` LOGFWDR_SCHEMA: any;`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (configToDTS.data_blobs) {
|
|
76
|
+
for (const dataBlobs in configToDTS.data_blobs) {
|
|
77
|
+
envTypeStructure.push(` ${dataBlobs}: ArrayBuffer;`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (configToDTS.text_blobs) {
|
|
82
|
+
for (const textBlobs in configToDTS.text_blobs) {
|
|
83
|
+
envTypeStructure.push(` ${textBlobs}: string;`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (configToDTS.unsafe) {
|
|
88
|
+
for (const unsafe of configToDTS.unsafe) {
|
|
89
|
+
envTypeStructure.push(` ${unsafe.name}: any;`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const modulesTypeStructure: string[] = [];
|
|
94
|
+
if (configToDTS.rules) {
|
|
95
|
+
const moduleTypeMap = {
|
|
96
|
+
Text: "string",
|
|
97
|
+
Data: "ArrayBuffer",
|
|
98
|
+
CompiledWasm: "WebAssembly.Module",
|
|
99
|
+
};
|
|
100
|
+
for (const ruleObject of configToDTS.rules) {
|
|
101
|
+
const typeScriptType =
|
|
102
|
+
moduleTypeMap[ruleObject.type as keyof typeof moduleTypeMap];
|
|
103
|
+
if (typeScriptType !== undefined) {
|
|
104
|
+
ruleObject.globs.forEach((glob) => {
|
|
105
|
+
modulesTypeStructure.push(`declare module "*.${glob
|
|
106
|
+
.split(".")
|
|
107
|
+
.at(-1)}" {
|
|
108
|
+
const value: ${typeScriptType};
|
|
109
|
+
export default value;
|
|
110
|
+
}`);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function writeDTSFile(
|
|
117
|
+
typesString: string[],
|
|
118
|
+
formatType: "modules" | "service-worker"
|
|
119
|
+
) {
|
|
120
|
+
const wranglerOverrideDTSPath = findUpSync("worker-configuration.d.ts");
|
|
121
|
+
try {
|
|
122
|
+
if (
|
|
123
|
+
wranglerOverrideDTSPath !== undefined &&
|
|
124
|
+
!fs
|
|
125
|
+
.readFileSync(wranglerOverrideDTSPath, "utf8")
|
|
126
|
+
.includes("***AUTO GENERATED BY WORKERS CLI WRANGLER***")
|
|
127
|
+
) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
"A non-wrangler worker-configuration.d.ts already exists, please rename and try again."
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (error instanceof Error && !error.message.includes("not found")) {
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let combinedTypeStrings = "";
|
|
139
|
+
if (formatType === "modules") {
|
|
140
|
+
combinedTypeStrings = `interface Env {\n${typesString.join(
|
|
141
|
+
"\n"
|
|
142
|
+
)} \n}\n${modulesTypeStructure.join("\n")}`;
|
|
143
|
+
} else {
|
|
144
|
+
combinedTypeStrings = `declare global {\n${typesString.join(
|
|
145
|
+
"\n"
|
|
146
|
+
)} \n}\n${modulesTypeStructure.join("\n")}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (envTypeStructure.length || modulesTypeStructure.length) {
|
|
150
|
+
fs.writeFileSync(
|
|
151
|
+
"worker-configuration.d.ts",
|
|
152
|
+
`// Generated by Wrangler on ${new Date()}` + "\n" + combinedTypeStrings
|
|
153
|
+
);
|
|
154
|
+
logger.log(combinedTypeStrings);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
writeDTSFile(envTypeStructure, entry.format);
|
|
159
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { isRoutingRuleMatch } from "../pages-dev-util";
|
|
2
|
+
|
|
3
|
+
describe("isRoutingRuleMatch", () => {
|
|
4
|
+
it("should match rules referencing root level correctly", () => {
|
|
5
|
+
const routingRule = "/";
|
|
6
|
+
|
|
7
|
+
expect(isRoutingRuleMatch("/", routingRule)).toBeTruthy();
|
|
8
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeFalsy();
|
|
9
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeFalsy();
|
|
10
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeFalsy();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("should match include-all rules correctly", () => {
|
|
14
|
+
const routingRule = "/*";
|
|
15
|
+
|
|
16
|
+
expect(isRoutingRuleMatch("/", routingRule)).toBeTruthy();
|
|
17
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeTruthy();
|
|
18
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeTruthy();
|
|
19
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
20
|
+
expect(isRoutingRuleMatch("/foo/bar/", routingRule)).toBeTruthy();
|
|
21
|
+
expect(isRoutingRuleMatch("/foo/bar/baz", routingRule)).toBeTruthy();
|
|
22
|
+
expect(isRoutingRuleMatch("/foo/bar/baz/", routingRule)).toBeTruthy();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should match `/*` suffix-ed rules correctly", () => {
|
|
26
|
+
let routingRule = "/foo/*";
|
|
27
|
+
|
|
28
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeTruthy();
|
|
29
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeTruthy();
|
|
30
|
+
expect(isRoutingRuleMatch("/foobar", routingRule)).toBeFalsy();
|
|
31
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
32
|
+
expect(isRoutingRuleMatch("/foo/bar/baz", routingRule)).toBeTruthy();
|
|
33
|
+
expect(isRoutingRuleMatch("/bar/foo", routingRule)).toBeFalsy();
|
|
34
|
+
expect(isRoutingRuleMatch("/bar/foo/baz", routingRule)).toBeFalsy();
|
|
35
|
+
|
|
36
|
+
routingRule = "/foo/bar/*";
|
|
37
|
+
|
|
38
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeFalsy();
|
|
39
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeFalsy();
|
|
40
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
41
|
+
expect(isRoutingRuleMatch("/foo/bar/baz", routingRule)).toBeTruthy();
|
|
42
|
+
expect(isRoutingRuleMatch("/foo/barfoo", routingRule)).toBeFalsy();
|
|
43
|
+
expect(isRoutingRuleMatch("baz/foo/bar", routingRule)).toBeFalsy();
|
|
44
|
+
expect(isRoutingRuleMatch("baz/foo/bar/", routingRule)).toBeFalsy();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should match `/` suffix-ed rules correctly", () => {
|
|
48
|
+
let routingRule = "/foo/";
|
|
49
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeTruthy();
|
|
50
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeTruthy();
|
|
51
|
+
|
|
52
|
+
routingRule = "/foo/bar/";
|
|
53
|
+
expect(isRoutingRuleMatch("/foo/bar/", routingRule)).toBeTruthy();
|
|
54
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should match `*` suffix-ed rules correctly", () => {
|
|
58
|
+
let routingRule = "/foo*";
|
|
59
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeTruthy();
|
|
60
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeTruthy();
|
|
61
|
+
expect(isRoutingRuleMatch("/foobar", routingRule)).toBeTruthy();
|
|
62
|
+
expect(isRoutingRuleMatch("/barfoo", routingRule)).toBeFalsy();
|
|
63
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
64
|
+
expect(isRoutingRuleMatch("/bar/foo", routingRule)).toBeFalsy();
|
|
65
|
+
expect(isRoutingRuleMatch("/bar/foobar", routingRule)).toBeFalsy();
|
|
66
|
+
expect(isRoutingRuleMatch("/foo/bar/baz", routingRule)).toBeTruthy();
|
|
67
|
+
expect(isRoutingRuleMatch("/bar/foo/baz", routingRule)).toBeFalsy();
|
|
68
|
+
|
|
69
|
+
routingRule = "/foo/bar*";
|
|
70
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
71
|
+
expect(isRoutingRuleMatch("/foo/bar/", routingRule)).toBeTruthy();
|
|
72
|
+
expect(isRoutingRuleMatch("/foo/barfoo", routingRule)).toBeTruthy();
|
|
73
|
+
expect(isRoutingRuleMatch("/bar/foo/barfoo", routingRule)).toBeFalsy();
|
|
74
|
+
expect(isRoutingRuleMatch("/foo/bar/baz", routingRule)).toBeTruthy();
|
|
75
|
+
expect(isRoutingRuleMatch("/bar/foo/bar/baz", routingRule)).toBeFalsy();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should match rules without wildcards correctly", () => {
|
|
79
|
+
let routingRule = "/foo";
|
|
80
|
+
|
|
81
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeTruthy();
|
|
82
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeTruthy();
|
|
83
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeFalsy();
|
|
84
|
+
expect(isRoutingRuleMatch("/bar/foo", routingRule)).toBeFalsy();
|
|
85
|
+
|
|
86
|
+
routingRule = "/foo/bar";
|
|
87
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
88
|
+
expect(isRoutingRuleMatch("/foo/bar/", routingRule)).toBeTruthy();
|
|
89
|
+
expect(isRoutingRuleMatch("/foo/bar/baz", routingRule)).toBeFalsy();
|
|
90
|
+
expect(isRoutingRuleMatch("/baz/foo/bar", routingRule)).toBeFalsy();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should throw an error if pathname or routing rule params are missing", () => {
|
|
94
|
+
// MISSING PATHNAME
|
|
95
|
+
expect(() =>
|
|
96
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
97
|
+
// @ts-ignore: sanity check
|
|
98
|
+
isRoutingRuleMatch(undefined, "/*")
|
|
99
|
+
).toThrow("Pathname is undefined.");
|
|
100
|
+
|
|
101
|
+
expect(() =>
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
103
|
+
// @ts-ignore: sanity check
|
|
104
|
+
isRoutingRuleMatch(null, "/*")
|
|
105
|
+
).toThrow("Pathname is undefined.");
|
|
106
|
+
|
|
107
|
+
expect(() => isRoutingRuleMatch("", "/*")).toThrow(
|
|
108
|
+
"Pathname is undefined."
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// MISSING ROUTING RULE
|
|
112
|
+
expect(() =>
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
114
|
+
// @ts-ignore: sanity check
|
|
115
|
+
isRoutingRuleMatch("/foo", undefined)
|
|
116
|
+
).toThrow("Routing rule is undefined.");
|
|
117
|
+
|
|
118
|
+
expect(() =>
|
|
119
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
120
|
+
// @ts-ignore: sanity check
|
|
121
|
+
isRoutingRuleMatch("/foo", null)
|
|
122
|
+
).toThrow("Routing rule is undefined.");
|
|
123
|
+
|
|
124
|
+
expect(() => isRoutingRuleMatch("/foo", "")).toThrow(
|
|
125
|
+
"Routing rule is undefined."
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
@@ -2,30 +2,23 @@
|
|
|
2
2
|
import worker from "__ENTRY_POINT__";
|
|
3
3
|
// @ts-ignore entry point will get replaced
|
|
4
4
|
export * from "__ENTRY_POINT__";
|
|
5
|
+
import { isRoutingRuleMatch } from "./pages-dev-util";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const routes = {
|
|
11
|
-
// @ts-ignore routes are injected
|
|
12
|
-
include: __ROUTES__.include.map(transformToRegex),
|
|
13
|
-
// @ts-ignore routes are injected
|
|
14
|
-
exclude: __ROUTES__.exclude.map(transformToRegex) || [],
|
|
15
|
-
};
|
|
7
|
+
// @ts-ignore routes are injected
|
|
8
|
+
const routes = __ROUTES__;
|
|
16
9
|
|
|
17
10
|
export default {
|
|
18
11
|
fetch(request, env, context) {
|
|
19
12
|
const { pathname } = new URL(request.url);
|
|
20
13
|
|
|
21
14
|
for (const exclude of routes.exclude) {
|
|
22
|
-
if (pathname
|
|
15
|
+
if (isRoutingRuleMatch(pathname, exclude)) {
|
|
23
16
|
return env.ASSETS.fetch(request);
|
|
24
17
|
}
|
|
25
18
|
}
|
|
26
19
|
|
|
27
20
|
for (const include of routes.include) {
|
|
28
|
-
if (pathname
|
|
21
|
+
if (isRoutingRuleMatch(pathname, include)) {
|
|
29
22
|
return worker.fetch(request, env, context);
|
|
30
23
|
}
|
|
31
24
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param pathname A pathname string, such as `/foo` or `/foo/bar`
|
|
3
|
+
* @param routingRule The routing rule, such as `/foo/*`
|
|
4
|
+
* @returns True if pathname matches the routing rule
|
|
5
|
+
*
|
|
6
|
+
* / -> /
|
|
7
|
+
* /* -> /*
|
|
8
|
+
* /foo -> /foo
|
|
9
|
+
* /foo* -> /foo, /foo-bar, /foo/*
|
|
10
|
+
* /foo/* -> /foo, /foo/bar
|
|
11
|
+
*/
|
|
12
|
+
export function isRoutingRuleMatch(
|
|
13
|
+
pathname: string,
|
|
14
|
+
routingRule: string
|
|
15
|
+
): boolean {
|
|
16
|
+
// sanity checks
|
|
17
|
+
if (!pathname) {
|
|
18
|
+
throw new Error("Pathname is undefined.");
|
|
19
|
+
}
|
|
20
|
+
if (!routingRule) {
|
|
21
|
+
throw new Error("Routing rule is undefined.");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const ruleRegExp = transformRoutingRuleToRegExp(routingRule);
|
|
25
|
+
return pathname.match(ruleRegExp) !== null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function transformRoutingRuleToRegExp(rule: string): RegExp {
|
|
29
|
+
let transformedRule;
|
|
30
|
+
|
|
31
|
+
if (rule === "/" || rule === "/*") {
|
|
32
|
+
transformedRule = rule;
|
|
33
|
+
} else if (rule.endsWith("/*")) {
|
|
34
|
+
// make `/*` an optional group so we can match both /foo/* and /foo
|
|
35
|
+
// /foo/* => /foo(/*)?
|
|
36
|
+
transformedRule = `${rule.substring(0, rule.length - 2)}(/*)?`;
|
|
37
|
+
} else if (rule.endsWith("/")) {
|
|
38
|
+
// make `/` an optional group so we can match both /foo/ and /foo
|
|
39
|
+
// /foo/ => /foo(/)?
|
|
40
|
+
transformedRule = `${rule.substring(0, rule.length - 1)}(/)?`;
|
|
41
|
+
} else if (rule.endsWith("*")) {
|
|
42
|
+
transformedRule = rule;
|
|
43
|
+
} else {
|
|
44
|
+
transformedRule = `${rule}(/)?`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// /foo* => /foo.* => ^/foo.*$
|
|
48
|
+
transformedRule = `^${transformedRule.replace("*", ".*")}$`;
|
|
49
|
+
|
|
50
|
+
// ^/foo.*$ => /^\/foo.*$/
|
|
51
|
+
return new RegExp(transformedRule);
|
|
52
|
+
}
|