wrangler 2.0.27 → 2.1.0

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 (65) hide show
  1. package/bin/wrangler.js +1 -1
  2. package/miniflare-dist/index.mjs +1141 -369
  3. package/package.json +6 -4
  4. package/src/__tests__/api-dev.test.ts +19 -0
  5. package/src/__tests__/configuration.test.ts +27 -27
  6. package/src/__tests__/dev.test.tsx +8 -6
  7. package/src/__tests__/helpers/hello-world-worker.js +5 -0
  8. package/src/__tests__/helpers/mock-cfetch.ts +4 -4
  9. package/src/__tests__/helpers/mock-console.ts +11 -2
  10. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
  11. package/src/__tests__/helpers/mock-known-routes.ts +7 -0
  12. package/src/__tests__/index.test.ts +37 -37
  13. package/src/__tests__/init.test.ts +356 -5
  14. package/src/__tests__/jest.setup.ts +13 -0
  15. package/src/__tests__/middleware.test.ts +768 -0
  16. package/src/__tests__/pages.test.ts +829 -104
  17. package/src/__tests__/paths.test.ts +17 -0
  18. package/src/__tests__/publish.test.ts +512 -445
  19. package/src/__tests__/tail.test.ts +79 -72
  20. package/src/__tests__/test-old-node-version.js +3 -3
  21. package/src/__tests__/worker-namespace.test.ts +37 -35
  22. package/src/api/dev.ts +93 -28
  23. package/src/bundle.ts +239 -12
  24. package/src/cfetch/internal.ts +64 -3
  25. package/src/cli.ts +1 -1
  26. package/src/config/environment.ts +1 -1
  27. package/src/config/index.ts +4 -4
  28. package/src/config/validation.ts +3 -3
  29. package/src/create-worker-upload-form.ts +29 -26
  30. package/src/dev/dev.tsx +3 -1
  31. package/src/dev/local.tsx +319 -171
  32. package/src/dev/remote.tsx +16 -4
  33. package/src/dev/start-server.ts +416 -0
  34. package/src/dev/use-esbuild.ts +4 -0
  35. package/src/dev.tsx +340 -166
  36. package/src/dialogs.tsx +12 -0
  37. package/src/{worker-namespace.ts → dispatch-namespace.ts} +18 -18
  38. package/src/entry.ts +2 -1
  39. package/src/index.tsx +59 -12
  40. package/src/init.ts +291 -16
  41. package/src/metrics/send-event.ts +6 -5
  42. package/src/miniflare-cli/assets.ts +130 -476
  43. package/src/miniflare-cli/index.ts +39 -33
  44. package/src/pages/constants.ts +3 -0
  45. package/src/pages/dev.tsx +8 -3
  46. package/src/pages/functions/buildPlugin.ts +2 -1
  47. package/src/pages/functions/buildWorker.ts +2 -1
  48. package/src/pages/functions/routes-transformation.test.ts +12 -1
  49. package/src/pages/functions/routes-transformation.ts +7 -1
  50. package/src/pages/hash.tsx +13 -0
  51. package/src/pages/publish.tsx +82 -38
  52. package/src/pages/upload.tsx +3 -18
  53. package/src/paths.ts +20 -1
  54. package/src/publish.ts +49 -8
  55. package/src/tail/filters.ts +1 -5
  56. package/src/tail/index.ts +6 -3
  57. package/src/worker.ts +10 -9
  58. package/src/zones.ts +91 -0
  59. package/templates/middleware/common.ts +62 -0
  60. package/templates/middleware/loader-modules.ts +84 -0
  61. package/templates/middleware/loader-sw.ts +213 -0
  62. package/templates/middleware/middleware-pretty-error.ts +40 -0
  63. package/templates/middleware/middleware-scheduled.ts +14 -0
  64. package/wrangler-dist/cli.d.ts +22 -8
  65. package/wrangler-dist/cli.js +71020 -65212
@@ -1,16 +1,27 @@
1
1
  import { existsSync, lstatSync, readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
+ import { createMetadataObject } from "@cloudflare/pages-shared/src/metadata-generator/createMetadataObject";
4
+ import { parseHeaders } from "@cloudflare/pages-shared/src/metadata-generator/parseHeaders";
5
+ import { parseRedirects } from "@cloudflare/pages-shared/src/metadata-generator/parseRedirects";
3
6
  import { fetch as miniflareFetch } from "@miniflare/core";
7
+ import {
8
+ Response as MiniflareResponse,
9
+ Request as MiniflareRequest,
10
+ } from "@miniflare/core";
4
11
  import { watch } from "chokidar";
5
12
  import { getType } from "mime";
6
- import { Response } from "miniflare";
7
- import type { Headers as MiniflareHeaders } from "@miniflare/core";
8
- import type { Log } from "miniflare";
13
+ import { hashFile } from "../pages/hash";
14
+ import type { Metadata } from "@cloudflare/pages-shared/src/asset-server/metadata";
9
15
  import type {
10
- Request as MiniflareRequest,
11
- RequestInfo,
12
- RequestInit,
13
- } from "miniflare";
16
+ fetch,
17
+ Request,
18
+ } from "@cloudflare/pages-shared/src/environment-polyfills/types";
19
+ import type {
20
+ ParsedRedirects,
21
+ ParsedHeaders,
22
+ } from "@cloudflare/pages-shared/src/metadata-generator/types";
23
+ import type { RequestInfo, RequestInit, FetcherFetch } from "@miniflare/core";
24
+ import type { Log } from "miniflare";
14
25
 
15
26
  export interface Options {
16
27
  log: Log;
@@ -24,269 +35,49 @@ export default async function generateASSETSBinding(options: Options) {
24
35
  ? await generateAssetsFetch(options.directory, options.log)
25
36
  : invalidAssetsFetch;
26
37
 
27
- return async function (request: MiniflareRequest) {
38
+ return async function (miniflareRequest: MiniflareRequest) {
28
39
  if (options.proxyPort) {
29
40
  try {
30
- const url = new URL(request.url);
41
+ const url = new URL(miniflareRequest.url);
31
42
  url.host = `localhost:${options.proxyPort}`;
32
- return await miniflareFetch(url, request);
43
+ return await miniflareFetch(url, miniflareRequest);
33
44
  } catch (thrown) {
34
45
  options.log.error(new Error(`Could not proxy request: ${thrown}`));
35
46
 
36
47
  // TODO: Pretty error page
37
- return new Response(`[wrangler] Could not proxy request: ${thrown}`, {
38
- status: 502,
39
- });
48
+ return new MiniflareResponse(
49
+ `[wrangler] Could not proxy request: ${thrown}`,
50
+ {
51
+ status: 502,
52
+ }
53
+ );
40
54
  }
41
55
  } else {
42
56
  try {
43
- return await assetsFetch(request);
57
+ return await assetsFetch(miniflareRequest);
44
58
  } catch (thrown) {
45
59
  options.log.error(new Error(`Could not serve static asset: ${thrown}`));
46
60
 
47
61
  // TODO: Pretty error page
48
- return new Response(
62
+ return new MiniflareResponse(
49
63
  `[wrangler] Could not serve static asset: ${thrown}`,
50
64
  { status: 502 }
51
65
  );
52
66
  }
53
67
  }
54
- };
55
- }
56
-
57
- function escapeRegex(str: string) {
58
- return str.replace(/[-/\\^$*+?.()|[]{}]/g, "\\$&");
59
- }
60
-
61
- type Replacements = Record<string, string>;
62
-
63
- function replacer(str: string, replacements: Replacements) {
64
- for (const [replacement, value] of Object.entries(replacements)) {
65
- str = str.replace(`:${replacement}`, value);
66
- }
67
- return str;
68
- }
69
-
70
- function generateRulesMatcher<T>(
71
- rules?: Record<string, T>,
72
- replacerFn: (match: T, replacements: Replacements) => T = (match) => match
73
- ) {
74
- // TODO: How can you test cross-host rules?
75
- if (!rules) return () => [];
76
-
77
- const compiledRules = Object.entries(rules)
78
- .map(([rule, match]) => {
79
- const crossHost = rule.startsWith("https://");
80
-
81
- rule = rule.split("*").map(escapeRegex).join("(?<splat>.*)");
82
-
83
- const host_matches = rule.matchAll(
84
- /(?<=^https:\\\/\\\/[^/]*?):([^\\]+)(?=\\)/g
85
- );
86
- for (const hostMatch of host_matches) {
87
- rule = rule.split(hostMatch[0]).join(`(?<${hostMatch[1]}>[^/.]+)`);
88
- }
89
-
90
- const path_matches = rule.matchAll(/:(\w+)/g);
91
- for (const pathMatch of path_matches) {
92
- rule = rule.split(pathMatch[0]).join(`(?<${pathMatch[1]}>[^/]+)`);
93
- }
94
-
95
- rule = "^" + rule + "$";
96
-
97
- try {
98
- const regExp = new RegExp(rule);
99
- return [{ crossHost, regExp }, match];
100
- } catch {}
101
- })
102
- .filter((value) => value !== undefined) as [
103
- { crossHost: boolean; regExp: RegExp },
104
- T
105
- ][];
106
-
107
- return ({ request }: { request: MiniflareRequest }) => {
108
- const { pathname, host } = new URL(request.url);
109
-
110
- return compiledRules
111
- .map(([{ crossHost, regExp }, match]) => {
112
- const test = crossHost ? `https://${host}${pathname}` : pathname;
113
- const result = regExp.exec(test);
114
- if (result) {
115
- return replacerFn(match, result.groups || {});
116
- }
117
- })
118
- .filter((value) => value !== undefined) as T[];
119
- };
120
- }
121
-
122
- function generateHeadersMatcher(headersFile: string) {
123
- if (existsSync(headersFile)) {
124
- const contents = readFileSync(headersFile).toString();
125
-
126
- // TODO: Log errors
127
- const lines = contents
128
- .split("\n")
129
- .map((line) => line.trim())
130
- .filter((line) => !line.startsWith("#") && line !== "");
131
-
132
- const rules: Record<string, Record<string, string>> = {};
133
- let rule: { path: string; headers: Record<string, string> } | undefined =
134
- undefined;
135
-
136
- for (const line of lines) {
137
- if (/^([^\s]+:\/\/|^\/)/.test(line)) {
138
- if (rule && Object.keys(rule.headers).length > 0) {
139
- rules[rule.path] = rule.headers;
140
- }
141
-
142
- const path = validateURL(line);
143
- if (path) {
144
- rule = {
145
- path,
146
- headers: {},
147
- };
148
- continue;
149
- }
150
- }
151
-
152
- if (!line.includes(":")) continue;
153
-
154
- const [rawName, ...rawValue] = line.split(":");
155
- const name = rawName.trim().toLowerCase();
156
- const value = rawValue.join(":").trim();
157
-
158
- if (name === "") continue;
159
- if (!rule) continue;
160
-
161
- const existingValues = rule.headers[name];
162
- rule.headers[name] = existingValues
163
- ? `${existingValues}, ${value}`
164
- : value;
165
- }
166
-
167
- if (rule && Object.keys(rule.headers).length > 0) {
168
- rules[rule.path] = rule.headers;
169
- }
170
-
171
- const rulesMatcher = generateRulesMatcher(rules, (match, replacements) =>
172
- Object.fromEntries(
173
- Object.entries(match).map(([name, value]) => [
174
- name,
175
- replacer(value, replacements),
176
- ])
177
- )
178
- );
179
-
180
- return (request: MiniflareRequest) => {
181
- const matches = rulesMatcher({
182
- request,
183
- });
184
- if (matches) return matches;
185
- };
186
- } else {
187
- return () => undefined;
188
- }
189
- }
190
-
191
- function generateRedirectsMatcher(redirectsFile: string) {
192
- if (existsSync(redirectsFile)) {
193
- const contents = readFileSync(redirectsFile).toString();
194
-
195
- // TODO: Log errors
196
- const lines = contents
197
- .split("\n")
198
- .map((line) => line.trim())
199
- .filter((line) => !line.startsWith("#") && line !== "");
200
-
201
- const rules = Object.fromEntries(
202
- lines
203
- .map((line) => line.split(" "))
204
- .filter((tokens) => tokens.length === 2 || tokens.length === 3)
205
- .map((tokens) => {
206
- const from = validateURL(tokens[0], true, false, false);
207
- const to = validateURL(tokens[1], false, true, true);
208
- let status: number | undefined = parseInt(tokens[2]) || 302;
209
- status = [301, 302, 303, 307, 308].includes(status)
210
- ? status
211
- : undefined;
212
-
213
- return from && to && status ? [from, { to, status }] : undefined;
214
- })
215
- .filter((rule) => rule !== undefined) as [
216
- string,
217
- { to: string; status?: number }
218
- ][]
219
- );
220
-
221
- const rulesMatcher = generateRulesMatcher(
222
- rules,
223
- ({ status, to }, replacements) => ({
224
- status,
225
- to: replacer(to, replacements),
226
- })
227
- );
228
-
229
- return (request: MiniflareRequest) => {
230
- const match = rulesMatcher({
231
- request,
232
- })[0];
233
- if (match) return match;
234
- };
235
- } else {
236
- return () => undefined;
237
- }
238
- }
239
-
240
- function extractPathname(
241
- path = "/",
242
- includeSearch: boolean,
243
- includeHash: boolean
244
- ) {
245
- if (!path.startsWith("/")) path = `/${path}`;
246
- const url = new URL(`//${path}`, "relative://");
247
- return `${url.pathname}${includeSearch ? url.search : ""}${
248
- includeHash ? url.hash : ""
249
- }`;
250
- }
251
-
252
- function validateURL(
253
- token: string,
254
- onlyRelative = false,
255
- includeSearch = false,
256
- includeHash = false
257
- ) {
258
- const host = /^https:\/\/+(?<host>[^/]+)\/?(?<path>.*)/.exec(token);
259
- if (host && host.groups && host.groups.host) {
260
- if (onlyRelative) return;
261
-
262
- return `https://${host.groups.host}${extractPathname(
263
- host.groups.path,
264
- includeSearch,
265
- includeHash
266
- )}`;
267
- } else {
268
- if (!token.startsWith("/") && onlyRelative) token = `/${token}`;
269
-
270
- const path = /^\//.exec(token);
271
- if (path) {
272
- try {
273
- return extractPathname(token, includeSearch, includeHash);
274
- } catch {}
275
- }
276
- }
277
- return "";
278
- }
279
-
280
- function hasFileExtension(pathname: string) {
281
- return /\/.+\.[a-z0-9]+$/i.test(pathname);
68
+ } as FetcherFetch;
282
69
  }
283
70
 
284
71
  async function generateAssetsFetch(
285
72
  directory: string,
286
73
  log: Log
287
- ): Promise<typeof miniflareFetch> {
74
+ ): Promise<typeof fetch> {
288
75
  // Defer importing miniflare until we really need it
289
- const { Headers, Request } = await import("@miniflare/core");
76
+ await import("@cloudflare/pages-shared/src/environment-polyfills/miniflare");
77
+
78
+ const { generateHandler, parseQualityWeightedList } = await import(
79
+ "@cloudflare/pages-shared/src/asset-server/handler"
80
+ );
290
81
 
291
82
  const headersFile = join(directory, "_headers");
292
83
  const redirectsFile = join(directory, "_redirects");
@@ -294,260 +85,123 @@ async function generateAssetsFetch(
294
85
 
295
86
  const ignoredFiles = [headersFile, redirectsFile, workerFile];
296
87
 
297
- const assetExists = (path: string) => {
298
- path = join(directory, path);
299
- return (
300
- existsSync(path) &&
301
- lstatSync(path).isFile() &&
302
- !ignoredFiles.includes(path)
303
- );
304
- };
305
-
306
- const getAsset = (path: string) => {
307
- if (assetExists(path)) {
308
- return join(directory, path);
309
- }
310
- };
88
+ let redirects: ParsedRedirects | undefined;
89
+ if (existsSync(redirectsFile)) {
90
+ const contents = readFileSync(redirectsFile, "utf-8");
91
+ redirects = parseRedirects(contents);
92
+ }
311
93
 
312
- let redirectsMatcher = generateRedirectsMatcher(redirectsFile);
313
- let headersMatcher = generateHeadersMatcher(headersFile);
94
+ let headers: ParsedHeaders | undefined;
95
+ if (existsSync(headersFile)) {
96
+ const contents = readFileSync(headersFile, "utf-8");
97
+ headers = parseHeaders(contents);
98
+ }
314
99
 
315
- watch([headersFile, redirectsFile], {
316
- persistent: true,
317
- }).on("change", (path) => {
318
- switch (path) {
319
- case headersFile: {
320
- log.log("_headers modified. Re-evaluating...");
321
- headersMatcher = generateHeadersMatcher(headersFile);
322
- break;
323
- }
324
- case redirectsFile: {
325
- log.log("_redirects modified. Re-evaluating...");
326
- redirectsMatcher = generateRedirectsMatcher(redirectsFile);
327
- break;
328
- }
329
- }
100
+ let metadata = createMetadataObject({
101
+ redirects,
102
+ headers,
103
+ logger: log.warn,
330
104
  });
331
105
 
332
- const serveAsset = (file: string) => {
333
- return readFileSync(file);
334
- };
335
-
336
- const generateResponse = (request: MiniflareRequest) => {
337
- const url = new URL(request.url);
338
- let assetName = url.pathname;
339
- try {
340
- //it's possible for someone to send a URL like http://fakehost/abc%2 which would fail to decode
341
- assetName = decodeURIComponent(url.pathname);
342
- } catch {}
343
-
344
- const deconstructedResponse: {
345
- status: number;
346
- headers: MiniflareHeaders;
347
- body?: Buffer;
348
- } = {
349
- status: 200,
350
- headers: new Headers(),
351
- body: undefined,
352
- };
353
-
354
- const match = redirectsMatcher(request);
355
- if (match) {
356
- const { status, to } = match;
357
-
358
- let location = to;
359
- let search;
360
-
361
- if (to.startsWith("/")) {
362
- search = new URL(location, "http://fakehost").search;
363
- } else {
364
- search = new URL(location).search;
365
- }
366
-
367
- location = `${location}${search ? "" : url.search}`;
368
-
369
- if (status && [301, 302, 303, 307, 308].includes(status)) {
370
- deconstructedResponse.status = status;
371
- } else {
372
- deconstructedResponse.status = 302;
373
- }
374
-
375
- deconstructedResponse.headers.set("Location", location);
376
- return deconstructedResponse;
377
- }
378
-
379
- if (!request.method?.match(/^(get|head)$/i)) {
380
- deconstructedResponse.status = 405;
381
- return deconstructedResponse;
382
- }
383
-
384
- const notFound = () => {
385
- let cwd = assetName;
386
- while (cwd) {
387
- cwd = cwd.slice(0, cwd.lastIndexOf("/"));
388
-
389
- if ((asset = getAsset(`${cwd}/404.html`))) {
390
- deconstructedResponse.status = 404;
391
- deconstructedResponse.body = serveAsset(asset);
392
- deconstructedResponse.headers.set(
393
- "Content-Type",
394
- getType(asset) || "application/octet-stream"
395
- );
396
- return deconstructedResponse;
106
+ watch([headersFile, redirectsFile], { persistent: true }).on(
107
+ "change",
108
+ (path) => {
109
+ switch (path) {
110
+ case headersFile: {
111
+ log.log("_headers modified. Re-evaluating...");
112
+ const contents = readFileSync(headersFile).toString();
113
+ headers = parseHeaders(contents);
114
+ break;
115
+ }
116
+ case redirectsFile: {
117
+ log.log("_redirects modified. Re-evaluating...");
118
+ const contents = readFileSync(redirectsFile).toString();
119
+ redirects = parseRedirects(contents);
120
+ break;
397
121
  }
398
122
  }
399
123
 
400
- if ((asset = getAsset(`/index.html`))) {
401
- deconstructedResponse.body = serveAsset(asset);
402
- deconstructedResponse.headers.set(
403
- "Content-Type",
404
- getType(asset) || "application/octet-stream"
405
- );
406
- return deconstructedResponse;
407
- }
408
-
409
- deconstructedResponse.status = 404;
410
- return deconstructedResponse;
411
- };
412
-
413
- let asset;
414
-
415
- if (assetName.endsWith("/")) {
416
- if ((asset = getAsset(`${assetName}/index.html`))) {
417
- deconstructedResponse.body = serveAsset(asset);
418
- deconstructedResponse.headers.set(
419
- "Content-Type",
420
- getType(asset) || "application/octet-stream"
421
- );
422
- return deconstructedResponse;
423
- } else if ((asset = getAsset(`${assetName.replace(/\/$/, ".html")}`))) {
424
- deconstructedResponse.status = 301;
425
- deconstructedResponse.headers.set(
426
- "Location",
427
- `${assetName.slice(0, -1)}${url.search}`
428
- );
429
- return deconstructedResponse;
430
- }
124
+ metadata = createMetadataObject({
125
+ redirects,
126
+ headers,
127
+ logger: log.warn,
128
+ });
431
129
  }
130
+ );
432
131
 
433
- if (assetName.endsWith("/index")) {
434
- deconstructedResponse.status = 301;
435
- deconstructedResponse.headers.set(
436
- "Location",
437
- `${assetName.slice(0, -"index".length)}${url.search}`
438
- );
439
- return deconstructedResponse;
440
- }
132
+ const generateResponse = async (request: Request) => {
133
+ const assetKeyEntryMap = new Map<string, string>();
134
+
135
+ return await generateHandler<string>({
136
+ request,
137
+ metadata: metadata as Metadata,
138
+ xServerEnvHeader: "dev",
139
+ logError: console.error,
140
+ findAssetEntryForPath: async (path) => {
141
+ const filepath = join(directory, path);
142
+
143
+ if (
144
+ existsSync(filepath) &&
145
+ lstatSync(filepath).isFile() &&
146
+ !ignoredFiles.includes(filepath)
147
+ ) {
148
+ const hash = hashFile(filepath);
149
+ assetKeyEntryMap.set(hash, filepath);
150
+ return hash;
151
+ }
441
152
 
442
- if ((asset = getAsset(assetName))) {
443
- if (assetName.endsWith(".html")) {
444
- const extensionlessPath = assetName.slice(0, -".html".length);
445
- if (getAsset(extensionlessPath) || extensionlessPath === "/") {
446
- deconstructedResponse.body = serveAsset(asset);
447
- deconstructedResponse.headers.set(
448
- "Content-Type",
449
- getType(asset) || "application/octet-stream"
450
- );
451
- return deconstructedResponse;
153
+ return null;
154
+ },
155
+ getAssetKey: (assetEntry) => {
156
+ return assetEntry;
157
+ },
158
+ negotiateContent: (contentRequest) => {
159
+ let rawAcceptEncoding: string | undefined;
160
+ if (
161
+ contentRequest.cf &&
162
+ "clientAcceptEncoding" in contentRequest.cf &&
163
+ contentRequest.cf.clientAcceptEncoding
164
+ ) {
165
+ rawAcceptEncoding = contentRequest.cf.clientAcceptEncoding as string;
452
166
  } else {
453
- deconstructedResponse.status = 301;
454
- deconstructedResponse.headers.set(
455
- "Location",
456
- `${extensionlessPath}${url.search}`
457
- );
458
- return deconstructedResponse;
167
+ rawAcceptEncoding =
168
+ contentRequest.headers.get("Accept-Encoding") || undefined;
459
169
  }
460
- } else {
461
- deconstructedResponse.body = serveAsset(asset);
462
- deconstructedResponse.headers.set(
463
- "Content-Type",
464
- getType(asset) || "application/octet-stream"
465
- );
466
- return deconstructedResponse;
467
- }
468
- } else if (hasFileExtension(assetName)) {
469
- if ((asset = getAsset(assetName + ".html"))) {
470
- deconstructedResponse.body = serveAsset(asset);
471
- deconstructedResponse.headers.set(
472
- "Content-Type",
473
- getType(asset) || "application/octet-stream"
474
- );
475
- return deconstructedResponse;
476
- }
477
- notFound();
478
- return deconstructedResponse;
479
- }
480
170
 
481
- if ((asset = getAsset(`${assetName}.html`))) {
482
- deconstructedResponse.body = serveAsset(asset);
483
- deconstructedResponse.headers.set(
484
- "Content-Type",
485
- getType(asset) || "application/octet-stream"
486
- );
487
- return deconstructedResponse;
488
- }
489
-
490
- if ((asset = getAsset(`${assetName}/index.html`))) {
491
- deconstructedResponse.status = 301;
492
- deconstructedResponse.headers.set(
493
- "Location",
494
- `${assetName}/${url.search}`
495
- );
496
- return deconstructedResponse;
497
- } else {
498
- notFound();
499
- return deconstructedResponse;
500
- }
501
- };
171
+ const acceptEncoding = parseQualityWeightedList(rawAcceptEncoding);
502
172
 
503
- const attachHeaders = (
504
- request: MiniflareRequest,
505
- deconstructedResponse: {
506
- status: number;
507
- headers: MiniflareHeaders;
508
- body?: Buffer;
509
- }
510
- ) => {
511
- const headers = deconstructedResponse.headers;
512
- const newHeaders = new Headers({});
513
- const matches = headersMatcher(request) || [];
514
-
515
- matches.forEach((match) => {
516
- Object.entries(match).forEach(([name, value]) => {
517
- newHeaders.append(name, `${value}`);
518
- });
519
- });
173
+ if (
174
+ acceptEncoding["identity"] === 0 ||
175
+ (acceptEncoding["*"] === 0 &&
176
+ acceptEncoding["identity"] === undefined)
177
+ ) {
178
+ throw new Error("No acceptable encodings available");
179
+ }
520
180
 
521
- const combinedHeaders = {
522
- ...Object.fromEntries(headers.entries()),
523
- ...Object.fromEntries(newHeaders.entries()),
524
- };
181
+ return { encoding: null };
182
+ },
183
+ fetchAsset: async (assetKey) => {
184
+ const filepath = assetKeyEntryMap.get(assetKey);
185
+ if (!filepath) {
186
+ throw new Error(
187
+ "Could not fetch asset. Please file an issue on GitHub (https://github.com/cloudflare/wrangler2/issues/new/choose) with reproduction steps."
188
+ );
189
+ }
190
+ const body = readFileSync(filepath) as unknown as ReadableStream;
525
191
 
526
- deconstructedResponse.headers = new Headers({});
527
- Object.entries(combinedHeaders).forEach(([name, value]) => {
528
- if (value) deconstructedResponse.headers.set(name, value);
192
+ const contentType = getType(filepath) || "application/octet-stream";
193
+ return { body, contentType };
194
+ },
529
195
  });
530
196
  };
531
197
 
532
198
  return async (input: RequestInfo, init?: RequestInit) => {
533
- const request = new Request(input, init);
534
- const deconstructedResponse = generateResponse(request);
535
- attachHeaders(request, deconstructedResponse);
536
-
537
- const headers = new Headers();
538
-
539
- [...deconstructedResponse.headers.entries()].forEach(([name, value]) => {
540
- if (value) headers.set(name, value);
541
- });
542
-
543
- return new Response(deconstructedResponse.body, {
544
- headers,
545
- status: deconstructedResponse.status,
546
- });
199
+ const request = new MiniflareRequest(input, init);
200
+ return await generateResponse(request as unknown as Request);
547
201
  };
548
202
  }
549
203
 
550
- const invalidAssetsFetch: typeof miniflareFetch = () => {
204
+ const invalidAssetsFetch: typeof fetch = () => {
551
205
  throw new Error(
552
206
  "Trying to fetch assets directly when there is no `directory` option specified."
553
207
  );