@solidjs/web 2.0.0-rc.3 → 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 (65) hide show
  1. package/dist/dev.cjs +398 -17
  2. package/dist/dev.js +396 -19
  3. package/dist/server.cjs +166 -38
  4. package/dist/server.js +165 -39
  5. package/dist/web.cjs +369 -17
  6. package/dist/web.js +367 -19
  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 +271 -47
  25. package/server-functions/dist/client.js +264 -47
  26. package/server-functions/dist/server.cjs +872 -131
  27. package/server-functions/dist/server.dev.cjs +892 -131
  28. package/server-functions/dist/server.dev.js +884 -131
  29. package/server-functions/dist/server.js +864 -131
  30. package/types/client.d.ts +4 -2
  31. package/types/cookies.d.ts +6 -14
  32. package/types/frames/frame-client.d.ts +4 -0
  33. package/types/frames/serializer-decode.d.ts +14 -1
  34. package/types/frames/serializer.d.ts +7 -0
  35. package/types/index.d.ts +1 -0
  36. package/types/jsx.d.ts +11 -16
  37. package/types/patch-driver.d.ts +3 -0
  38. package/types/response.d.ts +20 -1
  39. package/types/serializer-decode.d.ts +14 -1
  40. package/types/serializer.d.ts +7 -0
  41. package/types/server-functions/client.d.ts +58 -7
  42. package/types/server-functions/flash.d.ts +9 -0
  43. package/types/server-functions/registry.d.ts +38 -1
  44. package/types/server-functions/server.d.ts +66 -14
  45. package/types/server-functions/shared.d.ts +122 -16
  46. package/types/server-mock.d.ts +17 -2
  47. package/types/server.d.ts +16 -2
  48. package/types-cjs/client.d.cts +4 -2
  49. package/types-cjs/cookies.d.cts +6 -14
  50. package/types-cjs/frames/frame-client.d.cts +4 -0
  51. package/types-cjs/frames/serializer-decode.d.cts +14 -1
  52. package/types-cjs/frames/serializer.d.cts +7 -0
  53. package/types-cjs/index.d.cts +1 -0
  54. package/types-cjs/jsx.d.cts +11 -16
  55. package/types-cjs/patch-driver.d.cts +3 -0
  56. package/types-cjs/response.d.cts +20 -1
  57. package/types-cjs/serializer-decode.d.cts +14 -1
  58. package/types-cjs/serializer.d.cts +7 -0
  59. package/types-cjs/server-functions/client.d.cts +58 -7
  60. package/types-cjs/server-functions/flash.d.cts +9 -0
  61. package/types-cjs/server-functions/registry.d.cts +38 -1
  62. package/types-cjs/server-functions/server.d.cts +66 -14
  63. package/types-cjs/server-functions/shared.d.cts +122 -16
  64. package/types-cjs/server-mock.d.cts +17 -2
  65. 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
@@ -251,7 +258,13 @@ function redirect(url, init = 302) {
251
258
  if (responseInit.status === undefined) {
252
259
  responseInit.status = 302;
253
260
  }
254
- headers.set("Location", String(url));
261
+ const target = typeof url === "string" ? url : url[HREF];
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);
255
268
  return new Response(null, {
256
269
  ...responseInit,
257
270
  headers
@@ -267,11 +280,18 @@ function reload(init = {}) {
267
280
  headers
268
281
  });
269
282
  }
283
+ const NULL_BODY_STATUSES = new Set([204, 205, 304]);
270
284
  function respond(value, init = {}) {
271
285
  const {
272
286
  responseInit,
273
287
  headers
274
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
+ }
275
295
  headers.set("Content-Type", "application/json");
276
296
  return new ResponseEnvelope(new Response(JSON.stringify(value), {
277
297
  ...responseInit,
@@ -322,6 +342,7 @@ function serializeCookie(name, value, options = {}) {
322
342
  if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
323
343
  if (options.httpOnly) cookie += "; HttpOnly";
324
344
  if (options.secure) cookie += "; Secure";
345
+ if (options.partitioned) cookie += "; Partitioned";
325
346
  if (options.sameSite) {
326
347
  const sameSite = options.sameSite.toLowerCase();
327
348
  cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
@@ -339,6 +360,7 @@ function clearFlashCookie() {
339
360
 
340
361
  const ERROR_HEADER = "X-Server-Function-Error";
341
362
  const BODY_FORMAT_HEADER = "X-Server-Function-Format";
363
+ const REDIRECT_HEADER = "X-Server-Function-Redirect";
342
364
  const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
343
365
 
344
366
  const HEAD_ELIGIBLE_TAGS = new Set(["title", "meta", "link", "style", "script", "base"]);
@@ -377,7 +399,8 @@ function resourceIdentity(tag, props) {
377
399
  let id = "res:" + tag + ":" + (props.rel || "") + ":" + (props.href || props.src || "");
378
400
  for (let i = 0; i < RESOURCE_QUALIFIERS.length; i++) {
379
401
  const q = RESOURCE_QUALIFIERS[i];
380
- if (props[q] != null) id += ":" + q + "=" + props[q];
402
+ const value = props[q];
403
+ if (value != null) id += ":" + q + "=" + (value === true ? "" : value);
381
404
  }
382
405
  return id;
383
406
  }
@@ -439,6 +462,7 @@ function resolveAssets(moduleUrl, manifest) {
439
462
  if (!entry) return null;
440
463
  const css = [];
441
464
  const js = [];
465
+ let preloads;
442
466
  const visited = new Set();
443
467
  const walk = key => {
444
468
  if (visited.has(key)) return;
@@ -447,13 +471,26 @@ function resolveAssets(moduleUrl, manifest) {
447
471
  if (!e) return;
448
472
  js.push(joinAssetPath(base, e.file));
449
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
+ }
450
485
  if (e.imports) for (let i = 0; i < e.imports.length; i++) walk(e.imports[i]);
451
486
  };
452
487
  walk(moduleUrl);
453
- return {
488
+ const assets = {
454
489
  js,
455
490
  css
456
491
  };
492
+ if (preloads) assets.preloads = preloads;
493
+ return assets;
457
494
  }
458
495
  function registerEntryAssets(manifest) {
459
496
  if (!manifest || typeof manifest === "function" || typeof manifest.resolve === "function") return;
@@ -463,6 +500,7 @@ function registerEntryAssets(manifest) {
463
500
  if (manifest[key].isEntry) {
464
501
  const assets = resolveAssets(key, manifest);
465
502
  if (assets) {
503
+ if (assets.preloads) for (let i = 0; i < assets.preloads.length; i++) ctx.registerAsset("preload", assets.preloads[i]);
466
504
  for (let i = 0; i < assets.css.length; i++) ctx.registerAsset("style", assets.css[i]);
467
505
  for (let i = 1; i < assets.js.length; i++) ctx.registerAsset("module", assets.js[i]);
468
506
  }
@@ -481,6 +519,7 @@ function createAssetTracking() {
481
519
  boundaryStyles,
482
520
  emittedAssets,
483
521
  inlineStyles,
522
+ preloadLinks: null,
484
523
  registerInlineStyle(desc) {
485
524
  let entry = inlineStyles.get(desc.id);
486
525
  if (!entry) {
@@ -572,6 +611,56 @@ function isCssUrl(url) {
572
611
  const q = url.search(/[?#]/);
573
612
  return (q === -1 ? url : url.slice(0, q)).endsWith(".css");
574
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
+ }
575
664
  function createHeadRegistry() {
576
665
  return {
577
666
  pending: [],
@@ -1048,6 +1137,10 @@ function renderToString(code, options = {}) {
1048
1137
  serializer.write(id, p);
1049
1138
  },
1050
1139
  registerAsset(type, value) {
1140
+ if (type === "preload") {
1141
+ registerPreloadLink(tracking, headRegistry, value, nonce);
1142
+ return;
1143
+ }
1051
1144
  if (type === "inline-style") {
1052
1145
  tracking.registerInlineStyle(value);
1053
1146
  return;
@@ -1075,7 +1168,7 @@ function renderToString(code, options = {}) {
1075
1168
  solidJs.sharedConfig.context.noHydrate = true;
1076
1169
  serializer.close();
1077
1170
  const head = renderShellHead(headRegistry, nonce, null, noScripts);
1078
- 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);
1079
1172
  }
1080
1173
  function renderToStream(code, options = {}) {
1081
1174
  let {
@@ -1229,6 +1322,8 @@ function renderToStream(code, options = {}) {
1229
1322
  asset(type, value) {
1230
1323
  if (type === "module") {
1231
1324
  buffer.write(`<link rel="modulepreload" href="${value}"${nonceAttr(nonce, "script")}>`);
1325
+ } else if (type === "preload") {
1326
+ buffer.write(`<link${value.attrHtml}>`);
1232
1327
  } else if (type === "inline-style") {
1233
1328
  buffer.write(renderInlineStyle(value, nonce));
1234
1329
  } else if (type === "head-tag") {
@@ -1236,7 +1331,7 @@ function renderToStream(code, options = {}) {
1236
1331
  }
1237
1332
  },
1238
1333
  shell(shellHtml, meta) {
1239
- 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));
1240
1335
  },
1241
1336
  ...options.sink
1242
1337
  };
@@ -1269,6 +1364,29 @@ function renderToStream(code, options = {}) {
1269
1364
  }
1270
1365
  };
1271
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
+ };
1272
1390
  const writeTasks = () => {
1273
1391
  if (tasks.length && !completed && firstFlushed) {
1274
1392
  buffer.write(`<script${nonceAttr(nonce, "script")}>${tasks}</script>`);
@@ -1339,6 +1457,11 @@ function renderToStream(code, options = {}) {
1339
1457
  }, nonce, tags);
1340
1458
  },
1341
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
+ }
1342
1465
  if (type === "inline-style") {
1343
1466
  const entry = tracking.registerInlineStyle(value);
1344
1467
  if (firstFlushed && !tracking.currentBoundaryId && !entry.emitted) {
@@ -1383,13 +1506,14 @@ function renderToStream(code, options = {}) {
1383
1506
  },
1384
1507
  serialize(id, p, deferStream) {
1385
1508
  if (solidJs.sharedConfig.context.noHydrate) return;
1386
- if (!firstFlushed && p && typeof p === "object" && "then" in p) {
1387
- if (deferStream) {
1509
+ if (p && typeof p === "object" && typeof p.then === "function") {
1510
+ if (!firstFlushed && deferStream) {
1388
1511
  blockingPromises.add(p);
1389
1512
  p.then(d => serializer.write(id, d)).catch(e => serializer.write(id, e));
1390
1513
  return;
1391
1514
  }
1392
- if (canBatchStubs && !shellCompleted) {
1515
+ p = trackSerialized(id, p);
1516
+ if (!firstFlushed && canBatchStubs && !shellCompleted) {
1393
1517
  (stubBatch ||= new Map()).set(id, p);
1394
1518
  return;
1395
1519
  }
@@ -1434,6 +1558,7 @@ function renderToStream(code, options = {}) {
1434
1558
  if (registry.has(key)) {
1435
1559
  const item = registry.get(key);
1436
1560
  registry.delete(key);
1561
+ if (error) abandonSubtree(key);
1437
1562
  if (item.children) {
1438
1563
  for (const k in item.children) {
1439
1564
  value = replacePlaceholder(value, k, item.children[k]);
@@ -1558,6 +1683,7 @@ function renderToStream(code, options = {}) {
1558
1683
  const head = renderShellHead(headRegistry, nonce, k => registry.has(k), noScripts);
1559
1684
  sink.shell(resolveSSRSelectValues(html), {
1560
1685
  preloads: tracking.emittedAssets,
1686
+ preloadLinks: tracking.preloadLinks,
1561
1687
  inlineStyles: tracking.inlineStyles,
1562
1688
  tasks,
1563
1689
  head
@@ -2479,7 +2605,7 @@ function ssrClaim(map) {
2479
2605
  function decodeSSREntities(s) {
2480
2606
  return s.indexOf("&") < 0 ? s : s.replace(/&quot;/g, '"').replace(/&lt;/g, "<").replace(/&amp;/g, "&");
2481
2607
  }
2482
- const SELECT_VALUE_ATTR = /\svalue="([^"]*)"/;
2608
+ const SELECT_VALUE_ATTR = /\svalue(?:="([^"]*)")?(?=[\s>]|$)/;
2483
2609
  function tagEnd(html, i) {
2484
2610
  for (let j = i + 1; j < html.length; j++) {
2485
2611
  const c = html.charCodeAt(j);
@@ -2531,7 +2657,7 @@ function resolveSSRSelectValues(html) {
2531
2657
  cand = html.indexOf("<select", e0 + 1);
2532
2658
  continue;
2533
2659
  }
2534
- const bound = decodeSSREntities(m[1]);
2660
+ const bound = decodeSSREntities(m[1] ?? "");
2535
2661
  const sel = {
2536
2662
  values: /\smultiple(?=[\s>=])/.test(open) ? bound.split(",") : [bound],
2537
2663
  strip: cand + m.index,
@@ -2568,7 +2694,7 @@ function resolveSSRSelectValues(html) {
2568
2694
  const attrs = html.slice(i + 7, e);
2569
2695
  if (/\sselected(?=[\s=]|$)/.test(attrs)) sel.defaulted = true;else {
2570
2696
  const vm = SELECT_VALUE_ATTR.exec(attrs);
2571
- const value = vm ? decodeSSREntities(vm[1]) : decodeSSREntities(optionText(html, e + 1)).replace(/\s+/g, " ").trim();
2697
+ const value = vm ? decodeSSREntities(vm[1] ?? "") : decodeSSREntities(optionText(html, e + 1)).replace(/\s+/g, " ").trim();
2572
2698
  if (sel.values.includes(value)) sel.marks.push(e);
2573
2699
  }
2574
2700
  }
@@ -2704,12 +2830,12 @@ function allSettled(promises) {
2704
2830
  return;
2705
2831
  });
2706
2832
  }
2707
- function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, headTags, onHead) {
2833
+ function assembleDocument(html, emittedAssets, preloadLinks, inlineStyles, scripts, nonce, headTags, onHead) {
2708
2834
  const scriptTag = scripts ? `<script${nonceAttr(nonce, "script")}>${scripts}</script>` : "";
2709
2835
  const title = headTags ? headTags.title : null;
2710
2836
  let headTagsHtml = headTags ? headTags.html : "";
2711
2837
  const headPrelude = headTags ? headTags.prelude : "";
2712
- 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)) {
2713
2839
  if (!scriptTag) return html;
2714
2840
  const xs = html.indexOf("<!--xs-->");
2715
2841
  return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
@@ -2728,7 +2854,7 @@ function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, hea
2728
2854
  if (title != null) {
2729
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>`;
2730
2856
  }
2731
- onHead(headPrelude + headTagsHtml + titleHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce));
2857
+ onHead(headPrelude + headTagsHtml + titleHtml + renderHeadAssets(emittedAssets, preloadLinks, inlineStyles, nonce));
2732
2858
  }
2733
2859
  if (!scriptTag) return html;
2734
2860
  const xs = html.indexOf("<!--xs-->");
@@ -2748,13 +2874,13 @@ function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, hea
2748
2874
  headTagsHtml = `<title data-dh="title">${winner}</title>` + headTagsHtml;
2749
2875
  }
2750
2876
  }
2751
- const head = headTagsHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce);
2877
+ const head = headTagsHtml + renderHeadAssets(emittedAssets, preloadLinks, inlineStyles, nonce);
2752
2878
  if (!scriptTag) return html.slice(0, headIdx) + head + html.slice(headIdx);
2753
2879
  const xsIdx = html.indexOf("<!--xs-->");
2754
2880
  if (xsIdx === -1) return html.slice(0, headIdx) + head + html.slice(headIdx) + scriptTag;
2755
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);
2756
2882
  }
2757
- function renderHeadAssets(emittedAssets, inlineStyles, nonce) {
2883
+ function renderHeadAssets(emittedAssets, preloadLinks, inlineStyles, nonce) {
2758
2884
  let head = "";
2759
2885
  const styleAttr = nonceAttr(nonce, "style");
2760
2886
  const scriptAttr = nonceAttr(nonce, "script");
@@ -2763,6 +2889,9 @@ function renderHeadAssets(emittedAssets, inlineStyles, nonce) {
2763
2889
  head += isCssUrl(url) ? `<link rel="stylesheet" href="${url}"${styleAttr}>` : `<link rel="modulepreload" href="${url}"${scriptAttr}>`;
2764
2890
  }
2765
2891
  }
2892
+ if (preloadLinks) {
2893
+ for (const entry of preloadLinks) head += `<link${entry.attrHtml}>`;
2894
+ }
2766
2895
  if (inlineStyles && inlineStyles.size) {
2767
2896
  for (const entry of inlineStyles.values()) {
2768
2897
  if (entry.emitted) continue;
@@ -3027,7 +3156,7 @@ function copyInitHeaders(init) {
3027
3156
  for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
3028
3157
  return headers;
3029
3158
  }
3030
- 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()));
3031
3160
  function fillsStubGap(key, headers, response) {
3032
3161
  if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
3033
3162
  if (response.body === null && (key === "content-type" || key === "content-length")) return false;
@@ -3043,24 +3172,16 @@ function commitEventResponse(response, event = getRequestEvent()) {
3043
3172
  if (fillsStubGap(key, response.headers, response)) hasGaps = true;
3044
3173
  });
3045
3174
  if (!cookies.length && !hasGaps) return response;
3046
- try {
3047
- for (const cookie of cookies) response.headers.append("Set-Cookie", cookie);
3048
- stub.headers.forEach((value, key) => {
3049
- if (fillsStubGap(key, response.headers, response)) response.headers.set(key, value);
3050
- });
3051
- return response;
3052
- } catch {
3053
- const headers = copyInitHeaders(response.headers);
3054
- for (const cookie of cookies) headers.append("Set-Cookie", cookie);
3055
- stub.headers.forEach((value, key) => {
3056
- if (fillsStubGap(key, headers, response)) headers.set(key, value);
3057
- });
3058
- return new Response(response.body, {
3059
- status: response.status,
3060
- statusText: response.statusText,
3061
- headers
3062
- });
3063
- }
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
+ });
3064
3185
  }
3065
3186
  function deriveHead(stub, responseInit = {}) {
3066
3187
  const headers = mergeStubHeaders(copyInitHeaders(responseInit.headers), stub);
@@ -3226,6 +3347,11 @@ function registerClientOnlyPreload(moduleUrl) {
3226
3347
  const css = assets.css[i];
3227
3348
  if (typeof css === "string") registerAsset("style", css);else registerAsset("inline-style", css);
3228
3349
  }
3350
+ if (assets.preloads) {
3351
+ for (let i = 0; i < assets.preloads.length; i++) {
3352
+ registerAsset("preload", assets.preloads[i]);
3353
+ }
3354
+ }
3229
3355
  for (let i = 0; i < assets.js.length; i++) registerAsset("module", assets.js[i]);
3230
3356
  };
3231
3357
  const assets = resolve(moduleUrl);
@@ -3404,8 +3530,10 @@ exports.Dynamic = Dynamic;
3404
3530
  exports.HREF = HREF;
3405
3531
  exports.HydrationScript = HydrationScript;
3406
3532
  exports.MathMLElements = MathMLElements;
3533
+ exports.NULL_BODY_STATUSES = NULL_BODY_STATUSES;
3407
3534
  exports.Namespaces = Namespaces;
3408
3535
  exports.Portal = Portal;
3536
+ exports.RESPONSE_HEADER_VALUE_LIMIT = RESPONSE_HEADER_VALUE_LIMIT;
3409
3537
  exports.REVALIDATE_HEADER = REVALIDATE_HEADER;
3410
3538
  exports.RawTextElements = RawTextElements;
3411
3539
  exports.RequestContext = RequestContext;