@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.js CHANGED
@@ -150,13 +150,13 @@ function resolveSerializerPlugins(customPlugins) {
150
150
  Feature.RegExp;
151
151
 
152
152
  const DEFAULT_DISABLED_FEATURES = Feature.AggregateError | Feature.BigIntTypedArray;
153
- const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : Feature.ErrorPrototypeStack;
153
+ const serializeOnlyDisabledFeatures = serializeErrorStacks => (serializeErrorStacks === undefined ? process.env.NODE_ENV === "development" : serializeErrorStacks) ? 0 : Feature.ErrorPrototypeStack;
154
154
  const HYDRATION_GLOBAL = "_$HY.r";
155
155
  function createSerializer(options) {
156
156
  return new Serializer({
157
157
  ...options,
158
158
  plugins: resolveSerializerPlugins(options.plugins),
159
- disabledFeatures: (options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures) | serializeOnlyDisabledFeatures()
159
+ disabledFeatures: (options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures) | serializeOnlyDisabledFeatures(options.serializeErrorStacks)
160
160
  });
161
161
  }
162
162
  function createHydrationSerializer({
@@ -213,6 +213,7 @@ function isSafeError(value) {
213
213
  return !!(value && (typeof value === "object" || typeof value === "function") && value[SAFE_ERROR]);
214
214
  }
215
215
  const REVALIDATE_HEADER = "X-Revalidate";
216
+ const RESPONSE_HEADER_VALUE_LIMIT = 4096;
216
217
  function initWithRevalidate(init = {}) {
217
218
  const resolved = typeof init === "number" ? {
218
219
  status: init
@@ -233,7 +234,13 @@ function initWithRevalidate(init = {}) {
233
234
  } else {
234
235
  headers = new Headers(responseInit.headers);
235
236
  }
236
- revalidate !== undefined && headers.set(REVALIDATE_HEADER, revalidate.toString());
237
+ if (revalidate !== undefined) {
238
+ const keys = revalidate.toString();
239
+ if (keys.length > RESPONSE_HEADER_VALUE_LIMIT) {
240
+ 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.`);
241
+ }
242
+ headers.set(REVALIDATE_HEADER, keys);
243
+ }
237
244
  return {
238
245
  responseInit,
239
246
  headers
@@ -250,7 +257,13 @@ function redirect(url, init = 302) {
250
257
  if (responseInit.status === undefined) {
251
258
  responseInit.status = 302;
252
259
  }
253
- headers.set("Location", String(url));
260
+ const target = typeof url === "string" ? url : url[HREF];
261
+ const location = typeof target === "string" ? target : String(url);
262
+ const encoded = location.replace(/[^\x00-\x7f]/gu, encodeURIComponent);
263
+ if (encoded.length > RESPONSE_HEADER_VALUE_LIMIT) {
264
+ 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.`);
265
+ }
266
+ headers.set("Location", encoded);
254
267
  return new Response(null, {
255
268
  ...responseInit,
256
269
  headers
@@ -266,11 +279,18 @@ function reload(init = {}) {
266
279
  headers
267
280
  });
268
281
  }
282
+ const NULL_BODY_STATUSES = new Set([204, 205, 304]);
269
283
  function respond(value, init = {}) {
270
284
  const {
271
285
  responseInit,
272
286
  headers
273
287
  } = initWithRevalidate(init);
288
+ if (NULL_BODY_STATUSES.has(responseInit.status)) {
289
+ return new ResponseEnvelope(new Response(null, {
290
+ ...responseInit,
291
+ headers
292
+ }), value);
293
+ }
274
294
  headers.set("Content-Type", "application/json");
275
295
  return new ResponseEnvelope(new Response(JSON.stringify(value), {
276
296
  ...responseInit,
@@ -321,6 +341,7 @@ function serializeCookie(name, value, options = {}) {
321
341
  if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
322
342
  if (options.httpOnly) cookie += "; HttpOnly";
323
343
  if (options.secure) cookie += "; Secure";
344
+ if (options.partitioned) cookie += "; Partitioned";
324
345
  if (options.sameSite) {
325
346
  const sameSite = options.sameSite.toLowerCase();
326
347
  cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
@@ -338,6 +359,7 @@ function clearFlashCookie() {
338
359
 
339
360
  const ERROR_HEADER = "X-Server-Function-Error";
340
361
  const BODY_FORMAT_HEADER = "X-Server-Function-Format";
362
+ const REDIRECT_HEADER = "X-Server-Function-Redirect";
341
363
  const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
342
364
 
343
365
  const HEAD_ELIGIBLE_TAGS = new Set(["title", "meta", "link", "style", "script", "base"]);
@@ -376,7 +398,8 @@ function resourceIdentity(tag, props) {
376
398
  let id = "res:" + tag + ":" + (props.rel || "") + ":" + (props.href || props.src || "");
377
399
  for (let i = 0; i < RESOURCE_QUALIFIERS.length; i++) {
378
400
  const q = RESOURCE_QUALIFIERS[i];
379
- if (props[q] != null) id += ":" + q + "=" + props[q];
401
+ const value = props[q];
402
+ if (value != null) id += ":" + q + "=" + (value === true ? "" : value);
380
403
  }
381
404
  return id;
382
405
  }
@@ -438,6 +461,7 @@ function resolveAssets(moduleUrl, manifest) {
438
461
  if (!entry) return null;
439
462
  const css = [];
440
463
  const js = [];
464
+ let preloads;
441
465
  const visited = new Set();
442
466
  const walk = key => {
443
467
  if (visited.has(key)) return;
@@ -446,13 +470,26 @@ function resolveAssets(moduleUrl, manifest) {
446
470
  if (!e) return;
447
471
  js.push(joinAssetPath(base, e.file));
448
472
  if (e.css) for (let i = 0; i < e.css.length; i++) css.push(joinAssetPath(base, e.css[i]));
473
+ if (e.preloads) {
474
+ for (let i = 0; i < e.preloads.length; i++) {
475
+ const link = e.preloads[i];
476
+ if (!link || typeof link.href !== "string" || !link.href) continue;
477
+ if (!preloads) preloads = [];
478
+ preloads.push({
479
+ ...link,
480
+ href: joinAssetPath(base, link.href)
481
+ });
482
+ }
483
+ }
449
484
  if (e.imports) for (let i = 0; i < e.imports.length; i++) walk(e.imports[i]);
450
485
  };
451
486
  walk(moduleUrl);
452
- return {
487
+ const assets = {
453
488
  js,
454
489
  css
455
490
  };
491
+ if (preloads) assets.preloads = preloads;
492
+ return assets;
456
493
  }
457
494
  function registerEntryAssets(manifest) {
458
495
  if (!manifest || typeof manifest === "function" || typeof manifest.resolve === "function") return;
@@ -462,6 +499,7 @@ function registerEntryAssets(manifest) {
462
499
  if (manifest[key].isEntry) {
463
500
  const assets = resolveAssets(key, manifest);
464
501
  if (assets) {
502
+ if (assets.preloads) for (let i = 0; i < assets.preloads.length; i++) ctx.registerAsset("preload", assets.preloads[i]);
465
503
  for (let i = 0; i < assets.css.length; i++) ctx.registerAsset("style", assets.css[i]);
466
504
  for (let i = 1; i < assets.js.length; i++) ctx.registerAsset("module", assets.js[i]);
467
505
  }
@@ -480,6 +518,7 @@ function createAssetTracking() {
480
518
  boundaryStyles,
481
519
  emittedAssets,
482
520
  inlineStyles,
521
+ preloadLinks: null,
483
522
  registerInlineStyle(desc) {
484
523
  let entry = inlineStyles.get(desc.id);
485
524
  if (!entry) {
@@ -571,6 +610,56 @@ function isCssUrl(url) {
571
610
  const q = url.search(/[?#]/);
572
611
  return (q === -1 ? url : url.slice(0, q)).endsWith(".css");
573
612
  }
613
+ const PRELOAD_LINK_ATTRIBUTES = ["type", "crossorigin", "integrity", "referrerpolicy", "fetchpriority", "media"];
614
+ function registerPreloadLink(tracking, headRegistry, link, nonce) {
615
+ if (!link || typeof link !== "object" || typeof link.href !== "string" || !link.href) {
616
+ return null;
617
+ }
618
+ if (typeof link.as !== "string") {
619
+ return null;
620
+ }
621
+ const as = asciiLowerCase(link.as);
622
+ let destination = null;
623
+ switch (as) {
624
+ case "script":
625
+ case "style":
626
+ destination = as;
627
+ break;
628
+ case "fetch":
629
+ case "font":
630
+ case "image":
631
+ case "track":
632
+ break;
633
+ default:
634
+ return null;
635
+ }
636
+ const props = {
637
+ rel: "preload",
638
+ href: link.href,
639
+ as
640
+ };
641
+ for (let i = 0; i < PRELOAD_LINK_ATTRIBUTES.length; i++) {
642
+ const name = PRELOAD_LINK_ATTRIBUTES[i];
643
+ const value = link[name];
644
+ if (value == null || value === false) continue;
645
+ props[name] = value === true ? "" : String(value);
646
+ }
647
+ const identity = resourceIdentity("link", props);
648
+ if (headRegistry.resources.has(identity)) return null;
649
+ const attrs = headAttrRecord(props);
650
+ const nonceValue = destination && nonce && nonce[destination];
651
+ if (typeof nonceValue === "string" && nonceValue) attrs.nonce = nonceValue;
652
+ const entry = {
653
+ href: props.href,
654
+ attrs,
655
+ attrHtml: renderHeadAttrHtml(props) + nonceAttr(nonce, destination)
656
+ };
657
+ headRegistry.resources.add(identity);
658
+ let links = tracking.preloadLinks;
659
+ if (!links) tracking.preloadLinks = links = [];
660
+ links.push(entry);
661
+ return entry;
662
+ }
574
663
  function createHeadRegistry() {
575
664
  return {
576
665
  pending: [],
@@ -1047,6 +1136,10 @@ function renderToString(code, options = {}) {
1047
1136
  serializer.write(id, p);
1048
1137
  },
1049
1138
  registerAsset(type, value) {
1139
+ if (type === "preload") {
1140
+ registerPreloadLink(tracking, headRegistry, value, nonce);
1141
+ return;
1142
+ }
1050
1143
  if (type === "inline-style") {
1051
1144
  tracking.registerInlineStyle(value);
1052
1145
  return;
@@ -1074,7 +1167,7 @@ function renderToString(code, options = {}) {
1074
1167
  sharedConfig.context.noHydrate = true;
1075
1168
  serializer.close();
1076
1169
  const head = renderShellHead(headRegistry, nonce, null, noScripts);
1077
- return assembleDocument(resolveSSRSelectValues(html), tracking.emittedAssets, tracking.inlineStyles, scripts.length ? scripts : "", nonce, head, onHead);
1170
+ return assembleDocument(resolveSSRSelectValues(html), tracking.emittedAssets, tracking.preloadLinks, tracking.inlineStyles, scripts.length ? scripts : "", nonce, head, onHead);
1078
1171
  }
1079
1172
  function renderToStream(code, options = {}) {
1080
1173
  let {
@@ -1228,6 +1321,8 @@ function renderToStream(code, options = {}) {
1228
1321
  asset(type, value) {
1229
1322
  if (type === "module") {
1230
1323
  buffer.write(`<link rel="modulepreload" href="${value}"${nonceAttr(nonce, "script")}>`);
1324
+ } else if (type === "preload") {
1325
+ buffer.write(`<link${value.attrHtml}>`);
1231
1326
  } else if (type === "inline-style") {
1232
1327
  buffer.write(renderInlineStyle(value, nonce));
1233
1328
  } else if (type === "head-tag") {
@@ -1235,7 +1330,7 @@ function renderToStream(code, options = {}) {
1235
1330
  }
1236
1331
  },
1237
1332
  shell(shellHtml, meta) {
1238
- buffer.write(assembleDocument(shellHtml, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
1333
+ buffer.write(assembleDocument(shellHtml, meta.preloads, meta.preloadLinks, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
1239
1334
  },
1240
1335
  ...options.sink
1241
1336
  };
@@ -1268,6 +1363,29 @@ function renderToStream(code, options = {}) {
1268
1363
  }
1269
1364
  };
1270
1365
  const registry = new Map();
1366
+ const pendingSerialized = new Map();
1367
+ const trackSerialized = (id, p) => {
1368
+ let settle;
1369
+ const raced = Promise.race([p, new Promise(r => settle = r)]);
1370
+ pendingSerialized.set(id, settle);
1371
+ const drop = () => pendingSerialized.delete(id);
1372
+ p.then(drop, drop);
1373
+ return raced;
1374
+ };
1375
+ const abandonSubtree = key => {
1376
+ for (const [k, entry] of registry) {
1377
+ if (k.length > key.length && k.startsWith(key)) {
1378
+ registry.delete(k);
1379
+ entry.resolve();
1380
+ }
1381
+ }
1382
+ for (const [id, settle] of pendingSerialized) {
1383
+ if (id.startsWith(key)) {
1384
+ pendingSerialized.delete(id);
1385
+ settle();
1386
+ }
1387
+ }
1388
+ };
1271
1389
  const writeTasks = () => {
1272
1390
  if (tasks.length && !completed && firstFlushed) {
1273
1391
  buffer.write(`<script${nonceAttr(nonce, "script")}>${tasks}</script>`);
@@ -1338,6 +1456,11 @@ function renderToStream(code, options = {}) {
1338
1456
  }, nonce, tags);
1339
1457
  },
1340
1458
  registerAsset(type, value) {
1459
+ if (type === "preload") {
1460
+ const entry = registerPreloadLink(tracking, headRegistry, value, nonce);
1461
+ if (entry && firstFlushed) sink.asset("preload", entry);
1462
+ return;
1463
+ }
1341
1464
  if (type === "inline-style") {
1342
1465
  const entry = tracking.registerInlineStyle(value);
1343
1466
  if (firstFlushed && !tracking.currentBoundaryId && !entry.emitted) {
@@ -1382,13 +1505,14 @@ function renderToStream(code, options = {}) {
1382
1505
  },
1383
1506
  serialize(id, p, deferStream) {
1384
1507
  if (sharedConfig.context.noHydrate) return;
1385
- if (!firstFlushed && p && typeof p === "object" && "then" in p) {
1386
- if (deferStream) {
1508
+ if (p && typeof p === "object" && typeof p.then === "function") {
1509
+ if (!firstFlushed && deferStream) {
1387
1510
  blockingPromises.add(p);
1388
1511
  p.then(d => serializer.write(id, d)).catch(e => serializer.write(id, e));
1389
1512
  return;
1390
1513
  }
1391
- if (canBatchStubs && !shellCompleted) {
1514
+ p = trackSerialized(id, p);
1515
+ if (!firstFlushed && canBatchStubs && !shellCompleted) {
1392
1516
  (stubBatch ||= new Map()).set(id, p);
1393
1517
  return;
1394
1518
  }
@@ -1433,6 +1557,7 @@ function renderToStream(code, options = {}) {
1433
1557
  if (registry.has(key)) {
1434
1558
  const item = registry.get(key);
1435
1559
  registry.delete(key);
1560
+ if (error) abandonSubtree(key);
1436
1561
  if (item.children) {
1437
1562
  for (const k in item.children) {
1438
1563
  value = replacePlaceholder(value, k, item.children[k]);
@@ -1557,6 +1682,7 @@ function renderToStream(code, options = {}) {
1557
1682
  const head = renderShellHead(headRegistry, nonce, k => registry.has(k), noScripts);
1558
1683
  sink.shell(resolveSSRSelectValues(html), {
1559
1684
  preloads: tracking.emittedAssets,
1685
+ preloadLinks: tracking.preloadLinks,
1560
1686
  inlineStyles: tracking.inlineStyles,
1561
1687
  tasks,
1562
1688
  head
@@ -2478,7 +2604,7 @@ function ssrClaim(map) {
2478
2604
  function decodeSSREntities(s) {
2479
2605
  return s.indexOf("&") < 0 ? s : s.replace(/&quot;/g, '"').replace(/&lt;/g, "<").replace(/&amp;/g, "&");
2480
2606
  }
2481
- const SELECT_VALUE_ATTR = /\svalue="([^"]*)"/;
2607
+ const SELECT_VALUE_ATTR = /\svalue(?:="([^"]*)")?(?=[\s>]|$)/;
2482
2608
  function tagEnd(html, i) {
2483
2609
  for (let j = i + 1; j < html.length; j++) {
2484
2610
  const c = html.charCodeAt(j);
@@ -2530,7 +2656,7 @@ function resolveSSRSelectValues(html) {
2530
2656
  cand = html.indexOf("<select", e0 + 1);
2531
2657
  continue;
2532
2658
  }
2533
- const bound = decodeSSREntities(m[1]);
2659
+ const bound = decodeSSREntities(m[1] ?? "");
2534
2660
  const sel = {
2535
2661
  values: /\smultiple(?=[\s>=])/.test(open) ? bound.split(",") : [bound],
2536
2662
  strip: cand + m.index,
@@ -2567,7 +2693,7 @@ function resolveSSRSelectValues(html) {
2567
2693
  const attrs = html.slice(i + 7, e);
2568
2694
  if (/\sselected(?=[\s=]|$)/.test(attrs)) sel.defaulted = true;else {
2569
2695
  const vm = SELECT_VALUE_ATTR.exec(attrs);
2570
- const value = vm ? decodeSSREntities(vm[1]) : decodeSSREntities(optionText(html, e + 1)).replace(/\s+/g, " ").trim();
2696
+ const value = vm ? decodeSSREntities(vm[1] ?? "") : decodeSSREntities(optionText(html, e + 1)).replace(/\s+/g, " ").trim();
2571
2697
  if (sel.values.includes(value)) sel.marks.push(e);
2572
2698
  }
2573
2699
  }
@@ -2703,12 +2829,12 @@ function allSettled(promises) {
2703
2829
  return;
2704
2830
  });
2705
2831
  }
2706
- function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, headTags, onHead) {
2832
+ function assembleDocument(html, emittedAssets, preloadLinks, inlineStyles, scripts, nonce, headTags, onHead) {
2707
2833
  const scriptTag = scripts ? `<script${nonceAttr(nonce, "script")}>${scripts}</script>` : "";
2708
2834
  const title = headTags ? headTags.title : null;
2709
2835
  let headTagsHtml = headTags ? headTags.html : "";
2710
2836
  const headPrelude = headTags ? headTags.prelude : "";
2711
- if (!onHead && title == null && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !(inlineStyles && inlineStyles.size)) {
2837
+ if (!onHead && title == null && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !preloadLinks && !(inlineStyles && inlineStyles.size)) {
2712
2838
  if (!scriptTag) return html;
2713
2839
  const xs = html.indexOf("<!--xs-->");
2714
2840
  return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
@@ -2727,7 +2853,7 @@ function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, hea
2727
2853
  if (title != null) {
2728
2854
  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>`;
2729
2855
  }
2730
- onHead(headPrelude + headTagsHtml + titleHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce));
2856
+ onHead(headPrelude + headTagsHtml + titleHtml + renderHeadAssets(emittedAssets, preloadLinks, inlineStyles, nonce));
2731
2857
  }
2732
2858
  if (!scriptTag) return html;
2733
2859
  const xs = html.indexOf("<!--xs-->");
@@ -2747,13 +2873,13 @@ function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, hea
2747
2873
  headTagsHtml = `<title data-dh="title">${winner}</title>` + headTagsHtml;
2748
2874
  }
2749
2875
  }
2750
- const head = headTagsHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce);
2876
+ const head = headTagsHtml + renderHeadAssets(emittedAssets, preloadLinks, inlineStyles, nonce);
2751
2877
  if (!scriptTag) return html.slice(0, headIdx) + head + html.slice(headIdx);
2752
2878
  const xsIdx = html.indexOf("<!--xs-->");
2753
2879
  if (xsIdx === -1) return html.slice(0, headIdx) + head + html.slice(headIdx) + scriptTag;
2754
2880
  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);
2755
2881
  }
2756
- function renderHeadAssets(emittedAssets, inlineStyles, nonce) {
2882
+ function renderHeadAssets(emittedAssets, preloadLinks, inlineStyles, nonce) {
2757
2883
  let head = "";
2758
2884
  const styleAttr = nonceAttr(nonce, "style");
2759
2885
  const scriptAttr = nonceAttr(nonce, "script");
@@ -2762,6 +2888,9 @@ function renderHeadAssets(emittedAssets, inlineStyles, nonce) {
2762
2888
  head += isCssUrl(url) ? `<link rel="stylesheet" href="${url}"${styleAttr}>` : `<link rel="modulepreload" href="${url}"${scriptAttr}>`;
2763
2889
  }
2764
2890
  }
2891
+ if (preloadLinks) {
2892
+ for (const entry of preloadLinks) head += `<link${entry.attrHtml}>`;
2893
+ }
2765
2894
  if (inlineStyles && inlineStyles.size) {
2766
2895
  for (const entry of inlineStyles.values()) {
2767
2896
  if (entry.emitted) continue;
@@ -3026,7 +3155,7 @@ function copyInitHeaders(init) {
3026
3155
  for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
3027
3156
  return headers;
3028
3157
  }
3029
- const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, "Location"].map(header => header.toLowerCase()));
3158
+ 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()));
3030
3159
  function fillsStubGap(key, headers, response) {
3031
3160
  if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
3032
3161
  if (response.body === null && (key === "content-type" || key === "content-length")) return false;
@@ -3042,24 +3171,16 @@ function commitEventResponse(response, event = getRequestEvent()) {
3042
3171
  if (fillsStubGap(key, response.headers, response)) hasGaps = true;
3043
3172
  });
3044
3173
  if (!cookies.length && !hasGaps) return response;
3045
- try {
3046
- for (const cookie of cookies) response.headers.append("Set-Cookie", cookie);
3047
- stub.headers.forEach((value, key) => {
3048
- if (fillsStubGap(key, response.headers, response)) response.headers.set(key, value);
3049
- });
3050
- return response;
3051
- } catch {
3052
- const headers = copyInitHeaders(response.headers);
3053
- for (const cookie of cookies) headers.append("Set-Cookie", cookie);
3054
- stub.headers.forEach((value, key) => {
3055
- if (fillsStubGap(key, headers, response)) headers.set(key, value);
3056
- });
3057
- return new Response(response.body, {
3058
- status: response.status,
3059
- statusText: response.statusText,
3060
- headers
3061
- });
3062
- }
3174
+ const headers = copyInitHeaders(response.headers);
3175
+ for (const cookie of cookies) headers.append("Set-Cookie", cookie);
3176
+ stub.headers.forEach((value, key) => {
3177
+ if (fillsStubGap(key, headers, response)) headers.set(key, value);
3178
+ });
3179
+ return new Response(response.body, {
3180
+ status: response.status,
3181
+ statusText: response.statusText,
3182
+ headers
3183
+ });
3063
3184
  }
3064
3185
  function deriveHead(stub, responseInit = {}) {
3065
3186
  const headers = mergeStubHeaders(copyInitHeaders(responseInit.headers), stub);
@@ -3225,6 +3346,11 @@ function registerClientOnlyPreload(moduleUrl) {
3225
3346
  const css = assets.css[i];
3226
3347
  if (typeof css === "string") registerAsset("style", css);else registerAsset("inline-style", css);
3227
3348
  }
3349
+ if (assets.preloads) {
3350
+ for (let i = 0; i < assets.preloads.length; i++) {
3351
+ registerAsset("preload", assets.preloads[i]);
3352
+ }
3353
+ }
3228
3354
  for (let i = 0; i < assets.js.length; i++) registerAsset("module", assets.js[i]);
3229
3355
  };
3230
3356
  const assets = resolve(moduleUrl);
@@ -3328,4 +3454,4 @@ function httpHeader(name, value, options) {
3328
3454
  }
3329
3455
  }
3330
3456
 
3331
- export { CLAIMS_DOCUMENT, CLAIMS_STREAM, CLAIM_PROP, ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, HREF, HydrationScript, MathMLElements, Namespaces, Portal, REVALIDATE_HEADER, RawTextElements, RequestContext, ResponseEnvelope, SAFE_ERROR, SVGElements, VoidElements, notSup as acquireAsset, notSup as addEvent, applyRef, notSup as assign, claimElement, claimElementTree, notSup as className, clearFlashCookie, clientOnly, commitEventResponse, commitResponseStub, composeMiddleware, createLiveHoles, createRequestEvent, createResponseStub, createSSRResponse, notSup as delegateEvents, dynamic, notSup as dynamicProperty, effect, escape, generateHydrationScript, notSup as getDelegatedRoot, getExpectedRedirectStatus, getHydrationKey, notSup as getNextElement, notSup as getNextMarker, notSup as getNextMatch, getRequestEvent, getServerFunctionMetadata, getServerFunctionRPC, hasFlashCookie, httpHeader, httpStatus, notSup as hydrate, notSup as insert, isDev, isHref, isResponseEnvelope, isSafeError, isServer, isServerFunction, markSafeError, memo, parseCookieHeader, redirect, notSup as ref, notSup as registerDelegatedContainer, notSup as registerDelegatedRoot, registerElementClaim, reload, notSup as render, renderToStream, renderToString, resolveSSRNode, resolveSSRSelectValues, respond, notSup as runHydrationEvents, scriptNonce, serializeCookie, notSup as setAttribute, notSup as setAttributeNS, notSup as setProperty, notSup as setStyleProperty, notSup as spread, ssr, ssrAttribute, ssrClaim, ssrClassName, ssrElement, ssrGroup, ssrHydrationKey, ssrSelectValues, ssrStyle, ssrStyleProperty, notSup as style, styleNonce, notSup as template, notSup as unregisterDelegatedContainer, notSup as unregisterDelegatedRoot, useHead };
3457
+ export { CLAIMS_DOCUMENT, CLAIMS_STREAM, CLAIM_PROP, ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, HREF, HydrationScript, MathMLElements, NULL_BODY_STATUSES, Namespaces, Portal, RESPONSE_HEADER_VALUE_LIMIT, REVALIDATE_HEADER, RawTextElements, RequestContext, ResponseEnvelope, SAFE_ERROR, SVGElements, VoidElements, notSup as acquireAsset, notSup as addEvent, applyRef, notSup as assign, claimElement, claimElementTree, notSup as className, clearFlashCookie, clientOnly, commitEventResponse, commitResponseStub, composeMiddleware, createLiveHoles, createRequestEvent, createResponseStub, createSSRResponse, notSup as delegateEvents, dynamic, notSup as dynamicProperty, effect, escape, generateHydrationScript, notSup as getDelegatedRoot, getExpectedRedirectStatus, getHydrationKey, notSup as getNextElement, notSup as getNextMarker, notSup as getNextMatch, getRequestEvent, getServerFunctionMetadata, getServerFunctionRPC, hasFlashCookie, httpHeader, httpStatus, notSup as hydrate, notSup as insert, isDev, isHref, isResponseEnvelope, isSafeError, isServer, isServerFunction, markSafeError, memo, parseCookieHeader, redirect, notSup as ref, notSup as registerDelegatedContainer, notSup as registerDelegatedRoot, registerElementClaim, reload, notSup as render, renderToStream, renderToString, resolveSSRNode, resolveSSRSelectValues, respond, notSup as runHydrationEvents, scriptNonce, serializeCookie, notSup as setAttribute, notSup as setAttributeNS, notSup as setProperty, notSup as setStyleProperty, notSup as spread, ssr, ssrAttribute, ssrClaim, ssrClassName, ssrElement, ssrGroup, ssrHydrationKey, ssrSelectValues, ssrStyle, ssrStyleProperty, notSup as style, styleNonce, notSup as template, notSup as unregisterDelegatedContainer, notSup as unregisterDelegatedRoot, useHead };