wrangler 0.0.0-e178d6fb → 0.0.0-e1c2f5b9
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 +16 -2
- package/bin/wrangler.js +31 -11
- package/miniflare-dist/index.mjs +1340 -330
- package/package.json +40 -13
- package/src/__tests__/access.test.ts +25 -0
- package/src/__tests__/api-dev.test.ts +238 -0
- package/src/__tests__/api-devregistry.test.js +64 -0
- package/src/__tests__/api.test.ts +80 -0
- package/src/__tests__/configuration.test.ts +683 -470
- package/src/__tests__/d1.test.ts +123 -0
- package/src/__tests__/delete.test.ts +263 -0
- package/src/__tests__/deployments.test.ts +105 -0
- package/src/__tests__/dev.test.tsx +453 -70
- package/src/__tests__/dialogs.test.tsx +40 -0
- package/src/__tests__/generate.test.ts +235 -0
- package/src/__tests__/get-host-from-url.test.ts +16 -0
- package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
- package/src/__tests__/helpers/mock-cfetch.ts +92 -26
- package/src/__tests__/helpers/mock-console.ts +11 -2
- package/src/__tests__/helpers/mock-dialogs.ts +1 -1
- package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
- package/src/__tests__/helpers/mock-known-routes.ts +7 -0
- package/src/__tests__/helpers/mock-kv.ts +1 -1
- package/src/__tests__/helpers/mock-oauth-flow.ts +74 -53
- package/src/__tests__/helpers/mock-process.ts +8 -13
- package/src/__tests__/helpers/msw/handlers/access.ts +13 -0
- package/src/__tests__/helpers/msw/handlers/deployments.ts +59 -0
- package/src/__tests__/helpers/msw/handlers/namespaces.ts +104 -0
- package/src/__tests__/helpers/msw/handlers/oauth.ts +31 -0
- package/src/__tests__/helpers/msw/handlers/r2.ts +80 -0
- package/src/__tests__/helpers/msw/handlers/script.ts +75 -0
- package/src/__tests__/helpers/msw/handlers/user.ts +63 -0
- package/src/__tests__/helpers/msw/handlers/zones.ts +22 -0
- package/src/__tests__/helpers/msw/index.ts +21 -0
- package/src/__tests__/helpers/worker-scripts/child-wrangler.toml +1 -0
- package/src/__tests__/helpers/worker-scripts/hello-world-worker.js +5 -0
- package/src/__tests__/helpers/worker-scripts/hello-world-wrangler.toml +1 -0
- package/src/__tests__/helpers/worker-scripts/parent-worker.js +8 -0
- package/src/__tests__/helpers/worker-scripts/parent-wrangler.toml +5 -0
- package/src/__tests__/index.test.ts +103 -97
- package/src/__tests__/init.test.ts +1484 -382
- package/src/__tests__/jest.setup.ts +88 -5
- package/src/__tests__/kv.test.ts +655 -540
- package/src/__tests__/logout.test.ts +47 -0
- package/src/__tests__/metrics.test.ts +95 -45
- package/src/__tests__/middleware.scheduled.test.ts +145 -0
- package/src/__tests__/middleware.test.ts +750 -0
- package/src/__tests__/pages-deployment-tail.test.ts +884 -0
- package/src/__tests__/pages.test.ts +1301 -119
- package/src/__tests__/paths.test.ts +39 -0
- package/src/__tests__/publish.test.ts +2266 -1180
- package/src/__tests__/pubsub.test.ts +211 -88
- package/src/__tests__/queues.test.ts +522 -0
- package/src/__tests__/r2.test.ts +363 -203
- package/src/__tests__/secret.test.ts +261 -59
- package/src/__tests__/tail.test.ts +352 -151
- package/src/__tests__/test-old-node-version.js +3 -3
- package/src/__tests__/tsconfig-sanity.ts +12 -0
- package/src/__tests__/tsconfig.json +8 -0
- package/src/__tests__/tsconfig.tsbuildinfo +1 -0
- package/src/__tests__/type-generation.test.ts +233 -0
- package/src/__tests__/user.test.ts +59 -73
- package/src/__tests__/utils-collectKeyValues.test.ts +47 -0
- package/src/__tests__/validate-dev-props.test.ts +56 -0
- package/src/__tests__/whoami.test.tsx +114 -66
- package/src/__tests__/worker-namespace.test.ts +154 -155
- package/src/api/dev.ts +170 -38
- package/src/api/index.ts +1 -0
- package/src/bundle-reporter.tsx +41 -2
- package/src/bundle.ts +668 -81
- package/src/cfetch/index.ts +40 -3
- package/src/cfetch/internal.ts +144 -32
- package/src/cli.ts +4 -3
- package/src/config/config.ts +27 -3
- package/src/config/environment.ts +131 -7
- package/src/config/index.ts +128 -8
- package/src/config/validation-helpers.ts +19 -6
- package/src/config/validation.ts +411 -14
- package/src/config-cache.ts +3 -2
- package/src/create-worker-preview.ts +31 -6
- package/src/create-worker-upload-form.ts +84 -22
- package/src/d1/backups.tsx +223 -0
- package/src/d1/constants.ts +2 -0
- package/src/d1/create.tsx +63 -0
- package/src/d1/delete.tsx +56 -0
- package/src/d1/execute.tsx +352 -0
- package/src/d1/formatTimeAgo.ts +14 -0
- package/src/d1/index.ts +101 -0
- package/src/d1/list.tsx +48 -0
- package/src/d1/migrations/apply.tsx +196 -0
- package/src/d1/migrations/create.tsx +77 -0
- package/src/d1/migrations/helpers.ts +147 -0
- package/src/d1/migrations/index.tsx +3 -0
- package/src/d1/migrations/list.tsx +79 -0
- package/src/d1/migrations/options.ts +18 -0
- package/src/d1/options.ts +22 -0
- package/src/d1/types.tsx +24 -0
- package/src/d1/utils.ts +48 -0
- package/src/delete.ts +108 -0
- package/src/deployments.ts +83 -0
- package/src/deprecated/index.ts +145 -0
- package/src/dev/dev-vars.ts +11 -8
- package/src/dev/dev.tsx +220 -58
- package/src/dev/get-local-persistence-path.tsx +31 -0
- package/src/dev/local.tsx +740 -181
- package/src/dev/remote.tsx +340 -123
- package/src/dev/start-server.ts +543 -0
- package/src/dev/use-esbuild.ts +61 -7
- package/src/dev/validate-dev-props.ts +31 -0
- package/src/dev-registry.tsx +201 -0
- package/src/dev.tsx +614 -258
- package/src/dialogs.tsx +41 -8
- package/src/{worker-namespace.ts → dispatch-namespace.ts} +23 -22
- package/src/docs/index.ts +97 -0
- package/src/entry.ts +3 -2
- package/src/environment-variables/factory.ts +88 -0
- package/src/environment-variables/misc-variables.ts +30 -0
- package/src/generate/index.ts +300 -0
- package/src/git-client.ts +100 -7
- package/src/index.tsx +249 -1560
- package/src/init.ts +626 -150
- package/src/inspect.ts +137 -32
- package/src/{metrics/is-ci.ts → is-ci.ts} +0 -0
- package/src/is-interactive.ts +4 -0
- package/src/jest.d.ts +4 -0
- package/src/{kv.ts → kv/helpers.ts} +3 -3
- package/src/kv/index.ts +596 -0
- package/src/logger.ts +27 -8
- package/src/metrics/index.ts +1 -0
- package/src/metrics/metrics-config.ts +4 -4
- package/src/metrics/metrics-dispatcher.ts +1 -0
- package/src/metrics/metrics-usage-headers.ts +24 -0
- package/src/metrics/send-event.ts +13 -8
- package/src/miniflare-cli/assets.ts +172 -465
- package/src/miniflare-cli/index.ts +149 -24
- package/src/miniflare-cli/tsconfig.json +9 -0
- package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
- package/src/miniflare-cli/types.ts +11 -0
- package/src/module-collection.ts +12 -3
- package/src/pages/build.tsx +108 -42
- package/src/pages/constants.ts +11 -0
- package/src/pages/deployment-tails.tsx +284 -0
- package/src/pages/deployments.tsx +9 -31
- package/src/pages/dev.tsx +417 -108
- package/src/pages/errors.ts +66 -0
- package/src/pages/functions/buildPlugin.ts +86 -84
- package/src/pages/functions/buildWorker.ts +121 -106
- 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 +282 -0
- package/src/pages/functions/routes-transformation.ts +115 -0
- package/src/pages/functions/routes-validation.test.ts +403 -0
- package/src/pages/functions/routes-validation.ts +202 -0
- package/src/pages/functions/tsconfig.json +8 -0
- package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
- package/src/pages/functions.tsx +82 -0
- package/src/pages/hash.tsx +13 -0
- package/src/pages/index.tsx +73 -55
- package/src/pages/projects.tsx +9 -3
- package/src/pages/prompt-select-project.tsx +31 -0
- package/src/pages/publish.tsx +183 -60
- package/src/pages/types.ts +1 -0
- package/src/pages/upload.tsx +107 -56
- package/src/pages/utils.ts +13 -2
- package/src/paths.ts +49 -4
- package/src/proxy.ts +375 -157
- package/src/publish/index.ts +270 -0
- package/src/{publish.ts → publish/publish.ts} +431 -188
- package/src/pubsub/pubsub-commands.tsx +4 -3
- package/src/queues/cli/commands/consumer/add.ts +71 -0
- package/src/queues/cli/commands/consumer/index.ts +22 -0
- package/src/queues/cli/commands/consumer/remove.ts +38 -0
- package/src/queues/cli/commands/create.ts +25 -0
- package/src/queues/cli/commands/delete.ts +26 -0
- package/src/queues/cli/commands/index.ts +36 -0
- package/src/queues/cli/commands/list.ts +25 -0
- package/src/queues/client.ts +135 -0
- package/src/queues/utils.ts +18 -0
- package/src/r2/constants.ts +4 -0
- package/src/r2/helpers.ts +131 -0
- package/src/r2/index.ts +289 -0
- package/src/routes.ts +140 -0
- package/src/secret/index.ts +379 -0
- package/src/sites.tsx +3 -3
- package/src/tail/createTail.ts +379 -0
- package/src/tail/filters.ts +4 -6
- package/src/tail/index.ts +199 -284
- package/src/tail/printing.ts +43 -3
- package/src/tsconfig-sanity.ts +16 -0
- package/src/type-generation.ts +181 -0
- package/src/user/access.ts +68 -0
- package/src/user/auth-variables.ts +113 -0
- package/src/user/choose-account.tsx +1 -1
- package/src/user/index.ts +0 -1
- package/src/user/user.tsx +116 -49
- package/src/utils/collectKeyValues.ts +14 -0
- package/src/whoami.tsx +80 -2
- package/src/worker.ts +69 -9
- package/src/yargs-types.ts +24 -0
- package/src/zones.ts +124 -9
- package/templates/__tests__/pages-dev-util.test.ts +128 -0
- package/templates/__tests__/tsconfig-sanity.ts +12 -0
- package/templates/__tests__/tsconfig.json +8 -0
- package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
- package/templates/d1-beta-facade.js +205 -0
- package/templates/facade.d.ts +14 -0
- package/templates/first-party-worker-module-facade.ts +19 -0
- package/templates/format-dev-errors.ts +33 -0
- package/templates/init-tests/test-jest-new-worker.js +23 -0
- package/templates/init-tests/test-vitest-new-worker.js +24 -0
- package/templates/init-tests/test-vitest-new-worker.ts +25 -0
- package/templates/middleware/common.ts +62 -0
- package/templates/middleware/loader-modules.ts +82 -0
- package/templates/middleware/loader-sw.ts +233 -0
- package/templates/middleware/middleware-miniflare3-json-error.ts +20 -0
- package/templates/middleware/middleware-pretty-error.ts +40 -0
- package/templates/middleware/middleware-scheduled.ts +15 -0
- package/templates/new-worker.js +1 -1
- package/templates/pages-dev-pipeline.ts +31 -0
- package/templates/pages-dev-util.ts +52 -0
- package/templates/pages-shim.ts +4 -1
- package/templates/pages-template-plugin.ts +21 -5
- package/templates/pages-template-worker.ts +37 -9
- package/templates/{static-asset-facade.js → serve-static-assets.ts} +23 -7
- package/templates/service-bindings-module-facade.js +54 -0
- package/templates/service-bindings-sw-facade.js +42 -0
- package/templates/tsconfig-sanity.ts +11 -0
- package/templates/tsconfig.init.json +106 -0
- package/templates/tsconfig.json +5 -102
- package/templates/tsconfig.tsbuildinfo +1 -0
- package/wrangler-dist/cli.d.ts +621 -42
- package/wrangler-dist/cli.js +144441 -102606
- package/src/environment-variables.ts +0 -35
- package/src/faye-websocket.d.ts +0 -6
- package/src/generate.ts +0 -33
- package/src/miniflare-cli/enum-keys.ts +0 -17
- package/src/preview.ts +0 -31
- package/src/r2.ts +0 -50
- package/src/user/env-vars.ts +0 -46
|
@@ -2,28 +2,39 @@ import assert from "node:assert";
|
|
|
2
2
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { URLSearchParams } from "node:url";
|
|
5
|
+
import chalk from "chalk";
|
|
5
6
|
import tmp from "tmp-promise";
|
|
6
|
-
import { bundleWorker } from "
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import
|
|
7
|
+
import { bundleWorker } from "../bundle";
|
|
8
|
+
import {
|
|
9
|
+
printBundleSize,
|
|
10
|
+
printOffendingDependencies,
|
|
11
|
+
} from "../bundle-reporter";
|
|
12
|
+
import { fetchListResult, fetchResult } from "../cfetch";
|
|
13
|
+
import { printBindings } from "../config";
|
|
14
|
+
import { createWorkerUploadForm } from "../create-worker-upload-form";
|
|
15
|
+
import { confirm, fromDashMessagePrompt } from "../dialogs";
|
|
16
|
+
import { getMigrationsToUpload } from "../durable";
|
|
17
|
+
import { logger } from "../logger";
|
|
18
|
+
import { getMetricsUsageHeaders } from "../metrics";
|
|
19
|
+
import { ParseError } from "../parse";
|
|
20
|
+
import { getQueue, putConsumer } from "../queues/client";
|
|
21
|
+
import { getWorkersDevSubdomain } from "../routes";
|
|
22
|
+
import { syncAssets } from "../sites";
|
|
23
|
+
import { identifyD1BindingsAsBeta } from "../worker";
|
|
24
|
+
import { getZoneForRoute } from "../zones";
|
|
25
|
+
import type { FetchError } from "../cfetch";
|
|
26
|
+
import type { Config } from "../config";
|
|
18
27
|
import type {
|
|
19
28
|
Route,
|
|
20
29
|
ZoneIdRoute,
|
|
21
30
|
ZoneNameRoute,
|
|
22
31
|
CustomDomainRoute,
|
|
23
|
-
} from "
|
|
24
|
-
import type {
|
|
25
|
-
import type {
|
|
26
|
-
import type {
|
|
32
|
+
} from "../config/environment";
|
|
33
|
+
import type { DeploymentListRes } from "../deployments";
|
|
34
|
+
import type { Entry } from "../entry";
|
|
35
|
+
import type { PutConsumerBody } from "../queues/client";
|
|
36
|
+
import type { AssetPaths } from "../sites";
|
|
37
|
+
import type { CfWorkerInit } from "../worker";
|
|
27
38
|
|
|
28
39
|
type Props = {
|
|
29
40
|
config: Config;
|
|
@@ -35,6 +46,8 @@ type Props = {
|
|
|
35
46
|
compatibilityDate: string | undefined;
|
|
36
47
|
compatibilityFlags: string[] | undefined;
|
|
37
48
|
assetPaths: AssetPaths | undefined;
|
|
49
|
+
vars: Record<string, string> | undefined;
|
|
50
|
+
defines: Record<string, string> | undefined;
|
|
38
51
|
triggers: string[] | undefined;
|
|
39
52
|
routes: string[] | undefined;
|
|
40
53
|
legacyEnv: boolean | undefined;
|
|
@@ -47,14 +60,64 @@ type Props = {
|
|
|
47
60
|
outDir: string | undefined;
|
|
48
61
|
dryRun: boolean | undefined;
|
|
49
62
|
noBundle: boolean | undefined;
|
|
63
|
+
keepVars: boolean | undefined;
|
|
64
|
+
logpush: boolean | undefined;
|
|
50
65
|
};
|
|
51
66
|
|
|
52
67
|
type RouteObject = ZoneIdRoute | ZoneNameRoute | CustomDomainRoute;
|
|
53
68
|
|
|
69
|
+
export type CustomDomain = {
|
|
70
|
+
id: string;
|
|
71
|
+
zone_id: string;
|
|
72
|
+
zone_name: string;
|
|
73
|
+
hostname: string;
|
|
74
|
+
service: string;
|
|
75
|
+
environment: string;
|
|
76
|
+
};
|
|
77
|
+
type UpdatedCustomDomain = CustomDomain & { modified: boolean };
|
|
78
|
+
type ConflictingCustomDomain = CustomDomain & {
|
|
79
|
+
external_dns_record_id?: string;
|
|
80
|
+
external_cert_id?: string;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type CustomDomainChangeset = {
|
|
84
|
+
added: CustomDomain[];
|
|
85
|
+
removed: CustomDomain[];
|
|
86
|
+
updated: UpdatedCustomDomain[];
|
|
87
|
+
conflicting: ConflictingCustomDomain[];
|
|
88
|
+
};
|
|
89
|
+
|
|
54
90
|
function sleep(ms: number) {
|
|
55
91
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
56
92
|
}
|
|
57
93
|
|
|
94
|
+
const scriptStartupErrorRegex = /startup/i;
|
|
95
|
+
|
|
96
|
+
function errIsScriptSizeOrStartupErr(err: unknown) {
|
|
97
|
+
if (!err) return false;
|
|
98
|
+
|
|
99
|
+
// 10027 = workers.api.error.script_too_large
|
|
100
|
+
if ((err as { code: number }).code === 10027) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 10021 = validation error
|
|
105
|
+
// no explicit error code for more granular errors than "invalid script"
|
|
106
|
+
// but the error will contain a string error message directly from the
|
|
107
|
+
// validator.
|
|
108
|
+
// the error always SHOULD look like "Script startup exceeded CPU limit."
|
|
109
|
+
// (or the less likely "Script startup exceeded memory limits.")
|
|
110
|
+
if (
|
|
111
|
+
(err as { code: number }).code === 10021 &&
|
|
112
|
+
err instanceof ParseError &&
|
|
113
|
+
scriptStartupErrorRegex.test(err.notes[0]?.text)
|
|
114
|
+
) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
58
121
|
function renderRoute(route: Route): string {
|
|
59
122
|
let result = "";
|
|
60
123
|
if (typeof route === "string") {
|
|
@@ -79,58 +142,27 @@ function renderRoute(route: Route): string {
|
|
|
79
142
|
return result;
|
|
80
143
|
}
|
|
81
144
|
|
|
82
|
-
// this function takes a string with quotes in it
|
|
83
|
-
// (i.e. `hello "world", if that really is your name`)
|
|
84
|
-
// and peels out the first instance of a substring
|
|
85
|
-
// bounded by quotes (so, in the example above, `world`)
|
|
86
|
-
//
|
|
87
|
-
// this is useful because the /domains api will return
|
|
88
|
-
// which domains conflicted in an error message, bounded
|
|
89
|
-
// by a string, which we can use to provide helpful
|
|
90
|
-
// messages to a user
|
|
91
|
-
function getQuoteBoundedSubstring(content: string) {
|
|
92
|
-
const matches = content.split('"');
|
|
93
|
-
return matches[1] ?? "";
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function isOriginConflictError(
|
|
97
|
-
e: unknown
|
|
98
|
-
): e is { code: 100116; message: string; notes: Array<{ text: string }> } {
|
|
99
|
-
return (
|
|
100
|
-
typeof e === "object" &&
|
|
101
|
-
e !== null &&
|
|
102
|
-
(e as { code: number }).code === 100116
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function isDNSConflictError(
|
|
107
|
-
e: unknown
|
|
108
|
-
): e is { code: 100117; message: string; notes: Array<{ text: string }> } {
|
|
109
|
-
return (
|
|
110
|
-
typeof e === "object" &&
|
|
111
|
-
e !== null &&
|
|
112
|
-
(e as { code: number }).code === 100117
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// empty error class to throw and then explicitly catch via `instanceof`
|
|
117
|
-
class CustomDomainOverrideRejected extends Error {}
|
|
118
|
-
|
|
119
145
|
// publishing to custom domains involves a few more steps than just updating
|
|
120
146
|
// the routing table, and thus the api implementing it is fairly defensive -
|
|
121
147
|
// it will error eagerly on conflicts against existing domains or existing
|
|
122
148
|
// managed DNS records
|
|
123
|
-
|
|
124
|
-
// however, you can pass params to override the errors.
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
//
|
|
149
|
+
|
|
150
|
+
// however, you can pass params to override the errors. to know if we should
|
|
151
|
+
// override the current state, we generate a "changeset" of required actions
|
|
152
|
+
// to get to the state we want (specified by the list of custom domains). the
|
|
153
|
+
// changeset returns an "updated" collection (existing custom domains
|
|
154
|
+
// connected to other scripts) and a "conflicting" collection (the requested
|
|
155
|
+
// custom domains that have a managed, conflicting DNS record preventing the
|
|
156
|
+
// host's use as a custom domain). with this information, we can prompt to
|
|
157
|
+
// the user what will occur if we create the custom domains requested, and
|
|
158
|
+
// add the override param if they confirm the action
|
|
128
159
|
//
|
|
129
160
|
// if a user does not confirm that they want to override, we skip publishing
|
|
130
161
|
// to these custom domains, but continue on through the rest of the
|
|
131
162
|
// publish stage
|
|
132
|
-
function publishCustomDomains(
|
|
163
|
+
async function publishCustomDomains(
|
|
133
164
|
workerUrl: string,
|
|
165
|
+
accountId: string,
|
|
134
166
|
domains: Array<RouteObject>
|
|
135
167
|
): Promise<string[]> {
|
|
136
168
|
const config = {
|
|
@@ -146,88 +178,117 @@ function publishCustomDomains(
|
|
|
146
178
|
};
|
|
147
179
|
});
|
|
148
180
|
|
|
181
|
+
const fail = () => {
|
|
182
|
+
return [
|
|
183
|
+
domains.length > 1
|
|
184
|
+
? `Publishing to ${domains.length} Custom Domains was skipped, fix conflicts and try again`
|
|
185
|
+
: `Publishing to Custom Domain "${domains[0].pattern}" was skipped, fix conflict and try again`,
|
|
186
|
+
];
|
|
187
|
+
};
|
|
188
|
+
|
|
149
189
|
if (!process.stdout.isTTY) {
|
|
150
190
|
// running in non-interactive mode.
|
|
151
191
|
// existing origins / dns records are not indicative of errors,
|
|
152
192
|
// so we aggressively update rather than aggressively fail
|
|
153
193
|
config.override_existing_origin = true;
|
|
154
194
|
config.override_existing_dns_record = true;
|
|
195
|
+
} else {
|
|
196
|
+
// get a changeset for operations required to achieve a state with the requested domains
|
|
197
|
+
const changeset = await fetchResult<CustomDomainChangeset>(
|
|
198
|
+
`${workerUrl}/domains/changeset?replace_state=true`,
|
|
199
|
+
{
|
|
200
|
+
method: "POST",
|
|
201
|
+
body: JSON.stringify(origins),
|
|
202
|
+
headers: {
|
|
203
|
+
"Content-Type": "application/json",
|
|
204
|
+
},
|
|
205
|
+
}
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const updatesRequired = changeset.updated.filter(
|
|
209
|
+
(domain) => domain.modified
|
|
210
|
+
);
|
|
211
|
+
if (updatesRequired.length > 0) {
|
|
212
|
+
// find out which scripts the conflict domains are already attached to
|
|
213
|
+
// so we can provide that in the confirmation prompt
|
|
214
|
+
const existing = await Promise.all(
|
|
215
|
+
updatesRequired.map((domain) =>
|
|
216
|
+
fetchResult<CustomDomain>(
|
|
217
|
+
`/accounts/${accountId}/workers/domains/records/${domain.id}`
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
);
|
|
221
|
+
const existingRendered = existing
|
|
222
|
+
.map(
|
|
223
|
+
(domain) =>
|
|
224
|
+
`\t• ${domain.hostname} (used as a domain for "${domain.service}")`
|
|
225
|
+
)
|
|
226
|
+
.join("\n");
|
|
227
|
+
const message = `Custom Domains already exist for these domains:
|
|
228
|
+
${existingRendered}
|
|
229
|
+
Update them to point to this script instead?`;
|
|
230
|
+
if (!(await confirm(message))) return fail();
|
|
231
|
+
config.override_existing_origin = true;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (changeset.conflicting.length > 0) {
|
|
235
|
+
const conflicitingRendered = changeset.conflicting
|
|
236
|
+
.map((domain) => `\t• ${domain.hostname}`)
|
|
237
|
+
.join("\n");
|
|
238
|
+
const message = `You already have DNS records that conflict for these Custom Domains:
|
|
239
|
+
${conflicitingRendered}
|
|
240
|
+
Update them to point to this script instead?`;
|
|
241
|
+
if (!(await confirm(message))) return fail();
|
|
242
|
+
config.override_existing_dns_record = true;
|
|
243
|
+
}
|
|
155
244
|
}
|
|
156
245
|
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
// while retaining the flexibility of promise chain fall-throughs. We can group error
|
|
160
|
-
// handling logic in dedicated catch calls, and all we have to do is re-throw an
|
|
161
|
-
// error and it will pass down to the next catch call
|
|
162
|
-
return fetchResult(`${workerUrl}/domains`, {
|
|
246
|
+
// publish to domains
|
|
247
|
+
await fetchResult(`${workerUrl}/domains/records`, {
|
|
163
248
|
method: "PUT",
|
|
164
249
|
body: JSON.stringify({ ...config, origins }),
|
|
165
250
|
headers: {
|
|
166
251
|
"Content-Type": "application/json",
|
|
167
252
|
},
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const conflictingOrigins = getQuoteBoundedSubstring(err.notes[0].text);
|
|
172
|
-
const shouldContinue = await confirm(
|
|
173
|
-
`Custom Domains already exist for these domains: "${conflictingOrigins}"\nUpdate them to point to this script instead?`
|
|
174
|
-
);
|
|
175
|
-
if (!shouldContinue) {
|
|
176
|
-
throw new CustomDomainOverrideRejected();
|
|
177
|
-
}
|
|
178
|
-
config.override_existing_origin = true;
|
|
179
|
-
await fetchResult(`${workerUrl}/domains`, {
|
|
180
|
-
method: "PUT",
|
|
181
|
-
body: JSON.stringify({ ...config, origins }),
|
|
182
|
-
headers: {
|
|
183
|
-
"Content-Type": "application/json",
|
|
184
|
-
},
|
|
185
|
-
});
|
|
186
|
-
} else {
|
|
187
|
-
throw err;
|
|
188
|
-
}
|
|
189
|
-
})
|
|
190
|
-
.catch(async (err) => {
|
|
191
|
-
if (isDNSConflictError(err)) {
|
|
192
|
-
const conflictingOrigins = getQuoteBoundedSubstring(err.notes[0].text);
|
|
193
|
-
const shouldContinue = await confirm(
|
|
194
|
-
`You already have conflicting DNS records for these domains: "${conflictingOrigins}"\nUpdate them to point to this script instead?`
|
|
195
|
-
);
|
|
196
|
-
if (!shouldContinue) {
|
|
197
|
-
throw new CustomDomainOverrideRejected();
|
|
198
|
-
}
|
|
199
|
-
config.override_existing_dns_record = true;
|
|
200
|
-
await fetchResult(`${workerUrl}/domains`, {
|
|
201
|
-
method: "PUT",
|
|
202
|
-
body: JSON.stringify({ ...config, origins }),
|
|
203
|
-
headers: {
|
|
204
|
-
"Content-Type": "application/json",
|
|
205
|
-
},
|
|
206
|
-
});
|
|
207
|
-
} else {
|
|
208
|
-
throw err;
|
|
209
|
-
}
|
|
210
|
-
})
|
|
211
|
-
.then(() => domains.map((domain) => renderRoute(domain)))
|
|
212
|
-
.catch((err) => {
|
|
213
|
-
if (err instanceof CustomDomainOverrideRejected) {
|
|
214
|
-
return [
|
|
215
|
-
domains.length > 1
|
|
216
|
-
? `Publishing to ${domains.length} Custom Domains was skipped, fix conflicts and try again`
|
|
217
|
-
: `Publishing to Custom Domain "${domains[0].pattern}" was skipped, fix conflict and try again`,
|
|
218
|
-
];
|
|
219
|
-
}
|
|
220
|
-
throw err;
|
|
221
|
-
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
return domains.map((domain) => renderRoute(domain));
|
|
222
256
|
}
|
|
223
257
|
|
|
224
258
|
export default async function publish(props: Props): Promise<void> {
|
|
225
259
|
// TODO: warn if git/hg has uncommitted changes
|
|
226
|
-
const { config, accountId } = props;
|
|
260
|
+
const { config, accountId, name } = props;
|
|
261
|
+
if (accountId && name) {
|
|
262
|
+
try {
|
|
263
|
+
const serviceMetaData = await fetchResult(
|
|
264
|
+
`/accounts/${accountId}/workers/services/${name}`
|
|
265
|
+
);
|
|
266
|
+
const { default_environment } = serviceMetaData as {
|
|
267
|
+
default_environment: {
|
|
268
|
+
script: { last_deployed_from: "dash" | "wrangler" | "api" };
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
if (
|
|
273
|
+
(await fromDashMessagePrompt(
|
|
274
|
+
default_environment.script.last_deployed_from
|
|
275
|
+
)) === false
|
|
276
|
+
)
|
|
277
|
+
return;
|
|
278
|
+
} catch (e) {
|
|
279
|
+
// code: 10090, message: workers.api.error.service_not_found
|
|
280
|
+
// is thrown from the above fetchResult on the first publish of a Worker
|
|
281
|
+
if ((e as { code?: number }).code !== 10090) {
|
|
282
|
+
logger.error(e);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
227
286
|
|
|
228
287
|
if (!(props.compatibilityDate || config.compatibility_date)) {
|
|
229
288
|
const compatibilityDateStr = `${new Date().getFullYear()}-${(
|
|
230
|
-
new Date().getMonth() +
|
|
289
|
+
new Date().getMonth() +
|
|
290
|
+
1 +
|
|
291
|
+
""
|
|
231
292
|
).padStart(2, "0")}-${(new Date().getDate() + "").padStart(2, "0")}`;
|
|
232
293
|
|
|
233
294
|
throw new Error(`A compatibility_date is required when publishing. Add the following to your wrangler.toml file:.
|
|
@@ -266,6 +327,7 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
|
|
|
266
327
|
|
|
267
328
|
const jsxFactory = props.jsxFactory || config.jsx_factory;
|
|
268
329
|
const jsxFragment = props.jsxFragment || config.jsx_fragment;
|
|
330
|
+
const keepVars = props.keepVars ?? config.keep_vars;
|
|
269
331
|
|
|
270
332
|
const minify = props.minify ?? config.minify;
|
|
271
333
|
|
|
@@ -322,7 +384,8 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
|
|
|
322
384
|
? `/accounts/${accountId}/workers/services/${scriptName}/environments/${envName}`
|
|
323
385
|
: `/accounts/${accountId}/workers/scripts/${scriptName}`;
|
|
324
386
|
|
|
325
|
-
let available_on_subdomain; // we'll set this later
|
|
387
|
+
let available_on_subdomain: boolean | undefined = undefined; // we'll set this later
|
|
388
|
+
let scriptTag: string | null = null;
|
|
326
389
|
|
|
327
390
|
const { format } = props.entry;
|
|
328
391
|
|
|
@@ -365,14 +428,29 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
|
|
|
365
428
|
);
|
|
366
429
|
}
|
|
367
430
|
|
|
431
|
+
// If we are using d1 bindings, and are not bundling the worker
|
|
432
|
+
// we should error here as the d1 shim won't be added
|
|
433
|
+
const betaD1Shims = identifyD1BindingsAsBeta(config.d1_databases);
|
|
434
|
+
if (
|
|
435
|
+
Array.isArray(betaD1Shims) &&
|
|
436
|
+
betaD1Shims.length > 0 &&
|
|
437
|
+
props.noBundle
|
|
438
|
+
) {
|
|
439
|
+
throw new Error(
|
|
440
|
+
"While in beta, you cannot use D1 bindings without bundling your worker. Please remove `no_bundle` from your wrangler.toml file or remove the `--no-bundle` flag to access D1 bindings."
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
368
444
|
const {
|
|
369
445
|
modules,
|
|
446
|
+
dependencies,
|
|
370
447
|
resolvedEntryPointPath,
|
|
371
448
|
bundleType,
|
|
372
449
|
}: Awaited<ReturnType<typeof bundleWorker>> = props.noBundle
|
|
373
450
|
? // we can skip the whole bundling step and mock a bundle here
|
|
374
451
|
{
|
|
375
452
|
modules: [],
|
|
453
|
+
dependencies: {},
|
|
376
454
|
resolvedEntryPointPath: props.entry.file,
|
|
377
455
|
bundleType: props.entry.format === "modules" ? "esm" : "commonjs",
|
|
378
456
|
stop: undefined,
|
|
@@ -383,14 +461,33 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
|
|
|
383
461
|
{
|
|
384
462
|
serveAssetsFromWorker:
|
|
385
463
|
!props.isWorkersSite && Boolean(props.assetPaths),
|
|
464
|
+
betaD1Shims: identifyD1BindingsAsBeta(config.d1_databases)?.map(
|
|
465
|
+
(db) => db.binding
|
|
466
|
+
),
|
|
386
467
|
jsxFactory,
|
|
387
468
|
jsxFragment,
|
|
388
469
|
rules: props.rules,
|
|
389
470
|
tsconfig: props.tsconfig ?? config.tsconfig,
|
|
390
471
|
minify,
|
|
391
472
|
nodeCompat,
|
|
392
|
-
define: config.define,
|
|
473
|
+
define: { ...config.define, ...props.defines },
|
|
393
474
|
checkFetch: false,
|
|
475
|
+
assets: config.assets && {
|
|
476
|
+
...config.assets,
|
|
477
|
+
// enable the cache when publishing
|
|
478
|
+
bypassCache: false,
|
|
479
|
+
},
|
|
480
|
+
services: config.services,
|
|
481
|
+
// We don't set workerDefinitions here,
|
|
482
|
+
// because we don't want to apply the dev-time
|
|
483
|
+
// facades on top of it
|
|
484
|
+
workerDefinitions: undefined,
|
|
485
|
+
firstPartyWorkerDevFacade: false,
|
|
486
|
+
// We want to know if the build is for development or publishing
|
|
487
|
+
// This could potentially cause issues as we no longer have identical behaviour between dev and publish?
|
|
488
|
+
targetConsumer: "publish",
|
|
489
|
+
local: false,
|
|
490
|
+
experimentalLocal: false,
|
|
394
491
|
}
|
|
395
492
|
);
|
|
396
493
|
|
|
@@ -426,7 +523,7 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
|
|
|
426
523
|
? { binding: "__STATIC_CONTENT", id: assets.namespace }
|
|
427
524
|
: []
|
|
428
525
|
),
|
|
429
|
-
vars: config.vars,
|
|
526
|
+
vars: { ...config.vars, ...props.vars },
|
|
430
527
|
wasm_modules: config.wasm_modules,
|
|
431
528
|
text_blobs: {
|
|
432
529
|
...config.text_blobs,
|
|
@@ -437,9 +534,15 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
|
|
|
437
534
|
},
|
|
438
535
|
data_blobs: config.data_blobs,
|
|
439
536
|
durable_objects: config.durable_objects,
|
|
537
|
+
queues: config.queues.producers?.map((producer) => {
|
|
538
|
+
return { binding: producer.binding, queue_name: producer.queue };
|
|
539
|
+
}),
|
|
440
540
|
r2_buckets: config.r2_buckets,
|
|
541
|
+
d1_databases: identifyD1BindingsAsBeta(config.d1_databases),
|
|
441
542
|
services: config.services,
|
|
442
|
-
|
|
543
|
+
analytics_engine_datasets: config.analytics_engine_datasets,
|
|
544
|
+
dispatch_namespaces: config.dispatch_namespaces,
|
|
545
|
+
logfwdr: config.logfwdr,
|
|
443
546
|
unsafe: config.unsafe?.bindings,
|
|
444
547
|
};
|
|
445
548
|
|
|
@@ -465,51 +568,83 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
|
|
|
465
568
|
compatibility_flags:
|
|
466
569
|
props.compatibilityFlags ?? config.compatibility_flags,
|
|
467
570
|
usage_model: config.usage_model,
|
|
571
|
+
keepVars,
|
|
572
|
+
logpush: props.logpush !== undefined ? props.logpush : config.logpush,
|
|
468
573
|
};
|
|
469
574
|
|
|
470
|
-
|
|
575
|
+
// As this is not deterministic for testing, we detect if in a jest environment and run asynchronously
|
|
576
|
+
// We do not care about the timing outside of testing
|
|
577
|
+
const bundleSizePromise = printBundleSize(
|
|
471
578
|
{ name: path.basename(resolvedEntryPointPath), content: content },
|
|
472
579
|
modules
|
|
473
580
|
);
|
|
581
|
+
if (process.env.JEST_WORKER_ID !== undefined) await bundleSizePromise;
|
|
582
|
+
else void bundleSizePromise;
|
|
474
583
|
|
|
475
584
|
const withoutStaticAssets = {
|
|
476
585
|
...bindings,
|
|
477
586
|
kv_namespaces: config.kv_namespaces,
|
|
478
587
|
text_blobs: config.text_blobs,
|
|
479
588
|
};
|
|
480
|
-
|
|
589
|
+
|
|
590
|
+
// mask anything that was overridden in cli args
|
|
591
|
+
// so that we don't log potential secrets into the terminal
|
|
592
|
+
const maskedVars = { ...withoutStaticAssets.vars };
|
|
593
|
+
for (const key of Object.keys(maskedVars)) {
|
|
594
|
+
if (maskedVars[key] !== config.vars[key]) {
|
|
595
|
+
// This means it was overridden in cli args
|
|
596
|
+
// so let's mask it
|
|
597
|
+
maskedVars[key] = "(hidden)";
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
printBindings({ ...withoutStaticAssets, vars: maskedVars });
|
|
602
|
+
|
|
603
|
+
await ensureQueuesExist(config);
|
|
481
604
|
|
|
482
605
|
if (!props.dryRun) {
|
|
483
606
|
// Upload the script so it has time to propagate.
|
|
484
607
|
// We can also now tell whether available_on_subdomain is set
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
608
|
+
try {
|
|
609
|
+
const result = await fetchResult<{
|
|
610
|
+
available_on_subdomain: boolean;
|
|
611
|
+
id: string | null;
|
|
612
|
+
etag: string | null;
|
|
613
|
+
pipeline_hash: string | null;
|
|
614
|
+
tag: string | null;
|
|
615
|
+
}>(
|
|
616
|
+
workerUrl,
|
|
617
|
+
{
|
|
618
|
+
method: "PUT",
|
|
619
|
+
body: createWorkerUploadForm(worker),
|
|
620
|
+
headers: await getMetricsUsageHeaders(config.send_metrics),
|
|
621
|
+
},
|
|
622
|
+
new URLSearchParams({
|
|
623
|
+
include_subdomain_availability: "true",
|
|
624
|
+
// pass excludeScript so the whole body of the
|
|
625
|
+
// script doesn't get included in the response
|
|
626
|
+
excludeScript: "true",
|
|
627
|
+
})
|
|
628
|
+
);
|
|
505
629
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
630
|
+
available_on_subdomain = result.available_on_subdomain;
|
|
631
|
+
scriptTag = result.tag;
|
|
632
|
+
|
|
633
|
+
if (config.first_party_worker) {
|
|
634
|
+
// Print some useful information returned after publishing
|
|
635
|
+
// Not all fields will be populated for every worker
|
|
636
|
+
// These fields are likely to be scraped by tools, so do not rename
|
|
637
|
+
if (result.id) logger.log("Worker ID: ", result.id);
|
|
638
|
+
if (result.etag) logger.log("Worker ETag: ", result.etag);
|
|
639
|
+
if (result.pipeline_hash)
|
|
640
|
+
logger.log("Worker PipelineHash: ", result.pipeline_hash);
|
|
641
|
+
}
|
|
642
|
+
} catch (err) {
|
|
643
|
+
if (errIsScriptSizeOrStartupErr(err)) {
|
|
644
|
+
printOffendingDependencies(dependencies);
|
|
645
|
+
}
|
|
646
|
+
throw err;
|
|
647
|
+
}
|
|
513
648
|
}
|
|
514
649
|
} finally {
|
|
515
650
|
if (typeof destination !== "string") {
|
|
@@ -530,7 +665,7 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
|
|
|
530
665
|
|
|
531
666
|
if (deployToWorkersDev) {
|
|
532
667
|
// Deploy to a subdomain of `workers.dev`
|
|
533
|
-
const userSubdomain = await
|
|
668
|
+
const userSubdomain = await getWorkersDevSubdomain(accountId);
|
|
534
669
|
const scriptURL =
|
|
535
670
|
props.legacyEnv || !props.env
|
|
536
671
|
? `${scriptName}.${userSubdomain}.workers.dev`
|
|
@@ -568,6 +703,61 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
|
|
|
568
703
|
"Content-Type": "application/json",
|
|
569
704
|
},
|
|
570
705
|
});
|
|
706
|
+
} else if (routes.length !== 0) {
|
|
707
|
+
// if you get to this point it's because
|
|
708
|
+
// you're trying to deploy a worker to a custom
|
|
709
|
+
// domain that's already bound to another worker.
|
|
710
|
+
// so this thing is about finding workers that have
|
|
711
|
+
// bindings to the routes you're trying to deploy to.
|
|
712
|
+
//
|
|
713
|
+
// the logic is kinda similar (read: duplicated) from publishRoutesFallback,
|
|
714
|
+
// except here we know we have a good API token or whatever so we don't need
|
|
715
|
+
// to bother with all the error handling tomfoolery.
|
|
716
|
+
const routesWithOtherBindings: Record<string, string[]> = {};
|
|
717
|
+
for (const route of routes) {
|
|
718
|
+
const zone = await getZoneForRoute(route);
|
|
719
|
+
if (!zone) {
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
const routePattern = typeof route === "string" ? route : route.pattern;
|
|
724
|
+
const routesInZone = await fetchListResult<{
|
|
725
|
+
pattern: string;
|
|
726
|
+
script: string;
|
|
727
|
+
}>(`/zones/${zone.id}/workers/routes`);
|
|
728
|
+
|
|
729
|
+
routesInZone.forEach(({ script, pattern }) => {
|
|
730
|
+
if (pattern === routePattern && script !== scriptName) {
|
|
731
|
+
if (!(script in routesWithOtherBindings)) {
|
|
732
|
+
routesWithOtherBindings[script] = [];
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
routesWithOtherBindings[script].push(pattern);
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
if (Object.keys(routesWithOtherBindings).length > 0) {
|
|
741
|
+
let errorMessage =
|
|
742
|
+
"Can't publish a worker to routes that are assigned to another worker.\n";
|
|
743
|
+
|
|
744
|
+
for (const worker in routesWithOtherBindings) {
|
|
745
|
+
const assignedRoutes = routesWithOtherBindings[worker];
|
|
746
|
+
errorMessage += `"${worker}" is already assigned to routes:\n${assignedRoutes.map(
|
|
747
|
+
(r) => ` - ${chalk.underline(r)}\n`
|
|
748
|
+
)}`;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const resolution =
|
|
752
|
+
"Unassign other workers from the routes you want to publish to, and then try again.";
|
|
753
|
+
const dashLink = `Visit ${chalk.blue(
|
|
754
|
+
chalk.underline(
|
|
755
|
+
`https://dash.cloudflare.com/${accountId}/workers/overview`
|
|
756
|
+
)
|
|
757
|
+
)} to unassign a worker from a route.`;
|
|
758
|
+
|
|
759
|
+
throw new Error(`${errorMessage}\n${resolution}\n${dashLink}`);
|
|
760
|
+
}
|
|
571
761
|
}
|
|
572
762
|
}
|
|
573
763
|
|
|
@@ -590,7 +780,9 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
|
|
|
590
780
|
|
|
591
781
|
// Update custom domains for the script
|
|
592
782
|
if (customDomainsOnly.length > 0) {
|
|
593
|
-
deployments.push(
|
|
783
|
+
deployments.push(
|
|
784
|
+
publishCustomDomains(workerUrl, accountId, customDomainsOnly)
|
|
785
|
+
);
|
|
594
786
|
}
|
|
595
787
|
|
|
596
788
|
// Configure any schedules for the script.
|
|
@@ -608,48 +800,45 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
|
|
|
608
800
|
);
|
|
609
801
|
}
|
|
610
802
|
|
|
803
|
+
if (config.queues.consumers && config.queues.consumers.length) {
|
|
804
|
+
deployments.push(...updateQueueConsumers(config));
|
|
805
|
+
}
|
|
806
|
+
|
|
611
807
|
const targets = await Promise.all(deployments);
|
|
612
808
|
const deployMs = Date.now() - start - uploadMs;
|
|
613
809
|
|
|
614
810
|
if (deployments.length > 0) {
|
|
615
811
|
logger.log("Published", workerName, formatTime(deployMs));
|
|
616
812
|
for (const target of targets.flat()) {
|
|
617
|
-
|
|
813
|
+
// Append protocol only on workers.dev domains
|
|
814
|
+
logger.log(
|
|
815
|
+
" ",
|
|
816
|
+
(target.endsWith("workers.dev") ? "https://" : "") + target
|
|
817
|
+
);
|
|
618
818
|
}
|
|
619
819
|
} else {
|
|
620
820
|
logger.log("No publish targets for", workerName, formatTime(deployMs));
|
|
621
821
|
}
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
function formatTime(duration: number) {
|
|
625
|
-
return `(${(duration / 1000).toFixed(2)} sec)`;
|
|
626
|
-
}
|
|
627
822
|
|
|
628
|
-
async function getSubdomain(accountId: string): Promise<string> {
|
|
629
823
|
try {
|
|
630
|
-
const
|
|
631
|
-
`/accounts/${accountId}/workers/
|
|
824
|
+
const deploymentsList = await fetchResult<DeploymentListRes>(
|
|
825
|
+
`/accounts/${accountId}/workers/deployments/by-script/${scriptTag}`
|
|
632
826
|
);
|
|
633
|
-
|
|
827
|
+
|
|
828
|
+
logger.log("Current Deployment ID:", deploymentsList.latest.id);
|
|
634
829
|
} catch (e) {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
// 10007 error code: not found
|
|
638
|
-
// https://api.cloudflare.com/#worker-subdomain-get-subdomain
|
|
639
|
-
|
|
640
|
-
const errorMessage =
|
|
641
|
-
"Error: You need to register a workers.dev subdomain before publishing to workers.dev";
|
|
642
|
-
const solutionMessage =
|
|
643
|
-
"You can either publish your worker to one or more routes by specifying them in wrangler.toml, or register a workers.dev subdomain here:";
|
|
644
|
-
const onboardingLink = `https://dash.cloudflare.com/${accountId}/workers/onboarding`;
|
|
645
|
-
|
|
646
|
-
throw new Error(`${errorMessage}\n${solutionMessage}\n${onboardingLink}`);
|
|
830
|
+
if ((e as { code: number }).code === 10023) {
|
|
831
|
+
// TODO: remove this try/catch once deployments is completely rolled out
|
|
647
832
|
} else {
|
|
648
833
|
throw e;
|
|
649
834
|
}
|
|
650
835
|
}
|
|
651
836
|
}
|
|
652
837
|
|
|
838
|
+
function formatTime(duration: number) {
|
|
839
|
+
return `(${(duration / 1000).toFixed(2)} sec)`;
|
|
840
|
+
}
|
|
841
|
+
|
|
653
842
|
/**
|
|
654
843
|
* Associate the newly deployed Worker with the given routes.
|
|
655
844
|
*/
|
|
@@ -762,16 +951,19 @@ async function publishRoutesFallback(
|
|
|
762
951
|
}
|
|
763
952
|
}
|
|
764
953
|
|
|
765
|
-
const { pattern } = await fetchResult
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
954
|
+
const { pattern } = await fetchResult<{ pattern: string }>(
|
|
955
|
+
`/zones/${zoneId}/workers/routes`,
|
|
956
|
+
{
|
|
957
|
+
method: "POST",
|
|
958
|
+
body: JSON.stringify({
|
|
959
|
+
pattern: routePattern,
|
|
960
|
+
script: scriptName,
|
|
961
|
+
}),
|
|
962
|
+
headers: {
|
|
963
|
+
"Content-Type": "application/json",
|
|
964
|
+
},
|
|
965
|
+
}
|
|
966
|
+
);
|
|
775
967
|
|
|
776
968
|
deployedRoutes.push(pattern);
|
|
777
969
|
}
|
|
@@ -791,3 +983,54 @@ async function publishRoutesFallback(
|
|
|
791
983
|
function isAuthenticationError(e: unknown): e is ParseError {
|
|
792
984
|
return e instanceof ParseError && (e as { code?: number }).code === 10000;
|
|
793
985
|
}
|
|
986
|
+
|
|
987
|
+
async function ensureQueuesExist(config: Config) {
|
|
988
|
+
const producers = (config.queues.producers || []).map(
|
|
989
|
+
(producer) => producer.queue
|
|
990
|
+
);
|
|
991
|
+
const consumers = (config.queues.consumers || []).map(
|
|
992
|
+
(consumer) => consumer.queue
|
|
993
|
+
);
|
|
994
|
+
|
|
995
|
+
const queueNames = producers.concat(consumers);
|
|
996
|
+
for (const queue of queueNames) {
|
|
997
|
+
try {
|
|
998
|
+
await getQueue(config, queue);
|
|
999
|
+
} catch (err) {
|
|
1000
|
+
const queueErr = err as FetchError;
|
|
1001
|
+
if (queueErr.code === 11000) {
|
|
1002
|
+
// queue_not_found
|
|
1003
|
+
throw new Error(
|
|
1004
|
+
`Queue "${queue}" does not exist. To create it, run: wrangler queues create ${queue}`
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
throw err;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
function updateQueueConsumers(config: Config): Promise<string[]>[] {
|
|
1013
|
+
const consumers = config.queues.consumers || [];
|
|
1014
|
+
return consumers.map((consumer) => {
|
|
1015
|
+
const body: PutConsumerBody = {
|
|
1016
|
+
dead_letter_queue: consumer.dead_letter_queue,
|
|
1017
|
+
settings: {
|
|
1018
|
+
batch_size: consumer.max_batch_size,
|
|
1019
|
+
max_retries: consumer.max_retries,
|
|
1020
|
+
max_wait_time_ms: consumer.max_batch_timeout
|
|
1021
|
+
? 1000 * consumer.max_batch_timeout
|
|
1022
|
+
: undefined,
|
|
1023
|
+
},
|
|
1024
|
+
};
|
|
1025
|
+
|
|
1026
|
+
if (config.name === undefined) {
|
|
1027
|
+
// TODO: how can we reliably get the current script name?
|
|
1028
|
+
throw new Error("Script name is required to update queue consumers");
|
|
1029
|
+
}
|
|
1030
|
+
const scriptName = config.name;
|
|
1031
|
+
const envName = undefined; // TODO: script environment for wrangler publish?
|
|
1032
|
+
return putConsumer(config, consumer.queue, scriptName, envName, body).then(
|
|
1033
|
+
() => [`Consumer for ${consumer.queue}`]
|
|
1034
|
+
);
|
|
1035
|
+
});
|
|
1036
|
+
}
|