@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
@@ -4,19 +4,129 @@ var solidJs = require('solid-js');
4
4
  var seroval = require('seroval');
5
5
  var web = require('seroval-plugins/web');
6
6
 
7
+ const STATE = Symbol.for("dom-expressions.container-trace-state");
8
+ const state = globalThis[STATE] || (globalThis[STATE] = {
9
+ materialized: new WeakMap(),
10
+ materializedValues: new WeakSet()
11
+ });
12
+ function setContainerTraceResolver(fn) {
13
+ state.resolveTrace = fn;
14
+ }
15
+ function isContainerTraced(value) {
16
+ const resolve = state.resolveTrace;
17
+ return !!(resolve && value && typeof value === "object" && resolve(value));
18
+ }
19
+ const TRACE = Symbol.for("dom-expressions.container-trace");
20
+ function envelopeContainerTraces(value) {
21
+ if (!state.resolveTrace || value == null || typeof value !== "object") return value;
22
+ const trace = state.resolveTrace(value);
23
+ if (trace) return {
24
+ [TRACE]: trace
25
+ };
26
+ if (Array.isArray(value)) {
27
+ let out = value;
28
+ for (let i = 0; i < value.length; i++) {
29
+ const next = envelopeContainerTraces(value[i]);
30
+ if (next !== value[i]) {
31
+ if (out === value) out = value.slice();
32
+ out[i] = next;
33
+ }
34
+ }
35
+ return out;
36
+ }
37
+ if (Object.getPrototypeOf(value) === Object.prototype) {
38
+ let out = value;
39
+ for (const key of Object.keys(value)) {
40
+ const next = envelopeContainerTraces(value[key]);
41
+ if (next !== value[key]) {
42
+ if (out === value) out = {
43
+ ...value
44
+ };
45
+ out[key] = next;
46
+ }
47
+ }
48
+ return out;
49
+ }
50
+ return value;
51
+ }
52
+ function materialize(marker) {
53
+ let value = state.materialized.get(marker.$tr);
54
+ if (value === undefined) {
55
+ value = state.materializeTrace(marker);
56
+ state.materialized.set(marker.$tr, value);
57
+ if (value !== null && typeof value === "object") state.materializedValues.add(value);
58
+ }
59
+ return value;
60
+ }
61
+ function parseTrace(value, ctx) {
62
+ const trace = value[TRACE];
63
+ return {
64
+ a: trace.array ? 1 : 0,
65
+ i: ctx.parse(trace.subscribe())
66
+ };
67
+ }
68
+ const ContainerTracePlugin = {
69
+ tag: "dom-expressions/container-trace",
70
+ test(value) {
71
+ return value != null && typeof value === "object" && TRACE in value;
72
+ },
73
+ parse: {
74
+ sync() {
75
+ throw new Error("A reactive container can only be serialized by a streaming serializer.");
76
+ },
77
+ async async(value, ctx) {
78
+ const trace = value[TRACE];
79
+ return {
80
+ a: trace.array ? 1 : 0,
81
+ i: await ctx.parse(trace.subscribe())
82
+ };
83
+ },
84
+ stream: parseTrace
85
+ },
86
+ serialize(node, ctx) {
87
+ return "{$tr:" + ctx.serialize(node.i) + ",$ta:" + node.a + "}";
88
+ },
89
+ deserialize(node, ctx) {
90
+ const iterable = ctx.deserialize(node.i);
91
+ const marker = {
92
+ $tr: iterable,
93
+ $ta: node.a
94
+ };
95
+ return state.materializeTrace ? materialize(marker) : marker;
96
+ }
97
+ };
98
+
7
99
  const runWithHydrationScope = (id, fn) => solidJs.runWithOwner(solidJs.createOwner({
8
100
  id
9
101
  }), fn);
102
+ const ssrAsyncValue = value => solidJs.createMemo(() => value, {
103
+ serialize: false
104
+ });
10
105
 
11
- const DEFAULT_DISABLED_FEATURES = seroval.Feature.AggregateError | seroval.Feature.BigIntTypedArray;
12
- const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : seroval.Feature.ErrorPrototypeStack;
13
- const HYDRATION_GLOBAL = "_$HY.r";
14
106
  const DEFAULT_WEB_PLUGINS = Object.freeze([web.AbortSignalPlugin,
15
107
  web.CustomEventPlugin, web.DOMExceptionPlugin, web.EventPlugin,
16
- web.FormDataPlugin, web.HeadersPlugin, web.ReadableStreamPlugin, web.RequestPlugin, web.ResponsePlugin, web.URLSearchParamsPlugin, web.URLPlugin]);
108
+ web.FormDataPlugin, web.HeadersPlugin, web.ReadableStreamPlugin, web.RequestPlugin, web.ResponsePlugin, web.URLSearchParamsPlugin, web.URLPlugin,
109
+ ContainerTracePlugin]);
17
110
  function resolveSerializerPlugins(customPlugins) {
18
111
  return customPlugins ? [...customPlugins, ...DEFAULT_WEB_PLUGINS] : [...DEFAULT_WEB_PLUGINS];
19
112
  }
113
+ const JSON_CODEC_DISABLED_FEATURES = seroval.Feature.RegExp;
114
+ const JSON_CODEC_DEPTH_LIMIT = 64;
115
+ function resolveCodecOptions({
116
+ plugins,
117
+ disabledFeatures,
118
+ depthLimit
119
+ } = {}) {
120
+ return {
121
+ plugins: resolveSerializerPlugins(plugins),
122
+ disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
123
+ depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
124
+ };
125
+ }
126
+
127
+ const DEFAULT_DISABLED_FEATURES = seroval.Feature.AggregateError | seroval.Feature.BigIntTypedArray;
128
+ const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : seroval.Feature.ErrorPrototypeStack;
129
+ const HYDRATION_GLOBAL = "_$HY.r";
20
130
  function createSerializer(options) {
21
131
  return new seroval.Serializer({
22
132
  ...options,
@@ -43,34 +153,6 @@ function createHydrationSerializer({
43
153
  function getLocalHeaderScript(id) {
44
154
  return seroval.getCrossReferenceHeader(id) + ";";
45
155
  }
46
- const JSON_CODEC_DISABLED_FEATURES = seroval.Feature.RegExp;
47
- const JSON_CODEC_DEPTH_LIMIT = 64;
48
- function resolveCodecOptions({
49
- plugins,
50
- disabledFeatures,
51
- depthLimit
52
- } = {}) {
53
- return {
54
- plugins: resolveSerializerPlugins(plugins),
55
- disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
56
- depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
57
- };
58
- }
59
- function serializeJSON(value, {
60
- onParse,
61
- onDone,
62
- onError,
63
- ...codecOptions
64
- }) {
65
- const resolved = resolveCodecOptions(codecOptions);
66
- return seroval.toCrossJSONStream(value, {
67
- onParse,
68
- onDone,
69
- onError,
70
- ...resolved,
71
- disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures()
72
- });
73
- }
74
156
  function createJSONSerializer({
75
157
  onData,
76
158
  onDone,
@@ -137,6 +219,146 @@ function createJSONSerializer({
137
219
  };
138
220
  }
139
221
 
222
+ const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
223
+ function isResponseEnvelope(value) {
224
+ return !!(value && typeof value === "object" && value[ENVELOPE]);
225
+ }
226
+ const REVALIDATE_HEADER = "X-Revalidate";
227
+
228
+ function frameAddress(id, args) {
229
+ return args && args.length ? id + ":" + hashArguments(args) : id;
230
+ }
231
+ function hashArguments(args) {
232
+ let hash = 0;
233
+ const text = stableString(args);
234
+ for (let i = 0; i < text.length; i++) {
235
+ hash = (hash << 5) - hash + text.charCodeAt(i);
236
+ hash |= 0;
237
+ }
238
+ return (hash >>> 0).toString(36);
239
+ }
240
+ function stableString(value, seen) {
241
+ if (value === null || typeof value !== "object") {
242
+ return typeof value === "bigint" ? value + "n" : String(value);
243
+ }
244
+ if (value instanceof Date) return "Date:" + value.getTime();
245
+ seen || (seen = new Set());
246
+ if (seen.has(value)) return "~";
247
+ seen.add(value);
248
+ if (value instanceof Map) {
249
+ const entries = [];
250
+ for (const [k, v] of value) {
251
+ entries.push(stableString(k, seen) + "=>" + stableString(v, seen));
252
+ }
253
+ return "Map{" + entries.sort().join(",") + "}";
254
+ }
255
+ if (value instanceof Set) {
256
+ const members = [];
257
+ for (const v of value) members.push(stableString(v, seen));
258
+ return "Set{" + members.sort().join(",") + "}";
259
+ }
260
+ if (Array.isArray(value)) {
261
+ let out = "[";
262
+ for (let i = 0; i < value.length; i++) out += (i ? "," : "") + stableString(value[i], seen);
263
+ return out + "]";
264
+ }
265
+ const keys = Object.keys(value).sort();
266
+ let out = "{";
267
+ for (let i = 0; i < keys.length; i++) {
268
+ out += (i ? "," : "") + keys[i] + ":" + stableString(value[keys[i]], seen);
269
+ }
270
+ return out + "}";
271
+ }
272
+ const ERROR_HEADER = "X-Server-Function-Error";
273
+ const BODY_FORMAT_HEADER = "X-Server-Function-Format";
274
+ const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
275
+ function createChunk(data) {
276
+ const encoder = new TextEncoder();
277
+ const encodeData = encoder.encode(data);
278
+ const bytes = encodeData.length;
279
+ const chunk = new Uint8Array(12 + bytes);
280
+ chunk.set(encoder.encode(`;0x${bytes.toString(16).padStart(8, "0")};`));
281
+ chunk.set(encodeData, 12);
282
+ return chunk;
283
+ }
284
+ class ChunkReader {
285
+ constructor(stream) {
286
+ this.reader = stream.getReader();
287
+ this.buffer = new Uint8Array(0);
288
+ this.done = false;
289
+ }
290
+ async readChunk() {
291
+ const chunk = await this.reader.read();
292
+ if (!chunk.done) {
293
+ const newBuffer = new Uint8Array(this.buffer.length + chunk.value.length);
294
+ newBuffer.set(this.buffer);
295
+ newBuffer.set(chunk.value, this.buffer.length);
296
+ this.buffer = newBuffer;
297
+ } else {
298
+ this.done = true;
299
+ }
300
+ }
301
+ async next() {
302
+ while (this.buffer.length < 12) {
303
+ if (this.done) {
304
+ if (this.buffer.length === 0) return {
305
+ done: true,
306
+ value: undefined
307
+ };
308
+ throw new Error("Malformed server function stream.");
309
+ }
310
+ await this.readChunk();
311
+ }
312
+ const decoder = new TextDecoder();
313
+ const bytes = Number.parseInt(decoder.decode(this.buffer.subarray(1, 11)), 16);
314
+ if (Number.isNaN(bytes)) {
315
+ throw new Error("Malformed server function stream.");
316
+ }
317
+ while (bytes > this.buffer.length - 12) {
318
+ if (this.done) {
319
+ throw new Error("Malformed server function stream.");
320
+ }
321
+ await this.readChunk();
322
+ }
323
+ const partial = decoder.decode(this.buffer.subarray(12, 12 + bytes));
324
+ this.buffer = this.buffer.subarray(12 + bytes);
325
+ return {
326
+ done: false,
327
+ value: partial
328
+ };
329
+ }
330
+ async drain(interpret) {
331
+ while (true) {
332
+ const result = await this.next();
333
+ if (result.done) {
334
+ break;
335
+ }
336
+ interpret(result.value);
337
+ }
338
+ }
339
+ }
340
+ function serializeStream(value, codecOptions) {
341
+ return new ReadableStream({
342
+ async start(controller) {
343
+ const {
344
+ serializeJSON
345
+ } = await import('@solidjs/web/serialization');
346
+ serializeJSON(value, {
347
+ ...codecOptions,
348
+ onParse(node) {
349
+ controller.enqueue(createChunk(JSON.stringify(node)));
350
+ },
351
+ onDone() {
352
+ controller.close();
353
+ },
354
+ onError(error) {
355
+ controller.error(error);
356
+ }
357
+ });
358
+ }
359
+ });
360
+ }
361
+
140
362
  const HEAD_ELIGIBLE_TAGS = new Set(["title", "meta", "link", "style", "script", "base"]);
141
363
  const HEAD_ATTR_NAME = /^[a-zA-Z_][a-zA-Z0-9_:.-]*$/;
142
364
  const RESOURCE_LINK_RELS = new Set(["preload", "modulepreload", "prefetch", "preconnect", "dns-prefetch", "stylesheet"]);
@@ -207,7 +429,6 @@ function resolveHead(groups) {
207
429
  }
208
430
  for (const [identity, tags] of byIdentity) {
209
431
  if (identity === "title") {
210
- if (tags.length > 1) console.warn("Multiple <title> tags in one head group; the last one wins.");
211
432
  winners.set(identity, {
212
433
  seq: group.seq,
213
434
  tags: [tags[tags.length - 1]]
@@ -377,7 +598,8 @@ function createHeadRegistry() {
377
598
  resources: new Set(),
378
599
  eagerHtml: "",
379
600
  flushed: null,
380
- shellFlushed: false
601
+ shellFlushed: false,
602
+ parkedResources: []
381
603
  };
382
604
  }
383
605
  function registerHeadTags(registry, context, tracking, emitResource, nonce, tags) {
@@ -391,14 +613,24 @@ function registerHeadTags(registry, context, tracking, emitResource, nonce, tags
391
613
  return;
392
614
  }
393
615
  if (!Array.isArray(tags)) tags = [tags];
616
+ const probe = solidJs.sharedConfig.context && solidJs.sharedConfig.context._loadingPhase;
394
617
  let replaceable = null;
395
618
  for (let i = 0; i < tags.length; i++) {
396
619
  const desc = tags[i];
397
620
  if (!desc || !HEAD_ELIGIBLE_TAGS.has(desc.tag)) {
398
- console.warn(`useHead: ignoring non-head tag`, desc);
399
621
  continue;
400
622
  }
401
623
  const cls = classifyHeadTag(desc);
624
+ if (probe && !cls.resource) {
625
+ try {
626
+ evalHeadProps(desc.props || {}, cls.rel !== undefined ? {
627
+ rel: cls.rel
628
+ } : undefined);
629
+ evalHeadValue(desc.key);
630
+ } catch (err) {
631
+ if (solidJs.ssrHandleError(err)) throw err;
632
+ }
633
+ }
402
634
  if (cls.resource) {
403
635
  emitHeadResource(registry, context, tracking, emitResource, nonce, desc, cls.rel);
404
636
  } else {
@@ -415,6 +647,51 @@ function registerHeadTags(registry, context, tracking, emitResource, nonce, tags
415
647
  tags: replaceable
416
648
  });
417
649
  }
650
+ function headShellReady(registry, block) {
651
+ let ready = true;
652
+ const pends = err => {
653
+ const source = solidJs.ssrHandleError(err, true);
654
+ if (!source) return false;
655
+ block(source);
656
+ ready = false;
657
+ return true;
658
+ };
659
+ const parked = registry.parkedResources;
660
+ for (let i = parked.length - 1; i >= 0; i--) {
661
+ const {
662
+ desc,
663
+ rel,
664
+ emit
665
+ } = parked[i];
666
+ try {
667
+ evalHeadProps(desc.props || {}, rel !== undefined ? {
668
+ rel
669
+ } : undefined);
670
+ } catch (err) {
671
+ if (pends(err)) continue;
672
+ parked.splice(i, 1);
673
+ continue;
674
+ }
675
+ parked.splice(i, 1);
676
+ emit();
677
+ }
678
+ for (let i = 0; i < registry.pending.length; i++) {
679
+ const reg = registry.pending[i];
680
+ if (reg.boundary !== "" || reg.list) continue;
681
+ for (let j = 0; j < reg.tags.length; j++) {
682
+ const desc = reg.tags[j];
683
+ try {
684
+ evalHeadProps(desc.props || {}, desc.rel !== undefined ? {
685
+ rel: desc.rel
686
+ } : undefined);
687
+ evalHeadValue(desc.key);
688
+ } catch (err) {
689
+ pends(err);
690
+ }
691
+ }
692
+ }
693
+ return ready;
694
+ }
418
695
  function emitHeadResource(registry, context, tracking, emitResource, nonce, desc, rel) {
419
696
  let props;
420
697
  try {
@@ -422,7 +699,16 @@ function emitHeadResource(registry, context, tracking, emitResource, nonce, desc
422
699
  rel
423
700
  } : undefined);
424
701
  } catch (err) {
425
- console.warn(`useHead: error evaluating resource tag props`, err);
702
+ const loadingPhase = solidJs.sharedConfig.context && solidJs.sharedConfig.context._loadingPhase;
703
+ if (loadingPhase && solidJs.ssrHandleError(err)) throw err;
704
+ if (!loadingPhase && !context._currentBoundaryId && !registry.shellFlushed && typeof context.block === "function" && solidJs.ssrHandleError(err, true)) {
705
+ registry.parkedResources.push({
706
+ desc,
707
+ rel,
708
+ emit: () => emitHeadResource(registry, context, tracking, emitResource, nonce, desc, rel)
709
+ });
710
+ return;
711
+ }
426
712
  return;
427
713
  }
428
714
  const identity = resourceIdentity(desc.tag, props);
@@ -484,7 +770,6 @@ function commitHeadBoundary(registry, boundary, isPendingFragment) {
484
770
  try {
485
771
  resolved = reg.list();
486
772
  } catch (err) {
487
- console.warn(`useHead: error evaluating head group membership`, err);
488
773
  continue;
489
774
  }
490
775
  if (!Array.isArray(resolved)) resolved = [resolved];
@@ -492,7 +777,6 @@ function commitHeadBoundary(registry, boundary, isPendingFragment) {
492
777
  for (let j = 0; j < resolved.length; j++) {
493
778
  const desc = resolved[j];
494
779
  if (!desc || !HEAD_ELIGIBLE_TAGS.has(desc.tag)) {
495
- console.warn(`useHead: ignoring non-head tag`, desc);
496
780
  continue;
497
781
  }
498
782
  const cls = classifyHeadTag(desc);
@@ -518,12 +802,10 @@ function commitHeadBoundary(registry, boundary, isPendingFragment) {
518
802
  } : undefined);
519
803
  key = evalHeadValue(desc.key);
520
804
  } catch (err) {
521
- console.warn(`useHead: error evaluating tag props`, err);
522
805
  continue;
523
806
  }
524
807
  const identity = replaceableIdentity(desc.tag, props, key, "u:" + registry.uniq++);
525
808
  if ((identity === "base" || identity === "charset") && registry.shellFlushed) {
526
- console.warn(`useHead: <${desc.tag}> (${identity}) registered after shell flush is ignored`);
527
809
  continue;
528
810
  }
529
811
  tags.push({
@@ -605,7 +887,6 @@ function flushHeadFragment(registry, boundary) {
605
887
  for (const name in t.props) {
606
888
  if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
607
889
  if (!HEAD_ATTR_NAME.test(name)) {
608
- console.warn(`useHead: ignoring invalid attribute name "${name}"`);
609
890
  continue;
610
891
  }
611
892
  const v = t.props[name];
@@ -623,7 +904,6 @@ function renderHeadAttrHtml(props) {
623
904
  for (const name in props) {
624
905
  if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
625
906
  if (!HEAD_ATTR_NAME.test(name)) {
626
- console.warn(`useHead: ignoring invalid attribute name "${name}"`);
627
907
  continue;
628
908
  }
629
909
  const v = props[name];
@@ -683,6 +963,12 @@ function renderToStream(code, options = {}) {
683
963
  d();
684
964
  }
685
965
  };
966
+ const failRender = err => {
967
+ try {
968
+ options.onError ? options.onError(err) : console.error(err);
969
+ } catch (_) {}
970
+ abandon();
971
+ };
686
972
  const guardSink = w => ({
687
973
  write(payload) {
688
974
  if (dead) return;
@@ -764,7 +1050,7 @@ function renderToStream(code, options = {}) {
764
1050
  }
765
1051
  },
766
1052
  shell(shellHtml, meta) {
767
- buffer.write(assembleDocument(shellHtml, meta.assets, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
1053
+ buffer.write(assembleDocument(shellHtml, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
768
1054
  },
769
1055
  ...options.sink
770
1056
  };
@@ -781,10 +1067,18 @@ function renderToStream(code, options = {}) {
781
1067
  rootAssetsSerialized = true;
782
1068
  serializeFragmentAssets("", tracking.boundaryModules, context);
783
1069
  };
1070
+ let holds = 0;
784
1071
  const flushEnd = () => {
785
- if (!registry.size) {
1072
+ if (!registry.size && !holds) {
786
1073
  serializeRootAssets();
787
- queue(() => queue(() => serializer.flush()));
1074
+ queue(() => queue(() => {
1075
+ if (context.live.end) {
1076
+ const end = context.live.end;
1077
+ context.live.end = null;
1078
+ end();
1079
+ }
1080
+ serializer.flush();
1081
+ }));
788
1082
  }
789
1083
  };
790
1084
  const registry = new Map();
@@ -844,8 +1138,8 @@ function renderToStream(code, options = {}) {
844
1138
  };
845
1139
  solidJs.sharedConfig.context = context = {
846
1140
  async: true,
847
- assets: [],
848
1141
  nonce,
1142
+ live: {},
849
1143
  registerHeadTags(tags) {
850
1144
  registerHeadTags(headRegistry, context, tracking,
851
1145
  (markup, gateEntry) => {
@@ -882,6 +1176,16 @@ function renderToStream(code, options = {}) {
882
1176
  block(p) {
883
1177
  if (!firstFlushed) blockingPromises.add(p);
884
1178
  },
1179
+ hold() {
1180
+ holds++;
1181
+ let released = false;
1182
+ return () => {
1183
+ if (released) return;
1184
+ released = true;
1185
+ holds--;
1186
+ if (!holds) queue(flushEnd);
1187
+ };
1188
+ },
885
1189
  replace(id, payloadFn) {
886
1190
  if (firstFlushed) return;
887
1191
  const placeholder = `<!--!$${id}-->`;
@@ -990,6 +1294,7 @@ function renderToStream(code, options = {}) {
990
1294
  }
991
1295
  };
992
1296
  applyAssetTracking(context, tracking, manifest, noScripts);
1297
+ context.failRender = failRender;
993
1298
  registerEntryAssets(manifest);
994
1299
  let html = solidJs.createRoot(d => {
995
1300
  dispose = d;
@@ -1046,7 +1351,7 @@ function renderToStream(code, options = {}) {
1046
1351
  if (shellCompleted) return;
1047
1352
  solidJs.sharedConfig.context = context;
1048
1353
  if (!resolveRootHoles()) return;
1049
- const assetsHtml = resolveAssetsHtml(context.assets);
1354
+ if (!headShellReady(headRegistry, p => blockingPromises.add(p))) return;
1050
1355
  headStyles = new Set();
1051
1356
  for (const url of tracking.emittedAssets) {
1052
1357
  if (isCssUrl(url)) headStyles.add(url);
@@ -1054,7 +1359,6 @@ function renderToStream(code, options = {}) {
1054
1359
  serializeRootAssets();
1055
1360
  const head = renderShellHead(headRegistry, nonce, k => registry.has(k));
1056
1361
  sink.shell(html, {
1057
- assets: assetsHtml,
1058
1362
  preloads: tracking.emittedAssets,
1059
1363
  inlineStyles: tracking.inlineStyles,
1060
1364
  tasks,
@@ -1103,7 +1407,12 @@ function renderToStream(code, options = {}) {
1103
1407
  allSettled(blockingPromises).then(() => {
1104
1408
  scheduleFlush(() => {
1105
1409
  if (dead) return resolve();
1106
- doShell();
1410
+ try {
1411
+ doShell();
1412
+ } catch (err) {
1413
+ failRender(err);
1414
+ return resolve();
1415
+ }
1107
1416
  if (!shellCompleted) return flush();
1108
1417
  const encoder = new TextEncoder();
1109
1418
  const writer = w.getWriter();
@@ -1144,27 +1453,35 @@ function renderToStream(code, options = {}) {
1144
1453
  return p;
1145
1454
  };
1146
1455
  return {
1147
- then(fn) {
1148
- function complete() {
1149
- dispose();
1150
- fn(tmp);
1151
- }
1152
- if (onCompleteAll) {
1153
- let ogComplete = onCompleteAll;
1154
- onCompleteAll = options => {
1155
- ogComplete(options);
1156
- complete();
1157
- };
1158
- } else onCompleteAll = complete;
1159
- function flush() {
1160
- allSettled(blockingPromises).then(() => {
1161
- scheduleFlush(() => {
1162
- if (!resolveRootHoles()) return flush();
1163
- queue(flushEnd);
1456
+ then(onFulfilled, onRejected) {
1457
+ const p = new Promise(resolve => {
1458
+ function complete() {
1459
+ dispose();
1460
+ resolve(tmp);
1461
+ }
1462
+ if (onCompleteAll) {
1463
+ let ogComplete = onCompleteAll;
1464
+ onCompleteAll = options => {
1465
+ ogComplete(options);
1466
+ complete();
1467
+ };
1468
+ } else onCompleteAll = complete;
1469
+ function flush() {
1470
+ allSettled(blockingPromises).then(() => {
1471
+ scheduleFlush(() => {
1472
+ try {
1473
+ if (!resolveRootHoles() || !headShellReady(headRegistry, p => blockingPromises.add(p))) return flush();
1474
+ } catch (err) {
1475
+ failRender(err);
1476
+ return resolve(tmp);
1477
+ }
1478
+ queue(flushEnd);
1479
+ });
1164
1480
  });
1165
- });
1166
- }
1167
- flush();
1481
+ }
1482
+ flush();
1483
+ });
1484
+ return p.then(onFulfilled, onRejected);
1168
1485
  },
1169
1486
  pipe(w) {
1170
1487
  claimConsumer("pipe");
@@ -1172,7 +1489,15 @@ function renderToStream(code, options = {}) {
1172
1489
  allSettled(blockingPromises).then(() => {
1173
1490
  scheduleFlush(() => {
1174
1491
  if (dead) return;
1175
- doShell();
1492
+ try {
1493
+ doShell();
1494
+ } catch (err) {
1495
+ failRender(err);
1496
+ try {
1497
+ w.end();
1498
+ } catch (_) {}
1499
+ return;
1500
+ }
1176
1501
  if (!shellCompleted) return flush();
1177
1502
  buffer = writable = guardSink(w);
1178
1503
  buffer.write(tmp);
@@ -1204,9 +1529,27 @@ function renderToStream(code, options = {}) {
1204
1529
  function buildAsyncWrap(err, node) {
1205
1530
  const p = solidJs.ssrHandleError(err);
1206
1531
  if (!p) return null;
1532
+ if (node.$rw) return {
1533
+ fn: node,
1534
+ p
1535
+ };
1207
1536
  const owner = solidJs.getOwner();
1537
+ const live = solidJs.sharedConfig.context && solidJs.sharedConfig.context.liveHoles;
1538
+ const suppress = node.$lhSuppress || live && (live.suppressed || live.sweeping);
1539
+ if (!owner) {
1540
+ if (suppress) node.$lhSuppress = true;
1541
+ return {
1542
+ fn: node,
1543
+ p
1544
+ };
1545
+ }
1546
+ const fn = () => solidJs.runWithOwner(owner, node);
1547
+ fn.$rw = true;
1548
+ if (suppress) fn.$lhSuppress = true;
1549
+ if (node.$lhSkip) fn.$lhSkip = true;
1550
+ if (node.$lhBinding) fn.$lhBinding = node.$lhBinding;
1208
1551
  return {
1209
- fn: owner ? () => solidJs.runWithOwner(owner, node) : node,
1552
+ fn,
1210
1553
  p
1211
1554
  };
1212
1555
  }
@@ -1266,6 +1609,326 @@ function ssrGroupSlot(fn, idx) {
1266
1609
  }
1267
1610
  };
1268
1611
  }
1612
+ const holePositionCache = new WeakMap();
1613
+ function holeContentPositions(t) {
1614
+ let cached = holePositionCache.get(t);
1615
+ if (cached) return cached;
1616
+ const pos = [];
1617
+ const openOff = [];
1618
+ const closeOff = [];
1619
+ let inTag = false;
1620
+ let quote = "";
1621
+ let curOpen = null;
1622
+ let scanningName = false;
1623
+ for (let i = 0; i < t.length; i++) {
1624
+ const seg = t[i];
1625
+ let close = -1;
1626
+ const openAtStart = inTag;
1627
+ let reopened = false;
1628
+ for (let j = 0; j < seg.length; j++) {
1629
+ const ch = seg[j];
1630
+ if (quote) {
1631
+ if (ch === quote) quote = "";
1632
+ } else if (inTag) {
1633
+ if (scanningName && (ch === " " || ch === "\t" || ch === "\n" || ch === ">" || ch === "/")) {
1634
+ scanningName = false;
1635
+ curOpen = {
1636
+ seg: i,
1637
+ off: j
1638
+ };
1639
+ }
1640
+ if (ch === '"' || ch === "'") quote = ch;else if (ch === ">") {
1641
+ inTag = false;
1642
+ if (openAtStart && !reopened && close === -1) close = j;
1643
+ curOpen = null;
1644
+ }
1645
+ } else if (ch === "<") {
1646
+ inTag = true;
1647
+ scanningName = true;
1648
+ reopened = true;
1649
+ curOpen = null;
1650
+ }
1651
+ }
1652
+ if (inTag && scanningName) {
1653
+ scanningName = false;
1654
+ curOpen = {
1655
+ seg: i,
1656
+ off: seg.length
1657
+ };
1658
+ }
1659
+ closeOff.push(close);
1660
+ openOff.push(inTag && curOpen && curOpen.seg === i ? curOpen.off : -1);
1661
+ if (i < t.length - 1) pos.push(!inTag);
1662
+ }
1663
+ cached = {
1664
+ pos,
1665
+ openOff,
1666
+ closeOff
1667
+ };
1668
+ holePositionCache.set(t, cached);
1669
+ return cached;
1670
+ }
1671
+ function createLiveHoles(sink, scoped) {
1672
+ let nextId = 0;
1673
+ const stamp = typeof solidJs.creationStamp === "function" ? solidJs.creationStamp : () => 0;
1674
+ const inScope = scoped && typeof solidJs.inServerComponentScope === "function" ? solidJs.inServerComponentScope : null;
1675
+ const stripMarkers = html => html.replace(/<!--lh:\/?\d+-->/g, "");
1676
+ function resolveHoleValue(hole) {
1677
+ const result = {
1678
+ t: [""],
1679
+ h: [],
1680
+ p: []
1681
+ };
1682
+ try {
1683
+ resolveSSRNode(hole(), result);
1684
+ } catch (err) {
1685
+ const wrap = buildAsyncWrap(err, hole);
1686
+ if (!wrap) throw err;
1687
+ result.h.push(wrap.fn);
1688
+ result.p.push(wrap.p);
1689
+ result.t.push("");
1690
+ }
1691
+ return result;
1692
+ }
1693
+ function closeChildren(b) {
1694
+ for (const c of b.children) {
1695
+ c.closed = true;
1696
+ if (c.key) sink.closeBinding(c.key);
1697
+ closeChildren(c);
1698
+ }
1699
+ b.children.length = 0;
1700
+ }
1701
+ const engine = {
1702
+ suppressed: 0,
1703
+ sweeping: false,
1704
+ parent: null,
1705
+ recordStamp: 0,
1706
+ gateHit: false,
1707
+ content(hole) {
1708
+ if (hole.$lhSuppress) {
1709
+ const r = {
1710
+ t: [""],
1711
+ h: [],
1712
+ p: []
1713
+ };
1714
+ engine.suppressed++;
1715
+ try {
1716
+ try {
1717
+ resolveSSRNode(hole(), r);
1718
+ } catch (err) {
1719
+ const wrap = buildAsyncWrap(err, hole);
1720
+ if (wrap) {
1721
+ r.h.push(wrap.fn);
1722
+ r.p.push(wrap.p);
1723
+ r.t.push("");
1724
+ }
1725
+ }
1726
+ } finally {
1727
+ engine.suppressed--;
1728
+ }
1729
+ const b = hole.$lhBinding;
1730
+ if (b && !b.closed && !r.h.length && !engine.sweeping) {
1731
+ b.last = stripMarkers(r.t[0]);
1732
+ }
1733
+ return r.h.length ? r : r.t[0];
1734
+ }
1735
+ if (engine.suppressed || engine.sweeping) return null;
1736
+ if (hole.$lhSkip) return null;
1737
+ if (inScope && !inScope()) return null;
1738
+ const recordsBefore = engine.recordStamp;
1739
+ const ownersBefore = stamp();
1740
+ const owner = solidJs.getOwner();
1741
+ const b = {
1742
+ key: null,
1743
+ children: [],
1744
+ last: null,
1745
+ closed: false,
1746
+ sweep() {
1747
+ if (b.closed) return;
1748
+ const prevSweeping = engine.sweeping;
1749
+ engine.sweeping = true;
1750
+ engine.gateHit = false;
1751
+ const sweepOwnersBefore = stamp();
1752
+ let res;
1753
+ try {
1754
+ res = owner ? solidJs.runWithOwner(owner, () => resolveHoleValue(hole)) : resolveHoleValue(hole);
1755
+ } catch (err) {
1756
+ b.closed = true;
1757
+ sink.closeBinding(b.key);
1758
+ sink.error(b.key, String(err && err.message || err));
1759
+ return;
1760
+ } finally {
1761
+ engine.sweeping = prevSweeping;
1762
+ }
1763
+ if (engine.gateHit || stamp() !== sweepOwnersBefore) {
1764
+ b.closed = true;
1765
+ sink.closeBinding(b.key);
1766
+ return;
1767
+ }
1768
+ if (res.h.length) return;
1769
+ const html = res.t[0];
1770
+ if (b.last === null || html === b.last) return;
1771
+ b.last = html;
1772
+ closeChildren(b);
1773
+ sink.hole(b.key, html);
1774
+ }
1775
+ };
1776
+ if (engine.parent) engine.parent.children.push(b);
1777
+ const prevParent = engine.parent;
1778
+ engine.parent = b;
1779
+ let value;
1780
+ let escalated = null;
1781
+ try {
1782
+ value = hole();
1783
+ } catch (err) {
1784
+ const wrap = buildAsyncWrap(err, hole);
1785
+ if (!wrap) {
1786
+ engine.parent = prevParent;
1787
+ closeChildren(b);
1788
+ return "";
1789
+ }
1790
+ escalated = wrap;
1791
+ }
1792
+ if (!escalated && (typeof value === "function" && value.$lhSkip || value !== null && typeof value === "object" && value.$slot)) {
1793
+ engine.parent = prevParent;
1794
+ const r = {
1795
+ t: [""],
1796
+ h: [],
1797
+ p: []
1798
+ };
1799
+ engine.suppressed++;
1800
+ try {
1801
+ resolveSSRNode(value, r);
1802
+ } finally {
1803
+ engine.suppressed--;
1804
+ }
1805
+ return r.h.length ? r : r.t[0];
1806
+ }
1807
+ let res;
1808
+ if (escalated) {
1809
+ closeChildren(b);
1810
+ escalated.fn.$lhSuppress = true;
1811
+ escalated.fn.$lhBinding = b;
1812
+ res = {
1813
+ t: ["", ""],
1814
+ h: [escalated.fn],
1815
+ p: [escalated.p]
1816
+ };
1817
+ } else {
1818
+ res = {
1819
+ t: [""],
1820
+ h: [],
1821
+ p: []
1822
+ };
1823
+ try {
1824
+ resolveSSRNode(value, res);
1825
+ } catch (_) {
1826
+ engine.parent = prevParent;
1827
+ closeChildren(b);
1828
+ return "";
1829
+ }
1830
+ }
1831
+ engine.parent = prevParent;
1832
+ if (engine.recordStamp !== recordsBefore || stamp() !== ownersBefore) {
1833
+ return res.h.length ? res : res.t[0];
1834
+ }
1835
+ const id = nextId++;
1836
+ const key = b.key = "lh:" + id;
1837
+ const open = `<!--lh:${id}-->`;
1838
+ const close = `<!--lh:/${id}-->`;
1839
+ if (!res.h.length) {
1840
+ b.last = stripMarkers(res.t[0]);
1841
+ sink.openBinding(key, b);
1842
+ return open + res.t[0] + close;
1843
+ }
1844
+ const t = res.t.slice();
1845
+ t[0] = open + t[0];
1846
+ t[t.length - 1] += close;
1847
+ sink.openBinding(key, b);
1848
+ return {
1849
+ t,
1850
+ h: res.h,
1851
+ p: res.p
1852
+ };
1853
+ },
1854
+ mint() {
1855
+ return nextId++;
1856
+ },
1857
+ active() {
1858
+ return !inScope || inScope();
1859
+ },
1860
+ attr(cap) {
1861
+ const owner = solidJs.getOwner();
1862
+ const b = {
1863
+ key: "lha:" + cap.id,
1864
+ children: [],
1865
+ last: cap.base,
1866
+ closed: false,
1867
+ sweep() {
1868
+ if (b.closed) return;
1869
+ const prevSweeping = engine.sweeping;
1870
+ engine.sweeping = true;
1871
+ engine.gateHit = false;
1872
+ const sweepOwnersBefore = stamp();
1873
+ let html = "";
1874
+ try {
1875
+ let group = null;
1876
+ let groupVal = null;
1877
+ const run = () => {
1878
+ for (const part of cap.parts) {
1879
+ if (typeof part === "string") {
1880
+ html += part;
1881
+ continue;
1882
+ }
1883
+ let v;
1884
+ if (part.g) {
1885
+ if (group !== part.g) {
1886
+ group = part.g;
1887
+ groupVal = part.g();
1888
+ }
1889
+ v = groupVal[part.i];
1890
+ } else {
1891
+ v = part.f();
1892
+ }
1893
+ const vt = typeof v;
1894
+ if (vt === "string" || vt === "number") html += v;
1895
+ }
1896
+ };
1897
+ owner ? solidJs.runWithOwner(owner, run) : run();
1898
+ } catch (err) {
1899
+ if (solidJs.ssrHandleError(err, true)) return;
1900
+ b.closed = true;
1901
+ sink.closeBinding(b.key);
1902
+ sink.error("lha:" + cap.id, String(err && err.message || err));
1903
+ return;
1904
+ } finally {
1905
+ engine.sweeping = prevSweeping;
1906
+ }
1907
+ if (engine.gateHit || stamp() !== sweepOwnersBefore) {
1908
+ b.closed = true;
1909
+ sink.closeBinding(b.key);
1910
+ return;
1911
+ }
1912
+ if (html === b.last) return;
1913
+ const before = attrNames(b.last);
1914
+ const after = attrNames(html);
1915
+ const removed = before.filter(n => !after.includes(n));
1916
+ b.last = html;
1917
+ sink.attr(String(cap.id), html, removed);
1918
+ }
1919
+ };
1920
+ sink.openBinding(b.key, b);
1921
+ }
1922
+ };
1923
+ return engine;
1924
+ }
1925
+ function attrNames(text) {
1926
+ const names = [];
1927
+ const re = /(?:^|\s)([^\s=/>"']+)(?:="[^"]*")?/g;
1928
+ let m;
1929
+ while (m = re.exec(text)) names.push(m[1]);
1930
+ return names;
1931
+ }
1269
1932
  function ssr(t) {
1270
1933
  const len = arguments.length;
1271
1934
  if (len === 1) return {
@@ -1276,13 +1939,54 @@ function ssr(t) {
1276
1939
  let lastGroup = null;
1277
1940
  let lastGroupVal = null;
1278
1941
  let lastGroupIdx = 0;
1942
+ const live = solidJs.sharedConfig.context && solidJs.sharedConfig.context.liveHoles;
1943
+ const hp = live ? holeContentPositions(t) : null;
1944
+ let lastOpen = null;
1945
+ let cap = null;
1946
+ if (live && hp.openOff[0] >= 0) lastOpen = {
1947
+ r: null,
1948
+ seg: -1,
1949
+ off: hp.openOff[0]
1950
+ };
1951
+ const captureStart = () => {
1952
+ if (cap) return true;
1953
+ if (!lastOpen || live.suppressed || live.sweeping || !live.active()) return false;
1954
+ if (lastOpen.r !== result || result !== null && lastOpen.seg !== result.t.length - 1) {
1955
+ return false;
1956
+ }
1957
+ const id = live.mint();
1958
+ const inject = ` data-lha="${id}"`;
1959
+ let prefix;
1960
+ if (result === null) {
1961
+ s = s.slice(0, lastOpen.off) + inject + s.slice(lastOpen.off);
1962
+ prefix = s.slice(lastOpen.off + inject.length);
1963
+ } else {
1964
+ const seg = result.t[lastOpen.seg];
1965
+ result.t[lastOpen.seg] = seg.slice(0, lastOpen.off) + inject + seg.slice(lastOpen.off);
1966
+ prefix = result.t[lastOpen.seg].slice(lastOpen.off + inject.length);
1967
+ }
1968
+ cap = {
1969
+ id,
1970
+ parts: [prefix],
1971
+ base: prefix
1972
+ };
1973
+ return true;
1974
+ };
1279
1975
  for (let i = 1; i < len; i++) {
1280
1976
  const hole = arguments[i];
1281
1977
  const ht = typeof hole;
1282
1978
  if (ht === "string") {
1283
1979
  if (result === null) s += hole;else result.t[result.t.length - 1] += hole;
1980
+ if (cap) {
1981
+ cap.parts.push(hole);
1982
+ cap.base += hole;
1983
+ }
1284
1984
  } else if (ht === "number") {
1285
1985
  if (result === null) s += hole;else result.t[result.t.length - 1] += hole;
1986
+ if (cap) {
1987
+ cap.parts.push("" + hole);
1988
+ cap.base += hole;
1989
+ }
1286
1990
  } else if (hole == null || ht === "boolean") ; else if (ht === "function" && hole.$g) {
1287
1991
  let value;
1288
1992
  let hasValue = false;
@@ -1306,7 +2010,14 @@ function ssr(t) {
1306
2010
  if (Array.isArray(lastGroupVal)) {
1307
2011
  value = lastGroupVal[lastGroupIdx++];
1308
2012
  hasValue = true;
2013
+ if (live && !hp.pos[i - 1] && captureStart()) {
2014
+ cap.parts.push({
2015
+ g: hole,
2016
+ i: lastGroupIdx - 1
2017
+ });
2018
+ }
1309
2019
  } else {
2020
+ cap = null;
1310
2021
  result.h.push(ssrGroupSlot(lastGroupVal.fn, lastGroupIdx++));
1311
2022
  result.p.push(lastGroupVal.p);
1312
2023
  result.t.push("");
@@ -1316,6 +2027,7 @@ function ssr(t) {
1316
2027
  const vt = typeof value;
1317
2028
  if (vt === "string" || vt === "number") {
1318
2029
  if (result === null) s += value;else result.t[result.t.length - 1] += value;
2030
+ if (cap && !hp.pos[i - 1]) cap.base += value;
1319
2031
  } else if (value == null || vt === "boolean") ; else if (result !== null) {
1320
2032
  resolveSSRNode(value, result);
1321
2033
  } else {
@@ -1333,19 +2045,67 @@ function ssr(t) {
1333
2045
  }
1334
2046
  }
1335
2047
  }
1336
- } else if (result !== null) {
1337
- resolveSSRNode(hole, result);
1338
2048
  } else if (ht === "function") {
1339
- const r = tryResolveFunctionHole(hole);
1340
- if (typeof r === "string") s += r;else {
1341
- result = {
1342
- t: [s],
1343
- h: [],
1344
- p: []
1345
- };
1346
- s = "";
1347
- appendResolvedNode(result, r);
2049
+ let liveNode = null;
2050
+ if (live && hp.pos[i - 1] && (liveNode = live.content(hole)) !== null) {
2051
+ if (typeof liveNode === "string") {
2052
+ if (result === null) s += liveNode;else result.t[result.t.length - 1] += liveNode;
2053
+ } else {
2054
+ if (result === null) {
2055
+ result = {
2056
+ t: [s],
2057
+ h: [],
2058
+ p: []
2059
+ };
2060
+ s = "";
2061
+ }
2062
+ resolveSSRNode(liveNode, result);
2063
+ }
2064
+ } else if (result !== null) {
2065
+ const inTag = live && !hp.pos[i - 1];
2066
+ const capturing = inTag && captureStart();
2067
+ const li = capturing ? result.t.length - 1 : 0;
2068
+ const before = capturing ? result.t[li].length : 0;
2069
+ if (live) live.suppressed++;
2070
+ try {
2071
+ resolveSSRNode(hole, result);
2072
+ } finally {
2073
+ if (live) live.suppressed--;
2074
+ }
2075
+ if (capturing) {
2076
+ if (result.t.length - 1 === li) {
2077
+ cap.base += result.t[li].slice(before);
2078
+ cap.parts.push({
2079
+ f: hole
2080
+ });
2081
+ } else {
2082
+ cap = null;
2083
+ }
2084
+ }
2085
+ } else {
2086
+ const capturing = live && !hp.pos[i - 1] && captureStart();
2087
+ const r = tryResolveFunctionHole(hole);
2088
+ if (typeof r === "string") {
2089
+ s += r;
2090
+ if (capturing) {
2091
+ cap.base += r;
2092
+ cap.parts.push({
2093
+ f: hole
2094
+ });
2095
+ }
2096
+ } else {
2097
+ if (capturing) cap = null;
2098
+ result = {
2099
+ t: [s],
2100
+ h: [],
2101
+ p: []
2102
+ };
2103
+ s = "";
2104
+ appendResolvedNode(result, r);
2105
+ }
1348
2106
  }
2107
+ } else if (result !== null) {
2108
+ resolveSSRNode(hole, result);
1349
2109
  } else {
1350
2110
  const r = tryResolveString(hole);
1351
2111
  if (typeof r === "string") {
@@ -1361,6 +2121,32 @@ function ssr(t) {
1361
2121
  }
1362
2122
  }
1363
2123
  const next = t[i];
2124
+ if (live) {
2125
+ if (cap) {
2126
+ const co = hp.closeOff[i];
2127
+ if (co >= 0) {
2128
+ const tail = next.slice(0, co);
2129
+ cap.parts.push(tail);
2130
+ cap.base += tail;
2131
+ live.attr(cap);
2132
+ cap = null;
2133
+ } else {
2134
+ cap.parts.push(next);
2135
+ cap.base += next;
2136
+ }
2137
+ }
2138
+ if (hp.openOff[i] >= 0) {
2139
+ lastOpen = result === null ? {
2140
+ r: null,
2141
+ seg: -1,
2142
+ off: s.length + hp.openOff[i]
2143
+ } : {
2144
+ r: result,
2145
+ seg: result.t.length - 1,
2146
+ off: result.t[result.t.length - 1].length + hp.openOff[i]
2147
+ };
2148
+ }
2149
+ }
1364
2150
  if (result === null) s += next;else result.t[result.t.length - 1] += next;
1365
2151
  }
1366
2152
  if (result === null) return {
@@ -1449,17 +2235,11 @@ function allSettled(promises) {
1449
2235
  return;
1450
2236
  });
1451
2237
  }
1452
- function resolveAssetsHtml(assets) {
1453
- if (!assets || !assets.length) return "";
1454
- let out = "";
1455
- for (let i = 0, len = assets.length; i < len; i++) out += assets[i]();
1456
- return out;
1457
- }
1458
- function assembleDocument(html, assetsHtml, emittedAssets, inlineStyles, scripts, nonce, headTags, onHead) {
2238
+ function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, headTags, onHead) {
1459
2239
  const scriptTag = scripts ? `<script${nonce ? ` nonce="${nonce}"` : ""}>${scripts}</script>` : "";
1460
2240
  const headTagsHtml = headTags ? headTags.html : "";
1461
2241
  const headPrelude = headTags ? headTags.prelude : "";
1462
- if (!onHead && !assetsHtml && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !(inlineStyles && inlineStyles.size)) {
2242
+ if (!onHead && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !(inlineStyles && inlineStyles.size)) {
1463
2243
  if (!scriptTag) return html;
1464
2244
  const xs = html.indexOf("<!--xs-->");
1465
2245
  return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
@@ -1474,13 +2254,13 @@ function assembleDocument(html, assetsHtml, emittedAssets, inlineStyles, scripts
1474
2254
  const headIdx = html.indexOf("</head>");
1475
2255
  if (headIdx === -1) {
1476
2256
  if (onHead) {
1477
- onHead(headPrelude + headTagsHtml + (assetsHtml || "") + renderHeadAssets(emittedAssets, inlineStyles, nonce));
2257
+ onHead(headPrelude + headTagsHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce));
1478
2258
  }
1479
2259
  if (!scriptTag) return html;
1480
2260
  const xs = html.indexOf("<!--xs-->");
1481
2261
  return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
1482
2262
  }
1483
- const head = headTagsHtml + (assetsHtml || "") + renderHeadAssets(emittedAssets, inlineStyles, nonce);
2263
+ const head = headTagsHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce);
1484
2264
  if (!scriptTag) return html.slice(0, headIdx) + head + html.slice(headIdx);
1485
2265
  const xsIdx = html.indexOf("<!--xs-->");
1486
2266
  if (xsIdx === -1) return html.slice(0, headIdx) + head + html.slice(headIdx) + scriptTag;
@@ -1599,7 +2379,6 @@ function tryResolveString(node) {
1599
2379
  merge: node
1600
2380
  };
1601
2381
  if (node.t === undefined) {
1602
- console.warn(`Unrecognized value. Skipped inserting`, node);
1603
2382
  return "";
1604
2383
  }
1605
2384
  return Array.isArray(node.t) ? node.t[0] : node.t;
@@ -1624,13 +2403,19 @@ function resolveSSRNode(node, result = {
1624
2403
  if (t === "string" || t === "number") {
1625
2404
  result.t[result.t.length - 1] += node;
1626
2405
  } else if (node == null || t === "boolean") ; else if (Array.isArray(node)) {
1627
- let prevNonObj = false;
1628
- for (let i = 0, len = node.length; i < len; i++) {
1629
- const item = node[i];
1630
- const itemNonObj = item !== null && typeof item !== "object";
1631
- if (!top && prevNonObj && itemNonObj) result.t[result.t.length - 1] += `<!--!$-->`;
1632
- prevNonObj = itemNonObj;
1633
- resolveSSRNode(item, result);
2406
+ const slotLive = node.$slot && solidJs.sharedConfig.context && solidJs.sharedConfig.context.liveHoles;
2407
+ if (slotLive) slotLive.suppressed++;
2408
+ try {
2409
+ let prevNonObj = false;
2410
+ for (let i = 0, len = node.length; i < len; i++) {
2411
+ const item = node[i];
2412
+ const itemNonObj = item !== null && typeof item !== "object";
2413
+ if (!top && prevNonObj && itemNonObj) result.t[result.t.length - 1] += `<!--!$-->`;
2414
+ prevNonObj = itemNonObj;
2415
+ resolveSSRNode(item, result);
2416
+ }
2417
+ } finally {
2418
+ if (slotLive) slotLive.suppressed--;
1634
2419
  }
1635
2420
  } else if (t === "object") {
1636
2421
  if (node.h) {
@@ -1642,16 +2427,22 @@ function resolveSSRNode(node, result = {
1642
2427
  }
1643
2428
  } else if (node.t !== undefined) {
1644
2429
  result.t[result.t.length - 1] += node.t;
1645
- } else console.warn(`Unrecognized value. Skipped inserting`, node);
2430
+ } else ;
1646
2431
  } else if (t === "function") {
1647
- try {
1648
- resolveSSRNode(node(), result);
1649
- } catch (err) {
1650
- const wrap = buildAsyncWrap(err, node);
1651
- if (wrap) {
1652
- result.h.push(wrap.fn);
1653
- result.p.push(wrap.p);
1654
- result.t.push("");
2432
+ const live = solidJs.sharedConfig.context && solidJs.sharedConfig.context.liveHoles;
2433
+ let liveNode = null;
2434
+ if (live && (liveNode = live.content(node)) !== null) {
2435
+ if (typeof liveNode === "string") result.t[result.t.length - 1] += liveNode;else resolveSSRNode(liveNode, result);
2436
+ } else {
2437
+ try {
2438
+ resolveSSRNode(node(), result);
2439
+ } catch (err) {
2440
+ const wrap = buildAsyncWrap(err, node);
2441
+ if (wrap) {
2442
+ result.h.push(wrap.fn);
2443
+ result.p.push(wrap.p);
2444
+ result.t.push("");
2445
+ }
1655
2446
  }
1656
2447
  }
1657
2448
  }
@@ -1662,142 +2453,7 @@ function resolveSSRSync(node) {
1662
2453
  if (!res.h.length) return res.t[0];
1663
2454
  throw new Error("This value cannot be rendered synchronously. Are you missing a boundary?");
1664
2455
  }
1665
-
1666
- function frameAddress(id, args) {
1667
- return args && args.length ? id + ":" + hashArguments(args) : id;
1668
- }
1669
- function hashArguments(args) {
1670
- let hash = 0;
1671
- const text = stableString(args);
1672
- for (let i = 0; i < text.length; i++) {
1673
- hash = (hash << 5) - hash + text.charCodeAt(i);
1674
- hash |= 0;
1675
- }
1676
- return (hash >>> 0).toString(36);
1677
- }
1678
- function stableString(value, seen) {
1679
- if (value === null || typeof value !== "object") {
1680
- return typeof value === "bigint" ? value + "n" : String(value);
1681
- }
1682
- if (value instanceof Date) return "Date:" + value.getTime();
1683
- seen || (seen = new Set());
1684
- if (seen.has(value)) return "~";
1685
- seen.add(value);
1686
- if (value instanceof Map) {
1687
- const entries = [];
1688
- for (const [k, v] of value) {
1689
- entries.push(stableString(k, seen) + "=>" + stableString(v, seen));
1690
- }
1691
- return "Map{" + entries.sort().join(",") + "}";
1692
- }
1693
- if (value instanceof Set) {
1694
- const members = [];
1695
- for (const v of value) members.push(stableString(v, seen));
1696
- return "Set{" + members.sort().join(",") + "}";
1697
- }
1698
- if (Array.isArray(value)) {
1699
- let out = "[";
1700
- for (let i = 0; i < value.length; i++) out += (i ? "," : "") + stableString(value[i], seen);
1701
- return out + "]";
1702
- }
1703
- const keys = Object.keys(value).sort();
1704
- let out = "{";
1705
- for (let i = 0; i < keys.length; i++) {
1706
- out += (i ? "," : "") + keys[i] + ":" + stableString(value[keys[i]], seen);
1707
- }
1708
- return out + "}";
1709
- }
1710
- const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
1711
- function createChunk(data) {
1712
- const encodeData = new TextEncoder().encode(data);
1713
- const bytes = encodeData.length;
1714
- const baseHex = bytes.toString(16);
1715
- const totalHex = "00000000".substring(0, 8 - baseHex.length) + baseHex;
1716
- const head = new TextEncoder().encode(`;0x${totalHex};`);
1717
- const chunk = new Uint8Array(12 + bytes);
1718
- chunk.set(head);
1719
- chunk.set(encodeData, 12);
1720
- return chunk;
1721
- }
1722
- class ChunkReader {
1723
- constructor(stream) {
1724
- this.reader = stream.getReader();
1725
- this.buffer = new Uint8Array(0);
1726
- this.done = false;
1727
- }
1728
- async readChunk() {
1729
- const chunk = await this.reader.read();
1730
- if (!chunk.done) {
1731
- const newBuffer = new Uint8Array(this.buffer.length + chunk.value.length);
1732
- newBuffer.set(this.buffer);
1733
- newBuffer.set(chunk.value, this.buffer.length);
1734
- this.buffer = newBuffer;
1735
- } else {
1736
- this.done = true;
1737
- }
1738
- }
1739
- async next() {
1740
- while (this.buffer.length < 12) {
1741
- if (this.done) {
1742
- if (this.buffer.length === 0) return {
1743
- done: true,
1744
- value: undefined
1745
- };
1746
- throw new Error("Malformed server function stream.");
1747
- }
1748
- await this.readChunk();
1749
- }
1750
- const head = new TextDecoder().decode(this.buffer.subarray(1, 11));
1751
- const bytes = Number.parseInt(head, 16);
1752
- if (Number.isNaN(bytes)) {
1753
- throw new Error("Malformed server function stream.");
1754
- }
1755
- while (bytes > this.buffer.length - 12) {
1756
- if (this.done) {
1757
- throw new Error("Malformed server function stream.");
1758
- }
1759
- await this.readChunk();
1760
- }
1761
- const partial = new TextDecoder().decode(this.buffer.subarray(12, 12 + bytes));
1762
- this.buffer = this.buffer.subarray(12 + bytes);
1763
- return {
1764
- done: false,
1765
- value: partial
1766
- };
1767
- }
1768
- async drain(interpret) {
1769
- while (true) {
1770
- const result = await this.next();
1771
- if (result.done) {
1772
- break;
1773
- }
1774
- interpret(result.value);
1775
- }
1776
- }
1777
- }
1778
- function serializeStream(value, codecOptions) {
1779
- return new ReadableStream({
1780
- start(controller) {
1781
- serializeJSON(value, {
1782
- ...codecOptions,
1783
- onParse(node) {
1784
- controller.enqueue(createChunk(JSON.stringify(node)));
1785
- },
1786
- onDone() {
1787
- controller.close();
1788
- },
1789
- onError(error) {
1790
- controller.error(error);
1791
- }
1792
- });
1793
- }
1794
- });
1795
- }
1796
-
1797
- const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
1798
- function isResponseEnvelope(value) {
1799
- return !!(value && typeof value === "object" && value[ENVELOPE]);
1800
- }
2456
+ /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, "Location"].map(header => header.toLowerCase()));
1801
2457
 
1802
2458
  const INVOCATIONS = new WeakMap();
1803
2459
  function getEventServerFunctionInvocation(event) {
@@ -1821,7 +2477,7 @@ function parseServerComponent(value, ctx) {
1821
2477
  address: ctx.parse(value[SERVER_COMPONENT_ADDRESS])
1822
2478
  };
1823
2479
  }
1824
- const ServerComponentPlugin = /*#__PURE__*/seroval.createPlugin({
2480
+ const ServerComponentPlugin = {
1825
2481
  tag: "dom-expressions/server-component",
1826
2482
  test(value) {
1827
2483
  return typeof value === "function" && SERVER_COMPONENT in value;
@@ -1845,18 +2501,17 @@ const ServerComponentPlugin = /*#__PURE__*/seroval.createPlugin({
1845
2501
  ctx.deserialize(node.address);
1846
2502
  return globalThis._$SC.r(id);
1847
2503
  }
1848
- });
2504
+ };
1849
2505
  function flightCodec(codec) {
1850
2506
  const plugins = codec && codec.plugins || [];
1851
- for (const plugin of plugins) {
1852
- if (plugin && plugin.tag === "dom-expressions/server-component") return codec;
1853
- }
2507
+ if (plugins.some(plugin => plugin && plugin.tag === ServerComponentPlugin.tag)) return codec;
1854
2508
  return {
1855
2509
  ...codec,
1856
2510
  plugins: [...plugins, ServerComponentPlugin]
1857
2511
  };
1858
2512
  }
1859
2513
 
2514
+ const scopeStamp = typeof solidJs.creationStamp === "function" ? solidJs.creationStamp : () => 0;
1860
2515
  function serverOwned(render) {
1861
2516
  return solidJs.NoHydration ? solidJs.NoHydration({
1862
2517
  get children() {
@@ -1881,6 +2536,29 @@ function createFrameSink(emit, frame) {
1881
2536
  version
1882
2537
  } = frame;
1883
2538
  const styledKeys = new Set();
2539
+ const bindings = new Map();
2540
+ const sweepMinted = new Set();
2541
+ const argRefVersions = new Map();
2542
+ let sweepScheduled = false;
2543
+ let closed = false;
2544
+ let epoch = 0;
2545
+ const sweep = () => {
2546
+ epoch++;
2547
+ for (const b of [...bindings.values()]) {
2548
+ try {
2549
+ b.sweep();
2550
+ } catch (_) {
2551
+ }
2552
+ }
2553
+ };
2554
+ const scheduleSweep = () => {
2555
+ if (closed || sweepScheduled || !bindings.size) return;
2556
+ sweepScheduled = true;
2557
+ queueMicrotask(() => {
2558
+ sweepScheduled = false;
2559
+ if (!closed) sweep();
2560
+ });
2561
+ };
1884
2562
  const regionKeys = new Map();
1885
2563
  const frameOf = key => regionKeys.get(key) || id;
1886
2564
  return {
@@ -1922,6 +2600,7 @@ function createFrameSink(emit, frame) {
1922
2600
  version,
1923
2601
  payload: record
1924
2602
  });
2603
+ scheduleSweep();
1925
2604
  } else {
1926
2605
  emit({
1927
2606
  type: "data",
@@ -1931,6 +2610,7 @@ function createFrameSink(emit, frame) {
1931
2610
  node: record.node,
1932
2611
  initial: record.initial
1933
2612
  });
2613
+ if (!sweepMinted.has(record.key)) scheduleSweep();
1934
2614
  }
1935
2615
  },
1936
2616
  fragment(key, value, meta = {}) {
@@ -1967,6 +2647,7 @@ function createFrameSink(emit, frame) {
1967
2647
  key,
1968
2648
  html: value
1969
2649
  });
2650
+ scheduleSweep();
1970
2651
  if (meta.error) {
1971
2652
  emit({
1972
2653
  type: "error",
@@ -2021,6 +2702,8 @@ function createFrameSink(emit, frame) {
2021
2702
  });
2022
2703
  },
2023
2704
  end() {
2705
+ if (bindings.size) sweep();
2706
+ closed = true;
2024
2707
  emit({
2025
2708
  type: "complete",
2026
2709
  id,
@@ -2052,6 +2735,44 @@ function createFrameSink(emit, frame) {
2052
2735
  version,
2053
2736
  html
2054
2737
  });
2738
+ },
2739
+ hole(key, html) {
2740
+ emit({
2741
+ type: "hole",
2742
+ id,
2743
+ version,
2744
+ key,
2745
+ html
2746
+ });
2747
+ },
2748
+ attr(key, attrs, removed) {
2749
+ const chunk = {
2750
+ type: "attr",
2751
+ id,
2752
+ version,
2753
+ key,
2754
+ attrs
2755
+ };
2756
+ if (removed && removed.length) chunk.removed = removed;
2757
+ emit(chunk);
2758
+ },
2759
+ openBinding(key, b) {
2760
+ bindings.set(key, b);
2761
+ },
2762
+ closeBinding(key) {
2763
+ bindings.delete(key);
2764
+ },
2765
+ mintRef(ref) {
2766
+ sweepMinted.add(ref);
2767
+ },
2768
+ nextArgRef(ledgerKey) {
2769
+ const n = (argRefVersions.get(ledgerKey) || 0) + 1;
2770
+ argRefVersions.set(ledgerKey, n);
2771
+ return n;
2772
+ },
2773
+ commit: scheduleSweep,
2774
+ get epoch() {
2775
+ return epoch;
2055
2776
  }
2056
2777
  };
2057
2778
  }
@@ -2061,7 +2782,15 @@ function renderToFrameStream(code, options = {}) {
2061
2782
  function renderServerComponent(component, options = {}) {
2062
2783
  return frameStream((sink, frame) => {
2063
2784
  const props = createSlotProps(sink, frame);
2064
- return () => serverComponentScope(() => component(props));
2785
+ return () => {
2786
+ const ctx = solidJs.sharedConfig.context;
2787
+ if (ctx) {
2788
+ ctx.commit = sink.commit;
2789
+ ctx.commitEpoch = () => sink.epoch;
2790
+ ctx.liveHoles = createLiveHoles(sink);
2791
+ }
2792
+ return serverComponentScope(() => component(props));
2793
+ };
2065
2794
  }, options);
2066
2795
  }
2067
2796
  function frameStream(makeCode, options) {
@@ -2119,7 +2848,8 @@ function frameStream(makeCode, options) {
2119
2848
  }
2120
2849
  function slotRange(occurrence) {
2121
2850
  return {
2122
- t: `<!--slot:${occurrence}:start--><!--slot:${occurrence}:end-->`
2851
+ t: `<!--slot:${occurrence}:start--><!--slot:${occurrence}:end-->`,
2852
+ $slot: true
2123
2853
  };
2124
2854
  }
2125
2855
  const OCCURRENCE_UNSAFE = /[^A-Za-z0-9_.-]/g;
@@ -2138,14 +2868,57 @@ function occurrenceId(prop, raw, counts) {
2138
2868
  counts[prop] = n + 1;
2139
2869
  return `${prop}#${n}`;
2140
2870
  }
2871
+ function isAsyncValue(v) {
2872
+ return !!v && typeof v === "object" && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
2873
+ }
2874
+ function tapFirstYield(iterable) {
2875
+ const iter = iterable[Symbol.asyncIterator]();
2876
+ const firstStep = Promise.resolve(iter.next());
2877
+ return {
2878
+ first: firstStep.then(r => r.done ? undefined : r.value),
2879
+ rest: {
2880
+ [Symbol.asyncIterator]() {
2881
+ let replayed = false;
2882
+ return {
2883
+ next: () => {
2884
+ if (!replayed) {
2885
+ replayed = true;
2886
+ return firstStep;
2887
+ }
2888
+ return iter.next();
2889
+ },
2890
+ return: v => iter.return ? iter.return(v) : Promise.resolve({
2891
+ done: true,
2892
+ value: v
2893
+ }),
2894
+ throw: e => iter.throw ? iter.throw(e) : Promise.reject(e)
2895
+ };
2896
+ }
2897
+ }
2898
+ };
2899
+ }
2900
+ function suppressedFill(render) {
2901
+ const live = solidJs.sharedConfig.context && solidJs.sharedConfig.context.liveHoles;
2902
+ if (!live) return render();
2903
+ live.suppressed++;
2904
+ try {
2905
+ return render();
2906
+ } finally {
2907
+ live.suppressed--;
2908
+ }
2909
+ }
2141
2910
  function createDocumentSlotProps(clientProps, frameId) {
2142
2911
  const counts = Object.create(null);
2143
2912
  const getters = new Map();
2144
- const range = (occurrence, content) => [{
2145
- t: `<!--slot:${occurrence}:start-->`
2146
- }, content, {
2147
- t: `<!--slot:${occurrence}:end-->`
2148
- }];
2913
+ const range = (occurrence, content) => {
2914
+ const r = [{
2915
+ t: `<!--slot:${occurrence}:start-->`
2916
+ }, content, {
2917
+ t: `<!--slot:${occurrence}:end-->`
2918
+ }];
2919
+ r.$slot = true;
2920
+ return r;
2921
+ };
2149
2922
  const zoneOwner = solidJs.getOwner ? solidJs.getOwner() : null;
2150
2923
  const scoped = (occurrence, render) => {
2151
2924
  const id = `sc-${frameId}-${occurrence}-`;
@@ -2168,27 +2941,68 @@ function createDocumentSlotProps(clientProps, frameId) {
2168
2941
  if (!fn) {
2169
2942
  fn = (...callArgs) => {
2170
2943
  if (callArgs.length === 0 || callArgs[0] === undefined) {
2171
- return scoped(prop, () => {
2944
+ return suppressedFill(() => scoped(prop, () => {
2172
2945
  const value = clientProps[prop];
2173
2946
  return range(prop, typeof value === "function" ? value() : value);
2174
- });
2947
+ }));
2175
2948
  }
2176
2949
  const raw = callArgs[0];
2177
2950
  const occurrence = occurrenceId(prop, raw, counts);
2178
2951
  const slot = clientProps[prop];
2179
2952
  if (typeof slot !== "function") return range(occurrence, undefined);
2180
2953
  const resolved = {};
2954
+ const liveArgs = solidJs.sharedConfig.context && solidJs.sharedConfig.context.live && solidJs.sharedConfig.context.live.args;
2181
2955
  const vals = {};
2956
+ const evals = {};
2957
+ const states = {};
2958
+ const minted = {};
2182
2959
  for (const key of Object.keys(raw)) {
2183
2960
  if (key === "$key") continue;
2184
- let value = raw[key];
2185
- for (let d = 0; typeof value === "function" && d < 16; d++) value = value();
2961
+ const desc = Object.getOwnPropertyDescriptor(raw, key);
2962
+ let evaluate = null;
2963
+ let value;
2964
+ if (desc.get) {
2965
+ const get = desc.get;
2966
+ evaluate = () => unwrapThunks(get.call(raw));
2967
+ } else {
2968
+ value = desc.value;
2969
+ if (typeof value === "function") {
2970
+ const fn = value;
2971
+ evaluate = () => unwrapThunks(fn);
2972
+ }
2973
+ }
2974
+ if (evaluate) {
2975
+ evals[key] = evaluate;
2976
+ const stampBefore = scopeStamp();
2977
+ try {
2978
+ value = evaluate();
2979
+ states[key] = {
2980
+ settled: true,
2981
+ last: value
2982
+ };
2983
+ } catch (err) {
2984
+ const blocked = solidJs.ssrHandleError && solidJs.ssrHandleError(err);
2985
+ if (!blocked) throw err;
2986
+ const state = states[key] = {
2987
+ settled: false,
2988
+ last: undefined
2989
+ };
2990
+ value = retryArgUntilSettled(evaluate, blocked, key, occurrence, v => {
2991
+ state.settled = true;
2992
+ state.last = v;
2993
+ if (liveArgs) liveArgs.commit();
2994
+ });
2995
+ }
2996
+ if (scopeStamp() !== stampBefore) minted[key] = true;
2997
+ }
2186
2998
  vals[key] = value;
2187
2999
  }
2188
3000
  const regions = [];
2189
3001
  for (const key of Object.keys(vals)) {
2190
3002
  const value = vals[key];
2191
- if (isServerContent(value)) {
3003
+ if (isContainerTraced(value)) {
3004
+ resolved[key] = value;
3005
+ } else if (isServerContent(value)) {
2192
3006
  const childId = `${frameId}.${occurrence}.${key}`;
2193
3007
  const region = {
2194
3008
  key,
@@ -2207,11 +3021,27 @@ function createDocumentSlotProps(clientProps, frameId) {
2207
3021
  t: FRAME_ELEMENT_CLOSE
2208
3022
  }];
2209
3023
  };
3024
+ } else if (ssrAsyncValue && isAsyncValue(value)) {
3025
+ let readable = value;
3026
+ if (typeof value.then !== "function") {
3027
+ const {
3028
+ first,
3029
+ rest
3030
+ } = tapFirstYield(value);
3031
+ readable = first;
3032
+ vals[key] = rest;
3033
+ }
3034
+ const read = ssrAsyncValue(readable);
3035
+ Object.defineProperty(resolved, key, {
3036
+ get: read,
3037
+ enumerable: true,
3038
+ configurable: true
3039
+ });
2210
3040
  } else {
2211
3041
  resolved[key] = value;
2212
3042
  }
2213
3043
  }
2214
- const out = scoped(occurrence, () => range(occurrence, slot(resolved)));
3044
+ const out = suppressedFill(() => scoped(occurrence, () => range(occurrence, slot(resolved))));
2215
3045
  const unused = regions.filter(r => !r.used);
2216
3046
  if (solidJs.sharedConfig.context) {
2217
3047
  const args = {};
@@ -2224,17 +3054,33 @@ function createDocumentSlotProps(clientProps, frameId) {
2224
3054
  };
2225
3055
  continue;
2226
3056
  }
2227
- if (isServerContent(value)) continue;
2228
- args[key] = value;
3057
+ if (!isContainerTraced(value) && isServerContent(value)) continue;
3058
+ args[key] = envelopeContainerTraces(value);
2229
3059
  }
2230
- solidJs.sharedConfig.context.serialize(`sc:slot:${frameId}:${occurrence}`, args);
3060
+ solidJs.sharedConfig.context.serialize(`sc:slot:${frameId}:${occurrence}`, {
3061
+ ...args
3062
+ });
2231
3063
  for (const region of unused) {
2232
3064
  region.locked = true;
2233
3065
  solidJs.sharedConfig.context.serialize(`sc:region:${region.childId}`, resolveRegionHtml(solidJs.sharedConfig.context, region.value));
2234
3066
  }
3067
+ if (liveArgs) {
3068
+ for (const key of Object.keys(evals)) {
3069
+ if (regions.some(r => r.key === key)) continue;
3070
+ if (minted[key]) continue;
3071
+ const ledgerKey = `${frameId}:${occurrence}:${key}`;
3072
+ openArgBinding(liveArgs, ledgerKey, occurrence, key, evals[key], states[key], value => {
3073
+ args[key] = envelopeContainerTraces(value);
3074
+ liveArgs.slot(frameId, occurrence, {
3075
+ ...args
3076
+ });
3077
+ });
3078
+ }
3079
+ }
2235
3080
  }
2236
3081
  return out;
2237
3082
  };
3083
+ fn.$lhSkip = true;
2238
3084
  getters.set(prop, fn);
2239
3085
  }
2240
3086
  return fn;
@@ -2248,6 +3094,113 @@ function frameElementOpen(id) {
2248
3094
  return `<${FRAME_TAG} ${FRAME_ID_ATTR}="${escaped}" style="display:contents">`;
2249
3095
  }
2250
3096
  const FRAME_ELEMENT_CLOSE = `</${FRAME_TAG}>`;
3097
+ function armDocumentLiveHoles(ctx) {
3098
+ if (!ctx || ctx.liveHoles !== undefined) return;
3099
+ const live = ctx.live;
3100
+ if (live && live.holes !== undefined) {
3101
+ ctx.liveHoles = live.holes;
3102
+ if (live.holes) {
3103
+ ctx.commit = live.commit;
3104
+ ctx.commitEpoch = live.commitEpoch;
3105
+ }
3106
+ return;
3107
+ }
3108
+ if (!live || !ctx.async || ctx.noHydrate || !ctx.serialize || typeof ReadableStream !== "function") {
3109
+ ctx.liveHoles = null;
3110
+ if (live) live.holes = null;
3111
+ return;
3112
+ }
3113
+ const bindings = new Map();
3114
+ let epoch = 0;
3115
+ let sweepScheduled = false;
3116
+ let closed = false;
3117
+ const sweep = () => {
3118
+ epoch++;
3119
+ for (const b of [...bindings.values()]) {
3120
+ try {
3121
+ b.sweep();
3122
+ } catch (_) {
3123
+ }
3124
+ }
3125
+ };
3126
+ const scheduleSweep = () => {
3127
+ if (closed || sweepScheduled || !bindings.size) return;
3128
+ sweepScheduled = true;
3129
+ queueMicrotask(() => {
3130
+ sweepScheduled = false;
3131
+ if (!closed) sweep();
3132
+ });
3133
+ };
3134
+ let channel;
3135
+ ctx.serialize("sc:live", new ReadableStream({
3136
+ start(c) {
3137
+ channel = c;
3138
+ }
3139
+ }));
3140
+ const push = op => {
3141
+ if (!closed) channel.enqueue(op);
3142
+ };
3143
+ ctx.liveHoles = live.holes = createLiveHoles({
3144
+ openBinding(key, b) {
3145
+ bindings.set(key, b);
3146
+ },
3147
+ closeBinding(key) {
3148
+ bindings.delete(key);
3149
+ },
3150
+ hole(key, html) {
3151
+ push({
3152
+ type: "hole",
3153
+ key,
3154
+ html
3155
+ });
3156
+ },
3157
+ attr(key, attrs, removed) {
3158
+ const op = {
3159
+ type: "attr",
3160
+ key,
3161
+ attrs
3162
+ };
3163
+ if (removed && removed.length) op.removed = removed;
3164
+ push(op);
3165
+ },
3166
+ error(key, error) {
3167
+ push({
3168
+ type: "error",
3169
+ key,
3170
+ error
3171
+ });
3172
+ },
3173
+ commit: scheduleSweep,
3174
+ get epoch() {
3175
+ return epoch;
3176
+ }
3177
+ }, true);
3178
+ ctx.commit = live.commit = scheduleSweep;
3179
+ ctx.commitEpoch = live.commitEpoch = () => epoch;
3180
+ live.args = {
3181
+ openBinding(key, b) {
3182
+ bindings.set(key, b);
3183
+ },
3184
+ closeBinding(key) {
3185
+ bindings.delete(key);
3186
+ },
3187
+ slot(fid, occurrence, args) {
3188
+ push({
3189
+ type: "slot",
3190
+ fid,
3191
+ key: occurrence,
3192
+ args
3193
+ });
3194
+ },
3195
+ commit: scheduleSweep
3196
+ };
3197
+ live.end = () => {
3198
+ if (closed) return;
3199
+ if (bindings.size) sweep();
3200
+ closed = true;
3201
+ channel.close();
3202
+ };
3203
+ }
2251
3204
  function frameTransformDirectResult(value, {
2252
3205
  id,
2253
3206
  args
@@ -2258,6 +3211,7 @@ function frameTransformDirectResult(value, {
2258
3211
  t: frameElementOpen(id)
2259
3212
  },
2260
3213
  serverOwned(() => {
3214
+ armDocumentLiveHoles(solidJs.sharedConfig.context);
2261
3215
  const slotProps = createDocumentSlotProps(props, id);
2262
3216
  return serverComponentScope(() => component(slotProps));
2263
3217
  }), {
@@ -2294,6 +3248,76 @@ function isServerContent(value) {
2294
3248
  }
2295
3249
  return false;
2296
3250
  }
3251
+ function unwrapThunks(value) {
3252
+ for (let d = 0; typeof value === "function" && d < 16; d++) value = value();
3253
+ return value;
3254
+ }
3255
+ function contentArgError(key, occurrence) {
3256
+ return new Error("Async slot arg resolved to JSX (arg '" + key + "' of " + occurrence + "). Async args must resolve to serializable values; render async content through a boundary instead.");
3257
+ }
3258
+ function retryArgUntilSettled(evaluate, blocked, key, occurrence, onSettle) {
3259
+ const owner = solidJs.getOwner();
3260
+ return new Promise((resolve, reject) => {
3261
+ const retry = () => {
3262
+ try {
3263
+ const value = owner ? solidJs.runWithOwner(owner, evaluate) : evaluate();
3264
+ if (isServerContent(value)) {
3265
+ reject(contentArgError(key, occurrence));
3266
+ return;
3267
+ }
3268
+ if (onSettle) onSettle(value);
3269
+ resolve(value);
3270
+ } catch (err) {
3271
+ const next = solidJs.ssrHandleError && solidJs.ssrHandleError(err);
3272
+ if (next) next.then(retry, retry);else reject(err);
3273
+ }
3274
+ };
3275
+ blocked.then(retry, retry);
3276
+ });
3277
+ }
3278
+ function openArgBinding(sink, ledgerKey, occurrence, key, evaluate, state, emit) {
3279
+ const owner = solidJs.getOwner();
3280
+ sink.openBinding(ledgerKey, {
3281
+ sweep() {
3282
+ if (!state.settled) return;
3283
+ let value;
3284
+ const stampBefore = scopeStamp();
3285
+ try {
3286
+ value = owner ? solidJs.runWithOwner(owner, evaluate) : evaluate();
3287
+ } catch (err) {
3288
+ const blocked = solidJs.ssrHandleError && solidJs.ssrHandleError(err);
3289
+ if (!blocked) {
3290
+ sink.closeBinding(ledgerKey);
3291
+ emit(Promise.reject(err instanceof Error ? err : new Error(String(err))));
3292
+ return;
3293
+ }
3294
+ if (scopeStamp() !== stampBefore) {
3295
+ sink.closeBinding(ledgerKey);
3296
+ return;
3297
+ }
3298
+ state.settled = false;
3299
+ emit(retryArgUntilSettled(evaluate, blocked, key, occurrence, v => {
3300
+ state.settled = true;
3301
+ state.last = v;
3302
+ sink.commit();
3303
+ }));
3304
+ return;
3305
+ }
3306
+ if (scopeStamp() !== stampBefore) {
3307
+ sink.closeBinding(ledgerKey);
3308
+ return;
3309
+ }
3310
+ if (value === state.last) return;
3311
+ state.last = value;
3312
+ if (isServerContent(value)) {
3313
+ sink.closeBinding(ledgerKey);
3314
+ emit(Promise.reject(contentArgError(key, occurrence)));
3315
+ return;
3316
+ }
3317
+ emit(value);
3318
+ }
3319
+ });
3320
+ }
2297
3321
  function createSlotProps(sink, frame) {
2298
3322
  const counts = Object.create(null);
2299
3323
  const getters = new Map();
@@ -2310,9 +3334,21 @@ function createSlotProps(sink, frame) {
2310
3334
  if (callArgs.length === 0 || callArgs[0] === undefined) {
2311
3335
  return slotRange(prop);
2312
3336
  }
3337
+ const live = solidJs.sharedConfig.context && solidJs.sharedConfig.context.liveHoles;
3338
+ if (live) {
3339
+ if (live.sweeping) {
3340
+ live.gateHit = true;
3341
+ return {
3342
+ t: "",
3343
+ $slot: true
3344
+ };
3345
+ }
3346
+ live.recordStamp++;
3347
+ }
2313
3348
  const raw = callArgs[0];
2314
3349
  const occurrence = occurrenceId(prop, raw, counts);
2315
3350
  const args = {};
3351
+ const opened = [];
2316
3352
  for (const key of Object.keys(raw)) {
2317
3353
  if (key === "$key") continue;
2318
3354
  const childId = `${frame.id}.${occurrence}.${key}`;
@@ -2323,12 +3359,47 @@ function createSlotProps(sink, frame) {
2323
3359
  return origRegister.call(ctx, fragKey, fragOptions);
2324
3360
  };
2325
3361
  try {
2326
- let value = raw[key];
2327
- for (let d = 0; typeof value === "function" && d < 16; d++) value = value();
3362
+ const desc = Object.getOwnPropertyDescriptor(raw, key);
3363
+ let evaluate = null;
3364
+ let value;
3365
+ let state = null;
3366
+ const stampBefore = scopeStamp();
3367
+ try {
3368
+ if (desc.get) {
3369
+ const get = desc.get;
3370
+ evaluate = () => unwrapThunks(get.call(raw));
3371
+ value = evaluate();
3372
+ } else {
3373
+ value = desc.value;
3374
+ if (typeof value === "function") {
3375
+ const fn = value;
3376
+ evaluate = () => unwrapThunks(fn);
3377
+ value = evaluate();
3378
+ }
3379
+ }
3380
+ } catch (err) {
3381
+ const blocked = solidJs.ssrHandleError && solidJs.ssrHandleError(err);
3382
+ if (!blocked) throw err;
3383
+ state = {
3384
+ settled: false,
3385
+ last: undefined
3386
+ };
3387
+ const pendingState = state;
3388
+ value = retryArgUntilSettled(evaluate, blocked, key, occurrence, v => {
3389
+ pendingState.settled = true;
3390
+ pendingState.last = v;
3391
+ sink.commit();
3392
+ });
3393
+ }
3394
+ const mintedEval = scopeStamp() !== stampBefore;
2328
3395
  const t = typeof value;
2329
3396
  if (value == null || t === "string" || t === "number" || t === "boolean") {
2330
3397
  args[key] = value;
2331
- } else if (isServerContent(value)) {
3398
+ if (evaluate) state = {
3399
+ settled: true,
3400
+ last: value
3401
+ };
3402
+ } else if (!isContainerTraced(value) && isServerContent(value)) {
2332
3403
  const resolved = ctx.resolve(value);
2333
3404
  if (resolved.h.length) {
2334
3405
  throw new Error("Async server content in a slot arg needs a boundary (arg '" + key + "' of " + occurrence + "). Wrap the async read in a <Suspense>, or move it above the slot.");
@@ -2339,30 +3410,72 @@ function createSlotProps(sink, frame) {
2339
3410
  };
2340
3411
  } else {
2341
3412
  const ref = `arg:${occurrence}:${key}`;
2342
- ctx.serialize(ref, value);
3413
+ ctx.serialize(ref, envelopeContainerTraces(value));
2343
3414
  args[key] = {
2344
3415
  $ref: ref
2345
3416
  };
3417
+ if (evaluate && !state) state = {
3418
+ settled: true,
3419
+ last: value
3420
+ };
2346
3421
  }
3422
+ if (evaluate && state && !mintedEval) opened.push({
3423
+ key,
3424
+ evaluate,
3425
+ state
3426
+ });
2347
3427
  } finally {
2348
3428
  ctx.registerFragment = origRegister;
2349
3429
  }
2350
3430
  }
2351
- sink.slot(occurrence, args);
3431
+ sink.slot(occurrence, {
3432
+ ...args
3433
+ });
3434
+ const ctx = solidJs.sharedConfig.context;
3435
+ for (const b of opened) {
3436
+ const key = b.key;
3437
+ const ledgerKey = `${occurrence}:${key}`;
3438
+ openArgBinding(sink, ledgerKey, occurrence, key, b.evaluate, b.state, value => {
3439
+ const t = typeof value;
3440
+ if (value == null || t === "string" || t === "number" || t === "boolean") {
3441
+ args[key] = value;
3442
+ } else {
3443
+ const ref = `arg:${occurrence}:${key}@${sink.nextArgRef(ledgerKey)}`;
3444
+ sink.mintRef(ref);
3445
+ ctx.serialize(ref, envelopeContainerTraces(value));
3446
+ args[key] = {
3447
+ $ref: ref
3448
+ };
3449
+ }
3450
+ sink.slot(occurrence, {
3451
+ ...args
3452
+ });
3453
+ });
3454
+ }
2352
3455
  return slotRange(occurrence);
2353
3456
  };
3457
+ fn.$lhSkip = true;
2354
3458
  getters.set(prop, fn);
2355
3459
  }
2356
3460
  return fn;
2357
3461
  }
2358
3462
  });
2359
3463
  }
3464
+ function copyInitHeaders(init) {
3465
+ if (!init || !init.getSetCookie) return new Headers(init);
3466
+ const headers = new Headers();
3467
+ init.forEach((value, key) => {
3468
+ if (key !== "set-cookie") headers.append(key, value);
3469
+ });
3470
+ for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
3471
+ return headers;
3472
+ }
2360
3473
  function serverComponentResponse(component, options = {}, init = {}) {
2361
3474
  const {
2362
3475
  id = "",
2363
3476
  version = 1
2364
3477
  } = options.frame || {};
2365
- const headers = new Headers(init.headers);
3478
+ const headers = copyInitHeaders(init.headers);
2366
3479
  headers.set("Content-Type", "application/x-frame-stream");
2367
3480
  headers.set(FRAME_STREAM_HEADER, id);
2368
3481
  headers.set("X-Content-Raw", "1");
@@ -2373,16 +3486,27 @@ function serverComponentResponse(component, options = {}, init = {}) {
2373
3486
  version
2374
3487
  }
2375
3488
  });
3489
+ let closed = false;
2376
3490
  const body = new ReadableStream({
2377
3491
  start(controller) {
2378
3492
  stream.pipe({
2379
3493
  write(chunk) {
2380
- controller.enqueue(createChunk(JSON.stringify(chunk)));
3494
+ if (closed) return;
3495
+ try {
3496
+ controller.enqueue(createChunk(JSON.stringify(chunk)));
3497
+ } catch (_) {
3498
+ closed = true;
3499
+ }
2381
3500
  },
2382
3501
  end() {
3502
+ if (closed) return;
3503
+ closed = true;
2383
3504
  controller.close();
2384
3505
  }
2385
3506
  });
3507
+ },
3508
+ cancel() {
3509
+ closed = true;
2386
3510
  }
2387
3511
  });
2388
3512
  return new Response(body, {
@@ -2461,14 +3585,22 @@ function frameFlightResponse({
2461
3585
  codec
2462
3586
  }, init = {}) {
2463
3587
  const frames = primary ? [primary, ...regions] : regions;
2464
- const headers = new Headers(init.headers);
3588
+ const headers = copyInitHeaders(init.headers);
2465
3589
  headers.set("Content-Type", "application/x-frame-stream");
2466
3590
  headers.set(FRAME_STREAM_HEADER, primary ? primary.id : "");
2467
3591
  headers.set("X-Content-Raw", "1");
2468
3592
  headers.set(SINGLE_FLIGHT_HEADER, "true");
3593
+ let closed = false;
2469
3594
  const body = new ReadableStream({
2470
3595
  async start(controller) {
2471
- const write = chunk => controller.enqueue(createChunk(JSON.stringify(chunk)));
3596
+ const write = chunk => {
3597
+ if (closed) return;
3598
+ try {
3599
+ controller.enqueue(createChunk(JSON.stringify(chunk)));
3600
+ } catch (_) {
3601
+ closed = true;
3602
+ }
3603
+ };
2472
3604
  try {
2473
3605
  for (const {
2474
3606
  id,
@@ -2495,10 +3627,19 @@ function frameFlightResponse({
2495
3627
  });
2496
3628
  }
2497
3629
  }
2498
- controller.close();
3630
+ if (!closed) {
3631
+ closed = true;
3632
+ controller.close();
3633
+ }
2499
3634
  } catch (err) {
2500
- controller.error(err);
3635
+ if (!closed) {
3636
+ closed = true;
3637
+ controller.error(err);
3638
+ }
2501
3639
  }
3640
+ },
3641
+ cancel() {
3642
+ closed = true;
2502
3643
  }
2503
3644
  });
2504
3645
  return new Response(body, {
@@ -2507,9 +3648,15 @@ function frameFlightResponse({
2507
3648
  });
2508
3649
  }
2509
3650
 
3651
+ setContainerTraceResolver(solidJs.getProjectionTrace);
3652
+ function asyncArg(value) {
3653
+ return value;
3654
+ }
3655
+
2510
3656
  exports.FRAME_STREAM_HEADER = FRAME_STREAM_HEADER;
2511
3657
  exports.SERVER_COMPONENT_BOOTSTRAP = SERVER_COMPONENT_BOOTSTRAP;
2512
3658
  exports.ServerComponentPlugin = ServerComponentPlugin;
3659
+ exports.asyncArg = asyncArg;
2513
3660
  exports.createFrameSink = createFrameSink;
2514
3661
  exports.frameTransformDirectResult = frameTransformDirectResult;
2515
3662
  exports.frameTransformFlightResult = frameTransformFlightResult;