@solidjs/web 2.0.0-beta.31 → 2.0.0-beta.33

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 (73) hide show
  1. package/README.md +1 -6
  2. package/dist/dev.cjs +285 -60
  3. package/dist/dev.js +267 -57
  4. package/dist/server.cjs +1148 -176
  5. package/dist/server.js +1133 -175
  6. package/dist/web.cjs +285 -60
  7. package/dist/web.js +267 -57
  8. package/frames/dist/client.cjs +397 -175
  9. package/frames/dist/client.dev.cjs +401 -175
  10. package/frames/dist/client.dev.js +399 -173
  11. package/frames/dist/client.js +395 -173
  12. package/frames/dist/server.cjs +1424 -277
  13. package/frames/dist/server.js +1426 -280
  14. package/package.json +69 -7
  15. package/serialization/decode/package.json +20 -0
  16. package/serialization/dist/decode.cjs +110 -0
  17. package/serialization/dist/decode.js +104 -0
  18. package/serialization/dist/serialization.cjs +106 -43
  19. package/serialization/dist/serialization.js +100 -44
  20. package/serialization/types/index.d.ts +85 -60
  21. package/serialization/types/serializer-decode.d.ts +182 -0
  22. package/serialization/types-cjs/index.d.cts +85 -60
  23. package/serialization/types-cjs/serializer-decode.d.cts +182 -0
  24. package/server-functions/dist/client.cjs +131 -98
  25. package/server-functions/dist/client.js +131 -99
  26. package/server-functions/dist/rich-args.cjs +11 -0
  27. package/server-functions/dist/rich-args.js +9 -0
  28. package/server-functions/dist/server.cjs +367 -194
  29. package/server-functions/dist/server.dev.cjs +1077 -0
  30. package/server-functions/dist/server.dev.js +1045 -0
  31. package/server-functions/dist/server.js +365 -195
  32. package/server-functions/package.json +10 -0
  33. package/server-functions/rich-args/package.json +20 -0
  34. package/storage/types/index.d.ts +1 -1
  35. package/storage/types-cjs/index.d.cts +1 -1
  36. package/types/client.d.ts +149 -6
  37. package/types/cookies.d.ts +93 -0
  38. package/types/core.d.ts +4 -2
  39. package/types/frames/client.d.ts +15 -1
  40. package/types/frames/frame-client.d.ts +63 -7
  41. package/types/frames/frame-sink.d.ts +26 -3
  42. package/types/frames/frame-transport.d.ts +40 -8
  43. package/types/frames/serializer.d.ts +85 -60
  44. package/types/frames/server.d.ts +22 -0
  45. package/types/index.d.ts +2 -3
  46. package/types/response.d.ts +45 -0
  47. package/types/serializer-decode.d.ts +182 -0
  48. package/types/serializer.d.ts +85 -60
  49. package/types/server-functions/client.d.ts +2 -1
  50. package/types/server-functions/rich-args.d.ts +10 -0
  51. package/types/server-functions/server.d.ts +99 -1
  52. package/types/server-functions/shared.d.ts +79 -1
  53. package/types/server-mock.d.ts +171 -59
  54. package/types/server.d.ts +209 -37
  55. package/types-cjs/client.d.cts +149 -6
  56. package/types-cjs/cookies.d.cts +93 -0
  57. package/types-cjs/core.d.cts +4 -2
  58. package/types-cjs/frames/client.d.cts +15 -1
  59. package/types-cjs/frames/frame-client.d.cts +63 -7
  60. package/types-cjs/frames/frame-sink.d.cts +26 -3
  61. package/types-cjs/frames/frame-transport.d.cts +40 -8
  62. package/types-cjs/frames/serializer.d.cts +85 -60
  63. package/types-cjs/frames/server.d.cts +22 -0
  64. package/types-cjs/index.d.cts +2 -3
  65. package/types-cjs/response.d.cts +45 -0
  66. package/types-cjs/serializer-decode.d.cts +182 -0
  67. package/types-cjs/serializer.d.cts +85 -60
  68. package/types-cjs/server-functions/client.d.cts +2 -1
  69. package/types-cjs/server-functions/rich-args.d.cts +10 -0
  70. package/types-cjs/server-functions/server.d.cts +99 -1
  71. package/types-cjs/server-functions/shared.d.cts +79 -1
  72. package/types-cjs/server-mock.d.cts +171 -59
  73. package/types-cjs/server.d.cts +209 -37
package/dist/server.js CHANGED
@@ -1,6 +1,6 @@
1
- import { createRenderEffect, createMemo, sharedConfig, createRoot, ssrHandleError, getOwner, runWithOwner, createComponent, omit, getNextChildId, onCleanup } from 'solid-js';
1
+ import { createRenderEffect, createMemo, sharedConfig, createRoot, getOwner, ssrHandleError, runWithOwner, inServerComponentScope, creationStamp, createComponent, omit, getNextChildId, onCleanup, getProjectionTrace } from 'solid-js';
2
2
  export { Errored, For, Hydration, Loading, Match, NoHydration, Repeat, Reveal, Show, Switch, createComponent, getOwner, merge as mergeProps, ssrScope as scope, untrack } from 'solid-js';
3
- import { Serializer, getCrossReferenceHeader, Feature } from 'seroval';
3
+ import { Feature, Serializer, getCrossReferenceHeader } from 'seroval';
4
4
  import { AbortSignalPlugin, CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin } from 'seroval-plugins/web';
5
5
 
6
6
  const DOMWithState = {
@@ -63,15 +63,74 @@ const effect = (fn, effectFn, options) => createRenderEffect(fn, effectFn, optio
63
63
  } : transparentOptions);
64
64
  const memo = fn => createMemo(() => fn(), syncOptions);
65
65
 
66
- const DEFAULT_DISABLED_FEATURES = Feature.AggregateError | Feature.BigIntTypedArray;
67
- const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : Feature.ErrorPrototypeStack;
68
- const HYDRATION_GLOBAL = "_$HY.r";
66
+ const STATE = Symbol.for("dom-expressions.container-trace-state");
67
+ const state = globalThis[STATE] || (globalThis[STATE] = {
68
+ materialized: new WeakMap(),
69
+ materializedValues: new WeakSet()
70
+ });
71
+ function setContainerTraceResolver(fn) {
72
+ state.resolveTrace = fn;
73
+ }
74
+ const TRACE = Symbol.for("dom-expressions.container-trace");
75
+ function materialize(marker) {
76
+ let value = state.materialized.get(marker.$tr);
77
+ if (value === undefined) {
78
+ value = state.materializeTrace(marker);
79
+ state.materialized.set(marker.$tr, value);
80
+ if (value !== null && typeof value === "object") state.materializedValues.add(value);
81
+ }
82
+ return value;
83
+ }
84
+ function parseTrace(value, ctx) {
85
+ const trace = value[TRACE];
86
+ return {
87
+ a: trace.array ? 1 : 0,
88
+ i: ctx.parse(trace.subscribe())
89
+ };
90
+ }
91
+ const ContainerTracePlugin = {
92
+ tag: "dom-expressions/container-trace",
93
+ test(value) {
94
+ return value != null && typeof value === "object" && TRACE in value;
95
+ },
96
+ parse: {
97
+ sync() {
98
+ throw new Error("A reactive container can only be serialized by a streaming serializer.");
99
+ },
100
+ async async(value, ctx) {
101
+ const trace = value[TRACE];
102
+ return {
103
+ a: trace.array ? 1 : 0,
104
+ i: await ctx.parse(trace.subscribe())
105
+ };
106
+ },
107
+ stream: parseTrace
108
+ },
109
+ serialize(node, ctx) {
110
+ return "{$tr:" + ctx.serialize(node.i) + ",$ta:" + node.a + "}";
111
+ },
112
+ deserialize(node, ctx) {
113
+ const iterable = ctx.deserialize(node.i);
114
+ const marker = {
115
+ $tr: iterable,
116
+ $ta: node.a
117
+ };
118
+ return state.materializeTrace ? materialize(marker) : marker;
119
+ }
120
+ };
121
+
69
122
  const DEFAULT_WEB_PLUGINS = Object.freeze([AbortSignalPlugin,
70
123
  CustomEventPlugin, DOMExceptionPlugin, EventPlugin,
71
- FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin]);
124
+ FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin,
125
+ ContainerTracePlugin]);
72
126
  function resolveSerializerPlugins(customPlugins) {
73
127
  return customPlugins ? [...customPlugins, ...DEFAULT_WEB_PLUGINS] : [...DEFAULT_WEB_PLUGINS];
74
128
  }
129
+ Feature.RegExp;
130
+
131
+ const DEFAULT_DISABLED_FEATURES = Feature.AggregateError | Feature.BigIntTypedArray;
132
+ const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : Feature.ErrorPrototypeStack;
133
+ const HYDRATION_GLOBAL = "_$HY.r";
75
134
  function createSerializer(options) {
76
135
  return new Serializer({
77
136
  ...options,
@@ -98,7 +157,166 @@ function createHydrationSerializer({
98
157
  function getLocalHeaderScript(id) {
99
158
  return getCrossReferenceHeader(id) + ";";
100
159
  }
101
- Feature.RegExp;
160
+
161
+ const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
162
+ // PURE-annotated factory (same convention as solid's MockPromise): the brand
163
+ const ResponseEnvelope = /* @__PURE__ */(() => {
164
+ class ResponseEnvelope {
165
+ constructor(response, value) {
166
+ this.response = response;
167
+ this.value = value;
168
+ }
169
+ }
170
+ ResponseEnvelope.prototype[ENVELOPE] = true;
171
+ return ResponseEnvelope;
172
+ })();
173
+ function isResponseEnvelope(value) {
174
+ return !!(value && typeof value === "object" && value[ENVELOPE]);
175
+ }
176
+ const HREF = Symbol.for("solid.Href");
177
+ function isHref(value) {
178
+ return !!(value && (typeof value === "object" || typeof value === "function") && value[HREF]);
179
+ }
180
+ const SAFE_ERROR = Symbol.for("solid.SafeError");
181
+ function markSafeError(error) {
182
+ if (error && (typeof error === "object" || typeof error === "function")) {
183
+ Object.defineProperty(error, SAFE_ERROR, {
184
+ value: true,
185
+ enumerable: false,
186
+ configurable: true
187
+ });
188
+ }
189
+ return error;
190
+ }
191
+ function isSafeError(value) {
192
+ return !!(value && (typeof value === "object" || typeof value === "function") && value[SAFE_ERROR]);
193
+ }
194
+ const REVALIDATE_HEADER = "X-Revalidate";
195
+ function initWithRevalidate(init) {
196
+ const {
197
+ revalidate,
198
+ ...responseInit
199
+ } = init;
200
+ let headers;
201
+ if (responseInit.headers && responseInit.headers.getSetCookie) {
202
+ headers = new Headers();
203
+ responseInit.headers.forEach((value, key) => {
204
+ if (key !== "set-cookie") headers.append(key, value);
205
+ });
206
+ for (const cookie of responseInit.headers.getSetCookie()) {
207
+ headers.append("Set-Cookie", cookie);
208
+ }
209
+ } else {
210
+ headers = new Headers(responseInit.headers);
211
+ }
212
+ revalidate !== undefined && headers.set(REVALIDATE_HEADER, revalidate.toString());
213
+ return {
214
+ responseInit,
215
+ headers
216
+ };
217
+ }
218
+ function redirect(url, init = 302) {
219
+ if (typeof url !== "string" && !isHref(url)) {
220
+ throw new TypeError("redirect() expects a string URL or an Href-branded value (Symbol.for('solid.Href')).");
221
+ }
222
+ const {
223
+ responseInit,
224
+ headers
225
+ } = initWithRevalidate(typeof init === "number" ? {
226
+ status: init
227
+ } : init);
228
+ if (responseInit.status === undefined) {
229
+ responseInit.status = 302;
230
+ }
231
+ headers.set("Location", String(url));
232
+ return new Response(null, {
233
+ ...responseInit,
234
+ headers
235
+ });
236
+ }
237
+ function reload(init = {}) {
238
+ const {
239
+ responseInit,
240
+ headers
241
+ } = initWithRevalidate(init);
242
+ return new Response(null, {
243
+ ...responseInit,
244
+ headers
245
+ });
246
+ }
247
+ function respond(value, init = {}) {
248
+ const {
249
+ responseInit,
250
+ headers
251
+ } = initWithRevalidate(init);
252
+ headers.set("Content-Type", "application/json");
253
+ return new ResponseEnvelope(new Response(JSON.stringify(value), {
254
+ ...responseInit,
255
+ headers
256
+ }), value);
257
+ }
258
+
259
+ const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
260
+ function getServerFunctionMetadata(fn) {
261
+ if (typeof fn !== "function") return undefined;
262
+ return fn[SERVER_FUNCTION_METADATA] || undefined;
263
+ }
264
+ function isServerFunction(fn) {
265
+ return typeof fn === "function" && !!fn[SERVER_FUNCTION_METADATA];
266
+ }
267
+ const SERVER_FUNCTION_RPC = Symbol.for("solid.ServerFunctionRPC");
268
+ function getServerFunctionRPC() {
269
+ return globalThis[SERVER_FUNCTION_RPC];
270
+ }
271
+
272
+ function parseCookieHeader(header) {
273
+ const cookies = {};
274
+ if (!header) return cookies;
275
+ for (const part of header.split(";")) {
276
+ const eq = part.indexOf("=");
277
+ if (eq < 0) continue;
278
+ const name = decodeSafe(part.slice(0, eq).trim());
279
+ let value = part.slice(eq + 1).trim();
280
+ if (value.length > 1 && value[0] === '"' && value[value.length - 1] === '"') {
281
+ value = value.slice(1, -1);
282
+ }
283
+ cookies[name] = decodeSafe(value);
284
+ }
285
+ return cookies;
286
+ }
287
+ function decodeSafe(text) {
288
+ try {
289
+ return decodeURIComponent(text);
290
+ } catch {
291
+ return text;
292
+ }
293
+ }
294
+ function serializeCookie(name, value, options = {}) {
295
+ let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
296
+ cookie += `; Path=${options.path === undefined ? "/" : options.path}`;
297
+ if (options.domain) cookie += `; Domain=${options.domain}`;
298
+ if (options.maxAge !== undefined) cookie += `; Max-Age=${Math.trunc(options.maxAge)}`;
299
+ if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
300
+ if (options.httpOnly) cookie += "; HttpOnly";
301
+ if (options.secure) cookie += "; Secure";
302
+ if (options.sameSite) {
303
+ const sameSite = options.sameSite.toLowerCase();
304
+ cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
305
+ }
306
+ return cookie;
307
+ }
308
+ const FLASH_COOKIE = "flash";
309
+ const FLASH_MATCHER = new RegExp(`(?:^|;\\s*)${FLASH_COOKIE}=([^;]+)`);
310
+ function hasFlashCookie(cookieHeader) {
311
+ return !!cookieHeader && FLASH_MATCHER.test(cookieHeader);
312
+ }
313
+ function clearFlashCookie() {
314
+ return `${FLASH_COOKIE}=; Max-Age=0; Path=/`;
315
+ }
316
+
317
+ const ERROR_HEADER = "X-Server-Function-Error";
318
+ const BODY_FORMAT_HEADER = "X-Server-Function-Format";
319
+ const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
102
320
 
103
321
  const HEAD_ELIGIBLE_TAGS = new Set(["title", "meta", "link", "style", "script", "base"]);
104
322
  const HEAD_ATTR_NAME = /^[a-zA-Z_][a-zA-Z0-9_:.-]*$/;
@@ -170,7 +388,6 @@ function resolveHead(groups) {
170
388
  }
171
389
  for (const [identity, tags] of byIdentity) {
172
390
  if (identity === "title") {
173
- if (tags.length > 1) console.warn("Multiple <title> tags in one head group; the last one wins.");
174
391
  winners.set(identity, {
175
392
  seq: group.seq,
176
393
  tags: [tags[tags.length - 1]]
@@ -340,7 +557,8 @@ function createHeadRegistry() {
340
557
  resources: new Set(),
341
558
  eagerHtml: "",
342
559
  flushed: null,
343
- shellFlushed: false
560
+ shellFlushed: false,
561
+ parkedResources: []
344
562
  };
345
563
  }
346
564
  function registerHeadTags(registry, context, tracking, emitResource, nonce, tags) {
@@ -354,14 +572,24 @@ function registerHeadTags(registry, context, tracking, emitResource, nonce, tags
354
572
  return;
355
573
  }
356
574
  if (!Array.isArray(tags)) tags = [tags];
575
+ const probe = sharedConfig.context && sharedConfig.context._loadingPhase;
357
576
  let replaceable = null;
358
577
  for (let i = 0; i < tags.length; i++) {
359
578
  const desc = tags[i];
360
579
  if (!desc || !HEAD_ELIGIBLE_TAGS.has(desc.tag)) {
361
- console.warn(`useHead: ignoring non-head tag`, desc);
362
580
  continue;
363
581
  }
364
582
  const cls = classifyHeadTag(desc);
583
+ if (probe && !cls.resource) {
584
+ try {
585
+ evalHeadProps(desc.props || {}, cls.rel !== undefined ? {
586
+ rel: cls.rel
587
+ } : undefined);
588
+ evalHeadValue(desc.key);
589
+ } catch (err) {
590
+ if (ssrHandleError(err)) throw err;
591
+ }
592
+ }
365
593
  if (cls.resource) {
366
594
  emitHeadResource(registry, context, tracking, emitResource, nonce, desc, cls.rel);
367
595
  } else {
@@ -378,6 +606,51 @@ function registerHeadTags(registry, context, tracking, emitResource, nonce, tags
378
606
  tags: replaceable
379
607
  });
380
608
  }
609
+ function headShellReady(registry, block) {
610
+ let ready = true;
611
+ const pends = err => {
612
+ const source = ssrHandleError(err, true);
613
+ if (!source) return false;
614
+ block(source);
615
+ ready = false;
616
+ return true;
617
+ };
618
+ const parked = registry.parkedResources;
619
+ for (let i = parked.length - 1; i >= 0; i--) {
620
+ const {
621
+ desc,
622
+ rel,
623
+ emit
624
+ } = parked[i];
625
+ try {
626
+ evalHeadProps(desc.props || {}, rel !== undefined ? {
627
+ rel
628
+ } : undefined);
629
+ } catch (err) {
630
+ if (pends(err)) continue;
631
+ parked.splice(i, 1);
632
+ continue;
633
+ }
634
+ parked.splice(i, 1);
635
+ emit();
636
+ }
637
+ for (let i = 0; i < registry.pending.length; i++) {
638
+ const reg = registry.pending[i];
639
+ if (reg.boundary !== "" || reg.list) continue;
640
+ for (let j = 0; j < reg.tags.length; j++) {
641
+ const desc = reg.tags[j];
642
+ try {
643
+ evalHeadProps(desc.props || {}, desc.rel !== undefined ? {
644
+ rel: desc.rel
645
+ } : undefined);
646
+ evalHeadValue(desc.key);
647
+ } catch (err) {
648
+ pends(err);
649
+ }
650
+ }
651
+ }
652
+ return ready;
653
+ }
381
654
  function emitHeadResource(registry, context, tracking, emitResource, nonce, desc, rel) {
382
655
  let props;
383
656
  try {
@@ -385,7 +658,16 @@ function emitHeadResource(registry, context, tracking, emitResource, nonce, desc
385
658
  rel
386
659
  } : undefined);
387
660
  } catch (err) {
388
- console.warn(`useHead: error evaluating resource tag props`, err);
661
+ const loadingPhase = sharedConfig.context && sharedConfig.context._loadingPhase;
662
+ if (loadingPhase && ssrHandleError(err)) throw err;
663
+ if (!loadingPhase && !context._currentBoundaryId && !registry.shellFlushed && typeof context.block === "function" && ssrHandleError(err, true)) {
664
+ registry.parkedResources.push({
665
+ desc,
666
+ rel,
667
+ emit: () => emitHeadResource(registry, context, tracking, emitResource, nonce, desc, rel)
668
+ });
669
+ return;
670
+ }
389
671
  return;
390
672
  }
391
673
  const identity = resourceIdentity(desc.tag, props);
@@ -447,7 +729,6 @@ function commitHeadBoundary(registry, boundary, isPendingFragment) {
447
729
  try {
448
730
  resolved = reg.list();
449
731
  } catch (err) {
450
- console.warn(`useHead: error evaluating head group membership`, err);
451
732
  continue;
452
733
  }
453
734
  if (!Array.isArray(resolved)) resolved = [resolved];
@@ -455,7 +736,6 @@ function commitHeadBoundary(registry, boundary, isPendingFragment) {
455
736
  for (let j = 0; j < resolved.length; j++) {
456
737
  const desc = resolved[j];
457
738
  if (!desc || !HEAD_ELIGIBLE_TAGS.has(desc.tag)) {
458
- console.warn(`useHead: ignoring non-head tag`, desc);
459
739
  continue;
460
740
  }
461
741
  const cls = classifyHeadTag(desc);
@@ -481,12 +761,10 @@ function commitHeadBoundary(registry, boundary, isPendingFragment) {
481
761
  } : undefined);
482
762
  key = evalHeadValue(desc.key);
483
763
  } catch (err) {
484
- console.warn(`useHead: error evaluating tag props`, err);
485
764
  continue;
486
765
  }
487
766
  const identity = replaceableIdentity(desc.tag, props, key, "u:" + registry.uniq++);
488
767
  if ((identity === "base" || identity === "charset") && registry.shellFlushed) {
489
- console.warn(`useHead: <${desc.tag}> (${identity}) registered after shell flush is ignored`);
490
768
  continue;
491
769
  }
492
770
  tags.push({
@@ -568,7 +846,6 @@ function flushHeadFragment(registry, boundary) {
568
846
  for (const name in t.props) {
569
847
  if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
570
848
  if (!HEAD_ATTR_NAME.test(name)) {
571
- console.warn(`useHead: ignoring invalid attribute name "${name}"`);
572
849
  continue;
573
850
  }
574
851
  const v = t.props[name];
@@ -586,7 +863,6 @@ function renderHeadAttrHtml(props) {
586
863
  for (const name in props) {
587
864
  if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
588
865
  if (!HEAD_ATTR_NAME.test(name)) {
589
- console.warn(`useHead: ignoring invalid attribute name "${name}"`);
590
866
  continue;
591
867
  }
592
868
  const v = props[name];
@@ -619,7 +895,6 @@ function renderHeadTagMarkup(tag, props, identity, nonce) {
619
895
  function useHead(tags) {
620
896
  const ctx = sharedConfig.context;
621
897
  if (!ctx || !ctx.registerHeadTags) {
622
- console.warn("useHead() called outside of a server render; registration ignored.");
623
898
  return;
624
899
  }
625
900
  ctx.registerHeadTags(tags);
@@ -651,7 +926,6 @@ function renderToString(code, options = {}) {
651
926
  const tracking = createAssetTracking();
652
927
  const headRegistry = createHeadRegistry();
653
928
  sharedConfig.context = {
654
- assets: [],
655
929
  nonce,
656
930
  escape: escape,
657
931
  resolve: resolveSSRNode,
@@ -693,9 +967,8 @@ function renderToString(code, options = {}) {
693
967
  serializeFragmentAssets("", tracking.boundaryModules, sharedConfig.context);
694
968
  sharedConfig.context.noHydrate = true;
695
969
  serializer.close();
696
- const assetsHtml = resolveAssetsHtml(sharedConfig.context.assets);
697
970
  const head = renderShellHead(headRegistry, nonce, null);
698
- return assembleDocument(html, assetsHtml, tracking.emittedAssets, tracking.inlineStyles, scripts.length ? scripts : "", nonce, head, onHead);
971
+ return assembleDocument(html, tracking.emittedAssets, tracking.inlineStyles, scripts.length ? scripts : "", nonce, head, onHead);
699
972
  }
700
973
  function renderToStream(code, options = {}) {
701
974
  let {
@@ -725,6 +998,12 @@ function renderToStream(code, options = {}) {
725
998
  d();
726
999
  }
727
1000
  };
1001
+ const failRender = err => {
1002
+ try {
1003
+ options.onError ? options.onError(err) : console.error(err);
1004
+ } catch (_) {}
1005
+ abandon();
1006
+ };
728
1007
  const guardSink = w => ({
729
1008
  write(payload) {
730
1009
  if (dead) return;
@@ -806,7 +1085,7 @@ function renderToStream(code, options = {}) {
806
1085
  }
807
1086
  },
808
1087
  shell(shellHtml, meta) {
809
- buffer.write(assembleDocument(shellHtml, meta.assets, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
1088
+ buffer.write(assembleDocument(shellHtml, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
810
1089
  },
811
1090
  ...options.sink
812
1091
  };
@@ -823,10 +1102,18 @@ function renderToStream(code, options = {}) {
823
1102
  rootAssetsSerialized = true;
824
1103
  serializeFragmentAssets("", tracking.boundaryModules, context);
825
1104
  };
1105
+ let holds = 0;
826
1106
  const flushEnd = () => {
827
- if (!registry.size) {
1107
+ if (!registry.size && !holds) {
828
1108
  serializeRootAssets();
829
- queue(() => queue(() => serializer.flush()));
1109
+ queue(() => queue(() => {
1110
+ if (context.live.end) {
1111
+ const end = context.live.end;
1112
+ context.live.end = null;
1113
+ end();
1114
+ }
1115
+ serializer.flush();
1116
+ }));
830
1117
  }
831
1118
  };
832
1119
  const registry = new Map();
@@ -886,8 +1173,8 @@ function renderToStream(code, options = {}) {
886
1173
  };
887
1174
  sharedConfig.context = context = {
888
1175
  async: true,
889
- assets: [],
890
1176
  nonce,
1177
+ live: {},
891
1178
  registerHeadTags(tags) {
892
1179
  registerHeadTags(headRegistry, context, tracking,
893
1180
  (markup, gateEntry) => {
@@ -924,6 +1211,16 @@ function renderToStream(code, options = {}) {
924
1211
  block(p) {
925
1212
  if (!firstFlushed) blockingPromises.add(p);
926
1213
  },
1214
+ hold() {
1215
+ holds++;
1216
+ let released = false;
1217
+ return () => {
1218
+ if (released) return;
1219
+ released = true;
1220
+ holds--;
1221
+ if (!holds) queue(flushEnd);
1222
+ };
1223
+ },
927
1224
  replace(id, payloadFn) {
928
1225
  if (firstFlushed) return;
929
1226
  const placeholder = `<!--!$${id}-->`;
@@ -1032,6 +1329,7 @@ function renderToStream(code, options = {}) {
1032
1329
  }
1033
1330
  };
1034
1331
  applyAssetTracking(context, tracking, manifest, noScripts);
1332
+ context.failRender = failRender;
1035
1333
  registerEntryAssets(manifest);
1036
1334
  let html = createRoot(d => {
1037
1335
  dispose = d;
@@ -1088,7 +1386,7 @@ function renderToStream(code, options = {}) {
1088
1386
  if (shellCompleted) return;
1089
1387
  sharedConfig.context = context;
1090
1388
  if (!resolveRootHoles()) return;
1091
- const assetsHtml = resolveAssetsHtml(context.assets);
1389
+ if (!headShellReady(headRegistry, p => blockingPromises.add(p))) return;
1092
1390
  headStyles = new Set();
1093
1391
  for (const url of tracking.emittedAssets) {
1094
1392
  if (isCssUrl(url)) headStyles.add(url);
@@ -1096,7 +1394,6 @@ function renderToStream(code, options = {}) {
1096
1394
  serializeRootAssets();
1097
1395
  const head = renderShellHead(headRegistry, nonce, k => registry.has(k));
1098
1396
  sink.shell(html, {
1099
- assets: assetsHtml,
1100
1397
  preloads: tracking.emittedAssets,
1101
1398
  inlineStyles: tracking.inlineStyles,
1102
1399
  tasks,
@@ -1145,7 +1442,12 @@ function renderToStream(code, options = {}) {
1145
1442
  allSettled(blockingPromises).then(() => {
1146
1443
  scheduleFlush(() => {
1147
1444
  if (dead) return resolve();
1148
- doShell();
1445
+ try {
1446
+ doShell();
1447
+ } catch (err) {
1448
+ failRender(err);
1449
+ return resolve();
1450
+ }
1149
1451
  if (!shellCompleted) return flush();
1150
1452
  const encoder = new TextEncoder();
1151
1453
  const writer = w.getWriter();
@@ -1186,27 +1488,35 @@ function renderToStream(code, options = {}) {
1186
1488
  return p;
1187
1489
  };
1188
1490
  return {
1189
- then(fn) {
1190
- function complete() {
1191
- dispose();
1192
- fn(tmp);
1193
- }
1194
- if (onCompleteAll) {
1195
- let ogComplete = onCompleteAll;
1196
- onCompleteAll = options => {
1197
- ogComplete(options);
1198
- complete();
1199
- };
1200
- } else onCompleteAll = complete;
1201
- function flush() {
1202
- allSettled(blockingPromises).then(() => {
1203
- scheduleFlush(() => {
1204
- if (!resolveRootHoles()) return flush();
1205
- queue(flushEnd);
1491
+ then(onFulfilled, onRejected) {
1492
+ const p = new Promise(resolve => {
1493
+ function complete() {
1494
+ dispose();
1495
+ resolve(tmp);
1496
+ }
1497
+ if (onCompleteAll) {
1498
+ let ogComplete = onCompleteAll;
1499
+ onCompleteAll = options => {
1500
+ ogComplete(options);
1501
+ complete();
1502
+ };
1503
+ } else onCompleteAll = complete;
1504
+ function flush() {
1505
+ allSettled(blockingPromises).then(() => {
1506
+ scheduleFlush(() => {
1507
+ try {
1508
+ if (!resolveRootHoles() || !headShellReady(headRegistry, p => blockingPromises.add(p))) return flush();
1509
+ } catch (err) {
1510
+ failRender(err);
1511
+ return resolve(tmp);
1512
+ }
1513
+ queue(flushEnd);
1514
+ });
1206
1515
  });
1207
- });
1208
- }
1209
- flush();
1516
+ }
1517
+ flush();
1518
+ });
1519
+ return p.then(onFulfilled, onRejected);
1210
1520
  },
1211
1521
  pipe(w) {
1212
1522
  claimConsumer("pipe");
@@ -1214,7 +1524,15 @@ function renderToStream(code, options = {}) {
1214
1524
  allSettled(blockingPromises).then(() => {
1215
1525
  scheduleFlush(() => {
1216
1526
  if (dead) return;
1217
- doShell();
1527
+ try {
1528
+ doShell();
1529
+ } catch (err) {
1530
+ failRender(err);
1531
+ try {
1532
+ w.end();
1533
+ } catch (_) {}
1534
+ return;
1535
+ }
1218
1536
  if (!shellCompleted) return flush();
1219
1537
  buffer = writable = guardSink(w);
1220
1538
  buffer.write(tmp);
@@ -1259,9 +1577,27 @@ function ssrGroup(fn, n) {
1259
1577
  function buildAsyncWrap(err, node) {
1260
1578
  const p = ssrHandleError(err);
1261
1579
  if (!p) return null;
1580
+ if (node.$rw) return {
1581
+ fn: node,
1582
+ p
1583
+ };
1262
1584
  const owner = getOwner();
1585
+ const live = sharedConfig.context && sharedConfig.context.liveHoles;
1586
+ const suppress = node.$lhSuppress || live && (live.suppressed || live.sweeping);
1587
+ if (!owner) {
1588
+ if (suppress) node.$lhSuppress = true;
1589
+ return {
1590
+ fn: node,
1591
+ p
1592
+ };
1593
+ }
1594
+ const fn = () => runWithOwner(owner, node);
1595
+ fn.$rw = true;
1596
+ if (suppress) fn.$lhSuppress = true;
1597
+ if (node.$lhSkip) fn.$lhSkip = true;
1598
+ if (node.$lhBinding) fn.$lhBinding = node.$lhBinding;
1263
1599
  return {
1264
- fn: owner ? () => runWithOwner(owner, node) : node,
1600
+ fn,
1265
1601
  p
1266
1602
  };
1267
1603
  }
@@ -1321,6 +1657,326 @@ function ssrGroupSlot(fn, idx) {
1321
1657
  }
1322
1658
  };
1323
1659
  }
1660
+ const holePositionCache = new WeakMap();
1661
+ function holeContentPositions(t) {
1662
+ let cached = holePositionCache.get(t);
1663
+ if (cached) return cached;
1664
+ const pos = [];
1665
+ const openOff = [];
1666
+ const closeOff = [];
1667
+ let inTag = false;
1668
+ let quote = "";
1669
+ let curOpen = null;
1670
+ let scanningName = false;
1671
+ for (let i = 0; i < t.length; i++) {
1672
+ const seg = t[i];
1673
+ let close = -1;
1674
+ const openAtStart = inTag;
1675
+ let reopened = false;
1676
+ for (let j = 0; j < seg.length; j++) {
1677
+ const ch = seg[j];
1678
+ if (quote) {
1679
+ if (ch === quote) quote = "";
1680
+ } else if (inTag) {
1681
+ if (scanningName && (ch === " " || ch === "\t" || ch === "\n" || ch === ">" || ch === "/")) {
1682
+ scanningName = false;
1683
+ curOpen = {
1684
+ seg: i,
1685
+ off: j
1686
+ };
1687
+ }
1688
+ if (ch === '"' || ch === "'") quote = ch;else if (ch === ">") {
1689
+ inTag = false;
1690
+ if (openAtStart && !reopened && close === -1) close = j;
1691
+ curOpen = null;
1692
+ }
1693
+ } else if (ch === "<") {
1694
+ inTag = true;
1695
+ scanningName = true;
1696
+ reopened = true;
1697
+ curOpen = null;
1698
+ }
1699
+ }
1700
+ if (inTag && scanningName) {
1701
+ scanningName = false;
1702
+ curOpen = {
1703
+ seg: i,
1704
+ off: seg.length
1705
+ };
1706
+ }
1707
+ closeOff.push(close);
1708
+ openOff.push(inTag && curOpen && curOpen.seg === i ? curOpen.off : -1);
1709
+ if (i < t.length - 1) pos.push(!inTag);
1710
+ }
1711
+ cached = {
1712
+ pos,
1713
+ openOff,
1714
+ closeOff
1715
+ };
1716
+ holePositionCache.set(t, cached);
1717
+ return cached;
1718
+ }
1719
+ function createLiveHoles(sink, scoped) {
1720
+ let nextId = 0;
1721
+ const stamp = typeof creationStamp === "function" ? creationStamp : () => 0;
1722
+ const inScope = scoped && typeof inServerComponentScope === "function" ? inServerComponentScope : null;
1723
+ const stripMarkers = html => html.replace(/<!--lh:\/?\d+-->/g, "");
1724
+ function resolveHoleValue(hole) {
1725
+ const result = {
1726
+ t: [""],
1727
+ h: [],
1728
+ p: []
1729
+ };
1730
+ try {
1731
+ resolveSSRNode(hole(), result);
1732
+ } catch (err) {
1733
+ const wrap = buildAsyncWrap(err, hole);
1734
+ if (!wrap) throw err;
1735
+ result.h.push(wrap.fn);
1736
+ result.p.push(wrap.p);
1737
+ result.t.push("");
1738
+ }
1739
+ return result;
1740
+ }
1741
+ function closeChildren(b) {
1742
+ for (const c of b.children) {
1743
+ c.closed = true;
1744
+ if (c.key) sink.closeBinding(c.key);
1745
+ closeChildren(c);
1746
+ }
1747
+ b.children.length = 0;
1748
+ }
1749
+ const engine = {
1750
+ suppressed: 0,
1751
+ sweeping: false,
1752
+ parent: null,
1753
+ recordStamp: 0,
1754
+ gateHit: false,
1755
+ content(hole) {
1756
+ if (hole.$lhSuppress) {
1757
+ const r = {
1758
+ t: [""],
1759
+ h: [],
1760
+ p: []
1761
+ };
1762
+ engine.suppressed++;
1763
+ try {
1764
+ try {
1765
+ resolveSSRNode(hole(), r);
1766
+ } catch (err) {
1767
+ const wrap = buildAsyncWrap(err, hole);
1768
+ if (wrap) {
1769
+ r.h.push(wrap.fn);
1770
+ r.p.push(wrap.p);
1771
+ r.t.push("");
1772
+ }
1773
+ }
1774
+ } finally {
1775
+ engine.suppressed--;
1776
+ }
1777
+ const b = hole.$lhBinding;
1778
+ if (b && !b.closed && !r.h.length && !engine.sweeping) {
1779
+ b.last = stripMarkers(r.t[0]);
1780
+ }
1781
+ return r.h.length ? r : r.t[0];
1782
+ }
1783
+ if (engine.suppressed || engine.sweeping) return null;
1784
+ if (hole.$lhSkip) return null;
1785
+ if (inScope && !inScope()) return null;
1786
+ const recordsBefore = engine.recordStamp;
1787
+ const ownersBefore = stamp();
1788
+ const owner = getOwner();
1789
+ const b = {
1790
+ key: null,
1791
+ children: [],
1792
+ last: null,
1793
+ closed: false,
1794
+ sweep() {
1795
+ if (b.closed) return;
1796
+ const prevSweeping = engine.sweeping;
1797
+ engine.sweeping = true;
1798
+ engine.gateHit = false;
1799
+ const sweepOwnersBefore = stamp();
1800
+ let res;
1801
+ try {
1802
+ res = owner ? runWithOwner(owner, () => resolveHoleValue(hole)) : resolveHoleValue(hole);
1803
+ } catch (err) {
1804
+ b.closed = true;
1805
+ sink.closeBinding(b.key);
1806
+ sink.error(b.key, String(err && err.message || err));
1807
+ return;
1808
+ } finally {
1809
+ engine.sweeping = prevSweeping;
1810
+ }
1811
+ if (engine.gateHit || stamp() !== sweepOwnersBefore) {
1812
+ b.closed = true;
1813
+ sink.closeBinding(b.key);
1814
+ return;
1815
+ }
1816
+ if (res.h.length) return;
1817
+ const html = res.t[0];
1818
+ if (b.last === null || html === b.last) return;
1819
+ b.last = html;
1820
+ closeChildren(b);
1821
+ sink.hole(b.key, html);
1822
+ }
1823
+ };
1824
+ if (engine.parent) engine.parent.children.push(b);
1825
+ const prevParent = engine.parent;
1826
+ engine.parent = b;
1827
+ let value;
1828
+ let escalated = null;
1829
+ try {
1830
+ value = hole();
1831
+ } catch (err) {
1832
+ const wrap = buildAsyncWrap(err, hole);
1833
+ if (!wrap) {
1834
+ engine.parent = prevParent;
1835
+ closeChildren(b);
1836
+ return "";
1837
+ }
1838
+ escalated = wrap;
1839
+ }
1840
+ if (!escalated && (typeof value === "function" && value.$lhSkip || value !== null && typeof value === "object" && value.$slot)) {
1841
+ engine.parent = prevParent;
1842
+ const r = {
1843
+ t: [""],
1844
+ h: [],
1845
+ p: []
1846
+ };
1847
+ engine.suppressed++;
1848
+ try {
1849
+ resolveSSRNode(value, r);
1850
+ } finally {
1851
+ engine.suppressed--;
1852
+ }
1853
+ return r.h.length ? r : r.t[0];
1854
+ }
1855
+ let res;
1856
+ if (escalated) {
1857
+ closeChildren(b);
1858
+ escalated.fn.$lhSuppress = true;
1859
+ escalated.fn.$lhBinding = b;
1860
+ res = {
1861
+ t: ["", ""],
1862
+ h: [escalated.fn],
1863
+ p: [escalated.p]
1864
+ };
1865
+ } else {
1866
+ res = {
1867
+ t: [""],
1868
+ h: [],
1869
+ p: []
1870
+ };
1871
+ try {
1872
+ resolveSSRNode(value, res);
1873
+ } catch (_) {
1874
+ engine.parent = prevParent;
1875
+ closeChildren(b);
1876
+ return "";
1877
+ }
1878
+ }
1879
+ engine.parent = prevParent;
1880
+ if (engine.recordStamp !== recordsBefore || stamp() !== ownersBefore) {
1881
+ return res.h.length ? res : res.t[0];
1882
+ }
1883
+ const id = nextId++;
1884
+ const key = b.key = "lh:" + id;
1885
+ const open = `<!--lh:${id}-->`;
1886
+ const close = `<!--lh:/${id}-->`;
1887
+ if (!res.h.length) {
1888
+ b.last = stripMarkers(res.t[0]);
1889
+ sink.openBinding(key, b);
1890
+ return open + res.t[0] + close;
1891
+ }
1892
+ const t = res.t.slice();
1893
+ t[0] = open + t[0];
1894
+ t[t.length - 1] += close;
1895
+ sink.openBinding(key, b);
1896
+ return {
1897
+ t,
1898
+ h: res.h,
1899
+ p: res.p
1900
+ };
1901
+ },
1902
+ mint() {
1903
+ return nextId++;
1904
+ },
1905
+ active() {
1906
+ return !inScope || inScope();
1907
+ },
1908
+ attr(cap) {
1909
+ const owner = getOwner();
1910
+ const b = {
1911
+ key: "lha:" + cap.id,
1912
+ children: [],
1913
+ last: cap.base,
1914
+ closed: false,
1915
+ sweep() {
1916
+ if (b.closed) return;
1917
+ const prevSweeping = engine.sweeping;
1918
+ engine.sweeping = true;
1919
+ engine.gateHit = false;
1920
+ const sweepOwnersBefore = stamp();
1921
+ let html = "";
1922
+ try {
1923
+ let group = null;
1924
+ let groupVal = null;
1925
+ const run = () => {
1926
+ for (const part of cap.parts) {
1927
+ if (typeof part === "string") {
1928
+ html += part;
1929
+ continue;
1930
+ }
1931
+ let v;
1932
+ if (part.g) {
1933
+ if (group !== part.g) {
1934
+ group = part.g;
1935
+ groupVal = part.g();
1936
+ }
1937
+ v = groupVal[part.i];
1938
+ } else {
1939
+ v = part.f();
1940
+ }
1941
+ const vt = typeof v;
1942
+ if (vt === "string" || vt === "number") html += v;
1943
+ }
1944
+ };
1945
+ owner ? runWithOwner(owner, run) : run();
1946
+ } catch (err) {
1947
+ if (ssrHandleError(err, true)) return;
1948
+ b.closed = true;
1949
+ sink.closeBinding(b.key);
1950
+ sink.error("lha:" + cap.id, String(err && err.message || err));
1951
+ return;
1952
+ } finally {
1953
+ engine.sweeping = prevSweeping;
1954
+ }
1955
+ if (engine.gateHit || stamp() !== sweepOwnersBefore) {
1956
+ b.closed = true;
1957
+ sink.closeBinding(b.key);
1958
+ return;
1959
+ }
1960
+ if (html === b.last) return;
1961
+ const before = attrNames(b.last);
1962
+ const after = attrNames(html);
1963
+ const removed = before.filter(n => !after.includes(n));
1964
+ b.last = html;
1965
+ sink.attr(String(cap.id), html, removed);
1966
+ }
1967
+ };
1968
+ sink.openBinding(b.key, b);
1969
+ }
1970
+ };
1971
+ return engine;
1972
+ }
1973
+ function attrNames(text) {
1974
+ const names = [];
1975
+ const re = /(?:^|\s)([^\s=/>"']+)(?:="[^"]*")?/g;
1976
+ let m;
1977
+ while (m = re.exec(text)) names.push(m[1]);
1978
+ return names;
1979
+ }
1324
1980
  function ssr(t) {
1325
1981
  const len = arguments.length;
1326
1982
  if (len === 1) return {
@@ -1331,13 +1987,54 @@ function ssr(t) {
1331
1987
  let lastGroup = null;
1332
1988
  let lastGroupVal = null;
1333
1989
  let lastGroupIdx = 0;
1990
+ const live = sharedConfig.context && sharedConfig.context.liveHoles;
1991
+ const hp = live ? holeContentPositions(t) : null;
1992
+ let lastOpen = null;
1993
+ let cap = null;
1994
+ if (live && hp.openOff[0] >= 0) lastOpen = {
1995
+ r: null,
1996
+ seg: -1,
1997
+ off: hp.openOff[0]
1998
+ };
1999
+ const captureStart = () => {
2000
+ if (cap) return true;
2001
+ if (!lastOpen || live.suppressed || live.sweeping || !live.active()) return false;
2002
+ if (lastOpen.r !== result || result !== null && lastOpen.seg !== result.t.length - 1) {
2003
+ return false;
2004
+ }
2005
+ const id = live.mint();
2006
+ const inject = ` data-lha="${id}"`;
2007
+ let prefix;
2008
+ if (result === null) {
2009
+ s = s.slice(0, lastOpen.off) + inject + s.slice(lastOpen.off);
2010
+ prefix = s.slice(lastOpen.off + inject.length);
2011
+ } else {
2012
+ const seg = result.t[lastOpen.seg];
2013
+ result.t[lastOpen.seg] = seg.slice(0, lastOpen.off) + inject + seg.slice(lastOpen.off);
2014
+ prefix = result.t[lastOpen.seg].slice(lastOpen.off + inject.length);
2015
+ }
2016
+ cap = {
2017
+ id,
2018
+ parts: [prefix],
2019
+ base: prefix
2020
+ };
2021
+ return true;
2022
+ };
1334
2023
  for (let i = 1; i < len; i++) {
1335
2024
  const hole = arguments[i];
1336
2025
  const ht = typeof hole;
1337
2026
  if (ht === "string") {
1338
2027
  if (result === null) s += hole;else result.t[result.t.length - 1] += hole;
2028
+ if (cap) {
2029
+ cap.parts.push(hole);
2030
+ cap.base += hole;
2031
+ }
1339
2032
  } else if (ht === "number") {
1340
2033
  if (result === null) s += hole;else result.t[result.t.length - 1] += hole;
2034
+ if (cap) {
2035
+ cap.parts.push("" + hole);
2036
+ cap.base += hole;
2037
+ }
1341
2038
  } else if (hole == null || ht === "boolean") ; else if (ht === "function" && hole.$g) {
1342
2039
  let value;
1343
2040
  let hasValue = false;
@@ -1361,7 +2058,14 @@ function ssr(t) {
1361
2058
  if (Array.isArray(lastGroupVal)) {
1362
2059
  value = lastGroupVal[lastGroupIdx++];
1363
2060
  hasValue = true;
2061
+ if (live && !hp.pos[i - 1] && captureStart()) {
2062
+ cap.parts.push({
2063
+ g: hole,
2064
+ i: lastGroupIdx - 1
2065
+ });
2066
+ }
1364
2067
  } else {
2068
+ cap = null;
1365
2069
  result.h.push(ssrGroupSlot(lastGroupVal.fn, lastGroupIdx++));
1366
2070
  result.p.push(lastGroupVal.p);
1367
2071
  result.t.push("");
@@ -1371,6 +2075,7 @@ function ssr(t) {
1371
2075
  const vt = typeof value;
1372
2076
  if (vt === "string" || vt === "number") {
1373
2077
  if (result === null) s += value;else result.t[result.t.length - 1] += value;
2078
+ if (cap && !hp.pos[i - 1]) cap.base += value;
1374
2079
  } else if (value == null || vt === "boolean") ; else if (result !== null) {
1375
2080
  resolveSSRNode(value, result);
1376
2081
  } else {
@@ -1388,19 +2093,67 @@ function ssr(t) {
1388
2093
  }
1389
2094
  }
1390
2095
  }
1391
- } else if (result !== null) {
1392
- resolveSSRNode(hole, result);
1393
2096
  } else if (ht === "function") {
1394
- const r = tryResolveFunctionHole(hole);
1395
- if (typeof r === "string") s += r;else {
1396
- result = {
1397
- t: [s],
1398
- h: [],
1399
- p: []
1400
- };
1401
- s = "";
1402
- appendResolvedNode(result, r);
2097
+ let liveNode = null;
2098
+ if (live && hp.pos[i - 1] && (liveNode = live.content(hole)) !== null) {
2099
+ if (typeof liveNode === "string") {
2100
+ if (result === null) s += liveNode;else result.t[result.t.length - 1] += liveNode;
2101
+ } else {
2102
+ if (result === null) {
2103
+ result = {
2104
+ t: [s],
2105
+ h: [],
2106
+ p: []
2107
+ };
2108
+ s = "";
2109
+ }
2110
+ resolveSSRNode(liveNode, result);
2111
+ }
2112
+ } else if (result !== null) {
2113
+ const inTag = live && !hp.pos[i - 1];
2114
+ const capturing = inTag && captureStart();
2115
+ const li = capturing ? result.t.length - 1 : 0;
2116
+ const before = capturing ? result.t[li].length : 0;
2117
+ if (live) live.suppressed++;
2118
+ try {
2119
+ resolveSSRNode(hole, result);
2120
+ } finally {
2121
+ if (live) live.suppressed--;
2122
+ }
2123
+ if (capturing) {
2124
+ if (result.t.length - 1 === li) {
2125
+ cap.base += result.t[li].slice(before);
2126
+ cap.parts.push({
2127
+ f: hole
2128
+ });
2129
+ } else {
2130
+ cap = null;
2131
+ }
2132
+ }
2133
+ } else {
2134
+ const capturing = live && !hp.pos[i - 1] && captureStart();
2135
+ const r = tryResolveFunctionHole(hole);
2136
+ if (typeof r === "string") {
2137
+ s += r;
2138
+ if (capturing) {
2139
+ cap.base += r;
2140
+ cap.parts.push({
2141
+ f: hole
2142
+ });
2143
+ }
2144
+ } else {
2145
+ if (capturing) cap = null;
2146
+ result = {
2147
+ t: [s],
2148
+ h: [],
2149
+ p: []
2150
+ };
2151
+ s = "";
2152
+ appendResolvedNode(result, r);
2153
+ }
1403
2154
  }
2155
+ } else if (result !== null) {
2156
+ resolveSSRNode(hole, result);
1404
2157
  } else {
1405
2158
  const r = tryResolveString(hole);
1406
2159
  if (typeof r === "string") {
@@ -1416,6 +2169,32 @@ function ssr(t) {
1416
2169
  }
1417
2170
  }
1418
2171
  const next = t[i];
2172
+ if (live) {
2173
+ if (cap) {
2174
+ const co = hp.closeOff[i];
2175
+ if (co >= 0) {
2176
+ const tail = next.slice(0, co);
2177
+ cap.parts.push(tail);
2178
+ cap.base += tail;
2179
+ live.attr(cap);
2180
+ cap = null;
2181
+ } else {
2182
+ cap.parts.push(next);
2183
+ cap.base += next;
2184
+ }
2185
+ }
2186
+ if (hp.openOff[i] >= 0) {
2187
+ lastOpen = result === null ? {
2188
+ r: null,
2189
+ seg: -1,
2190
+ off: s.length + hp.openOff[i]
2191
+ } : {
2192
+ r: result,
2193
+ seg: result.t.length - 1,
2194
+ off: result.t[result.t.length - 1].length + hp.openOff[i]
2195
+ };
2196
+ }
2197
+ }
1419
2198
  if (result === null) s += next;else result.t[result.t.length - 1] += next;
1420
2199
  }
1421
2200
  if (result === null) return {
@@ -1577,18 +2356,6 @@ function getHydrationKey() {
1577
2356
  function applyRef(r, element) {
1578
2357
  Array.isArray(r) ? r.flat(Infinity).forEach(f => f && f(element)) : r(element);
1579
2358
  }
1580
- function useAssets(fn) {
1581
- sharedConfig.context.assets.push(() => resolveSSRSync(escape(fn())));
1582
- }
1583
- function getAssets() {
1584
- const assets = sharedConfig.context.assets;
1585
- let out = "";
1586
- for (let i = 0, len = assets.length; i < len; i++) out += assets[i]();
1587
- return out;
1588
- }
1589
- function Assets(props) {
1590
- useAssets(() => props.children);
1591
- }
1592
2359
  function generateHydrationScript({
1593
2360
  eventNames = ["click", "input"],
1594
2361
  nonce
@@ -1605,17 +2372,11 @@ function allSettled(promises) {
1605
2372
  return;
1606
2373
  });
1607
2374
  }
1608
- function resolveAssetsHtml(assets) {
1609
- if (!assets || !assets.length) return "";
1610
- let out = "";
1611
- for (let i = 0, len = assets.length; i < len; i++) out += assets[i]();
1612
- return out;
1613
- }
1614
- function assembleDocument(html, assetsHtml, emittedAssets, inlineStyles, scripts, nonce, headTags, onHead) {
2375
+ function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, headTags, onHead) {
1615
2376
  const scriptTag = scripts ? `<script${nonce ? ` nonce="${nonce}"` : ""}>${scripts}</script>` : "";
1616
2377
  const headTagsHtml = headTags ? headTags.html : "";
1617
2378
  const headPrelude = headTags ? headTags.prelude : "";
1618
- if (!onHead && !assetsHtml && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !(inlineStyles && inlineStyles.size)) {
2379
+ if (!onHead && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !(inlineStyles && inlineStyles.size)) {
1619
2380
  if (!scriptTag) return html;
1620
2381
  const xs = html.indexOf("<!--xs-->");
1621
2382
  return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
@@ -1630,13 +2391,13 @@ function assembleDocument(html, assetsHtml, emittedAssets, inlineStyles, scripts
1630
2391
  const headIdx = html.indexOf("</head>");
1631
2392
  if (headIdx === -1) {
1632
2393
  if (onHead) {
1633
- onHead(headPrelude + headTagsHtml + (assetsHtml || "") + renderHeadAssets(emittedAssets, inlineStyles, nonce));
2394
+ onHead(headPrelude + headTagsHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce));
1634
2395
  }
1635
2396
  if (!scriptTag) return html;
1636
2397
  const xs = html.indexOf("<!--xs-->");
1637
2398
  return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
1638
2399
  }
1639
- const head = headTagsHtml + (assetsHtml || "") + renderHeadAssets(emittedAssets, inlineStyles, nonce);
2400
+ const head = headTagsHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce);
1640
2401
  if (!scriptTag) return html.slice(0, headIdx) + head + html.slice(headIdx);
1641
2402
  const xsIdx = html.indexOf("<!--xs-->");
1642
2403
  if (xsIdx === -1) return html.slice(0, headIdx) + head + html.slice(headIdx) + scriptTag;
@@ -1769,7 +2530,6 @@ function tryResolveString(node) {
1769
2530
  merge: node
1770
2531
  };
1771
2532
  if (node.t === undefined) {
1772
- console.warn(`Unrecognized value. Skipped inserting`, node);
1773
2533
  return "";
1774
2534
  }
1775
2535
  return Array.isArray(node.t) ? node.t[0] : node.t;
@@ -1794,13 +2554,19 @@ function resolveSSRNode(node, result = {
1794
2554
  if (t === "string" || t === "number") {
1795
2555
  result.t[result.t.length - 1] += node;
1796
2556
  } else if (node == null || t === "boolean") ; else if (Array.isArray(node)) {
1797
- let prevNonObj = false;
1798
- for (let i = 0, len = node.length; i < len; i++) {
1799
- const item = node[i];
1800
- const itemNonObj = item !== null && typeof item !== "object";
1801
- if (!top && prevNonObj && itemNonObj) result.t[result.t.length - 1] += `<!--!$-->`;
1802
- prevNonObj = itemNonObj;
1803
- resolveSSRNode(item, result);
2557
+ const slotLive = node.$slot && sharedConfig.context && sharedConfig.context.liveHoles;
2558
+ if (slotLive) slotLive.suppressed++;
2559
+ try {
2560
+ let prevNonObj = false;
2561
+ for (let i = 0, len = node.length; i < len; i++) {
2562
+ const item = node[i];
2563
+ const itemNonObj = item !== null && typeof item !== "object";
2564
+ if (!top && prevNonObj && itemNonObj) result.t[result.t.length - 1] += `<!--!$-->`;
2565
+ prevNonObj = itemNonObj;
2566
+ resolveSSRNode(item, result);
2567
+ }
2568
+ } finally {
2569
+ if (slotLive) slotLive.suppressed--;
1804
2570
  }
1805
2571
  } else if (t === "object") {
1806
2572
  if (node.h) {
@@ -1812,16 +2578,22 @@ function resolveSSRNode(node, result = {
1812
2578
  }
1813
2579
  } else if (node.t !== undefined) {
1814
2580
  result.t[result.t.length - 1] += node.t;
1815
- } else console.warn(`Unrecognized value. Skipped inserting`, node);
2581
+ } else ;
1816
2582
  } else if (t === "function") {
1817
- try {
1818
- resolveSSRNode(node(), result);
1819
- } catch (err) {
1820
- const wrap = buildAsyncWrap(err, node);
1821
- if (wrap) {
1822
- result.h.push(wrap.fn);
1823
- result.p.push(wrap.p);
1824
- result.t.push("");
2583
+ const live = sharedConfig.context && sharedConfig.context.liveHoles;
2584
+ let liveNode = null;
2585
+ if (live && (liveNode = live.content(node)) !== null) {
2586
+ if (typeof liveNode === "string") result.t[result.t.length - 1] += liveNode;else resolveSSRNode(liveNode, result);
2587
+ } else {
2588
+ try {
2589
+ resolveSSRNode(node(), result);
2590
+ } catch (err) {
2591
+ const wrap = buildAsyncWrap(err, node);
2592
+ if (wrap) {
2593
+ result.h.push(wrap.fn);
2594
+ result.p.push(wrap.p);
2595
+ result.t.push("");
2596
+ }
1825
2597
  }
1826
2598
  }
1827
2599
  }
@@ -1836,92 +2608,229 @@ const RequestContext = Symbol.for("solid.RequestContext");
1836
2608
  function getRequestEvent() {
1837
2609
  return globalThis[RequestContext] ? globalThis[RequestContext].getStore() || sharedConfig.context && sharedConfig.context.event || console.warn("RequestEvent is missing. This is most likely due to accessing `getRequestEvent` non-managed async scope in a partially polyfilled environment. Try moving it above all `await` calls.") : undefined;
1838
2610
  }
1839
- function renderToStringAsync(code, options = {}) {
1840
- return new Promise(resolve => renderToStream(code, options).then(resolve));
1841
- }
1842
- function registerElementClaim() {
1843
- return noopCleanup;
1844
- }
1845
- function noopCleanup() {}
1846
- function claimElement(node) {
1847
- return node;
2611
+ function createResponseStub() {
2612
+ return {
2613
+ status: undefined,
2614
+ statusText: undefined,
2615
+ headers: new Headers(),
2616
+ committed: false
2617
+ };
1848
2618
  }
1849
- function claimElementTree(root) {
1850
- return root;
2619
+ function createRequestEvent(request, init) {
2620
+ return {
2621
+ request,
2622
+ locals: {},
2623
+ response: createResponseStub(),
2624
+ ...init
2625
+ };
1851
2626
  }
1852
- function notSup() {
1853
- throw new Error("Client-only API called on the server side. Run client-only code in onMount, or conditionally run client-only component with <Show>.");
2627
+ function reportLostHeaderWrite(method, name) {
2628
+ const message = `Response header write dropped: headers.${method}(${JSON.stringify(String(name))}) ` + "ran after the response head was sent. Write headers before the shell flushes " + "(or before the handler returns).";
2629
+ console.error(message);
1854
2630
  }
1855
-
1856
- const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
1857
- class ResponseEnvelope {
1858
- constructor(response, value) {
1859
- this.response = response;
1860
- this.value = value;
2631
+ function commitResponseStub(stub, {
2632
+ allowLateLocation = false
2633
+ } = {}) {
2634
+ if (!stub || stub.committed) return stub;
2635
+ stub.committed = true;
2636
+ const headers = stub.headers;
2637
+ if (!headers || typeof headers.set !== "function") return stub;
2638
+ for (const method of ["set", "append", "delete"]) {
2639
+ const original = headers[method].bind(headers);
2640
+ headers[method] = function (name, ...rest) {
2641
+ if (allowLateLocation && method === "set" && String(name).toLowerCase() === "location") {
2642
+ return original(name, ...rest);
2643
+ }
2644
+ reportLostHeaderWrite(method, name);
2645
+ };
1861
2646
  }
2647
+ return stub;
1862
2648
  }
1863
- ResponseEnvelope.prototype[ENVELOPE] = true;
1864
- function isResponseEnvelope(value) {
1865
- return !!(value && typeof value === "object" && value[ENVELOPE]);
2649
+ const validRedirectStatuses = /*#__PURE__*/new Set([301, 302, 303, 307, 308]);
2650
+ function getExpectedRedirectStatus(response) {
2651
+ if (response.status && validRedirectStatuses.has(response.status)) return response.status;
2652
+ return 302;
1866
2653
  }
1867
- const HREF = Symbol.for("solid.Href");
1868
- function isHref(value) {
1869
- return !!(value && (typeof value === "object" || typeof value === "function") && value[HREF]);
2654
+ function mergeStubHeaders(target, stub) {
2655
+ if (!stub) return target;
2656
+ stub.headers.forEach((value, key) => {
2657
+ if (key !== "set-cookie") target.set(key, value);
2658
+ });
2659
+ const setCookies = stub.headers.getSetCookie ? stub.headers.getSetCookie() : [];
2660
+ for (const cookie of setCookies) target.append("set-cookie", cookie);
2661
+ return target;
2662
+ }
2663
+ function copyInitHeaders(init) {
2664
+ if (!init || !init.getSetCookie) return new Headers(init);
2665
+ const headers = new Headers();
2666
+ init.forEach((value, key) => {
2667
+ if (key !== "set-cookie") headers.append(key, value);
2668
+ });
2669
+ for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
2670
+ return headers;
2671
+ }
2672
+ const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, "Location"].map(header => header.toLowerCase()));
2673
+ function fillsStubGap(key, headers, response) {
2674
+ if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
2675
+ if (response.body === null && (key === "content-type" || key === "content-length")) return false;
2676
+ return !headers.has(key);
2677
+ }
2678
+ function commitEventResponse(response, event = getRequestEvent()) {
2679
+ const stub = event && event.response;
2680
+ if (!stub || !stub.headers || stub.committed) return response;
2681
+ const cookies = stub.headers.getSetCookie ? stub.headers.getSetCookie() : [];
2682
+ commitResponseStub(stub);
2683
+ let hasGaps = false;
2684
+ stub.headers.forEach((value, key) => {
2685
+ if (fillsStubGap(key, response.headers, response)) hasGaps = true;
2686
+ });
2687
+ if (!cookies.length && !hasGaps) return response;
2688
+ try {
2689
+ for (const cookie of cookies) response.headers.append("Set-Cookie", cookie);
2690
+ stub.headers.forEach((value, key) => {
2691
+ if (fillsStubGap(key, response.headers, response)) response.headers.set(key, value);
2692
+ });
2693
+ return response;
2694
+ } catch {
2695
+ const headers = copyInitHeaders(response.headers);
2696
+ for (const cookie of cookies) headers.append("Set-Cookie", cookie);
2697
+ stub.headers.forEach((value, key) => {
2698
+ if (fillsStubGap(key, headers, response)) headers.set(key, value);
2699
+ });
2700
+ return new Response(response.body, {
2701
+ status: response.status,
2702
+ statusText: response.statusText,
2703
+ headers
2704
+ });
2705
+ }
1870
2706
  }
1871
- const REVALIDATE_HEADER = "X-Revalidate";
1872
- function initWithRevalidate(init) {
1873
- const {
1874
- revalidate,
1875
- ...responseInit
1876
- } = init;
1877
- const headers = new Headers(responseInit.headers);
1878
- revalidate !== undefined && headers.set(REVALIDATE_HEADER, revalidate.toString());
2707
+ function deriveHead(stub, responseInit = {}) {
2708
+ const headers = mergeStubHeaders(copyInitHeaders(responseInit.headers), stub);
2709
+ const status = stub && stub.status || responseInit.status || 200;
2710
+ const statusText = stub && stub.statusText || responseInit.statusText || undefined;
1879
2711
  return {
1880
- responseInit,
2712
+ status,
2713
+ statusText,
1881
2714
  headers
1882
2715
  };
1883
2716
  }
1884
- function redirect(url, init = 302) {
1885
- if (typeof url !== "string" && !isHref(url)) {
1886
- throw new TypeError("redirect() expects a string URL or an Href-branded value (Symbol.for('solid.Href')).");
1887
- }
2717
+ function escapeAttribute(value) {
2718
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
2719
+ }
2720
+ function createSSRResponse(result, event, options = {}) {
2721
+ const stub = event && event.response;
1888
2722
  const {
1889
2723
  responseInit,
1890
- headers
1891
- } = initWithRevalidate(typeof init === "number" ? {
1892
- status: init
1893
- } : init);
1894
- if (responseInit.status === undefined) {
1895
- responseInit.status = 302;
2724
+ nonce,
2725
+ transformChunk
2726
+ } = options;
2727
+ if (typeof result === "string") {
2728
+ if (stub) commitResponseStub(stub);
2729
+ const head = deriveHead(stub, responseInit);
2730
+ if (stub && stub.headers.get("Location")) {
2731
+ return new Response(null, {
2732
+ status: getExpectedRedirectStatus(stub),
2733
+ headers: head.headers
2734
+ });
2735
+ }
2736
+ if (!head.headers.has("content-type")) {
2737
+ head.headers.set("content-type", "text/html; charset=utf-8");
2738
+ }
2739
+ return new Response(transformChunk ? transformChunk(result) : result, {
2740
+ status: head.status,
2741
+ statusText: head.statusText,
2742
+ headers: head.headers
2743
+ });
1896
2744
  }
1897
- headers.set("Location", String(url));
1898
- return new Response(null, {
1899
- ...responseInit,
1900
- headers
2745
+ const encoder = new TextEncoder();
2746
+ return new Promise(resolve => {
2747
+ let controller;
2748
+ let closed = false;
2749
+ let flushed = false;
2750
+ const enqueue = value => {
2751
+ if (closed || !controller) return;
2752
+ try {
2753
+ controller.enqueue(encoder.encode(value));
2754
+ } catch {
2755
+ closed = true;
2756
+ }
2757
+ };
2758
+ result.pipe({
2759
+ write(chunk) {
2760
+ if (!flushed) {
2761
+ flushed = true;
2762
+ if (stub) commitResponseStub(stub, {
2763
+ allowLateLocation: true
2764
+ });
2765
+ const head = deriveHead(stub, responseInit);
2766
+ if (stub && stub.headers.get("Location")) {
2767
+ closed = true;
2768
+ resolve(new Response(null, {
2769
+ status: getExpectedRedirectStatus(stub),
2770
+ headers: head.headers
2771
+ }));
2772
+ return;
2773
+ }
2774
+ if (!head.headers.has("content-type")) {
2775
+ head.headers.set("content-type", "text/html; charset=utf-8");
2776
+ }
2777
+ resolve(new Response(new ReadableStream({
2778
+ start(c) {
2779
+ controller = c;
2780
+ },
2781
+ cancel() {
2782
+ closed = true;
2783
+ }
2784
+ }), {
2785
+ status: head.status,
2786
+ statusText: head.statusText,
2787
+ headers: head.headers
2788
+ }));
2789
+ }
2790
+ enqueue(transformChunk ? transformChunk(chunk) : chunk);
2791
+ },
2792
+ end() {
2793
+ if (closed || !controller) return;
2794
+ const location = stub && stub.headers.get("Location");
2795
+ if (location) {
2796
+ const attr = nonce ? ` nonce="${escapeAttribute(nonce)}"` : "";
2797
+ enqueue(`<script${attr}>window.location=${JSON.stringify(location).replace(/</g, "\\u003c")}</script>`);
2798
+ }
2799
+ closed = true;
2800
+ try {
2801
+ controller.close();
2802
+ } catch {}
2803
+ }
2804
+ });
1901
2805
  });
1902
2806
  }
1903
- function reload(init = {}) {
1904
- const {
1905
- responseInit,
1906
- headers
1907
- } = initWithRevalidate(init);
1908
- return new Response(null, {
1909
- ...responseInit,
1910
- headers
1911
- });
2807
+ function composeMiddleware(middlewares) {
2808
+ return function run(request, next) {
2809
+ let index = -1;
2810
+ function dispatch(i, req) {
2811
+ if (i <= index) return Promise.reject(new Error("next() called multiple times"));
2812
+ index = i;
2813
+ if (i === middlewares.length) return Promise.resolve(next(req));
2814
+ return Promise.resolve(middlewares[i](req, override => dispatch(i + 1, override || req)));
2815
+ }
2816
+ return dispatch(0, request);
2817
+ };
1912
2818
  }
1913
- function respond(value, init = {}) {
1914
- const {
1915
- responseInit,
1916
- headers
1917
- } = initWithRevalidate(init);
1918
- headers.set("Content-Type", "application/json");
1919
- return new ResponseEnvelope(new Response(JSON.stringify(value), {
1920
- ...responseInit,
1921
- headers
1922
- }), value);
2819
+ function registerElementClaim() {
2820
+ return noopCleanup;
2821
+ }
2822
+ function noopCleanup() {}
2823
+ function claimElement(node) {
2824
+ return node;
2825
+ }
2826
+ function claimElementTree(root) {
2827
+ return root;
2828
+ }
2829
+ function notSup() {
2830
+ throw new Error("Client-only API called on the server side. Run client-only code in onMount, or conditionally run client-only component with <Show>.");
1923
2831
  }
1924
2832
 
2833
+ setContainerTraceResolver(getProjectionTrace);
1925
2834
  const isServer = true;
1926
2835
  const isDev = false;
1927
2836
  function dynamic(source) {
@@ -1987,18 +2896,39 @@ function clientOnly(_fn, _options = {}, moduleUrl) {
1987
2896
  return createMemo(() => props.fallback);
1988
2897
  };
1989
2898
  }
2899
+ const statusLedgers = /* @__PURE__ */new WeakMap();
2900
+ const headerLedgers = /* @__PURE__ */new WeakMap();
1990
2901
  function httpStatus(code, text) {
1991
2902
  const event = getRequestEvent();
1992
2903
  const response = event && event.response;
1993
2904
  if (response && !response.committed) {
1994
- const prevStatus = response.status;
1995
- const prevStatusText = response.statusText;
2905
+ let ledger = statusLedgers.get(response);
2906
+ if (!ledger) {
2907
+ ledger = {
2908
+ base: {
2909
+ status: response.status,
2910
+ statusText: response.statusText
2911
+ },
2912
+ live: []
2913
+ };
2914
+ statusLedgers.set(response, ledger);
2915
+ }
2916
+ const declaration = {
2917
+ status: code,
2918
+ statusText: text
2919
+ };
2920
+ ledger.live.push(declaration);
1996
2921
  response.status = code;
1997
2922
  response.statusText = text;
1998
2923
  onCleanup(() => {
1999
2924
  if (response.committed) return;
2000
- response.status = prevStatus;
2001
- response.statusText = prevStatusText;
2925
+ const index = ledger.live.indexOf(declaration);
2926
+ if (index < 0) return;
2927
+ ledger.live.splice(index, 1);
2928
+ const effective = ledger.live.length ? ledger.live[ledger.live.length - 1] : ledger.base;
2929
+ response.status = effective.status;
2930
+ response.statusText = effective.statusText;
2931
+ if (!ledger.live.length) statusLedgers.delete(response);
2002
2932
  });
2003
2933
  }
2004
2934
  }
@@ -2007,13 +2937,41 @@ function httpHeader(name, value, options) {
2007
2937
  const response = event && event.response;
2008
2938
  if (response && !response.committed) {
2009
2939
  const headers = response.headers;
2010
- const prev = headers.get(name);
2011
- if (options && options.append) headers.append(name, value);else headers.set(name, value);
2940
+ const key = name.toLowerCase();
2941
+ const setCookie = key === "set-cookie";
2942
+ let ledgers = headerLedgers.get(response);
2943
+ if (!ledgers) headerLedgers.set(response, ledgers = new Map());
2944
+ let ledger = ledgers.get(key);
2945
+ if (!ledger) {
2946
+ ledger = {
2947
+ base: setCookie ? headers.getSetCookie() : headers.get(name),
2948
+ live: []
2949
+ };
2950
+ ledgers.set(key, ledger);
2951
+ }
2952
+ const declaration = {
2953
+ value,
2954
+ append: !!(options && options.append)
2955
+ };
2956
+ ledger.live.push(declaration);
2957
+ if (declaration.append) headers.append(name, value);else headers.set(name, value);
2012
2958
  onCleanup(() => {
2013
2959
  if (response.committed) return;
2014
- if (prev === null) headers.delete(name);else headers.set(name, prev);
2960
+ const index = ledger.live.indexOf(declaration);
2961
+ if (index < 0) return;
2962
+ ledger.live.splice(index, 1);
2963
+ headers.delete(name);
2964
+ if (setCookie) {
2965
+ for (const cookie of ledger.base) headers.append(name, cookie);
2966
+ } else if (ledger.base !== null) {
2967
+ headers.set(name, ledger.base);
2968
+ }
2969
+ for (const d of ledger.live) {
2970
+ if (d.append) headers.append(name, d.value);else headers.set(name, d.value);
2971
+ }
2972
+ if (!ledger.live.length) ledgers.delete(key);
2015
2973
  });
2016
2974
  }
2017
2975
  }
2018
2976
 
2019
- export { Assets, ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, HREF, HydrationScript, MathMLElements, Namespaces, Portal, REVALIDATE_HEADER, RawTextElements, RequestContext, ResponseEnvelope, SVGElements, VoidElements, notSup as acquireAsset, notSup as addEvent, applyRef, notSup as assign, claimElement, claimElementTree, notSup as className, clientOnly, notSup as delegateEvents, dynamic, notSup as dynamicProperty, effect, escape, generateHydrationScript, getAssets, notSup as getDelegatedRoot, getHydrationKey, notSup as getNextElement, notSup as getNextMarker, notSup as getNextMatch, getRequestEvent, httpHeader, httpStatus, notSup as hydrate, notSup as insert, isDev, isHref, isResponseEnvelope, isServer, memo, redirect, notSup as ref, notSup as registerDelegatedContainer, notSup as registerDelegatedRoot, registerElementClaim, reload, notSup as render, renderToStream, renderToString, renderToStringAsync, respond, notSup as runHydrationEvents, notSup as setAttribute, notSup as setAttributeNS, notSup as setProperty, notSup as setStyleProperty, notSup as spread, ssr, ssrAttribute, ssrClassName, ssrElement, ssrGroup, ssrHydrationKey, ssrStyle, ssrStyleProperty, notSup as style, notSup as template, notSup as unregisterDelegatedContainer, notSup as unregisterDelegatedRoot, useAssets, useHead };
2977
+ export { 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, respond, notSup as runHydrationEvents, serializeCookie, notSup as setAttribute, notSup as setAttributeNS, notSup as setProperty, notSup as setStyleProperty, notSup as spread, ssr, ssrAttribute, ssrClassName, ssrElement, ssrGroup, ssrHydrationKey, ssrStyle, ssrStyleProperty, notSup as style, notSup as template, notSup as unregisterDelegatedContainer, notSup as unregisterDelegatedRoot, useHead };