wrangler 0.0.0-e64812e → 0.0.0-e8e684c7
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 +27 -3
- package/bin/wrangler.js +150 -62
- package/kv-asset-handler.js +1 -0
- package/miniflare-dist/index.mjs +663 -7
- package/package.json +173 -152
- package/src/__tests__/config-cache-without-cache-dir.test.ts +38 -0
- package/src/__tests__/config-cache.test.ts +30 -24
- package/src/__tests__/configuration.test.ts +4015 -3363
- package/src/__tests__/dev.test.tsx +1290 -952
- package/src/__tests__/generate.test.ts +91 -0
- package/src/__tests__/guess-worker-format.test.ts +68 -68
- package/src/__tests__/helpers/cmd-shim.d.ts +6 -6
- package/src/__tests__/helpers/mock-account-id.ts +24 -24
- package/src/__tests__/helpers/mock-bin.ts +20 -20
- package/src/__tests__/helpers/mock-cfetch.ts +179 -94
- package/src/__tests__/helpers/mock-console.ts +49 -39
- package/src/__tests__/helpers/mock-dialogs.ts +94 -71
- package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
- package/src/__tests__/helpers/mock-http-server.ts +30 -30
- package/src/__tests__/helpers/mock-istty.ts +65 -18
- package/src/__tests__/helpers/mock-known-routes.ts +7 -0
- package/src/__tests__/helpers/mock-kv.ts +26 -26
- package/src/__tests__/helpers/mock-oauth-flow.ts +223 -228
- package/src/__tests__/helpers/mock-process.ts +39 -0
- package/src/__tests__/helpers/mock-stdin.ts +82 -77
- package/src/__tests__/helpers/mock-web-socket.ts +21 -21
- package/src/__tests__/helpers/run-in-tmp.ts +27 -28
- package/src/__tests__/helpers/run-wrangler.ts +8 -8
- package/src/__tests__/helpers/write-worker-source.ts +16 -16
- package/src/__tests__/helpers/write-wrangler-toml.ts +9 -9
- package/src/__tests__/https-options.test.ts +142 -109
- package/src/__tests__/index.test.ts +222 -233
- package/src/__tests__/init.test.ts +2139 -1603
- package/src/__tests__/jest.setup.ts +114 -34
- package/src/__tests__/kv.test.ts +1222 -1032
- package/src/__tests__/logger.test.ts +100 -74
- package/src/__tests__/metrics.test.ts +450 -0
- package/src/__tests__/package-manager.test.ts +303 -303
- package/src/__tests__/pages.test.ts +1173 -652
- package/src/__tests__/parse.test.ts +252 -252
- package/src/__tests__/publish.test.ts +6788 -5301
- package/src/__tests__/pubsub.test.ts +367 -0
- package/src/__tests__/r2.test.ts +328 -225
- package/src/__tests__/route.test.ts +18 -18
- package/src/__tests__/secret.test.ts +470 -459
- package/src/__tests__/tail.test.ts +676 -564
- package/src/__tests__/test-old-node-version.js +31 -0
- package/src/__tests__/user.test.ts +136 -112
- package/src/__tests__/validate-dev-props.test.ts +56 -0
- package/src/__tests__/version.test.ts +35 -0
- package/src/__tests__/whoami.test.tsx +267 -83
- package/src/__tests__/worker-namespace.test.ts +329 -0
- package/src/abort.d.ts +1 -1
- package/src/api/dev.ts +93 -0
- package/src/api/index.ts +1 -0
- package/src/bundle-reporter.tsx +29 -0
- package/src/bundle.ts +430 -157
- package/src/cfetch/index.ts +80 -80
- package/src/cfetch/internal.ts +244 -91
- package/src/cli.ts +21 -7
- package/src/config/config.ts +224 -195
- package/src/config/diagnostics.ts +61 -61
- package/src/config/environment.ts +422 -357
- package/src/config/index.ts +219 -193
- package/src/config/validation-helpers.ts +379 -357
- package/src/config/validation.ts +1690 -1367
- package/src/config-cache.ts +81 -41
- package/src/create-worker-preview.ts +208 -136
- package/src/create-worker-upload-form.ts +275 -238
- package/src/dev/dev-vars.ts +13 -13
- package/src/dev/dev.tsx +477 -351
- package/src/dev/local.tsx +426 -295
- package/src/dev/remote.tsx +406 -211
- package/src/dev/use-esbuild.ts +154 -94
- package/src/dev/validate-dev-props.ts +31 -0
- package/src/dev-registry.tsx +160 -0
- package/src/dev.tsx +696 -0
- package/src/dialogs.tsx +97 -97
- package/src/dispatch-namespace.ts +206 -0
- package/src/durable.ts +87 -87
- package/src/entry.ts +234 -228
- package/src/environment-variables.ts +23 -23
- package/src/errors.ts +6 -6
- package/src/faye-websocket.d.ts +6 -0
- package/src/generate.ts +131 -0
- package/src/git-client.ts +42 -0
- package/src/global-wrangler-config-path.ts +26 -0
- package/src/https-options.ts +84 -80
- package/src/index.tsx +2164 -2768
- package/src/init.ts +622 -0
- package/src/inspect.ts +678 -593
- package/src/intl-polyfill.d.ts +123 -123
- package/src/is-ci.ts +14 -0
- package/src/is-interactive.ts +12 -0
- package/src/kv.ts +299 -277
- package/src/logger.ts +46 -39
- package/src/metrics/index.ts +5 -0
- package/src/metrics/metrics-config.ts +239 -0
- package/src/metrics/metrics-dispatcher.ts +96 -0
- package/src/metrics/metrics-usage-headers.ts +24 -0
- package/src/metrics/send-event.ts +92 -0
- package/src/miniflare-cli/assets.ts +554 -0
- package/src/miniflare-cli/enum-keys.ts +8 -8
- package/src/miniflare-cli/index.ts +198 -32
- package/src/miniflare-cli/request-context.ts +18 -18
- package/src/module-collection.ts +212 -212
- package/src/open-in-browser.ts +4 -6
- package/src/package-manager.ts +173 -128
- package/src/pages/build.tsx +238 -0
- package/src/pages/constants.ts +12 -0
- package/src/pages/deployments.tsx +106 -0
- package/src/pages/dev.tsx +528 -0
- package/src/pages/errors.ts +22 -0
- package/src/pages/functions/buildPlugin.ts +109 -0
- package/src/pages/functions/buildWorker.ts +155 -0
- package/{pages → src/pages}/functions/filepath-routing.test.ts +113 -113
- package/src/pages/functions/filepath-routing.ts +189 -0
- package/src/pages/functions/identifiers.ts +78 -0
- package/src/pages/functions/routes-consolidation.test.ts +250 -0
- package/src/pages/functions/routes-consolidation.ts +73 -0
- package/src/pages/functions/routes-transformation.test.ts +271 -0
- package/src/pages/functions/routes-transformation.ts +122 -0
- package/src/pages/functions/routes.ts +151 -0
- package/src/pages/functions.tsx +96 -0
- package/src/pages/index.tsx +94 -0
- package/src/pages/projects.tsx +169 -0
- package/src/pages/publish.tsx +391 -0
- package/src/pages/types.ts +49 -0
- package/src/pages/upload.tsx +413 -0
- package/src/pages/utils.ts +12 -0
- package/src/parse.ts +209 -125
- package/src/paths.ts +6 -6
- package/src/preview.ts +31 -0
- package/src/proxy.ts +410 -389
- package/src/publish.ts +773 -534
- package/src/pubsub/index.ts +286 -0
- package/src/pubsub/pubsub-commands.tsx +623 -0
- package/src/r2.ts +100 -19
- package/src/selfsigned.d.ts +23 -23
- package/src/sites.tsx +278 -201
- package/src/tail/filters.ts +111 -109
- package/src/tail/index.ts +230 -217
- package/src/tail/printing.ts +86 -46
- package/src/update-check.ts +11 -11
- package/src/user/choose-account.tsx +69 -0
- package/src/user/env-vars.ts +46 -0
- package/src/user/generate-auth-url.ts +33 -0
- package/src/user/generate-random-state.ts +16 -0
- package/src/user/index.ts +3 -0
- package/src/user/user.tsx +1191 -0
- package/src/whoami.tsx +141 -42
- package/src/worker.ts +123 -99
- package/src/zones.ts +167 -0
- package/templates/checked-fetch.js +17 -0
- package/templates/first-party-worker-module-facade.ts +18 -0
- package/templates/format-dev-errors.ts +32 -0
- package/templates/new-worker-scheduled.js +3 -3
- package/templates/new-worker-scheduled.ts +15 -15
- package/templates/new-worker.js +3 -3
- package/templates/new-worker.ts +15 -15
- package/templates/no-op-worker.js +10 -0
- package/templates/pages-shim.ts +9 -0
- package/templates/pages-template-plugin.ts +167 -0
- package/templates/pages-template-worker.ts +172 -0
- package/templates/serve-static-assets.ts +63 -0
- package/templates/service-bindings-module-facade.js +54 -0
- package/templates/service-bindings-sw-facade.js +42 -0
- package/templates/tsconfig.json +95 -95
- package/wrangler-dist/cli.d.ts +338 -0
- package/wrangler-dist/cli.js +95449 -67524
- package/pages/functions/buildPlugin.ts +0 -105
- package/pages/functions/buildWorker.ts +0 -151
- package/pages/functions/filepath-routing.ts +0 -189
- package/pages/functions/identifiers.ts +0 -78
- package/pages/functions/routes.ts +0 -156
- package/pages/functions/template-plugin.ts +0 -147
- package/pages/functions/template-worker.ts +0 -143
- package/src/__tests__/helpers/faye-websocket.d.ts +0 -6
- package/src/pages.tsx +0 -2038
- package/src/user.tsx +0 -1203
- package/templates/static-asset-facade.js +0 -47
- 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
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { render, Text } from "ink";
|
|
2
|
+
import SelectInput from "ink-select-input";
|
|
3
|
+
import Table from "ink-table";
|
|
4
|
+
import React from "react";
|
|
5
|
+
import { format as timeagoFormat } from "timeago.js";
|
|
6
|
+
import { fetchResult } from "../cfetch";
|
|
7
|
+
import { getConfigCache, saveToConfigCache } from "../config-cache";
|
|
8
|
+
import { FatalError } from "../errors";
|
|
9
|
+
import * as metrics from "../metrics";
|
|
10
|
+
import { requireAuth } from "../user";
|
|
11
|
+
import { PAGES_CONFIG_CACHE_FILENAME } from "./constants";
|
|
12
|
+
import { listProjects } from "./projects";
|
|
13
|
+
import { pagesBetaWarning } from "./utils";
|
|
14
|
+
import type {
|
|
15
|
+
Deployment,
|
|
16
|
+
PagesConfigCache,
|
|
17
|
+
YargsOptionsToInterface,
|
|
18
|
+
} from "./types";
|
|
19
|
+
import type { Argv } from "yargs";
|
|
20
|
+
|
|
21
|
+
type ListArgs = YargsOptionsToInterface<typeof ListOptions>;
|
|
22
|
+
|
|
23
|
+
export function ListOptions(yargs: Argv) {
|
|
24
|
+
return yargs
|
|
25
|
+
.options({
|
|
26
|
+
"project-name": {
|
|
27
|
+
type: "string",
|
|
28
|
+
description:
|
|
29
|
+
"The name of the project you would like to list deployments for",
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
.epilogue(pagesBetaWarning);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function ListHandler({ projectName }: ListArgs) {
|
|
36
|
+
const config = getConfigCache<PagesConfigCache>(PAGES_CONFIG_CACHE_FILENAME);
|
|
37
|
+
const accountId = await requireAuth(config);
|
|
38
|
+
|
|
39
|
+
projectName ??= config.project_name;
|
|
40
|
+
|
|
41
|
+
const isInteractive = process.stdin.isTTY;
|
|
42
|
+
if (!projectName && isInteractive) {
|
|
43
|
+
const projects = await listProjects({ accountId });
|
|
44
|
+
projectName = await new Promise((resolve) => {
|
|
45
|
+
const { unmount } = render(
|
|
46
|
+
<>
|
|
47
|
+
<Text>Select a project:</Text>
|
|
48
|
+
<SelectInput
|
|
49
|
+
items={projects.map((project) => ({
|
|
50
|
+
key: project.name,
|
|
51
|
+
label: project.name,
|
|
52
|
+
value: project,
|
|
53
|
+
}))}
|
|
54
|
+
onSelect={async (selected) => {
|
|
55
|
+
resolve(selected.value.name);
|
|
56
|
+
unmount();
|
|
57
|
+
}}
|
|
58
|
+
/>
|
|
59
|
+
</>
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!projectName) {
|
|
65
|
+
throw new FatalError("Must specify a project name.", 1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const deployments: Array<Deployment> = await fetchResult(
|
|
69
|
+
`/accounts/${accountId}/pages/projects/${projectName}/deployments`
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const titleCase = (word: string) =>
|
|
73
|
+
word.charAt(0).toUpperCase() + word.slice(1);
|
|
74
|
+
|
|
75
|
+
const shortSha = (sha: string) => sha.slice(0, 7);
|
|
76
|
+
|
|
77
|
+
const getStatus = (deployment: Deployment) => {
|
|
78
|
+
// Return a pretty time since timestamp if successful otherwise the status
|
|
79
|
+
if (deployment.latest_stage.status === `success`) {
|
|
80
|
+
return timeagoFormat(deployment.latest_stage.ended_on);
|
|
81
|
+
}
|
|
82
|
+
return titleCase(deployment.latest_stage.status);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const data = deployments.map((deployment) => {
|
|
86
|
+
return {
|
|
87
|
+
Environment: titleCase(deployment.environment),
|
|
88
|
+
Branch: deployment.deployment_trigger.metadata.branch,
|
|
89
|
+
Source: shortSha(deployment.deployment_trigger.metadata.commit_hash),
|
|
90
|
+
Deployment: deployment.url,
|
|
91
|
+
Status: getStatus(deployment),
|
|
92
|
+
// TODO: Use a url shortener
|
|
93
|
+
Build: `https://dash.cloudflare.com/${accountId}/pages/view/${deployment.project_name}/${deployment.id}`,
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
saveToConfigCache<PagesConfigCache>(PAGES_CONFIG_CACHE_FILENAME, {
|
|
98
|
+
account_id: accountId,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const { unmount } = render(<Table data={data}></Table>, {
|
|
102
|
+
patchConsole: false,
|
|
103
|
+
});
|
|
104
|
+
unmount();
|
|
105
|
+
await metrics.sendMetricsEvent("list pages deployments");
|
|
106
|
+
}
|
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
import { execSync, spawn } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { homedir, tmpdir } from "node:os";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { watch } from "chokidar";
|
|
6
|
+
import { build as workerJsBuild } from "esbuild";
|
|
7
|
+
import { unstable_dev } from "../api";
|
|
8
|
+
import { FatalError } from "../errors";
|
|
9
|
+
import { logger } from "../logger";
|
|
10
|
+
import * as metrics from "../metrics";
|
|
11
|
+
import { buildFunctions } from "./build";
|
|
12
|
+
import { SECONDS_TO_WAIT_FOR_PROXY } from "./constants";
|
|
13
|
+
import { FunctionsNoRoutesError, getFunctionsNoRoutesWarning } from "./errors";
|
|
14
|
+
import { CLEANUP, CLEANUP_CALLBACKS, pagesBetaWarning } from "./utils";
|
|
15
|
+
import type { AdditionalDevProps } from "../dev";
|
|
16
|
+
import type { YargsOptionsToInterface } from "./types";
|
|
17
|
+
import type { Plugin } from "esbuild";
|
|
18
|
+
import type { Argv } from "yargs";
|
|
19
|
+
|
|
20
|
+
const DURABLE_OBJECTS_BINDING_REGEXP = new RegExp(
|
|
21
|
+
/^(?<binding>[^=]+)=(?<className>[^@\s]+)(@(?<scriptName>.*)$)?$/
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
type PagesDevArgs = YargsOptionsToInterface<typeof Options>;
|
|
25
|
+
|
|
26
|
+
export function Options(yargs: Argv) {
|
|
27
|
+
return yargs
|
|
28
|
+
.positional("directory", {
|
|
29
|
+
type: "string",
|
|
30
|
+
demandOption: undefined,
|
|
31
|
+
description: "The directory of static assets to serve",
|
|
32
|
+
})
|
|
33
|
+
.positional("command", {
|
|
34
|
+
type: "string",
|
|
35
|
+
demandOption: undefined,
|
|
36
|
+
description: "The proxy command to run",
|
|
37
|
+
})
|
|
38
|
+
.options({
|
|
39
|
+
local: {
|
|
40
|
+
type: "boolean",
|
|
41
|
+
default: true,
|
|
42
|
+
description: "Run on my machine",
|
|
43
|
+
},
|
|
44
|
+
"compatibility-date": {
|
|
45
|
+
describe: "Date to use for compatibility checks",
|
|
46
|
+
type: "string",
|
|
47
|
+
},
|
|
48
|
+
"compatibility-flags": {
|
|
49
|
+
describe: "Flags to use for compatibility checks",
|
|
50
|
+
alias: "compatibility-flag",
|
|
51
|
+
type: "string",
|
|
52
|
+
array: true,
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
// TODO
|
|
56
|
+
// For now, all Pages projects are set to 2021-11-02. We're adding compat date soon, and we can then adopt `wrangler dev`'s `default: true`.
|
|
57
|
+
// However, it looks like it isn't actually connected up properly in `wrangler dev` at the moment, hence commenting this out for now.
|
|
58
|
+
|
|
59
|
+
// latest: {
|
|
60
|
+
// describe: "Use the latest version of the worker runtime",
|
|
61
|
+
// type: "boolean",
|
|
62
|
+
// default: false,
|
|
63
|
+
// },
|
|
64
|
+
|
|
65
|
+
ip: {
|
|
66
|
+
type: "string",
|
|
67
|
+
default: "0.0.0.0",
|
|
68
|
+
description: "The IP address to listen on",
|
|
69
|
+
},
|
|
70
|
+
port: {
|
|
71
|
+
type: "number",
|
|
72
|
+
default: 8788,
|
|
73
|
+
description: "The port to listen on (serve from)",
|
|
74
|
+
},
|
|
75
|
+
"inspector-port": {
|
|
76
|
+
type: "number",
|
|
77
|
+
describe: "Port for devtools to connect to",
|
|
78
|
+
},
|
|
79
|
+
proxy: {
|
|
80
|
+
type: "number",
|
|
81
|
+
description: "The port to proxy (where the static assets are served)",
|
|
82
|
+
},
|
|
83
|
+
"script-path": {
|
|
84
|
+
type: "string",
|
|
85
|
+
default: "_worker.js",
|
|
86
|
+
description:
|
|
87
|
+
"The location of the single Worker script if not using functions",
|
|
88
|
+
},
|
|
89
|
+
binding: {
|
|
90
|
+
type: "array",
|
|
91
|
+
description: "Bind variable/secret (KEY=VALUE)",
|
|
92
|
+
alias: "b",
|
|
93
|
+
},
|
|
94
|
+
kv: {
|
|
95
|
+
type: "array",
|
|
96
|
+
description: "KV namespace to bind (--kv KV_BINDING)",
|
|
97
|
+
alias: "k",
|
|
98
|
+
},
|
|
99
|
+
do: {
|
|
100
|
+
type: "array",
|
|
101
|
+
description: "Durable Object to bind (--do NAME=CLASS)",
|
|
102
|
+
alias: "o",
|
|
103
|
+
},
|
|
104
|
+
r2: {
|
|
105
|
+
type: "array",
|
|
106
|
+
description: "R2 bucket to bind (--r2 R2_BINDING)",
|
|
107
|
+
},
|
|
108
|
+
"live-reload": {
|
|
109
|
+
type: "boolean",
|
|
110
|
+
default: false,
|
|
111
|
+
description: "Auto reload HTML pages when change is detected",
|
|
112
|
+
},
|
|
113
|
+
"local-protocol": {
|
|
114
|
+
describe: "Protocol to listen to requests on, defaults to http.",
|
|
115
|
+
choices: ["http", "https"] as const,
|
|
116
|
+
},
|
|
117
|
+
"experimental-enable-local-persistence": {
|
|
118
|
+
type: "boolean",
|
|
119
|
+
default: false,
|
|
120
|
+
describe: "Enable persistence for this session (only for local mode)",
|
|
121
|
+
},
|
|
122
|
+
"node-compat": {
|
|
123
|
+
describe: "Enable node.js compatibility",
|
|
124
|
+
default: false,
|
|
125
|
+
type: "boolean",
|
|
126
|
+
hidden: true,
|
|
127
|
+
},
|
|
128
|
+
config: {
|
|
129
|
+
describe: "Pages does not support wrangler.toml",
|
|
130
|
+
type: "string",
|
|
131
|
+
hidden: true,
|
|
132
|
+
},
|
|
133
|
+
})
|
|
134
|
+
.epilogue(pagesBetaWarning);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const Handler = async ({
|
|
138
|
+
local,
|
|
139
|
+
directory,
|
|
140
|
+
"compatibility-date": compatibilityDate = "2021-11-02",
|
|
141
|
+
"compatibility-flags": compatibilityFlags,
|
|
142
|
+
ip,
|
|
143
|
+
port,
|
|
144
|
+
"inspector-port": inspectorPort,
|
|
145
|
+
proxy: requestedProxyPort,
|
|
146
|
+
"script-path": singleWorkerScriptPath,
|
|
147
|
+
binding: bindings = [],
|
|
148
|
+
kv: kvs = [],
|
|
149
|
+
do: durableObjects = [],
|
|
150
|
+
r2: r2s = [],
|
|
151
|
+
"live-reload": liveReload,
|
|
152
|
+
"local-protocol": localProtocol,
|
|
153
|
+
"experimental-enable-local-persistence": experimentalEnableLocalPersistence,
|
|
154
|
+
"node-compat": nodeCompat,
|
|
155
|
+
config: config,
|
|
156
|
+
_: [_pages, _dev, ...remaining],
|
|
157
|
+
}: PagesDevArgs) => {
|
|
158
|
+
// Beta message for `wrangler pages <commands>` usage
|
|
159
|
+
logger.log(pagesBetaWarning);
|
|
160
|
+
|
|
161
|
+
if (!local) {
|
|
162
|
+
throw new FatalError("Only local mode is supported at the moment.", 1);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (config) {
|
|
166
|
+
throw new FatalError("Pages does not support wrangler.toml", 1);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const functionsDirectory = "./functions";
|
|
170
|
+
let usingFunctions = existsSync(functionsDirectory);
|
|
171
|
+
|
|
172
|
+
const command = remaining;
|
|
173
|
+
|
|
174
|
+
let proxyPort: number | undefined;
|
|
175
|
+
|
|
176
|
+
if (directory !== undefined && command.length > 0) {
|
|
177
|
+
throw new FatalError(
|
|
178
|
+
"Specify either a directory OR a proxy command, not both.",
|
|
179
|
+
1
|
|
180
|
+
);
|
|
181
|
+
} else if (directory === undefined) {
|
|
182
|
+
proxyPort = await spawnProxyProcess({
|
|
183
|
+
port: requestedProxyPort,
|
|
184
|
+
command,
|
|
185
|
+
});
|
|
186
|
+
if (proxyPort === undefined) return undefined;
|
|
187
|
+
} else {
|
|
188
|
+
directory = resolve(directory);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
let scriptReadyResolve: () => void;
|
|
192
|
+
const scriptReadyPromise = new Promise<void>(
|
|
193
|
+
(promiseResolve) => (scriptReadyResolve = promiseResolve)
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
let scriptPath = "";
|
|
197
|
+
|
|
198
|
+
// Try to use Functions
|
|
199
|
+
if (usingFunctions) {
|
|
200
|
+
const outfile = join(tmpdir(), `./functionsWorker-${Math.random()}.js`);
|
|
201
|
+
scriptPath = outfile;
|
|
202
|
+
|
|
203
|
+
if (nodeCompat) {
|
|
204
|
+
console.warn(
|
|
205
|
+
"Enabling node.js compatibility mode for builtins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details."
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
logger.log(`Compiling worker to "${outfile}"...`);
|
|
210
|
+
const onEnd = () => scriptReadyResolve();
|
|
211
|
+
try {
|
|
212
|
+
await buildFunctions({
|
|
213
|
+
outfile,
|
|
214
|
+
functionsDirectory,
|
|
215
|
+
sourcemap: true,
|
|
216
|
+
watch: true,
|
|
217
|
+
onEnd,
|
|
218
|
+
buildOutputDirectory: directory,
|
|
219
|
+
nodeCompat,
|
|
220
|
+
});
|
|
221
|
+
await metrics.sendMetricsEvent("build pages functions");
|
|
222
|
+
|
|
223
|
+
// If Functions found routes, continue using Functions
|
|
224
|
+
watch([functionsDirectory], {
|
|
225
|
+
persistent: true,
|
|
226
|
+
ignoreInitial: true,
|
|
227
|
+
}).on("all", async () => {
|
|
228
|
+
try {
|
|
229
|
+
await buildFunctions({
|
|
230
|
+
outfile,
|
|
231
|
+
functionsDirectory,
|
|
232
|
+
sourcemap: true,
|
|
233
|
+
watch: true,
|
|
234
|
+
onEnd,
|
|
235
|
+
buildOutputDirectory: directory,
|
|
236
|
+
nodeCompat,
|
|
237
|
+
});
|
|
238
|
+
await metrics.sendMetricsEvent("build pages functions");
|
|
239
|
+
} catch (e) {
|
|
240
|
+
if (e instanceof FunctionsNoRoutesError) {
|
|
241
|
+
logger.warn(
|
|
242
|
+
getFunctionsNoRoutesWarning(functionsDirectory, "skipping")
|
|
243
|
+
);
|
|
244
|
+
} else {
|
|
245
|
+
throw e;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
} catch (e) {
|
|
250
|
+
// If there are no Functions, then Pages will only serve assets.
|
|
251
|
+
if (e instanceof FunctionsNoRoutesError) {
|
|
252
|
+
logger.warn(
|
|
253
|
+
getFunctionsNoRoutesWarning(functionsDirectory, "skipping")
|
|
254
|
+
);
|
|
255
|
+
// Resolve anyway and run without Functions
|
|
256
|
+
onEnd();
|
|
257
|
+
// Turn off Functions
|
|
258
|
+
usingFunctions = false;
|
|
259
|
+
} else {
|
|
260
|
+
throw e;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// Depending on the result of building Functions, we may not actually be using
|
|
265
|
+
// Functions even if the directory exists.
|
|
266
|
+
if (!usingFunctions) {
|
|
267
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
268
|
+
scriptReadyResolve!();
|
|
269
|
+
|
|
270
|
+
scriptPath =
|
|
271
|
+
directory !== undefined
|
|
272
|
+
? join(directory, singleWorkerScriptPath)
|
|
273
|
+
: singleWorkerScriptPath;
|
|
274
|
+
|
|
275
|
+
if (!existsSync(scriptPath)) {
|
|
276
|
+
logger.log("No functions. Shimming...");
|
|
277
|
+
scriptPath = resolve(__dirname, "../templates/pages-shim.ts");
|
|
278
|
+
} else {
|
|
279
|
+
const runBuild = async () => {
|
|
280
|
+
try {
|
|
281
|
+
await workerJsBuild({
|
|
282
|
+
entryPoints: [scriptPath],
|
|
283
|
+
write: false,
|
|
284
|
+
plugins: [blockWorkerJsImports],
|
|
285
|
+
});
|
|
286
|
+
} catch {}
|
|
287
|
+
};
|
|
288
|
+
await runBuild();
|
|
289
|
+
watch([scriptPath], {
|
|
290
|
+
persistent: true,
|
|
291
|
+
ignoreInitial: true,
|
|
292
|
+
}).on("all", async () => {
|
|
293
|
+
await runBuild();
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
await scriptReadyPromise;
|
|
299
|
+
|
|
300
|
+
if (scriptPath === "") {
|
|
301
|
+
// Failed to get a script with or without Functions,
|
|
302
|
+
// something really bad must have happend.
|
|
303
|
+
throw new FatalError(
|
|
304
|
+
"Failed to start wrangler pages dev due to an unknown error",
|
|
305
|
+
1
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const { stop, waitUntilExit } = await unstable_dev(
|
|
310
|
+
scriptPath,
|
|
311
|
+
{
|
|
312
|
+
ip,
|
|
313
|
+
port,
|
|
314
|
+
inspectorPort,
|
|
315
|
+
watch: true,
|
|
316
|
+
localProtocol,
|
|
317
|
+
liveReload,
|
|
318
|
+
compatibilityDate,
|
|
319
|
+
compatibilityFlags,
|
|
320
|
+
nodeCompat,
|
|
321
|
+
vars: Object.fromEntries(
|
|
322
|
+
bindings
|
|
323
|
+
.map((binding) => binding.toString().split("="))
|
|
324
|
+
.map(([key, ...values]) => [key, values.join("=")])
|
|
325
|
+
),
|
|
326
|
+
kv: kvs.map((val) => ({
|
|
327
|
+
binding: val.toString(),
|
|
328
|
+
id: "",
|
|
329
|
+
})),
|
|
330
|
+
durableObjects: durableObjects
|
|
331
|
+
.map((durableObject) => {
|
|
332
|
+
const { binding, className, scriptName } =
|
|
333
|
+
DURABLE_OBJECTS_BINDING_REGEXP.exec(durableObject.toString())
|
|
334
|
+
?.groups || {};
|
|
335
|
+
|
|
336
|
+
if (!binding || !className) {
|
|
337
|
+
logger.warn(
|
|
338
|
+
"Could not parse Durable Object binding:",
|
|
339
|
+
durableObject.toString()
|
|
340
|
+
);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
name: binding,
|
|
346
|
+
class_name: className,
|
|
347
|
+
script_name: scriptName,
|
|
348
|
+
};
|
|
349
|
+
})
|
|
350
|
+
.filter(Boolean) as AdditionalDevProps["durableObjects"],
|
|
351
|
+
r2: r2s.map((binding) => {
|
|
352
|
+
return { binding: binding.toString(), bucket_name: "" };
|
|
353
|
+
}),
|
|
354
|
+
|
|
355
|
+
enablePagesAssetsServiceBinding: {
|
|
356
|
+
proxyPort,
|
|
357
|
+
directory,
|
|
358
|
+
},
|
|
359
|
+
forceLocal: true,
|
|
360
|
+
experimentalEnableLocalPersistence,
|
|
361
|
+
showInteractiveDevSession: undefined,
|
|
362
|
+
inspect: true,
|
|
363
|
+
logLevel: "error",
|
|
364
|
+
logPrefix: "pages",
|
|
365
|
+
},
|
|
366
|
+
true
|
|
367
|
+
);
|
|
368
|
+
await metrics.sendMetricsEvent("run pages dev");
|
|
369
|
+
|
|
370
|
+
CLEANUP_CALLBACKS.push(stop);
|
|
371
|
+
|
|
372
|
+
waitUntilExit().then(() => {
|
|
373
|
+
CLEANUP();
|
|
374
|
+
process.exit(0);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
process.on("exit", CLEANUP);
|
|
378
|
+
process.on("SIGINT", CLEANUP);
|
|
379
|
+
process.on("SIGTERM", CLEANUP);
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
function isWindows() {
|
|
383
|
+
return process.platform === "win32";
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async function sleep(ms: number) {
|
|
387
|
+
await new Promise((promiseResolve) => setTimeout(promiseResolve, ms));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function getPids(pid: number) {
|
|
391
|
+
const pids: number[] = [pid];
|
|
392
|
+
let command: string, regExp: RegExp;
|
|
393
|
+
|
|
394
|
+
if (isWindows()) {
|
|
395
|
+
command = `wmic process where (ParentProcessId=${pid}) get ProcessId`;
|
|
396
|
+
regExp = new RegExp(/(\d+)/);
|
|
397
|
+
} else {
|
|
398
|
+
command = `pgrep -P ${pid}`;
|
|
399
|
+
regExp = new RegExp(/(\d+)/);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
try {
|
|
403
|
+
const newPids = (
|
|
404
|
+
execSync(command)
|
|
405
|
+
.toString()
|
|
406
|
+
.split("\n")
|
|
407
|
+
.map((line) => line.match(regExp))
|
|
408
|
+
.filter((line) => line !== null) as RegExpExecArray[]
|
|
409
|
+
).map((match) => parseInt(match[1]));
|
|
410
|
+
|
|
411
|
+
pids.push(...newPids.map(getPids).flat());
|
|
412
|
+
} catch {}
|
|
413
|
+
|
|
414
|
+
return pids;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function getPort(pid: number) {
|
|
418
|
+
let command: string, regExp: RegExp;
|
|
419
|
+
|
|
420
|
+
if (isWindows()) {
|
|
421
|
+
const drive = homedir().split(":\\")[0];
|
|
422
|
+
command = drive + ":\\windows\\system32\\netstat.exe -nao";
|
|
423
|
+
regExp = new RegExp(`TCP\\s+.*:(\\d+)\\s+.*:\\d+\\s+LISTENING\\s+${pid}`);
|
|
424
|
+
} else {
|
|
425
|
+
command = "lsof -nPi";
|
|
426
|
+
regExp = new RegExp(`${pid}\\s+.*TCP\\s+.*:(\\d+)\\s+\\(LISTEN\\)`);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
try {
|
|
430
|
+
const matches = execSync(command)
|
|
431
|
+
.toString()
|
|
432
|
+
.split("\n")
|
|
433
|
+
.map((line) => line.match(regExp))
|
|
434
|
+
.filter((line) => line !== null) as RegExpExecArray[];
|
|
435
|
+
|
|
436
|
+
const match = matches[0];
|
|
437
|
+
if (match) return parseInt(match[1]);
|
|
438
|
+
} catch (thrown) {
|
|
439
|
+
logger.error(
|
|
440
|
+
`Error scanning for ports of process with PID ${pid}: ${thrown}`
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
async function spawnProxyProcess({
|
|
446
|
+
port,
|
|
447
|
+
command,
|
|
448
|
+
}: {
|
|
449
|
+
port?: number;
|
|
450
|
+
command: (string | number)[];
|
|
451
|
+
}): Promise<undefined | number> {
|
|
452
|
+
if (command.length === 0) {
|
|
453
|
+
CLEANUP();
|
|
454
|
+
throw new FatalError(
|
|
455
|
+
"Must specify a directory of static assets to serve or a command to run.",
|
|
456
|
+
1
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
logger.log(`Running ${command.join(" ")}...`);
|
|
461
|
+
const proxy = spawn(
|
|
462
|
+
command[0].toString(),
|
|
463
|
+
command.slice(1).map((value) => value.toString()),
|
|
464
|
+
{
|
|
465
|
+
shell: isWindows(),
|
|
466
|
+
env: {
|
|
467
|
+
BROWSER: "none",
|
|
468
|
+
...process.env,
|
|
469
|
+
},
|
|
470
|
+
}
|
|
471
|
+
);
|
|
472
|
+
CLEANUP_CALLBACKS.push(() => {
|
|
473
|
+
proxy.kill();
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
proxy.stdout.on("data", (data) => {
|
|
477
|
+
logger.log(`[proxy]: ${data}`);
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
proxy.stderr.on("data", (data) => {
|
|
481
|
+
logger.error(`[proxy]: ${data}`);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
proxy.on("close", (code) => {
|
|
485
|
+
logger.error(`Proxy exited with status ${code}.`);
|
|
486
|
+
CLEANUP();
|
|
487
|
+
process.exitCode = code ?? 0;
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
// Wait for proxy process to start...
|
|
491
|
+
while (!proxy.pid) {}
|
|
492
|
+
|
|
493
|
+
if (port === undefined) {
|
|
494
|
+
logger.log(
|
|
495
|
+
`Sleeping ${SECONDS_TO_WAIT_FOR_PROXY} seconds to allow proxy process to start before attempting to automatically determine port...`
|
|
496
|
+
);
|
|
497
|
+
logger.log("To skip, specify the proxy port with --proxy.");
|
|
498
|
+
await sleep(SECONDS_TO_WAIT_FOR_PROXY * 1000);
|
|
499
|
+
|
|
500
|
+
port = getPids(proxy.pid)
|
|
501
|
+
.map(getPort)
|
|
502
|
+
.filter((nr) => nr !== undefined)[0];
|
|
503
|
+
|
|
504
|
+
if (port === undefined) {
|
|
505
|
+
CLEANUP();
|
|
506
|
+
throw new FatalError(
|
|
507
|
+
"Could not automatically determine proxy port. Please specify the proxy port with --proxy.",
|
|
508
|
+
1
|
|
509
|
+
);
|
|
510
|
+
} else {
|
|
511
|
+
logger.log(`Automatically determined the proxy port to be ${port}.`);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return port;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const blockWorkerJsImports: Plugin = {
|
|
519
|
+
name: "block-worker-js-imports",
|
|
520
|
+
setup(build) {
|
|
521
|
+
build.onResolve({ filter: /.*/g }, (_args) => {
|
|
522
|
+
logger.error(
|
|
523
|
+
`_worker.js is importing from another file. This will throw an error if deployed.\nYou should bundle your Worker or remove the import if it is unused.`
|
|
524
|
+
);
|
|
525
|
+
return null;
|
|
526
|
+
});
|
|
527
|
+
},
|
|
528
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pages error when no routes are found in the functions directory
|
|
3
|
+
*/
|
|
4
|
+
export class FunctionsNoRoutesError extends Error {
|
|
5
|
+
constructor(message: string) {
|
|
6
|
+
super(message);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Exit code for `pages functions build` when no routes are found.
|
|
11
|
+
*/
|
|
12
|
+
export const EXIT_CODE_FUNCTIONS_NO_ROUTES_ERROR = 156;
|
|
13
|
+
|
|
14
|
+
/** Warning message for when buildFunctions throws FunctionsNoRoutesError */
|
|
15
|
+
export function getFunctionsNoRoutesWarning(
|
|
16
|
+
functionsDirectory: string,
|
|
17
|
+
suffix?: string
|
|
18
|
+
) {
|
|
19
|
+
return `No routes found when building Functions directory: ${functionsDirectory}${
|
|
20
|
+
suffix ? " - " + suffix : ""
|
|
21
|
+
}`;
|
|
22
|
+
}
|