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.
Files changed (214) hide show
  1. package/README.md +27 -3
  2. package/bin/wrangler.js +150 -62
  3. package/kv-asset-handler.js +1 -0
  4. package/miniflare-dist/index.mjs +663 -7
  5. package/package.json +173 -152
  6. package/src/__tests__/config-cache-without-cache-dir.test.ts +38 -0
  7. package/src/__tests__/config-cache.test.ts +30 -24
  8. package/src/__tests__/configuration.test.ts +4015 -3363
  9. package/src/__tests__/dev.test.tsx +1290 -952
  10. package/src/__tests__/generate.test.ts +91 -0
  11. package/src/__tests__/guess-worker-format.test.ts +68 -68
  12. package/src/__tests__/helpers/cmd-shim.d.ts +6 -6
  13. package/src/__tests__/helpers/mock-account-id.ts +24 -24
  14. package/src/__tests__/helpers/mock-bin.ts +20 -20
  15. package/src/__tests__/helpers/mock-cfetch.ts +179 -94
  16. package/src/__tests__/helpers/mock-console.ts +49 -39
  17. package/src/__tests__/helpers/mock-dialogs.ts +94 -71
  18. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
  19. package/src/__tests__/helpers/mock-http-server.ts +30 -30
  20. package/src/__tests__/helpers/mock-istty.ts +65 -18
  21. package/src/__tests__/helpers/mock-known-routes.ts +7 -0
  22. package/src/__tests__/helpers/mock-kv.ts +26 -26
  23. package/src/__tests__/helpers/mock-oauth-flow.ts +223 -228
  24. package/src/__tests__/helpers/mock-process.ts +39 -0
  25. package/src/__tests__/helpers/mock-stdin.ts +82 -77
  26. package/src/__tests__/helpers/mock-web-socket.ts +21 -21
  27. package/src/__tests__/helpers/run-in-tmp.ts +27 -28
  28. package/src/__tests__/helpers/run-wrangler.ts +8 -8
  29. package/src/__tests__/helpers/write-worker-source.ts +16 -16
  30. package/src/__tests__/helpers/write-wrangler-toml.ts +9 -9
  31. package/src/__tests__/https-options.test.ts +142 -109
  32. package/src/__tests__/index.test.ts +222 -233
  33. package/src/__tests__/init.test.ts +2139 -1603
  34. package/src/__tests__/jest.setup.ts +114 -34
  35. package/src/__tests__/kv.test.ts +1222 -1032
  36. package/src/__tests__/logger.test.ts +100 -74
  37. package/src/__tests__/metrics.test.ts +450 -0
  38. package/src/__tests__/package-manager.test.ts +303 -303
  39. package/src/__tests__/pages.test.ts +1173 -652
  40. package/src/__tests__/parse.test.ts +252 -252
  41. package/src/__tests__/publish.test.ts +6788 -5301
  42. package/src/__tests__/pubsub.test.ts +367 -0
  43. package/src/__tests__/r2.test.ts +328 -225
  44. package/src/__tests__/route.test.ts +18 -18
  45. package/src/__tests__/secret.test.ts +470 -459
  46. package/src/__tests__/tail.test.ts +676 -564
  47. package/src/__tests__/test-old-node-version.js +31 -0
  48. package/src/__tests__/user.test.ts +136 -112
  49. package/src/__tests__/validate-dev-props.test.ts +56 -0
  50. package/src/__tests__/version.test.ts +35 -0
  51. package/src/__tests__/whoami.test.tsx +267 -83
  52. package/src/__tests__/worker-namespace.test.ts +329 -0
  53. package/src/abort.d.ts +1 -1
  54. package/src/api/dev.ts +93 -0
  55. package/src/api/index.ts +1 -0
  56. package/src/bundle-reporter.tsx +29 -0
  57. package/src/bundle.ts +430 -157
  58. package/src/cfetch/index.ts +80 -80
  59. package/src/cfetch/internal.ts +244 -91
  60. package/src/cli.ts +21 -7
  61. package/src/config/config.ts +224 -195
  62. package/src/config/diagnostics.ts +61 -61
  63. package/src/config/environment.ts +422 -357
  64. package/src/config/index.ts +219 -193
  65. package/src/config/validation-helpers.ts +379 -357
  66. package/src/config/validation.ts +1690 -1367
  67. package/src/config-cache.ts +81 -41
  68. package/src/create-worker-preview.ts +208 -136
  69. package/src/create-worker-upload-form.ts +275 -238
  70. package/src/dev/dev-vars.ts +13 -13
  71. package/src/dev/dev.tsx +477 -351
  72. package/src/dev/local.tsx +426 -295
  73. package/src/dev/remote.tsx +406 -211
  74. package/src/dev/use-esbuild.ts +154 -94
  75. package/src/dev/validate-dev-props.ts +31 -0
  76. package/src/dev-registry.tsx +160 -0
  77. package/src/dev.tsx +696 -0
  78. package/src/dialogs.tsx +97 -97
  79. package/src/dispatch-namespace.ts +206 -0
  80. package/src/durable.ts +87 -87
  81. package/src/entry.ts +234 -228
  82. package/src/environment-variables.ts +23 -23
  83. package/src/errors.ts +6 -6
  84. package/src/faye-websocket.d.ts +6 -0
  85. package/src/generate.ts +131 -0
  86. package/src/git-client.ts +42 -0
  87. package/src/global-wrangler-config-path.ts +26 -0
  88. package/src/https-options.ts +84 -80
  89. package/src/index.tsx +2164 -2768
  90. package/src/init.ts +622 -0
  91. package/src/inspect.ts +678 -593
  92. package/src/intl-polyfill.d.ts +123 -123
  93. package/src/is-ci.ts +14 -0
  94. package/src/is-interactive.ts +12 -0
  95. package/src/kv.ts +299 -277
  96. package/src/logger.ts +46 -39
  97. package/src/metrics/index.ts +5 -0
  98. package/src/metrics/metrics-config.ts +239 -0
  99. package/src/metrics/metrics-dispatcher.ts +96 -0
  100. package/src/metrics/metrics-usage-headers.ts +24 -0
  101. package/src/metrics/send-event.ts +92 -0
  102. package/src/miniflare-cli/assets.ts +554 -0
  103. package/src/miniflare-cli/enum-keys.ts +8 -8
  104. package/src/miniflare-cli/index.ts +198 -32
  105. package/src/miniflare-cli/request-context.ts +18 -18
  106. package/src/module-collection.ts +212 -212
  107. package/src/open-in-browser.ts +4 -6
  108. package/src/package-manager.ts +173 -128
  109. package/src/pages/build.tsx +238 -0
  110. package/src/pages/constants.ts +12 -0
  111. package/src/pages/deployments.tsx +106 -0
  112. package/src/pages/dev.tsx +528 -0
  113. package/src/pages/errors.ts +22 -0
  114. package/src/pages/functions/buildPlugin.ts +109 -0
  115. package/src/pages/functions/buildWorker.ts +155 -0
  116. package/{pages → src/pages}/functions/filepath-routing.test.ts +113 -113
  117. package/src/pages/functions/filepath-routing.ts +189 -0
  118. package/src/pages/functions/identifiers.ts +78 -0
  119. package/src/pages/functions/routes-consolidation.test.ts +250 -0
  120. package/src/pages/functions/routes-consolidation.ts +73 -0
  121. package/src/pages/functions/routes-transformation.test.ts +271 -0
  122. package/src/pages/functions/routes-transformation.ts +122 -0
  123. package/src/pages/functions/routes.ts +151 -0
  124. package/src/pages/functions.tsx +96 -0
  125. package/src/pages/index.tsx +94 -0
  126. package/src/pages/projects.tsx +169 -0
  127. package/src/pages/publish.tsx +391 -0
  128. package/src/pages/types.ts +49 -0
  129. package/src/pages/upload.tsx +413 -0
  130. package/src/pages/utils.ts +12 -0
  131. package/src/parse.ts +209 -125
  132. package/src/paths.ts +6 -6
  133. package/src/preview.ts +31 -0
  134. package/src/proxy.ts +410 -389
  135. package/src/publish.ts +773 -534
  136. package/src/pubsub/index.ts +286 -0
  137. package/src/pubsub/pubsub-commands.tsx +623 -0
  138. package/src/r2.ts +100 -19
  139. package/src/selfsigned.d.ts +23 -23
  140. package/src/sites.tsx +278 -201
  141. package/src/tail/filters.ts +111 -109
  142. package/src/tail/index.ts +230 -217
  143. package/src/tail/printing.ts +86 -46
  144. package/src/update-check.ts +11 -11
  145. package/src/user/choose-account.tsx +69 -0
  146. package/src/user/env-vars.ts +46 -0
  147. package/src/user/generate-auth-url.ts +33 -0
  148. package/src/user/generate-random-state.ts +16 -0
  149. package/src/user/index.ts +3 -0
  150. package/src/user/user.tsx +1191 -0
  151. package/src/whoami.tsx +141 -42
  152. package/src/worker.ts +123 -99
  153. package/src/zones.ts +167 -0
  154. package/templates/checked-fetch.js +17 -0
  155. package/templates/first-party-worker-module-facade.ts +18 -0
  156. package/templates/format-dev-errors.ts +32 -0
  157. package/templates/new-worker-scheduled.js +3 -3
  158. package/templates/new-worker-scheduled.ts +15 -15
  159. package/templates/new-worker.js +3 -3
  160. package/templates/new-worker.ts +15 -15
  161. package/templates/no-op-worker.js +10 -0
  162. package/templates/pages-shim.ts +9 -0
  163. package/templates/pages-template-plugin.ts +167 -0
  164. package/templates/pages-template-worker.ts +172 -0
  165. package/templates/serve-static-assets.ts +63 -0
  166. package/templates/service-bindings-module-facade.js +54 -0
  167. package/templates/service-bindings-sw-facade.js +42 -0
  168. package/templates/tsconfig.json +95 -95
  169. package/wrangler-dist/cli.d.ts +338 -0
  170. package/wrangler-dist/cli.js +95449 -67524
  171. package/pages/functions/buildPlugin.ts +0 -105
  172. package/pages/functions/buildWorker.ts +0 -151
  173. package/pages/functions/filepath-routing.ts +0 -189
  174. package/pages/functions/identifiers.ts +0 -78
  175. package/pages/functions/routes.ts +0 -156
  176. package/pages/functions/template-plugin.ts +0 -147
  177. package/pages/functions/template-worker.ts +0 -143
  178. package/src/__tests__/helpers/faye-websocket.d.ts +0 -6
  179. package/src/pages.tsx +0 -2038
  180. package/src/user.tsx +0 -1203
  181. package/templates/static-asset-facade.js +0 -47
  182. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  183. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  184. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  185. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  186. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  187. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  188. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  189. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  190. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  191. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  192. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  193. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  194. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  195. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  196. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  197. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  198. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  199. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  200. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  201. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  202. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  203. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  204. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  205. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  206. package/vendor/wrangler-mime/LICENSE +0 -21
  207. package/vendor/wrangler-mime/Mime.js +0 -97
  208. package/vendor/wrangler-mime/README.md +0 -187
  209. package/vendor/wrangler-mime/cli.js +0 -46
  210. package/vendor/wrangler-mime/index.js +0 -4
  211. package/vendor/wrangler-mime/lite.js +0 -4
  212. package/vendor/wrangler-mime/package.json +0 -52
  213. package/vendor/wrangler-mime/types/other.js +0 -1
  214. package/vendor/wrangler-mime/types/standard.js +0 -1
@@ -0,0 +1,413 @@
1
+ import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
2
+ import {
3
+ basename,
4
+ dirname,
5
+ extname,
6
+ join,
7
+ relative,
8
+ resolve,
9
+ sep,
10
+ } from "node:path";
11
+ import { hash as blake3hash } from "blake3-wasm";
12
+ import { render, Text } from "ink";
13
+ import Spinner from "ink-spinner";
14
+ import { getType } from "mime";
15
+ import PQueue from "p-queue";
16
+ import prettyBytes from "pretty-bytes";
17
+ import React from "react";
18
+ import { fetchResult } from "../cfetch";
19
+ import { FatalError } from "../errors";
20
+ import { logger } from "../logger";
21
+ import {
22
+ BULK_UPLOAD_CONCURRENCY,
23
+ MAX_BUCKET_FILE_COUNT,
24
+ MAX_BUCKET_SIZE,
25
+ MAX_CHECK_MISSING_ATTEMPTS,
26
+ MAX_UPLOAD_ATTEMPTS,
27
+ } from "./constants";
28
+ import { pagesBetaWarning } from "./utils";
29
+ import type { UploadPayloadFile, YargsOptionsToInterface } from "./types";
30
+ import type { Argv } from "yargs";
31
+
32
+ type UploadArgs = YargsOptionsToInterface<typeof Options>;
33
+
34
+ export function Options(yargs: Argv) {
35
+ return yargs
36
+ .positional("directory", {
37
+ type: "string",
38
+ demandOption: true,
39
+ description: "The directory of static files to upload",
40
+ })
41
+ .options({
42
+ "output-manifest-path": {
43
+ type: "string",
44
+ description: "The name of the project you want to deploy to",
45
+ },
46
+ })
47
+ .epilogue(pagesBetaWarning);
48
+ }
49
+
50
+ export const Handler = async ({
51
+ directory,
52
+ outputManifestPath,
53
+ }: UploadArgs) => {
54
+ if (!directory) {
55
+ throw new FatalError("Must specify a directory.", 1);
56
+ }
57
+
58
+ if (!process.env.CF_PAGES_UPLOAD_JWT) {
59
+ throw new FatalError("No JWT given.", 1);
60
+ }
61
+
62
+ const manifest = await upload({
63
+ directory,
64
+ jwt: process.env.CF_PAGES_UPLOAD_JWT,
65
+ });
66
+
67
+ if (outputManifestPath) {
68
+ await mkdir(dirname(outputManifestPath), { recursive: true });
69
+ await writeFile(outputManifestPath, JSON.stringify(manifest));
70
+ }
71
+
72
+ logger.log(`✨ Upload complete!`);
73
+ };
74
+
75
+ export const upload = async (
76
+ args:
77
+ | {
78
+ directory: string;
79
+ jwt: string;
80
+ }
81
+ | { directory: string; accountId: string; projectName: string }
82
+ ) => {
83
+ async function fetchJwt(): Promise<string> {
84
+ if ("jwt" in args) {
85
+ return args.jwt;
86
+ } else {
87
+ return (
88
+ await fetchResult<{ jwt: string }>(
89
+ `/accounts/${args.accountId}/pages/projects/${args.projectName}/upload-token`
90
+ )
91
+ ).jwt;
92
+ }
93
+ }
94
+
95
+ type FileContainer = {
96
+ path: string;
97
+ contentType: string;
98
+ sizeInBytes: number;
99
+ hash: string;
100
+ };
101
+
102
+ const IGNORE_LIST = [
103
+ "_worker.js",
104
+ "_redirects",
105
+ "_headers",
106
+ "_routes.json",
107
+ ".DS_Store",
108
+ "node_modules",
109
+ ".git",
110
+ ];
111
+
112
+ const directory = resolve(args.directory);
113
+
114
+ // TODO(future): Use this to more efficiently load files in and speed up uploading
115
+ // Limit memory to 1 GB unless more is specified
116
+ // let maxMemory = 1_000_000_000;
117
+ // if (process.env.NODE_OPTIONS && (process.env.NODE_OPTIONS.includes('--max-old-space-size=') || process.env.NODE_OPTIONS.includes('--max_old_space_size='))) {
118
+ // const parsed = parser(process.env.NODE_OPTIONS);
119
+ // maxMemory = (parsed['max-old-space-size'] ? parsed['max-old-space-size'] : parsed['max_old_space_size']) * 1000 * 1000; // Turn MB into bytes
120
+ // }
121
+
122
+ const walk = async (
123
+ dir: string,
124
+ fileMap: Map<string, FileContainer> = new Map(),
125
+ startingDir: string = dir
126
+ ) => {
127
+ const files = await readdir(dir);
128
+
129
+ await Promise.all(
130
+ files.map(async (file) => {
131
+ const filepath = join(dir, file);
132
+ const filestat = await stat(filepath);
133
+
134
+ if (IGNORE_LIST.includes(file)) {
135
+ return;
136
+ }
137
+
138
+ if (filestat.isSymbolicLink()) {
139
+ return;
140
+ }
141
+
142
+ if (filestat.isDirectory()) {
143
+ fileMap = await walk(filepath, fileMap, startingDir);
144
+ } else {
145
+ const name = relative(startingDir, filepath).split(sep).join("/");
146
+
147
+ const fileContent = await readFile(filepath);
148
+
149
+ const base64Content = fileContent.toString("base64");
150
+ const extension = extname(basename(name)).substring(1);
151
+
152
+ if (filestat.size > 25 * 1024 * 1024) {
153
+ throw new FatalError(
154
+ `Error: Pages only supports files up to ${prettyBytes(
155
+ 25 * 1024 * 1024
156
+ )} in size\n${name} is ${prettyBytes(filestat.size)} in size`,
157
+ 1
158
+ );
159
+ }
160
+
161
+ // We don't want to hold the content in memory. We instead only want to read it when it's needed
162
+ fileMap.set(name, {
163
+ path: filepath,
164
+ contentType: getType(name) || "application/octet-stream",
165
+ sizeInBytes: filestat.size,
166
+ hash: blake3hash(base64Content + extension)
167
+ .toString("hex")
168
+ .slice(0, 32),
169
+ });
170
+ }
171
+ })
172
+ );
173
+
174
+ return fileMap;
175
+ };
176
+
177
+ const fileMap = await walk(directory);
178
+
179
+ if (fileMap.size > 20000) {
180
+ throw new FatalError(
181
+ `Error: Pages only supports up to 20,000 files in a deployment. Ensure you have specified your build output directory correctly.`,
182
+ 1
183
+ );
184
+ }
185
+
186
+ const files = [...fileMap.values()];
187
+
188
+ let jwt = await fetchJwt();
189
+
190
+ const start = Date.now();
191
+
192
+ let attempts = 0;
193
+ const getMissingHashes = async (): Promise<string[]> => {
194
+ try {
195
+ return await fetchResult<string[]>(`/pages/assets/check-missing`, {
196
+ method: "POST",
197
+ headers: {
198
+ "Content-Type": "application/json",
199
+ Authorization: `Bearer ${jwt}`,
200
+ },
201
+ body: JSON.stringify({
202
+ hashes: files.map(({ hash }) => hash),
203
+ }),
204
+ });
205
+ } catch (e) {
206
+ if (attempts < MAX_CHECK_MISSING_ATTEMPTS) {
207
+ // Exponential backoff, 1 second first time, then 2 second, then 4 second etc.
208
+ await new Promise((resolvePromise) =>
209
+ setTimeout(resolvePromise, Math.pow(2, attempts++) * 1000)
210
+ );
211
+
212
+ if ((e as { code: number }).code === 8000013) {
213
+ // Looks like the JWT expired, fetch another one
214
+ jwt = await fetchJwt();
215
+ }
216
+ return getMissingHashes();
217
+ } else {
218
+ throw e;
219
+ }
220
+ }
221
+ };
222
+ const missingHashes = await getMissingHashes();
223
+
224
+ const sortedFiles = files
225
+ .filter((file) => missingHashes.includes(file.hash))
226
+ .sort((a, b) => b.sizeInBytes - a.sizeInBytes);
227
+
228
+ // Start with a few buckets so small projects still get
229
+ // the benefit of multiple upload streams
230
+ const buckets: {
231
+ files: FileContainer[];
232
+ remainingSize: number;
233
+ }[] = new Array(BULK_UPLOAD_CONCURRENCY).fill(null).map(() => ({
234
+ files: [],
235
+ remainingSize: MAX_BUCKET_SIZE,
236
+ }));
237
+
238
+ let bucketOffset = 0;
239
+ for (const file of sortedFiles) {
240
+ let inserted = false;
241
+
242
+ for (let i = 0; i < buckets.length; i++) {
243
+ // Start at a different bucket for each new file
244
+ const bucket = buckets[(i + bucketOffset) % buckets.length];
245
+ if (
246
+ bucket.remainingSize >= file.sizeInBytes &&
247
+ bucket.files.length < MAX_BUCKET_FILE_COUNT
248
+ ) {
249
+ bucket.files.push(file);
250
+ bucket.remainingSize -= file.sizeInBytes;
251
+ inserted = true;
252
+ break;
253
+ }
254
+ }
255
+
256
+ if (!inserted) {
257
+ buckets.push({
258
+ files: [file],
259
+ remainingSize: MAX_BUCKET_SIZE - file.sizeInBytes,
260
+ });
261
+ }
262
+ bucketOffset++;
263
+ }
264
+
265
+ let counter = fileMap.size - sortedFiles.length;
266
+ const { rerender, unmount } = render(
267
+ <Progress done={counter} total={fileMap.size} />
268
+ );
269
+
270
+ const queue = new PQueue({ concurrency: BULK_UPLOAD_CONCURRENCY });
271
+
272
+ for (const bucket of buckets) {
273
+ // Don't upload empty buckets (can happen for tiny projects)
274
+ if (bucket.files.length === 0) continue;
275
+
276
+ attempts = 0;
277
+ const doUpload = async (): Promise<void> => {
278
+ // Populate the payload only when actually uploading (this is limited to 3 concurrent uploads at 50 MiB per bucket meaning we'd only load in a max of ~150 MiB)
279
+ // This is so we don't run out of memory trying to upload the files.
280
+ const payload: UploadPayloadFile[] = await Promise.all(
281
+ bucket.files.map(async (file) => ({
282
+ key: file.hash,
283
+ value: (await readFile(file.path)).toString("base64"),
284
+ metadata: {
285
+ contentType: file.contentType,
286
+ },
287
+ base64: true,
288
+ }))
289
+ );
290
+
291
+ try {
292
+ return await fetchResult(`/pages/assets/upload`, {
293
+ method: "POST",
294
+ headers: {
295
+ "Content-Type": "application/json",
296
+ Authorization: `Bearer ${jwt}`,
297
+ },
298
+ body: JSON.stringify(payload),
299
+ });
300
+ } catch (e) {
301
+ if (attempts < MAX_UPLOAD_ATTEMPTS) {
302
+ // Exponential backoff, 1 second first time, then 2 second, then 4 second etc.
303
+ await new Promise((resolvePromise) =>
304
+ setTimeout(resolvePromise, Math.pow(2, attempts++) * 1000)
305
+ );
306
+
307
+ if ((e as { code: number }).code === 8000013) {
308
+ // Looks like the JWT expired, fetch another one
309
+ jwt = await fetchJwt();
310
+ }
311
+ return doUpload();
312
+ } else {
313
+ throw e;
314
+ }
315
+ }
316
+ };
317
+
318
+ queue.add(() =>
319
+ doUpload().then(
320
+ () => {
321
+ counter += bucket.files.length;
322
+ rerender(<Progress done={counter} total={fileMap.size} />);
323
+ },
324
+ (error) => {
325
+ return Promise.reject(
326
+ new FatalError(
327
+ "Failed to upload files. Please try again.",
328
+ error.code || 1
329
+ )
330
+ );
331
+ }
332
+ )
333
+ );
334
+ }
335
+
336
+ await queue.onIdle();
337
+
338
+ unmount();
339
+
340
+ const uploadMs = Date.now() - start;
341
+
342
+ const skipped = fileMap.size - missingHashes.length;
343
+ const skippedMessage = skipped > 0 ? `(${skipped} already uploaded) ` : "";
344
+
345
+ logger.log(
346
+ `✨ Success! Uploaded ${
347
+ sortedFiles.length
348
+ } files ${skippedMessage}${formatTime(uploadMs)}\n`
349
+ );
350
+
351
+ const doUpsertHashes = async (): Promise<void> => {
352
+ try {
353
+ return await fetchResult(`/pages/assets/upsert-hashes`, {
354
+ method: "POST",
355
+ headers: {
356
+ "Content-Type": "application/json",
357
+ Authorization: `Bearer ${jwt}`,
358
+ },
359
+ body: JSON.stringify({
360
+ hashes: files.map(({ hash }) => hash),
361
+ }),
362
+ });
363
+ } catch (e) {
364
+ await new Promise((resolvePromise) => setTimeout(resolvePromise, 1000));
365
+
366
+ if ((e as { code: number }).code === 8000013) {
367
+ // Looks like the JWT expired, fetch another one
368
+ jwt = await fetchJwt();
369
+ }
370
+
371
+ return await fetchResult(`/pages/assets/upsert-hashes`, {
372
+ method: "POST",
373
+ headers: {
374
+ "Content-Type": "application/json",
375
+ Authorization: `Bearer ${jwt}`,
376
+ },
377
+ body: JSON.stringify({
378
+ hashes: files.map(({ hash }) => hash),
379
+ }),
380
+ });
381
+ }
382
+ };
383
+
384
+ try {
385
+ await doUpsertHashes();
386
+ } catch {
387
+ logger.warn(
388
+ "Failed to update file hashes. Every upload appeared to succeed for this deployment, but you might need to re-upload for future deployments. This shouldn't have any impact other than slowing the upload speed of your next deployment."
389
+ );
390
+ }
391
+
392
+ return Object.fromEntries(
393
+ [...fileMap.entries()].map(([fileName, file]) => [
394
+ `/${fileName}`,
395
+ file.hash,
396
+ ])
397
+ );
398
+ };
399
+
400
+ function formatTime(duration: number) {
401
+ return `(${(duration / 1000).toFixed(2)} sec)`;
402
+ }
403
+
404
+ function Progress({ done, total }: { done: number; total: number }) {
405
+ return (
406
+ <>
407
+ <Text>
408
+ <Spinner type="earth" />
409
+ {` Uploading... (${done}/${total})\n`}
410
+ </Text>
411
+ </>
412
+ );
413
+ }
@@ -0,0 +1,12 @@
1
+ import type { BuildResult } from "esbuild";
2
+
3
+ export const RUNNING_BUILDERS: BuildResult[] = [];
4
+
5
+ export const CLEANUP_CALLBACKS: (() => void)[] = [];
6
+ export const CLEANUP = () => {
7
+ CLEANUP_CALLBACKS.forEach((callback) => callback());
8
+ RUNNING_BUILDERS.forEach((builder) => builder.stop?.());
9
+ };
10
+
11
+ export const pagesBetaWarning =
12
+ "🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose";