wrangler 0.0.0-e5d3690 → 0.0.0-e5dbedd78

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.
Files changed (124) hide show
  1. package/README.md +49 -26
  2. package/bin/wrangler.js +88 -31
  3. package/config-schema.json +2278 -0
  4. package/kv-asset-handler.js +1 -0
  5. package/package.json +146 -92
  6. package/templates/__tests__/pages-dev-util.test.ts +128 -0
  7. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  8. package/templates/__tests__/tsconfig.json +8 -0
  9. package/templates/checked-fetch.js +30 -0
  10. package/templates/facade.d.ts +19 -0
  11. package/templates/gitignore +170 -0
  12. package/templates/init-tests/test-jest-new-worker.js +23 -0
  13. package/templates/init-tests/test-vitest-new-worker.js +24 -0
  14. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  15. package/templates/middleware/common.ts +67 -0
  16. package/templates/middleware/loader-modules.ts +134 -0
  17. package/templates/middleware/loader-sw.ts +229 -0
  18. package/templates/middleware/middleware-ensure-req-body-drained.ts +18 -0
  19. package/templates/middleware/middleware-miniflare3-json-error.ts +32 -0
  20. package/templates/middleware/middleware-mock-analytics-engine.d.ts +3 -0
  21. package/templates/middleware/middleware-mock-analytics-engine.ts +30 -0
  22. package/templates/middleware/middleware-patch-console-prefix.d.ts +3 -0
  23. package/templates/middleware/middleware-patch-console-prefix.ts +21 -0
  24. package/templates/middleware/middleware-pretty-error.ts +40 -0
  25. package/templates/middleware/middleware-scheduled.ts +29 -0
  26. package/templates/modules-watch-stub.js +4 -0
  27. package/templates/new-worker-scheduled.js +17 -0
  28. package/templates/new-worker-scheduled.ts +32 -0
  29. package/templates/new-worker.js +15 -0
  30. package/templates/new-worker.ts +33 -0
  31. package/templates/no-op-worker.js +10 -0
  32. package/templates/pages-dev-pipeline.ts +33 -0
  33. package/templates/pages-dev-util.ts +55 -0
  34. package/templates/pages-shim.ts +9 -0
  35. package/templates/pages-template-plugin.ts +190 -0
  36. package/templates/pages-template-worker.ts +198 -0
  37. package/templates/startDevWorker/InspectorProxyWorker.ts +664 -0
  38. package/templates/startDevWorker/ProxyWorker.ts +336 -0
  39. package/templates/tsconfig-sanity.ts +11 -0
  40. package/templates/tsconfig.init.json +22 -0
  41. package/templates/tsconfig.json +15 -0
  42. package/templates/tsconfig.tsbuildinfo +1 -0
  43. package/wrangler-dist/InspectorProxyWorker.js +460 -0
  44. package/wrangler-dist/InspectorProxyWorker.js.map +6 -0
  45. package/wrangler-dist/ProxyWorker.js +238 -0
  46. package/wrangler-dist/ProxyWorker.js.map +6 -0
  47. package/wrangler-dist/cli.d.ts +26693 -0
  48. package/wrangler-dist/cli.js +149006 -119006
  49. package/import_meta_url.js +0 -3
  50. package/miniflare-config-stubs/.env.empty +0 -0
  51. package/miniflare-config-stubs/package.empty.json +0 -1
  52. package/miniflare-config-stubs/wrangler.empty.toml +0 -0
  53. package/pages/functions/buildWorker.ts +0 -62
  54. package/pages/functions/filepath-routing.test.ts +0 -39
  55. package/pages/functions/filepath-routing.ts +0 -228
  56. package/pages/functions/identifiers.ts +0 -78
  57. package/pages/functions/routes.ts +0 -158
  58. package/pages/functions/template-worker.ts +0 -136
  59. package/src/__tests__/clipboardy-mock.js +0 -4
  60. package/src/__tests__/dev.test.tsx +0 -67
  61. package/src/__tests__/index.test.ts +0 -289
  62. package/src/__tests__/jest.setup.ts +0 -22
  63. package/src/__tests__/kv.test.ts +0 -1199
  64. package/src/__tests__/mock-cfetch.ts +0 -173
  65. package/src/__tests__/mock-dialogs.ts +0 -65
  66. package/src/__tests__/publish.test.ts +0 -672
  67. package/src/__tests__/run-in-tmp.ts +0 -19
  68. package/src/__tests__/run-wrangler.ts +0 -32
  69. package/src/__tests__/whoami.test.tsx +0 -130
  70. package/src/api/form_data.ts +0 -131
  71. package/src/api/preview.ts +0 -128
  72. package/src/api/worker.ts +0 -155
  73. package/src/cfetch/index.ts +0 -110
  74. package/src/cfetch/internal.ts +0 -71
  75. package/src/cli.ts +0 -9
  76. package/src/config.ts +0 -646
  77. package/src/dev.tsx +0 -779
  78. package/src/dialogs.tsx +0 -77
  79. package/src/index.tsx +0 -1975
  80. package/src/inspect.ts +0 -543
  81. package/src/kv.tsx +0 -276
  82. package/src/module-collection.ts +0 -64
  83. package/src/pages.tsx +0 -1040
  84. package/src/proxy.ts +0 -302
  85. package/src/publish.ts +0 -382
  86. package/src/sites.tsx +0 -243
  87. package/src/tail.tsx +0 -73
  88. package/src/user.tsx +0 -1019
  89. package/src/whoami.tsx +0 -69
  90. package/static-asset-facade.js +0 -47
  91. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  92. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  93. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  94. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  95. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  96. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  97. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  98. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  99. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  100. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  101. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  102. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  103. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  104. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  105. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  106. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  107. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  108. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  109. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  110. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  111. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  112. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  113. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  114. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  115. package/vendor/wrangler-mime/LICENSE +0 -21
  116. package/vendor/wrangler-mime/Mime.js +0 -97
  117. package/vendor/wrangler-mime/README.md +0 -187
  118. package/vendor/wrangler-mime/cli.js +0 -46
  119. package/vendor/wrangler-mime/index.js +0 -4
  120. package/vendor/wrangler-mime/lite.js +0 -4
  121. package/vendor/wrangler-mime/package.json +0 -52
  122. package/vendor/wrangler-mime/types/other.js +0 -1
  123. package/vendor/wrangler-mime/types/standard.js +0 -1
  124. package/wrangler-dist/cli.js.map +0 -7
package/src/proxy.ts DELETED
@@ -1,302 +0,0 @@
1
- import { connect } from "node:http2";
2
- import type { ClientHttp2Session, ServerHttp2Stream } from "node:http2";
3
- import { createServer } from "node:http";
4
- import type {
5
- IncomingHttpHeaders,
6
- RequestListener,
7
- IncomingMessage,
8
- ServerResponse,
9
- Server,
10
- } from "node:http";
11
- import WebSocket from "faye-websocket";
12
- import serveStatic from "serve-static";
13
- import type { CfPreviewToken } from "./api/preview";
14
- import { useEffect, useRef } from "react";
15
-
16
- /**
17
- * `usePreviewServer` is a React hook that creates a local development
18
- * server that can be used to develop a Worker.
19
- *
20
- * When we run `wrangler dev`, we start by uploading the compiled worker
21
- * to the preview service, which responds with a preview token.
22
- * (see `useWorker`/`createWorker` for details.)
23
- * We can then use that token to connect to the preview server for a
24
- * great local development experience. Further, as we change the worker,
25
- * we can update the preview token transparently without having to restart
26
- * the development server.
27
- */
28
-
29
- /** Rewrite request headers to add the preview token. */
30
- function addCfPreviewTokenHeader(
31
- headers: IncomingHttpHeaders,
32
- previewTokenValue: string
33
- ) {
34
- headers["cf-workers-preview-token"] = previewTokenValue;
35
- }
36
-
37
- /**
38
- * Rewrite references in request headers
39
- * from the preview host to the local host.
40
- */
41
- function rewriteRemoteHostToLocalHostInHeaders(
42
- headers: IncomingHttpHeaders,
43
- remoteHost: string,
44
- localPort: number
45
- ) {
46
- for (const [name, value] of Object.entries(headers)) {
47
- // Rewrite the remote host to the local host.
48
- if (typeof value === "string" && value.includes(remoteHost)) {
49
- headers[name] = value
50
- .replaceAll(`https://${remoteHost}`, `http://localhost:${localPort}`)
51
- .replaceAll(remoteHost, `localhost:${localPort}`);
52
- }
53
- }
54
- }
55
-
56
- export function usePreviewServer({
57
- previewToken,
58
- publicRoot,
59
- port,
60
- }: {
61
- previewToken: CfPreviewToken | undefined;
62
- publicRoot: undefined | string;
63
- port: number;
64
- }) {
65
- /** Creates an HTTP/1 proxy that sends requests over HTTP/2. */
66
- const proxyServer = useRef<Server>();
67
- const proxy = (proxyServer.current ??= createProxyServer());
68
-
69
- /**
70
- * When we're not connected / getting a fresh token on changes,
71
- * we'd like to buffer streams/requests until we're connected.
72
- * Once connected, we can flush the buffered streams/requests.
73
- * streamBufferRef is used to buffer http/2 streams, while
74
- * requestResponseBufferRef is used to buffer http/1 requests.
75
- */
76
- const streamBufferRef = useRef<
77
- { stream: ServerHttp2Stream; headers: IncomingHttpHeaders }[]
78
- >([]);
79
- const requestResponseBufferRef = useRef<
80
- { request: IncomingMessage; response: ServerResponse }[]
81
- >([]);
82
-
83
- useEffect(() => {
84
- // If we don't have a token, that means either we're just starting up,
85
- // or we're refreshing the token.
86
- if (!previewToken) {
87
- const cleanupListeners: (() => void)[] = [];
88
- const bufferStream = (
89
- stream: ServerHttp2Stream,
90
- headers: IncomingHttpHeaders
91
- ) => {
92
- // store the stream in a buffer so we can replay it later
93
- streamBufferRef.current.push({ stream, headers });
94
- };
95
- proxy.on("stream", bufferStream);
96
- cleanupListeners.push(() => proxy.off("stream", bufferStream));
97
-
98
- const bufferRequestResponse = (
99
- request: IncomingMessage,
100
- response: ServerResponse
101
- ) => {
102
- // store the request and response in a buffer so we can replay it later
103
- requestResponseBufferRef.current.push({ request, response });
104
- };
105
-
106
- proxy.on("request", bufferRequestResponse);
107
- cleanupListeners.push(() => proxy.off("request", bufferRequestResponse));
108
- return () => {
109
- cleanupListeners.forEach((cleanup) => cleanup());
110
- };
111
- }
112
-
113
- // We have a token. Let's proxy requests to the preview end point.
114
- const cleanupListeners: (() => void)[] = [];
115
-
116
- const assetPath = typeof publicRoot === "string" ? publicRoot : null;
117
-
118
- // create a ClientHttp2Session
119
- const remote = connect(`https://${previewToken.host}`);
120
- cleanupListeners.push(() => remote.destroy());
121
-
122
- /** HTTP/2 -> HTTP/2 */
123
- const handleStream = createStreamHandler(previewToken, remote, port);
124
- proxy.on("stream", handleStream);
125
- cleanupListeners.push(() => proxy.off("stream", handleStream));
126
-
127
- // flush and replay buffered streams
128
- streamBufferRef.current.forEach((buffer) =>
129
- handleStream(buffer.stream, buffer.headers)
130
- );
131
- streamBufferRef.current = [];
132
-
133
- /** HTTP/1 -> HTTP/2 */
134
- const handleRequest: RequestListener = (
135
- message: IncomingMessage,
136
- response: ServerResponse
137
- ) => {
138
- const { httpVersionMajor, headers, method, url } = message;
139
- if (httpVersionMajor >= 2) {
140
- return; // Already handled by the "stream" event.
141
- }
142
- addCfPreviewTokenHeader(headers, previewToken.value);
143
- headers[":method"] = method;
144
- headers[":path"] = url;
145
- headers[":authority"] = previewToken.host;
146
- headers[":scheme"] = "https";
147
- for (const name of Object.keys(headers)) {
148
- if (HTTP1_HEADERS.has(name.toLowerCase())) {
149
- delete headers[name];
150
- }
151
- }
152
- const request = message.pipe(remote.request(headers));
153
- request.on("response", (responseHeaders) => {
154
- const status = responseHeaders[":status"] ?? 500;
155
- rewriteRemoteHostToLocalHostInHeaders(
156
- responseHeaders,
157
- previewToken.host,
158
- port
159
- );
160
- for (const name of Object.keys(responseHeaders)) {
161
- if (name.startsWith(":")) {
162
- delete responseHeaders[name];
163
- }
164
- }
165
- response.writeHead(status, responseHeaders);
166
- request.pipe(response, { end: true });
167
- });
168
- };
169
-
170
- // If an asset path is defined, check the file system
171
- // for a file first and serve if it exists.
172
- const actualHandleRequest = assetPath
173
- ? createHandleAssetsRequest(assetPath, handleRequest)
174
- : handleRequest;
175
-
176
- proxy.on("request", actualHandleRequest);
177
- cleanupListeners.push(() => proxy.off("request", actualHandleRequest));
178
-
179
- // flush and replay buffered requests
180
- requestResponseBufferRef.current.forEach(({ request, response }) =>
181
- actualHandleRequest(request, response)
182
- );
183
- requestResponseBufferRef.current = [];
184
-
185
- /** HTTP/1 -> WebSocket (over HTTP/1) */
186
- const handleUpgrade = (
187
- message: IncomingMessage,
188
- socket: WebSocket,
189
- body: Buffer
190
- ) => {
191
- const { headers, url } = message;
192
- addCfPreviewTokenHeader(headers, previewToken.value);
193
- headers["host"] = previewToken.host;
194
- const localWebsocket = new WebSocket(message, socket, body);
195
- // TODO(soon): Custom WebSocket protocol is not working?
196
- const remoteWebsocketClient = new WebSocket.Client(
197
- `wss://${previewToken.host}${url}`,
198
- [],
199
- { headers }
200
- );
201
- localWebsocket.pipe(remoteWebsocketClient).pipe(localWebsocket);
202
- // We close down websockets whenever we refresh the token.
203
- cleanupListeners.push(() => {
204
- localWebsocket.destroy();
205
- remoteWebsocketClient.destroy();
206
- });
207
- };
208
- proxy.on("upgrade", handleUpgrade);
209
- cleanupListeners.push(() => proxy.off("upgrade", handleUpgrade));
210
-
211
- return () => {
212
- cleanupListeners.forEach((d) => d());
213
- };
214
- }, [previewToken, publicRoot, port, proxy]);
215
-
216
- // Start/stop the server whenever the
217
- // containing component is mounted/unmounted.
218
- useEffect(() => {
219
- proxy.listen(port);
220
- console.log(`⬣ Listening at http://localhost:${port}`);
221
-
222
- return () => {
223
- proxy.close();
224
- };
225
- }, [port, proxy]);
226
- }
227
-
228
- function createHandleAssetsRequest(
229
- assetPath: string,
230
- handleRequest: RequestListener
231
- ) {
232
- const handleAsset = serveStatic(assetPath, {
233
- cacheControl: false,
234
- });
235
- return (request: IncomingMessage, response: ServerResponse) => {
236
- handleAsset(request, response, () => {
237
- handleRequest(request, response);
238
- });
239
- };
240
- }
241
-
242
- /** A Set of headers we want to remove from HTTP/1 requests. */
243
- const HTTP1_HEADERS = new Set([
244
- "host",
245
- "connection",
246
- "upgrade",
247
- "keep-alive",
248
- "proxy-connection",
249
- "transfer-encoding",
250
- "http2-settings",
251
- ]);
252
-
253
- function createProxyServer() {
254
- return createServer()
255
- .on("request", function (req, res) {
256
- // log all requests
257
- console.log(
258
- new Date().toLocaleTimeString(),
259
- req.method,
260
- req.url,
261
- res.statusCode
262
- );
263
- })
264
- .on("upgrade", (req) => {
265
- // log all websocket connections
266
- console.log(
267
- new Date().toLocaleTimeString(),
268
- req.method,
269
- req.url,
270
- 101,
271
- "(WebSocket)"
272
- );
273
- })
274
- .on("error", (err) => {
275
- // log all connection errors
276
- console.error(new Date().toLocaleTimeString(), err);
277
- });
278
- }
279
-
280
- function createStreamHandler(
281
- previewToken: CfPreviewToken,
282
- remote: ClientHttp2Session,
283
- port: number
284
- ) {
285
- return function handleStream(
286
- stream: ServerHttp2Stream,
287
- headers: IncomingHttpHeaders
288
- ) {
289
- addCfPreviewTokenHeader(headers, previewToken.value);
290
- headers[":authority"] = previewToken.host;
291
- const request = stream.pipe(remote.request(headers));
292
- request.on("response", (responseHeaders: IncomingHttpHeaders) => {
293
- rewriteRemoteHostToLocalHostInHeaders(
294
- responseHeaders,
295
- previewToken.host,
296
- port
297
- );
298
- stream.respond(responseHeaders);
299
- request.pipe(stream, { end: true });
300
- });
301
- };
302
- }
package/src/publish.ts DELETED
@@ -1,382 +0,0 @@
1
- import assert from "node:assert";
2
- import path from "node:path";
3
- import { readFile } from "node:fs/promises";
4
- import * as esbuild from "esbuild";
5
- import type { Metafile } from "esbuild";
6
- import { execa } from "execa";
7
- import tmp from "tmp-promise";
8
- import type { CfWorkerInit } from "./api/worker";
9
- import { toFormData } from "./api/form_data";
10
- import { fetchResult } from "./cfetch";
11
- import type { Config } from "./config";
12
- import makeModuleCollector from "./module-collection";
13
- import type { AssetPaths } from "./sites";
14
- import { syncAssets } from "./sites";
15
-
16
- type CfScriptFormat = undefined | "modules" | "service-worker";
17
-
18
- type Props = {
19
- config: Config;
20
- format: CfScriptFormat | undefined;
21
- script: string | undefined;
22
- name: string | undefined;
23
- env: string | undefined;
24
- compatibilityDate: string | undefined;
25
- compatibilityFlags: string[] | undefined;
26
- assetPaths: AssetPaths | undefined;
27
- triggers: (string | number)[] | undefined;
28
- routes: (string | number)[] | undefined;
29
- legacyEnv: boolean | undefined;
30
- jsxFactory: undefined | string;
31
- jsxFragment: undefined | string;
32
- experimentalPublic: boolean;
33
- };
34
-
35
- function sleep(ms: number) {
36
- return new Promise((resolve) => setTimeout(resolve, ms));
37
- }
38
-
39
- export default async function publish(props: Props): Promise<void> {
40
- if (props.experimentalPublic && props.format === "service-worker") {
41
- // TODO: check config too
42
- throw new Error(
43
- "You cannot publish in the service worker format with a public directory."
44
- );
45
- }
46
- // TODO: warn if git/hg has uncommitted changes
47
- const { config } = props;
48
- const {
49
- account_id: accountId,
50
- build,
51
- // @ts-expect-error hidden
52
- __path__,
53
- } = config;
54
-
55
- const envRootObj =
56
- props.env && config.env ? config.env[props.env] || {} : config;
57
-
58
- assert(
59
- envRootObj.compatibility_date || props.compatibilityDate,
60
- "A compatibility_date is required when publishing. Add one to your wrangler.toml file, or pass it in your terminal as --compatibility_date. See https://developers.cloudflare.com/workers/platform/compatibility-dates for more information."
61
- );
62
-
63
- if (accountId === undefined) {
64
- throw new Error("No account_id provided.");
65
- }
66
-
67
- const triggers = props.triggers || config.triggers?.crons;
68
- const routes = props.routes || config.routes;
69
-
70
- const jsxFactory = props.jsxFactory || config.jsx_factory;
71
- const jsxFragment = props.jsxFragment || config.jsx_fragment;
72
-
73
- assert(config.account_id, "missing account id");
74
-
75
- let scriptName = props.name || config.name;
76
- assert(
77
- scriptName,
78
- 'You need to provide a name when publishing a worker. Either pass it as a cli arg with `--name <name>` or in your config file as `name = "<name>"`'
79
- );
80
-
81
- let file: string;
82
- if (props.script) {
83
- // If the script name comes from the command line it is relative to the current working directory.
84
- file = path.resolve(props.script);
85
- } else {
86
- // If the script name comes from the config, then it is relative to the wrangler.toml file.
87
- assert(build?.upload?.main, "missing main file");
88
- file = path.resolve(path.dirname(__path__), build.upload.main);
89
- }
90
-
91
- if (props.legacyEnv) {
92
- scriptName += props.env ? `-${props.env}` : "";
93
- }
94
- const envName = props.env ?? "production";
95
-
96
- const destination = await tmp.dir({ unsafeCleanup: true });
97
- if (props.config.build?.command) {
98
- // TODO: add a deprecation message here?
99
- console.log("running:", props.config.build.command);
100
- const buildCommandPieces = props.config.build.command.split(" ");
101
- await execa(buildCommandPieces[0], buildCommandPieces.slice(1), {
102
- stdout: "inherit",
103
- stderr: "inherit",
104
- ...(props.config.build?.cwd && { cwd: props.config.build.cwd }),
105
- });
106
- }
107
-
108
- const moduleCollector = makeModuleCollector();
109
- const result = await esbuild.build({
110
- ...(props.experimentalPublic
111
- ? {
112
- stdin: {
113
- contents: (
114
- await readFile(
115
- path.join(__dirname, "../static-asset-facade.js"),
116
- "utf8"
117
- )
118
- ).replace("__ENTRY_POINT__", file),
119
- sourcefile: "static-asset-facade.js",
120
- resolveDir: path.dirname(file),
121
- },
122
- nodePaths: [path.join(__dirname, "../vendor")],
123
- }
124
- : { entryPoints: [file] }),
125
- bundle: true,
126
- outdir: destination.path,
127
- external: ["__STATIC_CONTENT_MANIFEST"],
128
- format: "esm",
129
- sourcemap: true,
130
- metafile: true,
131
- conditions: ["worker", "browser"],
132
- loader: {
133
- ".js": "jsx",
134
- },
135
- plugins: [moduleCollector.plugin],
136
- ...(jsxFactory && { jsxFactory }),
137
- ...(jsxFragment && { jsxFragment }),
138
- });
139
-
140
- // result.metafile is defined because of the `metafile: true` option above.
141
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
142
- const metafile = result.metafile!;
143
- const entryPoints = Object.entries(metafile.outputs).filter(
144
- ([_path, output]) => output.entryPoint !== undefined
145
- );
146
- assert(
147
- entryPoints.length > 0,
148
- `Cannot find entry-point "${file}" in generated bundle.` +
149
- listEntryPoints(entryPoints)
150
- );
151
- assert(
152
- entryPoints.length < 2,
153
- "More than one entry-point found for generated bundle." +
154
- listEntryPoints(entryPoints)
155
- );
156
- const entryPointExports = entryPoints[0][1].exports;
157
- const resolvedEntryPointPath = entryPoints[0][0];
158
- const { format } = props;
159
- const bundle = {
160
- type: entryPointExports.length > 0 ? "esm" : "commonjs",
161
- exports: entryPointExports,
162
- };
163
-
164
- // TODO: instead of bundling the facade with the worker, we should just bundle the worker and expose it as a module.
165
- // That way we'll be able to accurately tell if this is a service worker or not.
166
-
167
- if (format === "modules" && bundle.type === "commonjs") {
168
- console.error("⎔ Cannot use modules with a commonjs bundle.");
169
- // TODO: a much better error message here, with what to do next
170
- return;
171
- }
172
- if (format === "service-worker" && bundle.type !== "esm") {
173
- console.error("⎔ Cannot use service-worker with a esm bundle.");
174
- // TODO: a much better error message here, with what to do next
175
- return;
176
- }
177
-
178
- const content = await readFile(resolvedEntryPointPath, { encoding: "utf-8" });
179
- await destination.cleanup();
180
-
181
- // if config.migrations
182
- // get current migration tag
183
- let migrations;
184
- if (config.migrations !== undefined) {
185
- const scripts = await fetchResult<{ id: string; migration_tag: string }[]>(
186
- `/accounts/${accountId}/workers/scripts`
187
- );
188
- const script = scripts.find(({ id }) => id === scriptName);
189
- if (script?.migration_tag) {
190
- // was already published once
191
- const foundIndex = config.migrations.findIndex(
192
- (migration) => migration.tag === script.migration_tag
193
- );
194
- if (foundIndex === -1) {
195
- console.warn(
196
- `The published script ${scriptName} has a migration tag "${script.migration_tag}, which was not found in wrangler.toml. You may have already deleted it. Applying all available migrations to the script...`
197
- );
198
- migrations = {
199
- old_tag: script.migration_tag,
200
- new_tag: config.migrations[config.migrations.length - 1].tag,
201
- steps: config.migrations.map(({ tag: _tag, ...rest }) => rest),
202
- };
203
- } else {
204
- migrations = {
205
- old_tag: script.migration_tag,
206
- new_tag: config.migrations[config.migrations.length - 1].tag,
207
- steps: config.migrations
208
- .slice(foundIndex + 1)
209
- .map(({ tag: _tag, ...rest }) => rest),
210
- };
211
- }
212
- } else {
213
- migrations = {
214
- new_tag: config.migrations[config.migrations.length - 1].tag,
215
- steps: config.migrations.map(({ tag: _tag, ...rest }) => rest),
216
- };
217
- }
218
- }
219
-
220
- const assets = await syncAssets(
221
- accountId,
222
- scriptName,
223
- props.assetPaths,
224
- false
225
- );
226
-
227
- const bindings: CfWorkerInit["bindings"] = {
228
- kv_namespaces: envRootObj.kv_namespaces?.concat(
229
- assets.namespace
230
- ? { binding: "__STATIC_CONTENT", id: assets.namespace }
231
- : []
232
- ),
233
- vars: envRootObj.vars,
234
- durable_objects: envRootObj.durable_objects,
235
- services: envRootObj.experimental_services,
236
- };
237
-
238
- const worker: CfWorkerInit = {
239
- name: scriptName,
240
- main: {
241
- name: path.basename(resolvedEntryPointPath),
242
- content: content,
243
- type: bundle.type === "esm" ? "esm" : "commonjs",
244
- },
245
- bindings,
246
- ...(migrations && { migrations }),
247
- modules: moduleCollector.modules.concat(
248
- assets.manifest
249
- ? {
250
- name: "__STATIC_CONTENT_MANIFEST",
251
- content: JSON.stringify(assets.manifest),
252
- type: "text",
253
- }
254
- : []
255
- ),
256
- compatibility_date: config.compatibility_date,
257
- compatibility_flags: config.compatibility_flags,
258
- usage_model: config.usage_model,
259
- };
260
-
261
- const start = Date.now();
262
- function formatTime(duration: number) {
263
- return `(${(duration / 1000).toFixed(2)} sec)`;
264
- }
265
-
266
- const notProd = !props.legacyEnv && props.env;
267
- const workerName = notProd ? `${scriptName} (${envName})` : scriptName;
268
- const workerUrl = notProd
269
- ? `/accounts/${accountId}/workers/services/${scriptName}/environments/${envName}`
270
- : `/accounts/${accountId}/workers/scripts/${scriptName}`;
271
-
272
- // Upload the script so it has time to propagate.
273
- const { available_on_subdomain } = await fetchResult(
274
- workerUrl,
275
- {
276
- method: "PUT",
277
- // @ts-expect-error: TODO: fix this type error!
278
- body: toFormData(worker),
279
- },
280
- new URLSearchParams({ available_on_subdomains: "true" })
281
- );
282
-
283
- const uploadMs = Date.now() - start;
284
- console.log("Uploaded", workerName, formatTime(uploadMs));
285
- const deployments: Promise<string[]>[] = [];
286
-
287
- const userSubdomain = (
288
- await fetchResult<{ subdomain: string }>(
289
- `/accounts/${accountId}/workers/subdomain`
290
- )
291
- ).subdomain;
292
-
293
- const scriptURL =
294
- props.legacyEnv || !props.env
295
- ? `${scriptName}.${userSubdomain}.workers.dev`
296
- : `${envName}.${scriptName}.${userSubdomain}.workers.dev`;
297
-
298
- // Enable the `workers.dev` subdomain.
299
- // TODO: Make this configurable.
300
- if (!available_on_subdomain) {
301
- deployments.push(
302
- fetchResult(`${workerUrl}/subdomain`, {
303
- method: "POST",
304
- body: JSON.stringify({ enabled: true }),
305
- headers: {
306
- "Content-Type": "application/json",
307
- },
308
- })
309
- .then(() => [scriptURL])
310
- // Add a delay when the subdomain is first created.
311
- // This is to prevent an issue where a negative cache-hit
312
- // causes the subdomain to be unavailable for 30 seconds.
313
- // This is a temporary measure until we fix this on the edge.
314
- .then(async (url) => {
315
- await sleep(3000);
316
- return url;
317
- })
318
- );
319
- } else {
320
- deployments.push(Promise.resolve([scriptURL]));
321
- }
322
-
323
- // Update routing table for the script.
324
- if (routes && routes.length) {
325
- deployments.push(
326
- fetchResult(`${workerUrl}/routes`, {
327
- // TODO: PATCH will not delete previous routes on this script,
328
- // whereas PUT will. We need to decide on the default behaviour
329
- // and how to configure it.
330
- method: "PUT",
331
- body: JSON.stringify(routes.map((pattern) => ({ pattern }))),
332
- headers: {
333
- "Content-Type": "application/json",
334
- },
335
- }).then(() => {
336
- if (routes.length > 10) {
337
- return routes
338
- .slice(0, 9)
339
- .map(String)
340
- .concat([`...and ${routes.length - 10} more routes`]);
341
- }
342
- return routes.map(String);
343
- })
344
- );
345
- }
346
-
347
- // Configure any schedules for the script.
348
- // TODO: rename this to `schedules`?
349
- if (triggers && triggers.length) {
350
- deployments.push(
351
- fetchResult(`${workerUrl}/schedules`, {
352
- // TODO: Unlike routes, this endpoint does not support PATCH.
353
- // So technically, this will override any previous schedules.
354
- // We should change the endpoint to support PATCH.
355
- method: "PUT",
356
- body: JSON.stringify(triggers.map((cron) => ({ cron }))),
357
- headers: {
358
- "Content-Type": "application/json",
359
- },
360
- }).then(() => triggers.map(String))
361
- );
362
- }
363
-
364
- if (!deployments.length) {
365
- return;
366
- }
367
-
368
- const targets = await Promise.all(deployments);
369
- const deployMs = Date.now() - start - uploadMs;
370
- console.log("Deployed", workerName, formatTime(deployMs));
371
- for (const target of targets.flat()) {
372
- console.log(" ", target);
373
- }
374
- }
375
-
376
- function listEntryPoints(
377
- outputs: [string, ValueOf<Metafile["outputs"]>][]
378
- ): string {
379
- return outputs.map(([_input, output]) => output.entryPoint).join("\n");
380
- }
381
-
382
- type ValueOf<T> = T[keyof T];