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

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 (61) hide show
  1. package/dist/dev.cjs +163 -36
  2. package/dist/dev.js +161 -37
  3. package/dist/server.cjs +178 -37
  4. package/dist/server.js +177 -38
  5. package/dist/web.cjs +143 -36
  6. package/dist/web.js +141 -37
  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 +497 -44
  12. package/frames/dist/server.js +497 -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 +164 -35
  25. package/server-functions/dist/client.js +161 -36
  26. package/server-functions/dist/server.cjs +899 -136
  27. package/server-functions/dist/server.dev.cjs +919 -136
  28. package/server-functions/dist/server.dev.js +915 -137
  29. package/server-functions/dist/server.js +895 -137
  30. package/types/client.d.ts +2 -1
  31. package/types/constants.d.ts +3 -1
  32. package/types/cookies.d.ts +6 -14
  33. package/types/frames/frame-client.d.ts +4 -0
  34. package/types/frames/serializer-decode.d.ts +14 -1
  35. package/types/frames/serializer.d.ts +7 -0
  36. package/types/jsx.d.ts +11 -16
  37. package/types/response.d.ts +11 -0
  38. package/types/serializer-decode.d.ts +14 -1
  39. package/types/serializer.d.ts +7 -0
  40. package/types/server-functions/client.d.ts +22 -2
  41. package/types/server-functions/flash.d.ts +9 -0
  42. package/types/server-functions/server.d.ts +131 -11
  43. package/types/server-functions/shared.d.ts +77 -14
  44. package/types/server-mock.d.ts +17 -2
  45. package/types/server.d.ts +16 -2
  46. package/types-cjs/client.d.cts +2 -1
  47. package/types-cjs/constants.d.cts +3 -1
  48. package/types-cjs/cookies.d.cts +6 -14
  49. package/types-cjs/frames/frame-client.d.cts +4 -0
  50. package/types-cjs/frames/serializer-decode.d.cts +14 -1
  51. package/types-cjs/frames/serializer.d.cts +7 -0
  52. package/types-cjs/jsx.d.cts +11 -16
  53. package/types-cjs/response.d.cts +11 -0
  54. package/types-cjs/serializer-decode.d.cts +14 -1
  55. package/types-cjs/serializer.d.cts +7 -0
  56. package/types-cjs/server-functions/client.d.cts +22 -2
  57. package/types-cjs/server-functions/flash.d.cts +9 -0
  58. package/types-cjs/server-functions/server.d.cts +131 -11
  59. package/types-cjs/server-functions/shared.d.cts +77 -14
  60. package/types-cjs/server-mock.d.cts +17 -2
  61. package/types-cjs/server.d.cts +16 -2
package/dist/server.js CHANGED
@@ -48,6 +48,15 @@ const Namespaces = {
48
48
  const VoidElements = /*#__PURE__*/new Set(["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"]);
49
49
  const RawTextElements = /*#__PURE__*/new Set(["style", "script", "noscript", "template", "textarea", "title"]);
50
50
  const DOMElements = /*#__PURE__*/new Set(/*#__PURE__*/"a,abbr,acronym,address,applet,area,article,aside,audio,b,base,basefont,bdi,bdo,bgsound,big,blink,blockquote,body,br,button,canvas,caption,center,cite,code,col,colgroup,content,data,datalist,dd,del,details,dfn,dialog,dir,div,dl,dt,em,embed,fieldset,figcaption,figure,font,footer,form,frame,frameset,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,i,iframe,image,img,input,ins,isindex,kbd,keygen,label,legend,li,link,listing,main,map,mark,marquee,math,menu,menuitem,meta,meter,multicol,nav,nextid,nobr,noembed,noframes,noindex,noscript,object,ol,optgroup,option,output,p,param,picture,plaintext,portal,pre,progress,q,rb,rp,rt,rtc,ruby,s,samp,script,search,section,select,shadow,slot,small,source,spacer,span,strike,strong,style,sub,summary,sup,svg,table,tbody,td,template,textarea,tfoot,th,thead,time,title,tr,track,tt,u,ul,var,video,wbr,webview,xmp".split(","));
51
+ const COMPOSED_BODY_FRAMING = /*#__PURE__*/new Set(["content-length", "content-encoding", "transfer-encoding"]);
52
+ function isHttpNavigationTarget(target) {
53
+ try {
54
+ const protocol = new URL(target, "http://base.invalid").protocol;
55
+ return protocol === "http:" || protocol === "https:";
56
+ } catch {
57
+ return false;
58
+ }
59
+ }
51
60
 
52
61
  const transparentOptions = {
53
62
  transparent: true,
@@ -150,13 +159,13 @@ function resolveSerializerPlugins(customPlugins) {
150
159
  Feature.RegExp;
151
160
 
152
161
  const DEFAULT_DISABLED_FEATURES = Feature.AggregateError | Feature.BigIntTypedArray;
153
- const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : Feature.ErrorPrototypeStack;
162
+ const serializeOnlyDisabledFeatures = serializeErrorStacks => (serializeErrorStacks === undefined ? process.env.NODE_ENV === "development" : serializeErrorStacks) ? 0 : Feature.ErrorPrototypeStack;
154
163
  const HYDRATION_GLOBAL = "_$HY.r";
155
164
  function createSerializer(options) {
156
165
  return new Serializer({
157
166
  ...options,
158
167
  plugins: resolveSerializerPlugins(options.plugins),
159
- disabledFeatures: (options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures) | serializeOnlyDisabledFeatures()
168
+ disabledFeatures: (options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures) | serializeOnlyDisabledFeatures(options.serializeErrorStacks)
160
169
  });
161
170
  }
162
171
  function createHydrationSerializer({
@@ -213,6 +222,7 @@ function isSafeError(value) {
213
222
  return !!(value && (typeof value === "object" || typeof value === "function") && value[SAFE_ERROR]);
214
223
  }
215
224
  const REVALIDATE_HEADER = "X-Revalidate";
225
+ const RESPONSE_HEADER_VALUE_LIMIT = 4096;
216
226
  function initWithRevalidate(init = {}) {
217
227
  const resolved = typeof init === "number" ? {
218
228
  status: init
@@ -233,7 +243,13 @@ function initWithRevalidate(init = {}) {
233
243
  } else {
234
244
  headers = new Headers(responseInit.headers);
235
245
  }
236
- revalidate !== undefined && headers.set(REVALIDATE_HEADER, revalidate.toString());
246
+ if (revalidate !== undefined) {
247
+ const keys = revalidate.toString();
248
+ if (keys.length > RESPONSE_HEADER_VALUE_LIMIT) {
249
+ 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.`);
250
+ }
251
+ headers.set(REVALIDATE_HEADER, keys);
252
+ }
237
253
  return {
238
254
  responseInit,
239
255
  headers
@@ -251,7 +267,12 @@ function redirect(url, init = 302) {
251
267
  responseInit.status = 302;
252
268
  }
253
269
  const target = typeof url === "string" ? url : url[HREF];
254
- headers.set("Location", typeof target === "string" ? target : String(url));
270
+ const location = typeof target === "string" ? target : String(url);
271
+ const encoded = location.replace(/[^\x00-\x7f]/gu, encodeURIComponent);
272
+ if (encoded.length > RESPONSE_HEADER_VALUE_LIMIT) {
273
+ 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.`);
274
+ }
275
+ headers.set("Location", encoded);
255
276
  return new Response(null, {
256
277
  ...responseInit,
257
278
  headers
@@ -267,11 +288,19 @@ function reload(init = {}) {
267
288
  headers
268
289
  });
269
290
  }
291
+ const NULL_BODY_STATUSES = new Set([204, 205, 304]);
270
292
  function respond(value, init = {}) {
271
293
  const {
272
294
  responseInit,
273
295
  headers
274
296
  } = initWithRevalidate(init);
297
+ for (const header of COMPOSED_BODY_FRAMING) headers.delete(header);
298
+ if (NULL_BODY_STATUSES.has(responseInit.status)) {
299
+ return new ResponseEnvelope(new Response(null, {
300
+ ...responseInit,
301
+ headers
302
+ }), value);
303
+ }
275
304
  headers.set("Content-Type", "application/json");
276
305
  return new ResponseEnvelope(new Response(JSON.stringify(value), {
277
306
  ...responseInit,
@@ -322,6 +351,7 @@ function serializeCookie(name, value, options = {}) {
322
351
  if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
323
352
  if (options.httpOnly) cookie += "; HttpOnly";
324
353
  if (options.secure) cookie += "; Secure";
354
+ if (options.partitioned) cookie += "; Partitioned";
325
355
  if (options.sameSite) {
326
356
  const sameSite = options.sameSite.toLowerCase();
327
357
  cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
@@ -339,6 +369,7 @@ function clearFlashCookie() {
339
369
 
340
370
  const ERROR_HEADER = "X-Server-Function-Error";
341
371
  const BODY_FORMAT_HEADER = "X-Server-Function-Format";
372
+ const REDIRECT_HEADER = "X-Server-Function-Redirect";
342
373
  const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
343
374
 
344
375
  const HEAD_ELIGIBLE_TAGS = new Set(["title", "meta", "link", "style", "script", "base"]);
@@ -377,7 +408,8 @@ function resourceIdentity(tag, props) {
377
408
  let id = "res:" + tag + ":" + (props.rel || "") + ":" + (props.href || props.src || "");
378
409
  for (let i = 0; i < RESOURCE_QUALIFIERS.length; i++) {
379
410
  const q = RESOURCE_QUALIFIERS[i];
380
- if (props[q] != null) id += ":" + q + "=" + props[q];
411
+ const value = props[q];
412
+ if (value != null) id += ":" + q + "=" + (value === true ? "" : value);
381
413
  }
382
414
  return id;
383
415
  }
@@ -439,6 +471,7 @@ function resolveAssets(moduleUrl, manifest) {
439
471
  if (!entry) return null;
440
472
  const css = [];
441
473
  const js = [];
474
+ let preloads;
442
475
  const visited = new Set();
443
476
  const walk = key => {
444
477
  if (visited.has(key)) return;
@@ -447,13 +480,26 @@ function resolveAssets(moduleUrl, manifest) {
447
480
  if (!e) return;
448
481
  js.push(joinAssetPath(base, e.file));
449
482
  if (e.css) for (let i = 0; i < e.css.length; i++) css.push(joinAssetPath(base, e.css[i]));
483
+ if (e.preloads) {
484
+ for (let i = 0; i < e.preloads.length; i++) {
485
+ const link = e.preloads[i];
486
+ if (!link || typeof link.href !== "string" || !link.href) continue;
487
+ if (!preloads) preloads = [];
488
+ preloads.push({
489
+ ...link,
490
+ href: joinAssetPath(base, link.href)
491
+ });
492
+ }
493
+ }
450
494
  if (e.imports) for (let i = 0; i < e.imports.length; i++) walk(e.imports[i]);
451
495
  };
452
496
  walk(moduleUrl);
453
- return {
497
+ const assets = {
454
498
  js,
455
499
  css
456
500
  };
501
+ if (preloads) assets.preloads = preloads;
502
+ return assets;
457
503
  }
458
504
  function registerEntryAssets(manifest) {
459
505
  if (!manifest || typeof manifest === "function" || typeof manifest.resolve === "function") return;
@@ -463,6 +509,7 @@ function registerEntryAssets(manifest) {
463
509
  if (manifest[key].isEntry) {
464
510
  const assets = resolveAssets(key, manifest);
465
511
  if (assets) {
512
+ if (assets.preloads) for (let i = 0; i < assets.preloads.length; i++) ctx.registerAsset("preload", assets.preloads[i]);
466
513
  for (let i = 0; i < assets.css.length; i++) ctx.registerAsset("style", assets.css[i]);
467
514
  for (let i = 1; i < assets.js.length; i++) ctx.registerAsset("module", assets.js[i]);
468
515
  }
@@ -481,6 +528,7 @@ function createAssetTracking() {
481
528
  boundaryStyles,
482
529
  emittedAssets,
483
530
  inlineStyles,
531
+ preloadLinks: null,
484
532
  registerInlineStyle(desc) {
485
533
  let entry = inlineStyles.get(desc.id);
486
534
  if (!entry) {
@@ -572,6 +620,56 @@ function isCssUrl(url) {
572
620
  const q = url.search(/[?#]/);
573
621
  return (q === -1 ? url : url.slice(0, q)).endsWith(".css");
574
622
  }
623
+ const PRELOAD_LINK_ATTRIBUTES = ["type", "crossorigin", "integrity", "referrerpolicy", "fetchpriority", "media"];
624
+ function registerPreloadLink(tracking, headRegistry, link, nonce) {
625
+ if (!link || typeof link !== "object" || typeof link.href !== "string" || !link.href) {
626
+ return null;
627
+ }
628
+ if (typeof link.as !== "string") {
629
+ return null;
630
+ }
631
+ const as = asciiLowerCase(link.as);
632
+ let destination = null;
633
+ switch (as) {
634
+ case "script":
635
+ case "style":
636
+ destination = as;
637
+ break;
638
+ case "fetch":
639
+ case "font":
640
+ case "image":
641
+ case "track":
642
+ break;
643
+ default:
644
+ return null;
645
+ }
646
+ const props = {
647
+ rel: "preload",
648
+ href: link.href,
649
+ as
650
+ };
651
+ for (let i = 0; i < PRELOAD_LINK_ATTRIBUTES.length; i++) {
652
+ const name = PRELOAD_LINK_ATTRIBUTES[i];
653
+ const value = link[name];
654
+ if (value == null || value === false) continue;
655
+ props[name] = value === true ? "" : String(value);
656
+ }
657
+ const identity = resourceIdentity("link", props);
658
+ if (headRegistry.resources.has(identity)) return null;
659
+ const attrs = headAttrRecord(props);
660
+ const nonceValue = destination && nonce && nonce[destination];
661
+ if (typeof nonceValue === "string" && nonceValue) attrs.nonce = nonceValue;
662
+ const entry = {
663
+ href: props.href,
664
+ attrs,
665
+ attrHtml: renderHeadAttrHtml(props) + nonceAttr(nonce, destination)
666
+ };
667
+ headRegistry.resources.add(identity);
668
+ let links = tracking.preloadLinks;
669
+ if (!links) tracking.preloadLinks = links = [];
670
+ links.push(entry);
671
+ return entry;
672
+ }
575
673
  function createHeadRegistry() {
576
674
  return {
577
675
  pending: [],
@@ -1048,6 +1146,10 @@ function renderToString(code, options = {}) {
1048
1146
  serializer.write(id, p);
1049
1147
  },
1050
1148
  registerAsset(type, value) {
1149
+ if (type === "preload") {
1150
+ registerPreloadLink(tracking, headRegistry, value, nonce);
1151
+ return;
1152
+ }
1051
1153
  if (type === "inline-style") {
1052
1154
  tracking.registerInlineStyle(value);
1053
1155
  return;
@@ -1075,7 +1177,7 @@ function renderToString(code, options = {}) {
1075
1177
  sharedConfig.context.noHydrate = true;
1076
1178
  serializer.close();
1077
1179
  const head = renderShellHead(headRegistry, nonce, null, noScripts);
1078
- return assembleDocument(resolveSSRSelectValues(html), tracking.emittedAssets, tracking.inlineStyles, scripts.length ? scripts : "", nonce, head, onHead);
1180
+ return assembleDocument(resolveSSRSelectValues(html), tracking.emittedAssets, tracking.preloadLinks, tracking.inlineStyles, scripts.length ? scripts : "", nonce, head, onHead);
1079
1181
  }
1080
1182
  function renderToStream(code, options = {}) {
1081
1183
  let {
@@ -1229,6 +1331,8 @@ function renderToStream(code, options = {}) {
1229
1331
  asset(type, value) {
1230
1332
  if (type === "module") {
1231
1333
  buffer.write(`<link rel="modulepreload" href="${value}"${nonceAttr(nonce, "script")}>`);
1334
+ } else if (type === "preload") {
1335
+ buffer.write(`<link${value.attrHtml}>`);
1232
1336
  } else if (type === "inline-style") {
1233
1337
  buffer.write(renderInlineStyle(value, nonce));
1234
1338
  } else if (type === "head-tag") {
@@ -1236,7 +1340,7 @@ function renderToStream(code, options = {}) {
1236
1340
  }
1237
1341
  },
1238
1342
  shell(shellHtml, meta) {
1239
- buffer.write(assembleDocument(shellHtml, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
1343
+ buffer.write(assembleDocument(shellHtml, meta.preloads, meta.preloadLinks, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
1240
1344
  },
1241
1345
  ...options.sink
1242
1346
  };
@@ -1269,6 +1373,29 @@ function renderToStream(code, options = {}) {
1269
1373
  }
1270
1374
  };
1271
1375
  const registry = new Map();
1376
+ const pendingSerialized = new Map();
1377
+ const trackSerialized = (id, p) => {
1378
+ let settle;
1379
+ const raced = Promise.race([p, new Promise(r => settle = r)]);
1380
+ pendingSerialized.set(id, settle);
1381
+ const drop = () => pendingSerialized.delete(id);
1382
+ p.then(drop, drop);
1383
+ return raced;
1384
+ };
1385
+ const abandonSubtree = key => {
1386
+ for (const [k, entry] of registry) {
1387
+ if (k.length > key.length && k.startsWith(key)) {
1388
+ registry.delete(k);
1389
+ entry.resolve();
1390
+ }
1391
+ }
1392
+ for (const [id, settle] of pendingSerialized) {
1393
+ if (id.startsWith(key)) {
1394
+ pendingSerialized.delete(id);
1395
+ settle();
1396
+ }
1397
+ }
1398
+ };
1272
1399
  const writeTasks = () => {
1273
1400
  if (tasks.length && !completed && firstFlushed) {
1274
1401
  buffer.write(`<script${nonceAttr(nonce, "script")}>${tasks}</script>`);
@@ -1339,6 +1466,11 @@ function renderToStream(code, options = {}) {
1339
1466
  }, nonce, tags);
1340
1467
  },
1341
1468
  registerAsset(type, value) {
1469
+ if (type === "preload") {
1470
+ const entry = registerPreloadLink(tracking, headRegistry, value, nonce);
1471
+ if (entry && firstFlushed) sink.asset("preload", entry);
1472
+ return;
1473
+ }
1342
1474
  if (type === "inline-style") {
1343
1475
  const entry = tracking.registerInlineStyle(value);
1344
1476
  if (firstFlushed && !tracking.currentBoundaryId && !entry.emitted) {
@@ -1383,13 +1515,14 @@ function renderToStream(code, options = {}) {
1383
1515
  },
1384
1516
  serialize(id, p, deferStream) {
1385
1517
  if (sharedConfig.context.noHydrate) return;
1386
- if (!firstFlushed && p && typeof p === "object" && "then" in p) {
1387
- if (deferStream) {
1518
+ if (p && typeof p === "object" && typeof p.then === "function") {
1519
+ if (!firstFlushed && deferStream) {
1388
1520
  blockingPromises.add(p);
1389
1521
  p.then(d => serializer.write(id, d)).catch(e => serializer.write(id, e));
1390
1522
  return;
1391
1523
  }
1392
- if (canBatchStubs && !shellCompleted) {
1524
+ p = trackSerialized(id, p);
1525
+ if (!firstFlushed && canBatchStubs && !shellCompleted) {
1393
1526
  (stubBatch ||= new Map()).set(id, p);
1394
1527
  return;
1395
1528
  }
@@ -1434,6 +1567,7 @@ function renderToStream(code, options = {}) {
1434
1567
  if (registry.has(key)) {
1435
1568
  const item = registry.get(key);
1436
1569
  registry.delete(key);
1570
+ if (error) abandonSubtree(key);
1437
1571
  if (item.children) {
1438
1572
  for (const k in item.children) {
1439
1573
  value = replacePlaceholder(value, k, item.children[k]);
@@ -1558,6 +1692,7 @@ function renderToStream(code, options = {}) {
1558
1692
  const head = renderShellHead(headRegistry, nonce, k => registry.has(k), noScripts);
1559
1693
  sink.shell(resolveSSRSelectValues(html), {
1560
1694
  preloads: tracking.emittedAssets,
1695
+ preloadLinks: tracking.preloadLinks,
1561
1696
  inlineStyles: tracking.inlineStyles,
1562
1697
  tasks,
1563
1698
  head
@@ -2375,6 +2510,7 @@ function ssr(t) {
2375
2510
  return result;
2376
2511
  }
2377
2512
  function ssrClassName(value) {
2513
+ if (typeof value === "number") return "" + value;
2378
2514
  if (!value) return "";
2379
2515
  if (typeof value === "string") return escape(value, true);
2380
2516
  value = classListToObject(value);
@@ -2704,12 +2840,12 @@ function allSettled(promises) {
2704
2840
  return;
2705
2841
  });
2706
2842
  }
2707
- function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, headTags, onHead) {
2843
+ function assembleDocument(html, emittedAssets, preloadLinks, inlineStyles, scripts, nonce, headTags, onHead) {
2708
2844
  const scriptTag = scripts ? `<script${nonceAttr(nonce, "script")}>${scripts}</script>` : "";
2709
2845
  const title = headTags ? headTags.title : null;
2710
2846
  let headTagsHtml = headTags ? headTags.html : "";
2711
2847
  const headPrelude = headTags ? headTags.prelude : "";
2712
- if (!onHead && title == null && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !(inlineStyles && inlineStyles.size)) {
2848
+ if (!onHead && title == null && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !preloadLinks && !(inlineStyles && inlineStyles.size)) {
2713
2849
  if (!scriptTag) return html;
2714
2850
  const xs = html.indexOf("<!--xs-->");
2715
2851
  return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
@@ -2728,7 +2864,7 @@ function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, hea
2728
2864
  if (title != null) {
2729
2865
  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
2866
  }
2731
- onHead(headPrelude + headTagsHtml + titleHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce));
2867
+ onHead(headPrelude + headTagsHtml + titleHtml + renderHeadAssets(emittedAssets, preloadLinks, inlineStyles, nonce));
2732
2868
  }
2733
2869
  if (!scriptTag) return html;
2734
2870
  const xs = html.indexOf("<!--xs-->");
@@ -2748,13 +2884,13 @@ function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, hea
2748
2884
  headTagsHtml = `<title data-dh="title">${winner}</title>` + headTagsHtml;
2749
2885
  }
2750
2886
  }
2751
- const head = headTagsHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce);
2887
+ const head = headTagsHtml + renderHeadAssets(emittedAssets, preloadLinks, inlineStyles, nonce);
2752
2888
  if (!scriptTag) return html.slice(0, headIdx) + head + html.slice(headIdx);
2753
2889
  const xsIdx = html.indexOf("<!--xs-->");
2754
2890
  if (xsIdx === -1) return html.slice(0, headIdx) + head + html.slice(headIdx) + scriptTag;
2755
2891
  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
2892
  }
2757
- function renderHeadAssets(emittedAssets, inlineStyles, nonce) {
2893
+ function renderHeadAssets(emittedAssets, preloadLinks, inlineStyles, nonce) {
2758
2894
  let head = "";
2759
2895
  const styleAttr = nonceAttr(nonce, "style");
2760
2896
  const scriptAttr = nonceAttr(nonce, "script");
@@ -2763,6 +2899,9 @@ function renderHeadAssets(emittedAssets, inlineStyles, nonce) {
2763
2899
  head += isCssUrl(url) ? `<link rel="stylesheet" href="${url}"${styleAttr}>` : `<link rel="modulepreload" href="${url}"${scriptAttr}>`;
2764
2900
  }
2765
2901
  }
2902
+ if (preloadLinks) {
2903
+ for (const entry of preloadLinks) head += `<link${entry.attrHtml}>`;
2904
+ }
2766
2905
  if (inlineStyles && inlineStyles.size) {
2767
2906
  for (const entry of inlineStyles.values()) {
2768
2907
  if (entry.emitted) continue;
@@ -2857,7 +2996,8 @@ function classListToObject(classList) {
2857
2996
  function flattenClassList(list, result) {
2858
2997
  for (let i = 0, len = list.length; i < len; i++) {
2859
2998
  const item = list[i];
2860
- if (Array.isArray(item)) flattenClassList(item, result);else if (typeof item === "object" && item != null) Object.assign(result, item);else if (item || item === 0) result[item] = true;
2999
+ if (Array.isArray(item)) flattenClassList(item, result);else if (typeof item === "object" && item != null) Object.assign(result, item);
3000
+ else if (typeof item !== "boolean" && (item || item === 0)) result[item] = true;
2861
3001
  }
2862
3002
  }
2863
3003
  function tryResolveString(node) {
@@ -3027,7 +3167,8 @@ function copyInitHeaders(init) {
3027
3167
  for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
3028
3168
  return headers;
3029
3169
  }
3030
- const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, "Location"].map(header => header.toLowerCase()));
3170
+ const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, REDIRECT_HEADER, "Location",
3171
+ ...COMPOSED_BODY_FRAMING].map(header => header.toLowerCase()));
3031
3172
  function fillsStubGap(key, headers, response) {
3032
3173
  if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
3033
3174
  if (response.body === null && (key === "content-type" || key === "content-length")) return false;
@@ -3043,27 +3184,20 @@ function commitEventResponse(response, event = getRequestEvent()) {
3043
3184
  if (fillsStubGap(key, response.headers, response)) hasGaps = true;
3044
3185
  });
3045
3186
  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
- }
3187
+ const headers = copyInitHeaders(response.headers);
3188
+ for (const cookie of cookies) headers.append("Set-Cookie", cookie);
3189
+ stub.headers.forEach((value, key) => {
3190
+ if (fillsStubGap(key, headers, response)) headers.set(key, value);
3191
+ });
3192
+ return new Response(response.body, {
3193
+ status: response.status,
3194
+ statusText: response.statusText,
3195
+ headers
3196
+ });
3064
3197
  }
3065
3198
  function deriveHead(stub, responseInit = {}) {
3066
3199
  const headers = mergeStubHeaders(copyInitHeaders(responseInit.headers), stub);
3200
+ for (const header of COMPOSED_BODY_FRAMING) headers.delete(header);
3067
3201
  const status = stub && stub.status || responseInit.status || 200;
3068
3202
  const statusText = stub && stub.statusText || responseInit.statusText || undefined;
3069
3203
  return {
@@ -3147,7 +3281,7 @@ function createSSRResponse(result, event, options = {}) {
3147
3281
  end() {
3148
3282
  if (closed || !controller) return;
3149
3283
  const location = stub && stub.headers.get("Location");
3150
- if (location) {
3284
+ if (location && isHttpNavigationTarget(location)) {
3151
3285
  const attr = nonceAttr(nonce, "script");
3152
3286
  enqueue(`<script${attr}>window.location=${JSON.stringify(location).replace(/</g, "\\u003c")}</script>`);
3153
3287
  }
@@ -3226,6 +3360,11 @@ function registerClientOnlyPreload(moduleUrl) {
3226
3360
  const css = assets.css[i];
3227
3361
  if (typeof css === "string") registerAsset("style", css);else registerAsset("inline-style", css);
3228
3362
  }
3363
+ if (assets.preloads) {
3364
+ for (let i = 0; i < assets.preloads.length; i++) {
3365
+ registerAsset("preload", assets.preloads[i]);
3366
+ }
3367
+ }
3229
3368
  for (let i = 0; i < assets.js.length; i++) registerAsset("module", assets.js[i]);
3230
3369
  };
3231
3370
  const assets = resolve(moduleUrl);
@@ -3329,4 +3468,4 @@ function httpHeader(name, value, options) {
3329
3468
  }
3330
3469
  }
3331
3470
 
3332
- 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 };
3471
+ 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 };