@solidjs/web 2.0.0-rc.4 → 2.0.0-rc.5

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 (57) hide show
  1. package/dist/dev.cjs +52 -7
  2. package/dist/dev.js +51 -8
  3. package/dist/server.cjs +162 -35
  4. package/dist/server.js +161 -36
  5. package/dist/web.cjs +32 -7
  6. package/dist/web.js +31 -8
  7. package/frames/dist/client.cjs +41 -8
  8. package/frames/dist/client.dev.cjs +41 -8
  9. package/frames/dist/client.dev.js +41 -8
  10. package/frames/dist/client.js +41 -8
  11. package/frames/dist/server.cjs +432 -44
  12. package/frames/dist/server.js +432 -44
  13. package/package.json +2 -2
  14. package/serialization/dist/decode.cjs +4 -2
  15. package/serialization/dist/decode.js +4 -2
  16. package/serialization/dist/serialization.cjs +12 -8
  17. package/serialization/dist/serialization.js +12 -8
  18. package/serialization/types/index.d.ts +7 -0
  19. package/serialization/types/serializer-decode.d.ts +14 -1
  20. package/serialization/types/serializer.d.ts +7 -0
  21. package/serialization/types-cjs/index.d.cts +7 -0
  22. package/serialization/types-cjs/serializer-decode.d.cts +14 -1
  23. package/serialization/types-cjs/serializer.d.cts +7 -0
  24. package/server-functions/dist/client.cjs +150 -33
  25. package/server-functions/dist/client.js +147 -34
  26. package/server-functions/dist/server.cjs +731 -118
  27. package/server-functions/dist/server.dev.cjs +751 -118
  28. package/server-functions/dist/server.dev.js +747 -119
  29. package/server-functions/dist/server.js +727 -119
  30. package/types/cookies.d.ts +6 -14
  31. package/types/frames/frame-client.d.ts +4 -0
  32. package/types/frames/serializer-decode.d.ts +14 -1
  33. package/types/frames/serializer.d.ts +7 -0
  34. package/types/jsx.d.ts +11 -16
  35. package/types/response.d.ts +11 -0
  36. package/types/serializer-decode.d.ts +14 -1
  37. package/types/serializer.d.ts +7 -0
  38. package/types/server-functions/client.d.ts +22 -2
  39. package/types/server-functions/flash.d.ts +9 -0
  40. package/types/server-functions/server.d.ts +58 -9
  41. package/types/server-functions/shared.d.ts +77 -14
  42. package/types/server-mock.d.ts +17 -2
  43. package/types/server.d.ts +16 -2
  44. package/types-cjs/cookies.d.cts +6 -14
  45. package/types-cjs/frames/frame-client.d.cts +4 -0
  46. package/types-cjs/frames/serializer-decode.d.cts +14 -1
  47. package/types-cjs/frames/serializer.d.cts +7 -0
  48. package/types-cjs/jsx.d.cts +11 -16
  49. package/types-cjs/response.d.cts +11 -0
  50. package/types-cjs/serializer-decode.d.cts +14 -1
  51. package/types-cjs/serializer.d.cts +7 -0
  52. package/types-cjs/server-functions/client.d.cts +22 -2
  53. package/types-cjs/server-functions/flash.d.cts +9 -0
  54. package/types-cjs/server-functions/server.d.cts +58 -9
  55. package/types-cjs/server-functions/shared.d.cts +77 -14
  56. package/types-cjs/server-mock.d.cts +17 -2
  57. package/types-cjs/server.d.cts +16 -2
package/dist/server.cjs CHANGED
@@ -151,13 +151,13 @@ function resolveSerializerPlugins(customPlugins) {
151
151
  seroval.Feature.RegExp;
152
152
 
153
153
  const DEFAULT_DISABLED_FEATURES = seroval.Feature.AggregateError | seroval.Feature.BigIntTypedArray;
154
- const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : seroval.Feature.ErrorPrototypeStack;
154
+ const serializeOnlyDisabledFeatures = serializeErrorStacks => (serializeErrorStacks === undefined ? process.env.NODE_ENV === "development" : serializeErrorStacks) ? 0 : seroval.Feature.ErrorPrototypeStack;
155
155
  const HYDRATION_GLOBAL = "_$HY.r";
156
156
  function createSerializer(options) {
157
157
  return new seroval.Serializer({
158
158
  ...options,
159
159
  plugins: resolveSerializerPlugins(options.plugins),
160
- disabledFeatures: (options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures) | serializeOnlyDisabledFeatures()
160
+ disabledFeatures: (options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures) | serializeOnlyDisabledFeatures(options.serializeErrorStacks)
161
161
  });
162
162
  }
163
163
  function createHydrationSerializer({
@@ -214,6 +214,7 @@ function isSafeError(value) {
214
214
  return !!(value && (typeof value === "object" || typeof value === "function") && value[SAFE_ERROR]);
215
215
  }
216
216
  const REVALIDATE_HEADER = "X-Revalidate";
217
+ const RESPONSE_HEADER_VALUE_LIMIT = 4096;
217
218
  function initWithRevalidate(init = {}) {
218
219
  const resolved = typeof init === "number" ? {
219
220
  status: init
@@ -234,7 +235,13 @@ function initWithRevalidate(init = {}) {
234
235
  } else {
235
236
  headers = new Headers(responseInit.headers);
236
237
  }
237
- revalidate !== undefined && headers.set(REVALIDATE_HEADER, revalidate.toString());
238
+ if (revalidate !== undefined) {
239
+ const keys = revalidate.toString();
240
+ if (keys.length > RESPONSE_HEADER_VALUE_LIMIT) {
241
+ throw new TypeError(`revalidate names ${keys.length} characters of cache keys; past ` + `${RESPONSE_HEADER_VALUE_LIMIT} the ${REVALIDATE_HEADER} header would overflow ` + `receivers (an 8 KiB proxy buffer holds the whole header block) and the response ` + `dies at the socket after the mutation committed. Split the invalidation across ` + `calls or use coarser keys — a dropped key would be a silently stale cache, so ` + `the runtime refuses rather than trims.`);
242
+ }
243
+ headers.set(REVALIDATE_HEADER, keys);
244
+ }
238
245
  return {
239
246
  responseInit,
240
247
  headers
@@ -252,7 +259,12 @@ function redirect(url, init = 302) {
252
259
  responseInit.status = 302;
253
260
  }
254
261
  const target = typeof url === "string" ? url : url[HREF];
255
- headers.set("Location", typeof target === "string" ? target : String(url));
262
+ const location = typeof target === "string" ? target : String(url);
263
+ const encoded = location.replace(/[^\x00-\x7f]/gu, encodeURIComponent);
264
+ if (encoded.length > RESPONSE_HEADER_VALUE_LIMIT) {
265
+ throw new TypeError(`redirect() target is ${encoded.length} characters; past ` + `${RESPONSE_HEADER_VALUE_LIMIT} the Location header (and the scripted transport's ` + `redirect header) would overflow receivers and the response dies at the socket. ` + `A target this size is usually unbounded input echoed into the url — carry the ` + `state server-side instead. Refused rather than trimmed: a cut target is a ` + `different address.`);
266
+ }
267
+ headers.set("Location", encoded);
256
268
  return new Response(null, {
257
269
  ...responseInit,
258
270
  headers
@@ -268,11 +280,18 @@ function reload(init = {}) {
268
280
  headers
269
281
  });
270
282
  }
283
+ const NULL_BODY_STATUSES = new Set([204, 205, 304]);
271
284
  function respond(value, init = {}) {
272
285
  const {
273
286
  responseInit,
274
287
  headers
275
288
  } = initWithRevalidate(init);
289
+ if (NULL_BODY_STATUSES.has(responseInit.status)) {
290
+ return new ResponseEnvelope(new Response(null, {
291
+ ...responseInit,
292
+ headers
293
+ }), value);
294
+ }
276
295
  headers.set("Content-Type", "application/json");
277
296
  return new ResponseEnvelope(new Response(JSON.stringify(value), {
278
297
  ...responseInit,
@@ -323,6 +342,7 @@ function serializeCookie(name, value, options = {}) {
323
342
  if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
324
343
  if (options.httpOnly) cookie += "; HttpOnly";
325
344
  if (options.secure) cookie += "; Secure";
345
+ if (options.partitioned) cookie += "; Partitioned";
326
346
  if (options.sameSite) {
327
347
  const sameSite = options.sameSite.toLowerCase();
328
348
  cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
@@ -340,6 +360,7 @@ function clearFlashCookie() {
340
360
 
341
361
  const ERROR_HEADER = "X-Server-Function-Error";
342
362
  const BODY_FORMAT_HEADER = "X-Server-Function-Format";
363
+ const REDIRECT_HEADER = "X-Server-Function-Redirect";
343
364
  const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
344
365
 
345
366
  const HEAD_ELIGIBLE_TAGS = new Set(["title", "meta", "link", "style", "script", "base"]);
@@ -378,7 +399,8 @@ function resourceIdentity(tag, props) {
378
399
  let id = "res:" + tag + ":" + (props.rel || "") + ":" + (props.href || props.src || "");
379
400
  for (let i = 0; i < RESOURCE_QUALIFIERS.length; i++) {
380
401
  const q = RESOURCE_QUALIFIERS[i];
381
- if (props[q] != null) id += ":" + q + "=" + props[q];
402
+ const value = props[q];
403
+ if (value != null) id += ":" + q + "=" + (value === true ? "" : value);
382
404
  }
383
405
  return id;
384
406
  }
@@ -440,6 +462,7 @@ function resolveAssets(moduleUrl, manifest) {
440
462
  if (!entry) return null;
441
463
  const css = [];
442
464
  const js = [];
465
+ let preloads;
443
466
  const visited = new Set();
444
467
  const walk = key => {
445
468
  if (visited.has(key)) return;
@@ -448,13 +471,26 @@ function resolveAssets(moduleUrl, manifest) {
448
471
  if (!e) return;
449
472
  js.push(joinAssetPath(base, e.file));
450
473
  if (e.css) for (let i = 0; i < e.css.length; i++) css.push(joinAssetPath(base, e.css[i]));
474
+ if (e.preloads) {
475
+ for (let i = 0; i < e.preloads.length; i++) {
476
+ const link = e.preloads[i];
477
+ if (!link || typeof link.href !== "string" || !link.href) continue;
478
+ if (!preloads) preloads = [];
479
+ preloads.push({
480
+ ...link,
481
+ href: joinAssetPath(base, link.href)
482
+ });
483
+ }
484
+ }
451
485
  if (e.imports) for (let i = 0; i < e.imports.length; i++) walk(e.imports[i]);
452
486
  };
453
487
  walk(moduleUrl);
454
- return {
488
+ const assets = {
455
489
  js,
456
490
  css
457
491
  };
492
+ if (preloads) assets.preloads = preloads;
493
+ return assets;
458
494
  }
459
495
  function registerEntryAssets(manifest) {
460
496
  if (!manifest || typeof manifest === "function" || typeof manifest.resolve === "function") return;
@@ -464,6 +500,7 @@ function registerEntryAssets(manifest) {
464
500
  if (manifest[key].isEntry) {
465
501
  const assets = resolveAssets(key, manifest);
466
502
  if (assets) {
503
+ if (assets.preloads) for (let i = 0; i < assets.preloads.length; i++) ctx.registerAsset("preload", assets.preloads[i]);
467
504
  for (let i = 0; i < assets.css.length; i++) ctx.registerAsset("style", assets.css[i]);
468
505
  for (let i = 1; i < assets.js.length; i++) ctx.registerAsset("module", assets.js[i]);
469
506
  }
@@ -482,6 +519,7 @@ function createAssetTracking() {
482
519
  boundaryStyles,
483
520
  emittedAssets,
484
521
  inlineStyles,
522
+ preloadLinks: null,
485
523
  registerInlineStyle(desc) {
486
524
  let entry = inlineStyles.get(desc.id);
487
525
  if (!entry) {
@@ -573,6 +611,56 @@ function isCssUrl(url) {
573
611
  const q = url.search(/[?#]/);
574
612
  return (q === -1 ? url : url.slice(0, q)).endsWith(".css");
575
613
  }
614
+ const PRELOAD_LINK_ATTRIBUTES = ["type", "crossorigin", "integrity", "referrerpolicy", "fetchpriority", "media"];
615
+ function registerPreloadLink(tracking, headRegistry, link, nonce) {
616
+ if (!link || typeof link !== "object" || typeof link.href !== "string" || !link.href) {
617
+ return null;
618
+ }
619
+ if (typeof link.as !== "string") {
620
+ return null;
621
+ }
622
+ const as = asciiLowerCase(link.as);
623
+ let destination = null;
624
+ switch (as) {
625
+ case "script":
626
+ case "style":
627
+ destination = as;
628
+ break;
629
+ case "fetch":
630
+ case "font":
631
+ case "image":
632
+ case "track":
633
+ break;
634
+ default:
635
+ return null;
636
+ }
637
+ const props = {
638
+ rel: "preload",
639
+ href: link.href,
640
+ as
641
+ };
642
+ for (let i = 0; i < PRELOAD_LINK_ATTRIBUTES.length; i++) {
643
+ const name = PRELOAD_LINK_ATTRIBUTES[i];
644
+ const value = link[name];
645
+ if (value == null || value === false) continue;
646
+ props[name] = value === true ? "" : String(value);
647
+ }
648
+ const identity = resourceIdentity("link", props);
649
+ if (headRegistry.resources.has(identity)) return null;
650
+ const attrs = headAttrRecord(props);
651
+ const nonceValue = destination && nonce && nonce[destination];
652
+ if (typeof nonceValue === "string" && nonceValue) attrs.nonce = nonceValue;
653
+ const entry = {
654
+ href: props.href,
655
+ attrs,
656
+ attrHtml: renderHeadAttrHtml(props) + nonceAttr(nonce, destination)
657
+ };
658
+ headRegistry.resources.add(identity);
659
+ let links = tracking.preloadLinks;
660
+ if (!links) tracking.preloadLinks = links = [];
661
+ links.push(entry);
662
+ return entry;
663
+ }
576
664
  function createHeadRegistry() {
577
665
  return {
578
666
  pending: [],
@@ -1049,6 +1137,10 @@ function renderToString(code, options = {}) {
1049
1137
  serializer.write(id, p);
1050
1138
  },
1051
1139
  registerAsset(type, value) {
1140
+ if (type === "preload") {
1141
+ registerPreloadLink(tracking, headRegistry, value, nonce);
1142
+ return;
1143
+ }
1052
1144
  if (type === "inline-style") {
1053
1145
  tracking.registerInlineStyle(value);
1054
1146
  return;
@@ -1076,7 +1168,7 @@ function renderToString(code, options = {}) {
1076
1168
  solidJs.sharedConfig.context.noHydrate = true;
1077
1169
  serializer.close();
1078
1170
  const head = renderShellHead(headRegistry, nonce, null, noScripts);
1079
- return assembleDocument(resolveSSRSelectValues(html), tracking.emittedAssets, tracking.inlineStyles, scripts.length ? scripts : "", nonce, head, onHead);
1171
+ return assembleDocument(resolveSSRSelectValues(html), tracking.emittedAssets, tracking.preloadLinks, tracking.inlineStyles, scripts.length ? scripts : "", nonce, head, onHead);
1080
1172
  }
1081
1173
  function renderToStream(code, options = {}) {
1082
1174
  let {
@@ -1230,6 +1322,8 @@ function renderToStream(code, options = {}) {
1230
1322
  asset(type, value) {
1231
1323
  if (type === "module") {
1232
1324
  buffer.write(`<link rel="modulepreload" href="${value}"${nonceAttr(nonce, "script")}>`);
1325
+ } else if (type === "preload") {
1326
+ buffer.write(`<link${value.attrHtml}>`);
1233
1327
  } else if (type === "inline-style") {
1234
1328
  buffer.write(renderInlineStyle(value, nonce));
1235
1329
  } else if (type === "head-tag") {
@@ -1237,7 +1331,7 @@ function renderToStream(code, options = {}) {
1237
1331
  }
1238
1332
  },
1239
1333
  shell(shellHtml, meta) {
1240
- buffer.write(assembleDocument(shellHtml, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
1334
+ buffer.write(assembleDocument(shellHtml, meta.preloads, meta.preloadLinks, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
1241
1335
  },
1242
1336
  ...options.sink
1243
1337
  };
@@ -1270,6 +1364,29 @@ function renderToStream(code, options = {}) {
1270
1364
  }
1271
1365
  };
1272
1366
  const registry = new Map();
1367
+ const pendingSerialized = new Map();
1368
+ const trackSerialized = (id, p) => {
1369
+ let settle;
1370
+ const raced = Promise.race([p, new Promise(r => settle = r)]);
1371
+ pendingSerialized.set(id, settle);
1372
+ const drop = () => pendingSerialized.delete(id);
1373
+ p.then(drop, drop);
1374
+ return raced;
1375
+ };
1376
+ const abandonSubtree = key => {
1377
+ for (const [k, entry] of registry) {
1378
+ if (k.length > key.length && k.startsWith(key)) {
1379
+ registry.delete(k);
1380
+ entry.resolve();
1381
+ }
1382
+ }
1383
+ for (const [id, settle] of pendingSerialized) {
1384
+ if (id.startsWith(key)) {
1385
+ pendingSerialized.delete(id);
1386
+ settle();
1387
+ }
1388
+ }
1389
+ };
1273
1390
  const writeTasks = () => {
1274
1391
  if (tasks.length && !completed && firstFlushed) {
1275
1392
  buffer.write(`<script${nonceAttr(nonce, "script")}>${tasks}</script>`);
@@ -1340,6 +1457,11 @@ function renderToStream(code, options = {}) {
1340
1457
  }, nonce, tags);
1341
1458
  },
1342
1459
  registerAsset(type, value) {
1460
+ if (type === "preload") {
1461
+ const entry = registerPreloadLink(tracking, headRegistry, value, nonce);
1462
+ if (entry && firstFlushed) sink.asset("preload", entry);
1463
+ return;
1464
+ }
1343
1465
  if (type === "inline-style") {
1344
1466
  const entry = tracking.registerInlineStyle(value);
1345
1467
  if (firstFlushed && !tracking.currentBoundaryId && !entry.emitted) {
@@ -1384,13 +1506,14 @@ function renderToStream(code, options = {}) {
1384
1506
  },
1385
1507
  serialize(id, p, deferStream) {
1386
1508
  if (solidJs.sharedConfig.context.noHydrate) return;
1387
- if (!firstFlushed && p && typeof p === "object" && "then" in p) {
1388
- if (deferStream) {
1509
+ if (p && typeof p === "object" && typeof p.then === "function") {
1510
+ if (!firstFlushed && deferStream) {
1389
1511
  blockingPromises.add(p);
1390
1512
  p.then(d => serializer.write(id, d)).catch(e => serializer.write(id, e));
1391
1513
  return;
1392
1514
  }
1393
- if (canBatchStubs && !shellCompleted) {
1515
+ p = trackSerialized(id, p);
1516
+ if (!firstFlushed && canBatchStubs && !shellCompleted) {
1394
1517
  (stubBatch ||= new Map()).set(id, p);
1395
1518
  return;
1396
1519
  }
@@ -1435,6 +1558,7 @@ function renderToStream(code, options = {}) {
1435
1558
  if (registry.has(key)) {
1436
1559
  const item = registry.get(key);
1437
1560
  registry.delete(key);
1561
+ if (error) abandonSubtree(key);
1438
1562
  if (item.children) {
1439
1563
  for (const k in item.children) {
1440
1564
  value = replacePlaceholder(value, k, item.children[k]);
@@ -1559,6 +1683,7 @@ function renderToStream(code, options = {}) {
1559
1683
  const head = renderShellHead(headRegistry, nonce, k => registry.has(k), noScripts);
1560
1684
  sink.shell(resolveSSRSelectValues(html), {
1561
1685
  preloads: tracking.emittedAssets,
1686
+ preloadLinks: tracking.preloadLinks,
1562
1687
  inlineStyles: tracking.inlineStyles,
1563
1688
  tasks,
1564
1689
  head
@@ -2705,12 +2830,12 @@ function allSettled(promises) {
2705
2830
  return;
2706
2831
  });
2707
2832
  }
2708
- function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, headTags, onHead) {
2833
+ function assembleDocument(html, emittedAssets, preloadLinks, inlineStyles, scripts, nonce, headTags, onHead) {
2709
2834
  const scriptTag = scripts ? `<script${nonceAttr(nonce, "script")}>${scripts}</script>` : "";
2710
2835
  const title = headTags ? headTags.title : null;
2711
2836
  let headTagsHtml = headTags ? headTags.html : "";
2712
2837
  const headPrelude = headTags ? headTags.prelude : "";
2713
- if (!onHead && title == null && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !(inlineStyles && inlineStyles.size)) {
2838
+ if (!onHead && title == null && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !preloadLinks && !(inlineStyles && inlineStyles.size)) {
2714
2839
  if (!scriptTag) return html;
2715
2840
  const xs = html.indexOf("<!--xs-->");
2716
2841
  return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
@@ -2729,7 +2854,7 @@ function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, hea
2729
2854
  if (title != null) {
2730
2855
  titleHtml = headTags.noScripts ? `<title data-dh="title">${escape(title)}</title>` : `<script${nonceAttr(nonce, "script")}>(function(x,t){(t=document.querySelector("title"))?(t.hasAttribute("data-dh")||t.setAttribute("data-dhf",t.textContent),t.textContent=x):(document.title=x,t=document.querySelector("title"));t&&t.setAttribute("data-dh","title")})(${JSON.stringify(title).replace(/</g, "\\u003C")})</script>`;
2731
2856
  }
2732
- onHead(headPrelude + headTagsHtml + titleHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce));
2857
+ onHead(headPrelude + headTagsHtml + titleHtml + renderHeadAssets(emittedAssets, preloadLinks, inlineStyles, nonce));
2733
2858
  }
2734
2859
  if (!scriptTag) return html;
2735
2860
  const xs = html.indexOf("<!--xs-->");
@@ -2749,13 +2874,13 @@ function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, hea
2749
2874
  headTagsHtml = `<title data-dh="title">${winner}</title>` + headTagsHtml;
2750
2875
  }
2751
2876
  }
2752
- const head = headTagsHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce);
2877
+ const head = headTagsHtml + renderHeadAssets(emittedAssets, preloadLinks, inlineStyles, nonce);
2753
2878
  if (!scriptTag) return html.slice(0, headIdx) + head + html.slice(headIdx);
2754
2879
  const xsIdx = html.indexOf("<!--xs-->");
2755
2880
  if (xsIdx === -1) return html.slice(0, headIdx) + head + html.slice(headIdx) + scriptTag;
2756
2881
  return xsIdx < headIdx ? html.slice(0, xsIdx) + scriptTag + html.slice(xsIdx, headIdx) + head + html.slice(headIdx) : html.slice(0, headIdx) + head + html.slice(headIdx, xsIdx) + scriptTag + html.slice(xsIdx);
2757
2882
  }
2758
- function renderHeadAssets(emittedAssets, inlineStyles, nonce) {
2883
+ function renderHeadAssets(emittedAssets, preloadLinks, inlineStyles, nonce) {
2759
2884
  let head = "";
2760
2885
  const styleAttr = nonceAttr(nonce, "style");
2761
2886
  const scriptAttr = nonceAttr(nonce, "script");
@@ -2764,6 +2889,9 @@ function renderHeadAssets(emittedAssets, inlineStyles, nonce) {
2764
2889
  head += isCssUrl(url) ? `<link rel="stylesheet" href="${url}"${styleAttr}>` : `<link rel="modulepreload" href="${url}"${scriptAttr}>`;
2765
2890
  }
2766
2891
  }
2892
+ if (preloadLinks) {
2893
+ for (const entry of preloadLinks) head += `<link${entry.attrHtml}>`;
2894
+ }
2767
2895
  if (inlineStyles && inlineStyles.size) {
2768
2896
  for (const entry of inlineStyles.values()) {
2769
2897
  if (entry.emitted) continue;
@@ -3028,7 +3156,7 @@ function copyInitHeaders(init) {
3028
3156
  for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
3029
3157
  return headers;
3030
3158
  }
3031
- const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, "Location"].map(header => header.toLowerCase()));
3159
+ const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, REDIRECT_HEADER, "Location"].map(header => header.toLowerCase()));
3032
3160
  function fillsStubGap(key, headers, response) {
3033
3161
  if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
3034
3162
  if (response.body === null && (key === "content-type" || key === "content-length")) return false;
@@ -3044,24 +3172,16 @@ function commitEventResponse(response, event = getRequestEvent()) {
3044
3172
  if (fillsStubGap(key, response.headers, response)) hasGaps = true;
3045
3173
  });
3046
3174
  if (!cookies.length && !hasGaps) return response;
3047
- try {
3048
- for (const cookie of cookies) response.headers.append("Set-Cookie", cookie);
3049
- stub.headers.forEach((value, key) => {
3050
- if (fillsStubGap(key, response.headers, response)) response.headers.set(key, value);
3051
- });
3052
- return response;
3053
- } catch {
3054
- const headers = copyInitHeaders(response.headers);
3055
- for (const cookie of cookies) headers.append("Set-Cookie", cookie);
3056
- stub.headers.forEach((value, key) => {
3057
- if (fillsStubGap(key, headers, response)) headers.set(key, value);
3058
- });
3059
- return new Response(response.body, {
3060
- status: response.status,
3061
- statusText: response.statusText,
3062
- headers
3063
- });
3064
- }
3175
+ const headers = copyInitHeaders(response.headers);
3176
+ for (const cookie of cookies) headers.append("Set-Cookie", cookie);
3177
+ stub.headers.forEach((value, key) => {
3178
+ if (fillsStubGap(key, headers, response)) headers.set(key, value);
3179
+ });
3180
+ return new Response(response.body, {
3181
+ status: response.status,
3182
+ statusText: response.statusText,
3183
+ headers
3184
+ });
3065
3185
  }
3066
3186
  function deriveHead(stub, responseInit = {}) {
3067
3187
  const headers = mergeStubHeaders(copyInitHeaders(responseInit.headers), stub);
@@ -3227,6 +3347,11 @@ function registerClientOnlyPreload(moduleUrl) {
3227
3347
  const css = assets.css[i];
3228
3348
  if (typeof css === "string") registerAsset("style", css);else registerAsset("inline-style", css);
3229
3349
  }
3350
+ if (assets.preloads) {
3351
+ for (let i = 0; i < assets.preloads.length; i++) {
3352
+ registerAsset("preload", assets.preloads[i]);
3353
+ }
3354
+ }
3230
3355
  for (let i = 0; i < assets.js.length; i++) registerAsset("module", assets.js[i]);
3231
3356
  };
3232
3357
  const assets = resolve(moduleUrl);
@@ -3405,8 +3530,10 @@ exports.Dynamic = Dynamic;
3405
3530
  exports.HREF = HREF;
3406
3531
  exports.HydrationScript = HydrationScript;
3407
3532
  exports.MathMLElements = MathMLElements;
3533
+ exports.NULL_BODY_STATUSES = NULL_BODY_STATUSES;
3408
3534
  exports.Namespaces = Namespaces;
3409
3535
  exports.Portal = Portal;
3536
+ exports.RESPONSE_HEADER_VALUE_LIMIT = RESPONSE_HEADER_VALUE_LIMIT;
3410
3537
  exports.REVALIDATE_HEADER = REVALIDATE_HEADER;
3411
3538
  exports.RawTextElements = RawTextElements;
3412
3539
  exports.RequestContext = RequestContext;