@solidjs/web 2.0.0-beta.32 → 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 (52) hide show
  1. package/dist/dev.cjs +51 -15
  2. package/dist/dev.js +47 -16
  3. package/dist/server.cjs +710 -71
  4. package/dist/server.js +707 -74
  5. package/dist/web.cjs +51 -15
  6. package/dist/web.js +47 -16
  7. package/frames/dist/client.cjs +181 -64
  8. package/frames/dist/client.dev.cjs +185 -64
  9. package/frames/dist/client.dev.js +183 -62
  10. package/frames/dist/client.js +179 -62
  11. package/frames/dist/server.cjs +969 -133
  12. package/frames/dist/server.js +971 -135
  13. package/package.json +17 -6
  14. package/serialization/decode/package.json +20 -0
  15. package/serialization/dist/decode.cjs +110 -0
  16. package/serialization/dist/decode.js +104 -0
  17. package/serialization/dist/serialization.cjs +98 -43
  18. package/serialization/dist/serialization.js +99 -44
  19. package/serialization/types/index.d.ts +18 -160
  20. package/serialization/types/serializer-decode.d.ts +182 -0
  21. package/serialization/types-cjs/index.d.cts +18 -160
  22. package/serialization/types-cjs/serializer-decode.d.cts +182 -0
  23. package/server-functions/dist/client.cjs +101 -105
  24. package/server-functions/dist/client.js +101 -105
  25. package/server-functions/dist/server.cjs +131 -107
  26. package/server-functions/dist/server.dev.cjs +131 -107
  27. package/server-functions/dist/server.dev.js +132 -108
  28. package/server-functions/dist/server.js +132 -108
  29. package/types/client.d.ts +23 -1
  30. package/types/cookies.d.ts +93 -0
  31. package/types/core.d.ts +1 -1
  32. package/types/frames/frame-client.d.ts +26 -0
  33. package/types/frames/frame-transport.d.ts +1 -1
  34. package/types/frames/serializer.d.ts +18 -160
  35. package/types/serializer-decode.d.ts +182 -0
  36. package/types/serializer.d.ts +18 -160
  37. package/types/server-functions/client.d.ts +1 -1
  38. package/types/server-functions/server.d.ts +1 -1
  39. package/types/server-functions/shared.d.ts +57 -1
  40. package/types/server.d.ts +21 -1
  41. package/types-cjs/client.d.cts +23 -1
  42. package/types-cjs/cookies.d.cts +93 -0
  43. package/types-cjs/core.d.cts +1 -1
  44. package/types-cjs/frames/frame-client.d.cts +26 -0
  45. package/types-cjs/frames/frame-transport.d.cts +1 -1
  46. package/types-cjs/frames/serializer.d.cts +18 -160
  47. package/types-cjs/serializer-decode.d.cts +182 -0
  48. package/types-cjs/serializer.d.cts +18 -160
  49. package/types-cjs/server-functions/client.d.cts +1 -1
  50. package/types-cjs/server-functions/server.d.cts +1 -1
  51. package/types-cjs/server-functions/shared.d.cts +57 -1
  52. package/types-cjs/server.d.cts +21 -1
@@ -1,7 +1,99 @@
1
- import { createMemo, runWithOwner, createOwner, sharedConfig, createRoot, ssrHandleError, getOwner, NoHydration, runInServerComponentScope, Hydration } from 'solid-js';
2
- import { toCrossJSONStream, Feature, Serializer, getCrossReferenceHeader, createPlugin } from 'seroval';
1
+ import { createMemo, runWithOwner, createOwner, sharedConfig, createRoot, ssrHandleError, getOwner, inServerComponentScope, creationStamp, NoHydration, runInServerComponentScope, Hydration, getProjectionTrace } from 'solid-js';
2
+ import { Feature, toCrossJSONStream, Serializer, getCrossReferenceHeader } from 'seroval';
3
3
  import { AbortSignalPlugin, CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin } from 'seroval-plugins/web';
4
4
 
5
+ const STATE = Symbol.for("dom-expressions.container-trace-state");
6
+ const state = globalThis[STATE] || (globalThis[STATE] = {
7
+ materialized: new WeakMap(),
8
+ materializedValues: new WeakSet()
9
+ });
10
+ function setContainerTraceResolver(fn) {
11
+ state.resolveTrace = fn;
12
+ }
13
+ function isContainerTraced(value) {
14
+ const resolve = state.resolveTrace;
15
+ return !!(resolve && value && typeof value === "object" && resolve(value));
16
+ }
17
+ const TRACE = Symbol.for("dom-expressions.container-trace");
18
+ function envelopeContainerTraces(value) {
19
+ if (!state.resolveTrace || value == null || typeof value !== "object") return value;
20
+ const trace = state.resolveTrace(value);
21
+ if (trace) return {
22
+ [TRACE]: trace
23
+ };
24
+ if (Array.isArray(value)) {
25
+ let out = value;
26
+ for (let i = 0; i < value.length; i++) {
27
+ const next = envelopeContainerTraces(value[i]);
28
+ if (next !== value[i]) {
29
+ if (out === value) out = value.slice();
30
+ out[i] = next;
31
+ }
32
+ }
33
+ return out;
34
+ }
35
+ if (Object.getPrototypeOf(value) === Object.prototype) {
36
+ let out = value;
37
+ for (const key of Object.keys(value)) {
38
+ const next = envelopeContainerTraces(value[key]);
39
+ if (next !== value[key]) {
40
+ if (out === value) out = {
41
+ ...value
42
+ };
43
+ out[key] = next;
44
+ }
45
+ }
46
+ return out;
47
+ }
48
+ return value;
49
+ }
50
+ function materialize(marker) {
51
+ let value = state.materialized.get(marker.$tr);
52
+ if (value === undefined) {
53
+ value = state.materializeTrace(marker);
54
+ state.materialized.set(marker.$tr, value);
55
+ if (value !== null && typeof value === "object") state.materializedValues.add(value);
56
+ }
57
+ return value;
58
+ }
59
+ function parseTrace(value, ctx) {
60
+ const trace = value[TRACE];
61
+ return {
62
+ a: trace.array ? 1 : 0,
63
+ i: ctx.parse(trace.subscribe())
64
+ };
65
+ }
66
+ const ContainerTracePlugin = {
67
+ tag: "dom-expressions/container-trace",
68
+ test(value) {
69
+ return value != null && typeof value === "object" && TRACE in value;
70
+ },
71
+ parse: {
72
+ sync() {
73
+ throw new Error("A reactive container can only be serialized by a streaming serializer.");
74
+ },
75
+ async async(value, ctx) {
76
+ const trace = value[TRACE];
77
+ return {
78
+ a: trace.array ? 1 : 0,
79
+ i: await ctx.parse(trace.subscribe())
80
+ };
81
+ },
82
+ stream: parseTrace
83
+ },
84
+ serialize(node, ctx) {
85
+ return "{$tr:" + ctx.serialize(node.i) + ",$ta:" + node.a + "}";
86
+ },
87
+ deserialize(node, ctx) {
88
+ const iterable = ctx.deserialize(node.i);
89
+ const marker = {
90
+ $tr: iterable,
91
+ $ta: node.a
92
+ };
93
+ return state.materializeTrace ? materialize(marker) : marker;
94
+ }
95
+ };
96
+
5
97
  const runWithHydrationScope = (id, fn) => runWithOwner(createOwner({
6
98
  id
7
99
  }), fn);
@@ -9,15 +101,30 @@ const ssrAsyncValue = value => createMemo(() => value, {
9
101
  serialize: false
10
102
  });
11
103
 
12
- const DEFAULT_DISABLED_FEATURES = Feature.AggregateError | Feature.BigIntTypedArray;
13
- const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : Feature.ErrorPrototypeStack;
14
- const HYDRATION_GLOBAL = "_$HY.r";
15
104
  const DEFAULT_WEB_PLUGINS = Object.freeze([AbortSignalPlugin,
16
105
  CustomEventPlugin, DOMExceptionPlugin, EventPlugin,
17
- FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin]);
106
+ FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin,
107
+ ContainerTracePlugin]);
18
108
  function resolveSerializerPlugins(customPlugins) {
19
109
  return customPlugins ? [...customPlugins, ...DEFAULT_WEB_PLUGINS] : [...DEFAULT_WEB_PLUGINS];
20
110
  }
111
+ const JSON_CODEC_DISABLED_FEATURES = Feature.RegExp;
112
+ const JSON_CODEC_DEPTH_LIMIT = 64;
113
+ function resolveCodecOptions({
114
+ plugins,
115
+ disabledFeatures,
116
+ depthLimit
117
+ } = {}) {
118
+ return {
119
+ plugins: resolveSerializerPlugins(plugins),
120
+ disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
121
+ depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
122
+ };
123
+ }
124
+
125
+ const DEFAULT_DISABLED_FEATURES = Feature.AggregateError | Feature.BigIntTypedArray;
126
+ const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : Feature.ErrorPrototypeStack;
127
+ const HYDRATION_GLOBAL = "_$HY.r";
21
128
  function createSerializer(options) {
22
129
  return new Serializer({
23
130
  ...options,
@@ -44,34 +151,6 @@ function createHydrationSerializer({
44
151
  function getLocalHeaderScript(id) {
45
152
  return getCrossReferenceHeader(id) + ";";
46
153
  }
47
- const JSON_CODEC_DISABLED_FEATURES = Feature.RegExp;
48
- const JSON_CODEC_DEPTH_LIMIT = 64;
49
- function resolveCodecOptions({
50
- plugins,
51
- disabledFeatures,
52
- depthLimit
53
- } = {}) {
54
- return {
55
- plugins: resolveSerializerPlugins(plugins),
56
- disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
57
- depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
58
- };
59
- }
60
- function serializeJSON(value, {
61
- onParse,
62
- onDone,
63
- onError,
64
- ...codecOptions
65
- }) {
66
- const resolved = resolveCodecOptions(codecOptions);
67
- return toCrossJSONStream(value, {
68
- onParse,
69
- onDone,
70
- onError,
71
- ...resolved,
72
- disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures()
73
- });
74
- }
75
154
  function createJSONSerializer({
76
155
  onData,
77
156
  onDone,
@@ -258,7 +337,10 @@ class ChunkReader {
258
337
  }
259
338
  function serializeStream(value, codecOptions) {
260
339
  return new ReadableStream({
261
- start(controller) {
340
+ async start(controller) {
341
+ const {
342
+ serializeJSON
343
+ } = await import('@solidjs/web/serialization');
262
344
  serializeJSON(value, {
263
345
  ...codecOptions,
264
346
  onParse(node) {
@@ -345,7 +427,6 @@ function resolveHead(groups) {
345
427
  }
346
428
  for (const [identity, tags] of byIdentity) {
347
429
  if (identity === "title") {
348
- if (tags.length > 1) console.warn("Multiple <title> tags in one head group; the last one wins.");
349
430
  winners.set(identity, {
350
431
  seq: group.seq,
351
432
  tags: [tags[tags.length - 1]]
@@ -535,7 +616,6 @@ function registerHeadTags(registry, context, tracking, emitResource, nonce, tags
535
616
  for (let i = 0; i < tags.length; i++) {
536
617
  const desc = tags[i];
537
618
  if (!desc || !HEAD_ELIGIBLE_TAGS.has(desc.tag)) {
538
- console.warn(`useHead: ignoring non-head tag`, desc);
539
619
  continue;
540
620
  }
541
621
  const cls = classifyHeadTag(desc);
@@ -587,7 +667,6 @@ function headShellReady(registry, block) {
587
667
  } : undefined);
588
668
  } catch (err) {
589
669
  if (pends(err)) continue;
590
- console.warn(`useHead: error evaluating resource tag props`, err);
591
670
  parked.splice(i, 1);
592
671
  continue;
593
672
  }
@@ -628,7 +707,6 @@ function emitHeadResource(registry, context, tracking, emitResource, nonce, desc
628
707
  });
629
708
  return;
630
709
  }
631
- console.warn(`useHead: error evaluating resource tag props`, err);
632
710
  return;
633
711
  }
634
712
  const identity = resourceIdentity(desc.tag, props);
@@ -690,7 +768,6 @@ function commitHeadBoundary(registry, boundary, isPendingFragment) {
690
768
  try {
691
769
  resolved = reg.list();
692
770
  } catch (err) {
693
- console.warn(`useHead: error evaluating head group membership`, err);
694
771
  continue;
695
772
  }
696
773
  if (!Array.isArray(resolved)) resolved = [resolved];
@@ -698,7 +775,6 @@ function commitHeadBoundary(registry, boundary, isPendingFragment) {
698
775
  for (let j = 0; j < resolved.length; j++) {
699
776
  const desc = resolved[j];
700
777
  if (!desc || !HEAD_ELIGIBLE_TAGS.has(desc.tag)) {
701
- console.warn(`useHead: ignoring non-head tag`, desc);
702
778
  continue;
703
779
  }
704
780
  const cls = classifyHeadTag(desc);
@@ -724,12 +800,10 @@ function commitHeadBoundary(registry, boundary, isPendingFragment) {
724
800
  } : undefined);
725
801
  key = evalHeadValue(desc.key);
726
802
  } catch (err) {
727
- console.warn(`useHead: error evaluating tag props`, err);
728
803
  continue;
729
804
  }
730
805
  const identity = replaceableIdentity(desc.tag, props, key, "u:" + registry.uniq++);
731
806
  if ((identity === "base" || identity === "charset") && registry.shellFlushed) {
732
- console.warn(`useHead: <${desc.tag}> (${identity}) registered after shell flush is ignored`);
733
807
  continue;
734
808
  }
735
809
  tags.push({
@@ -811,7 +885,6 @@ function flushHeadFragment(registry, boundary) {
811
885
  for (const name in t.props) {
812
886
  if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
813
887
  if (!HEAD_ATTR_NAME.test(name)) {
814
- console.warn(`useHead: ignoring invalid attribute name "${name}"`);
815
888
  continue;
816
889
  }
817
890
  const v = t.props[name];
@@ -829,7 +902,6 @@ function renderHeadAttrHtml(props) {
829
902
  for (const name in props) {
830
903
  if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
831
904
  if (!HEAD_ATTR_NAME.test(name)) {
832
- console.warn(`useHead: ignoring invalid attribute name "${name}"`);
833
905
  continue;
834
906
  }
835
907
  const v = props[name];
@@ -889,6 +961,12 @@ function renderToStream(code, options = {}) {
889
961
  d();
890
962
  }
891
963
  };
964
+ const failRender = err => {
965
+ try {
966
+ options.onError ? options.onError(err) : console.error(err);
967
+ } catch (_) {}
968
+ abandon();
969
+ };
892
970
  const guardSink = w => ({
893
971
  write(payload) {
894
972
  if (dead) return;
@@ -987,10 +1065,18 @@ function renderToStream(code, options = {}) {
987
1065
  rootAssetsSerialized = true;
988
1066
  serializeFragmentAssets("", tracking.boundaryModules, context);
989
1067
  };
1068
+ let holds = 0;
990
1069
  const flushEnd = () => {
991
- if (!registry.size) {
1070
+ if (!registry.size && !holds) {
992
1071
  serializeRootAssets();
993
- queue(() => queue(() => serializer.flush()));
1072
+ queue(() => queue(() => {
1073
+ if (context.live.end) {
1074
+ const end = context.live.end;
1075
+ context.live.end = null;
1076
+ end();
1077
+ }
1078
+ serializer.flush();
1079
+ }));
994
1080
  }
995
1081
  };
996
1082
  const registry = new Map();
@@ -1051,6 +1137,7 @@ function renderToStream(code, options = {}) {
1051
1137
  sharedConfig.context = context = {
1052
1138
  async: true,
1053
1139
  nonce,
1140
+ live: {},
1054
1141
  registerHeadTags(tags) {
1055
1142
  registerHeadTags(headRegistry, context, tracking,
1056
1143
  (markup, gateEntry) => {
@@ -1087,6 +1174,16 @@ function renderToStream(code, options = {}) {
1087
1174
  block(p) {
1088
1175
  if (!firstFlushed) blockingPromises.add(p);
1089
1176
  },
1177
+ hold() {
1178
+ holds++;
1179
+ let released = false;
1180
+ return () => {
1181
+ if (released) return;
1182
+ released = true;
1183
+ holds--;
1184
+ if (!holds) queue(flushEnd);
1185
+ };
1186
+ },
1090
1187
  replace(id, payloadFn) {
1091
1188
  if (firstFlushed) return;
1092
1189
  const placeholder = `<!--!$${id}-->`;
@@ -1195,6 +1292,7 @@ function renderToStream(code, options = {}) {
1195
1292
  }
1196
1293
  };
1197
1294
  applyAssetTracking(context, tracking, manifest, noScripts);
1295
+ context.failRender = failRender;
1198
1296
  registerEntryAssets(manifest);
1199
1297
  let html = createRoot(d => {
1200
1298
  dispose = d;
@@ -1307,7 +1405,12 @@ function renderToStream(code, options = {}) {
1307
1405
  allSettled(blockingPromises).then(() => {
1308
1406
  scheduleFlush(() => {
1309
1407
  if (dead) return resolve();
1310
- doShell();
1408
+ try {
1409
+ doShell();
1410
+ } catch (err) {
1411
+ failRender(err);
1412
+ return resolve();
1413
+ }
1311
1414
  if (!shellCompleted) return flush();
1312
1415
  const encoder = new TextEncoder();
1313
1416
  const writer = w.getWriter();
@@ -1364,7 +1467,12 @@ function renderToStream(code, options = {}) {
1364
1467
  function flush() {
1365
1468
  allSettled(blockingPromises).then(() => {
1366
1469
  scheduleFlush(() => {
1367
- if (!resolveRootHoles() || !headShellReady(headRegistry, p => blockingPromises.add(p))) return flush();
1470
+ try {
1471
+ if (!resolveRootHoles() || !headShellReady(headRegistry, p => blockingPromises.add(p))) return flush();
1472
+ } catch (err) {
1473
+ failRender(err);
1474
+ return resolve(tmp);
1475
+ }
1368
1476
  queue(flushEnd);
1369
1477
  });
1370
1478
  });
@@ -1379,7 +1487,15 @@ function renderToStream(code, options = {}) {
1379
1487
  allSettled(blockingPromises).then(() => {
1380
1488
  scheduleFlush(() => {
1381
1489
  if (dead) return;
1382
- doShell();
1490
+ try {
1491
+ doShell();
1492
+ } catch (err) {
1493
+ failRender(err);
1494
+ try {
1495
+ w.end();
1496
+ } catch (_) {}
1497
+ return;
1498
+ }
1383
1499
  if (!shellCompleted) return flush();
1384
1500
  buffer = writable = guardSink(w);
1385
1501
  buffer.write(tmp);
@@ -1411,9 +1527,27 @@ function renderToStream(code, options = {}) {
1411
1527
  function buildAsyncWrap(err, node) {
1412
1528
  const p = ssrHandleError(err);
1413
1529
  if (!p) return null;
1530
+ if (node.$rw) return {
1531
+ fn: node,
1532
+ p
1533
+ };
1414
1534
  const owner = getOwner();
1535
+ const live = sharedConfig.context && sharedConfig.context.liveHoles;
1536
+ const suppress = node.$lhSuppress || live && (live.suppressed || live.sweeping);
1537
+ if (!owner) {
1538
+ if (suppress) node.$lhSuppress = true;
1539
+ return {
1540
+ fn: node,
1541
+ p
1542
+ };
1543
+ }
1544
+ const fn = () => runWithOwner(owner, node);
1545
+ fn.$rw = true;
1546
+ if (suppress) fn.$lhSuppress = true;
1547
+ if (node.$lhSkip) fn.$lhSkip = true;
1548
+ if (node.$lhBinding) fn.$lhBinding = node.$lhBinding;
1415
1549
  return {
1416
- fn: owner ? () => runWithOwner(owner, node) : node,
1550
+ fn,
1417
1551
  p
1418
1552
  };
1419
1553
  }
@@ -1473,6 +1607,326 @@ function ssrGroupSlot(fn, idx) {
1473
1607
  }
1474
1608
  };
1475
1609
  }
1610
+ const holePositionCache = new WeakMap();
1611
+ function holeContentPositions(t) {
1612
+ let cached = holePositionCache.get(t);
1613
+ if (cached) return cached;
1614
+ const pos = [];
1615
+ const openOff = [];
1616
+ const closeOff = [];
1617
+ let inTag = false;
1618
+ let quote = "";
1619
+ let curOpen = null;
1620
+ let scanningName = false;
1621
+ for (let i = 0; i < t.length; i++) {
1622
+ const seg = t[i];
1623
+ let close = -1;
1624
+ const openAtStart = inTag;
1625
+ let reopened = false;
1626
+ for (let j = 0; j < seg.length; j++) {
1627
+ const ch = seg[j];
1628
+ if (quote) {
1629
+ if (ch === quote) quote = "";
1630
+ } else if (inTag) {
1631
+ if (scanningName && (ch === " " || ch === "\t" || ch === "\n" || ch === ">" || ch === "/")) {
1632
+ scanningName = false;
1633
+ curOpen = {
1634
+ seg: i,
1635
+ off: j
1636
+ };
1637
+ }
1638
+ if (ch === '"' || ch === "'") quote = ch;else if (ch === ">") {
1639
+ inTag = false;
1640
+ if (openAtStart && !reopened && close === -1) close = j;
1641
+ curOpen = null;
1642
+ }
1643
+ } else if (ch === "<") {
1644
+ inTag = true;
1645
+ scanningName = true;
1646
+ reopened = true;
1647
+ curOpen = null;
1648
+ }
1649
+ }
1650
+ if (inTag && scanningName) {
1651
+ scanningName = false;
1652
+ curOpen = {
1653
+ seg: i,
1654
+ off: seg.length
1655
+ };
1656
+ }
1657
+ closeOff.push(close);
1658
+ openOff.push(inTag && curOpen && curOpen.seg === i ? curOpen.off : -1);
1659
+ if (i < t.length - 1) pos.push(!inTag);
1660
+ }
1661
+ cached = {
1662
+ pos,
1663
+ openOff,
1664
+ closeOff
1665
+ };
1666
+ holePositionCache.set(t, cached);
1667
+ return cached;
1668
+ }
1669
+ function createLiveHoles(sink, scoped) {
1670
+ let nextId = 0;
1671
+ const stamp = typeof creationStamp === "function" ? creationStamp : () => 0;
1672
+ const inScope = scoped && typeof inServerComponentScope === "function" ? inServerComponentScope : null;
1673
+ const stripMarkers = html => html.replace(/<!--lh:\/?\d+-->/g, "");
1674
+ function resolveHoleValue(hole) {
1675
+ const result = {
1676
+ t: [""],
1677
+ h: [],
1678
+ p: []
1679
+ };
1680
+ try {
1681
+ resolveSSRNode(hole(), result);
1682
+ } catch (err) {
1683
+ const wrap = buildAsyncWrap(err, hole);
1684
+ if (!wrap) throw err;
1685
+ result.h.push(wrap.fn);
1686
+ result.p.push(wrap.p);
1687
+ result.t.push("");
1688
+ }
1689
+ return result;
1690
+ }
1691
+ function closeChildren(b) {
1692
+ for (const c of b.children) {
1693
+ c.closed = true;
1694
+ if (c.key) sink.closeBinding(c.key);
1695
+ closeChildren(c);
1696
+ }
1697
+ b.children.length = 0;
1698
+ }
1699
+ const engine = {
1700
+ suppressed: 0,
1701
+ sweeping: false,
1702
+ parent: null,
1703
+ recordStamp: 0,
1704
+ gateHit: false,
1705
+ content(hole) {
1706
+ if (hole.$lhSuppress) {
1707
+ const r = {
1708
+ t: [""],
1709
+ h: [],
1710
+ p: []
1711
+ };
1712
+ engine.suppressed++;
1713
+ try {
1714
+ try {
1715
+ resolveSSRNode(hole(), r);
1716
+ } catch (err) {
1717
+ const wrap = buildAsyncWrap(err, hole);
1718
+ if (wrap) {
1719
+ r.h.push(wrap.fn);
1720
+ r.p.push(wrap.p);
1721
+ r.t.push("");
1722
+ }
1723
+ }
1724
+ } finally {
1725
+ engine.suppressed--;
1726
+ }
1727
+ const b = hole.$lhBinding;
1728
+ if (b && !b.closed && !r.h.length && !engine.sweeping) {
1729
+ b.last = stripMarkers(r.t[0]);
1730
+ }
1731
+ return r.h.length ? r : r.t[0];
1732
+ }
1733
+ if (engine.suppressed || engine.sweeping) return null;
1734
+ if (hole.$lhSkip) return null;
1735
+ if (inScope && !inScope()) return null;
1736
+ const recordsBefore = engine.recordStamp;
1737
+ const ownersBefore = stamp();
1738
+ const owner = getOwner();
1739
+ const b = {
1740
+ key: null,
1741
+ children: [],
1742
+ last: null,
1743
+ closed: false,
1744
+ sweep() {
1745
+ if (b.closed) return;
1746
+ const prevSweeping = engine.sweeping;
1747
+ engine.sweeping = true;
1748
+ engine.gateHit = false;
1749
+ const sweepOwnersBefore = stamp();
1750
+ let res;
1751
+ try {
1752
+ res = owner ? runWithOwner(owner, () => resolveHoleValue(hole)) : resolveHoleValue(hole);
1753
+ } catch (err) {
1754
+ b.closed = true;
1755
+ sink.closeBinding(b.key);
1756
+ sink.error(b.key, String(err && err.message || err));
1757
+ return;
1758
+ } finally {
1759
+ engine.sweeping = prevSweeping;
1760
+ }
1761
+ if (engine.gateHit || stamp() !== sweepOwnersBefore) {
1762
+ b.closed = true;
1763
+ sink.closeBinding(b.key);
1764
+ return;
1765
+ }
1766
+ if (res.h.length) return;
1767
+ const html = res.t[0];
1768
+ if (b.last === null || html === b.last) return;
1769
+ b.last = html;
1770
+ closeChildren(b);
1771
+ sink.hole(b.key, html);
1772
+ }
1773
+ };
1774
+ if (engine.parent) engine.parent.children.push(b);
1775
+ const prevParent = engine.parent;
1776
+ engine.parent = b;
1777
+ let value;
1778
+ let escalated = null;
1779
+ try {
1780
+ value = hole();
1781
+ } catch (err) {
1782
+ const wrap = buildAsyncWrap(err, hole);
1783
+ if (!wrap) {
1784
+ engine.parent = prevParent;
1785
+ closeChildren(b);
1786
+ return "";
1787
+ }
1788
+ escalated = wrap;
1789
+ }
1790
+ if (!escalated && (typeof value === "function" && value.$lhSkip || value !== null && typeof value === "object" && value.$slot)) {
1791
+ engine.parent = prevParent;
1792
+ const r = {
1793
+ t: [""],
1794
+ h: [],
1795
+ p: []
1796
+ };
1797
+ engine.suppressed++;
1798
+ try {
1799
+ resolveSSRNode(value, r);
1800
+ } finally {
1801
+ engine.suppressed--;
1802
+ }
1803
+ return r.h.length ? r : r.t[0];
1804
+ }
1805
+ let res;
1806
+ if (escalated) {
1807
+ closeChildren(b);
1808
+ escalated.fn.$lhSuppress = true;
1809
+ escalated.fn.$lhBinding = b;
1810
+ res = {
1811
+ t: ["", ""],
1812
+ h: [escalated.fn],
1813
+ p: [escalated.p]
1814
+ };
1815
+ } else {
1816
+ res = {
1817
+ t: [""],
1818
+ h: [],
1819
+ p: []
1820
+ };
1821
+ try {
1822
+ resolveSSRNode(value, res);
1823
+ } catch (_) {
1824
+ engine.parent = prevParent;
1825
+ closeChildren(b);
1826
+ return "";
1827
+ }
1828
+ }
1829
+ engine.parent = prevParent;
1830
+ if (engine.recordStamp !== recordsBefore || stamp() !== ownersBefore) {
1831
+ return res.h.length ? res : res.t[0];
1832
+ }
1833
+ const id = nextId++;
1834
+ const key = b.key = "lh:" + id;
1835
+ const open = `<!--lh:${id}-->`;
1836
+ const close = `<!--lh:/${id}-->`;
1837
+ if (!res.h.length) {
1838
+ b.last = stripMarkers(res.t[0]);
1839
+ sink.openBinding(key, b);
1840
+ return open + res.t[0] + close;
1841
+ }
1842
+ const t = res.t.slice();
1843
+ t[0] = open + t[0];
1844
+ t[t.length - 1] += close;
1845
+ sink.openBinding(key, b);
1846
+ return {
1847
+ t,
1848
+ h: res.h,
1849
+ p: res.p
1850
+ };
1851
+ },
1852
+ mint() {
1853
+ return nextId++;
1854
+ },
1855
+ active() {
1856
+ return !inScope || inScope();
1857
+ },
1858
+ attr(cap) {
1859
+ const owner = getOwner();
1860
+ const b = {
1861
+ key: "lha:" + cap.id,
1862
+ children: [],
1863
+ last: cap.base,
1864
+ closed: false,
1865
+ sweep() {
1866
+ if (b.closed) return;
1867
+ const prevSweeping = engine.sweeping;
1868
+ engine.sweeping = true;
1869
+ engine.gateHit = false;
1870
+ const sweepOwnersBefore = stamp();
1871
+ let html = "";
1872
+ try {
1873
+ let group = null;
1874
+ let groupVal = null;
1875
+ const run = () => {
1876
+ for (const part of cap.parts) {
1877
+ if (typeof part === "string") {
1878
+ html += part;
1879
+ continue;
1880
+ }
1881
+ let v;
1882
+ if (part.g) {
1883
+ if (group !== part.g) {
1884
+ group = part.g;
1885
+ groupVal = part.g();
1886
+ }
1887
+ v = groupVal[part.i];
1888
+ } else {
1889
+ v = part.f();
1890
+ }
1891
+ const vt = typeof v;
1892
+ if (vt === "string" || vt === "number") html += v;
1893
+ }
1894
+ };
1895
+ owner ? runWithOwner(owner, run) : run();
1896
+ } catch (err) {
1897
+ if (ssrHandleError(err, true)) return;
1898
+ b.closed = true;
1899
+ sink.closeBinding(b.key);
1900
+ sink.error("lha:" + cap.id, String(err && err.message || err));
1901
+ return;
1902
+ } finally {
1903
+ engine.sweeping = prevSweeping;
1904
+ }
1905
+ if (engine.gateHit || stamp() !== sweepOwnersBefore) {
1906
+ b.closed = true;
1907
+ sink.closeBinding(b.key);
1908
+ return;
1909
+ }
1910
+ if (html === b.last) return;
1911
+ const before = attrNames(b.last);
1912
+ const after = attrNames(html);
1913
+ const removed = before.filter(n => !after.includes(n));
1914
+ b.last = html;
1915
+ sink.attr(String(cap.id), html, removed);
1916
+ }
1917
+ };
1918
+ sink.openBinding(b.key, b);
1919
+ }
1920
+ };
1921
+ return engine;
1922
+ }
1923
+ function attrNames(text) {
1924
+ const names = [];
1925
+ const re = /(?:^|\s)([^\s=/>"']+)(?:="[^"]*")?/g;
1926
+ let m;
1927
+ while (m = re.exec(text)) names.push(m[1]);
1928
+ return names;
1929
+ }
1476
1930
  function ssr(t) {
1477
1931
  const len = arguments.length;
1478
1932
  if (len === 1) return {
@@ -1483,13 +1937,54 @@ function ssr(t) {
1483
1937
  let lastGroup = null;
1484
1938
  let lastGroupVal = null;
1485
1939
  let lastGroupIdx = 0;
1940
+ const live = sharedConfig.context && sharedConfig.context.liveHoles;
1941
+ const hp = live ? holeContentPositions(t) : null;
1942
+ let lastOpen = null;
1943
+ let cap = null;
1944
+ if (live && hp.openOff[0] >= 0) lastOpen = {
1945
+ r: null,
1946
+ seg: -1,
1947
+ off: hp.openOff[0]
1948
+ };
1949
+ const captureStart = () => {
1950
+ if (cap) return true;
1951
+ if (!lastOpen || live.suppressed || live.sweeping || !live.active()) return false;
1952
+ if (lastOpen.r !== result || result !== null && lastOpen.seg !== result.t.length - 1) {
1953
+ return false;
1954
+ }
1955
+ const id = live.mint();
1956
+ const inject = ` data-lha="${id}"`;
1957
+ let prefix;
1958
+ if (result === null) {
1959
+ s = s.slice(0, lastOpen.off) + inject + s.slice(lastOpen.off);
1960
+ prefix = s.slice(lastOpen.off + inject.length);
1961
+ } else {
1962
+ const seg = result.t[lastOpen.seg];
1963
+ result.t[lastOpen.seg] = seg.slice(0, lastOpen.off) + inject + seg.slice(lastOpen.off);
1964
+ prefix = result.t[lastOpen.seg].slice(lastOpen.off + inject.length);
1965
+ }
1966
+ cap = {
1967
+ id,
1968
+ parts: [prefix],
1969
+ base: prefix
1970
+ };
1971
+ return true;
1972
+ };
1486
1973
  for (let i = 1; i < len; i++) {
1487
1974
  const hole = arguments[i];
1488
1975
  const ht = typeof hole;
1489
1976
  if (ht === "string") {
1490
1977
  if (result === null) s += hole;else result.t[result.t.length - 1] += hole;
1978
+ if (cap) {
1979
+ cap.parts.push(hole);
1980
+ cap.base += hole;
1981
+ }
1491
1982
  } else if (ht === "number") {
1492
1983
  if (result === null) s += hole;else result.t[result.t.length - 1] += hole;
1984
+ if (cap) {
1985
+ cap.parts.push("" + hole);
1986
+ cap.base += hole;
1987
+ }
1493
1988
  } else if (hole == null || ht === "boolean") ; else if (ht === "function" && hole.$g) {
1494
1989
  let value;
1495
1990
  let hasValue = false;
@@ -1513,7 +2008,14 @@ function ssr(t) {
1513
2008
  if (Array.isArray(lastGroupVal)) {
1514
2009
  value = lastGroupVal[lastGroupIdx++];
1515
2010
  hasValue = true;
2011
+ if (live && !hp.pos[i - 1] && captureStart()) {
2012
+ cap.parts.push({
2013
+ g: hole,
2014
+ i: lastGroupIdx - 1
2015
+ });
2016
+ }
1516
2017
  } else {
2018
+ cap = null;
1517
2019
  result.h.push(ssrGroupSlot(lastGroupVal.fn, lastGroupIdx++));
1518
2020
  result.p.push(lastGroupVal.p);
1519
2021
  result.t.push("");
@@ -1523,6 +2025,7 @@ function ssr(t) {
1523
2025
  const vt = typeof value;
1524
2026
  if (vt === "string" || vt === "number") {
1525
2027
  if (result === null) s += value;else result.t[result.t.length - 1] += value;
2028
+ if (cap && !hp.pos[i - 1]) cap.base += value;
1526
2029
  } else if (value == null || vt === "boolean") ; else if (result !== null) {
1527
2030
  resolveSSRNode(value, result);
1528
2031
  } else {
@@ -1540,19 +2043,67 @@ function ssr(t) {
1540
2043
  }
1541
2044
  }
1542
2045
  }
1543
- } else if (result !== null) {
1544
- resolveSSRNode(hole, result);
1545
2046
  } else if (ht === "function") {
1546
- const r = tryResolveFunctionHole(hole);
1547
- if (typeof r === "string") s += r;else {
1548
- result = {
1549
- t: [s],
1550
- h: [],
1551
- p: []
1552
- };
1553
- s = "";
1554
- appendResolvedNode(result, r);
2047
+ let liveNode = null;
2048
+ if (live && hp.pos[i - 1] && (liveNode = live.content(hole)) !== null) {
2049
+ if (typeof liveNode === "string") {
2050
+ if (result === null) s += liveNode;else result.t[result.t.length - 1] += liveNode;
2051
+ } else {
2052
+ if (result === null) {
2053
+ result = {
2054
+ t: [s],
2055
+ h: [],
2056
+ p: []
2057
+ };
2058
+ s = "";
2059
+ }
2060
+ resolveSSRNode(liveNode, result);
2061
+ }
2062
+ } else if (result !== null) {
2063
+ const inTag = live && !hp.pos[i - 1];
2064
+ const capturing = inTag && captureStart();
2065
+ const li = capturing ? result.t.length - 1 : 0;
2066
+ const before = capturing ? result.t[li].length : 0;
2067
+ if (live) live.suppressed++;
2068
+ try {
2069
+ resolveSSRNode(hole, result);
2070
+ } finally {
2071
+ if (live) live.suppressed--;
2072
+ }
2073
+ if (capturing) {
2074
+ if (result.t.length - 1 === li) {
2075
+ cap.base += result.t[li].slice(before);
2076
+ cap.parts.push({
2077
+ f: hole
2078
+ });
2079
+ } else {
2080
+ cap = null;
2081
+ }
2082
+ }
2083
+ } else {
2084
+ const capturing = live && !hp.pos[i - 1] && captureStart();
2085
+ const r = tryResolveFunctionHole(hole);
2086
+ if (typeof r === "string") {
2087
+ s += r;
2088
+ if (capturing) {
2089
+ cap.base += r;
2090
+ cap.parts.push({
2091
+ f: hole
2092
+ });
2093
+ }
2094
+ } else {
2095
+ if (capturing) cap = null;
2096
+ result = {
2097
+ t: [s],
2098
+ h: [],
2099
+ p: []
2100
+ };
2101
+ s = "";
2102
+ appendResolvedNode(result, r);
2103
+ }
1555
2104
  }
2105
+ } else if (result !== null) {
2106
+ resolveSSRNode(hole, result);
1556
2107
  } else {
1557
2108
  const r = tryResolveString(hole);
1558
2109
  if (typeof r === "string") {
@@ -1568,6 +2119,32 @@ function ssr(t) {
1568
2119
  }
1569
2120
  }
1570
2121
  const next = t[i];
2122
+ if (live) {
2123
+ if (cap) {
2124
+ const co = hp.closeOff[i];
2125
+ if (co >= 0) {
2126
+ const tail = next.slice(0, co);
2127
+ cap.parts.push(tail);
2128
+ cap.base += tail;
2129
+ live.attr(cap);
2130
+ cap = null;
2131
+ } else {
2132
+ cap.parts.push(next);
2133
+ cap.base += next;
2134
+ }
2135
+ }
2136
+ if (hp.openOff[i] >= 0) {
2137
+ lastOpen = result === null ? {
2138
+ r: null,
2139
+ seg: -1,
2140
+ off: s.length + hp.openOff[i]
2141
+ } : {
2142
+ r: result,
2143
+ seg: result.t.length - 1,
2144
+ off: result.t[result.t.length - 1].length + hp.openOff[i]
2145
+ };
2146
+ }
2147
+ }
1571
2148
  if (result === null) s += next;else result.t[result.t.length - 1] += next;
1572
2149
  }
1573
2150
  if (result === null) return {
@@ -1800,7 +2377,6 @@ function tryResolveString(node) {
1800
2377
  merge: node
1801
2378
  };
1802
2379
  if (node.t === undefined) {
1803
- console.warn(`Unrecognized value. Skipped inserting`, node);
1804
2380
  return "";
1805
2381
  }
1806
2382
  return Array.isArray(node.t) ? node.t[0] : node.t;
@@ -1825,13 +2401,19 @@ function resolveSSRNode(node, result = {
1825
2401
  if (t === "string" || t === "number") {
1826
2402
  result.t[result.t.length - 1] += node;
1827
2403
  } else if (node == null || t === "boolean") ; else if (Array.isArray(node)) {
1828
- let prevNonObj = false;
1829
- for (let i = 0, len = node.length; i < len; i++) {
1830
- const item = node[i];
1831
- const itemNonObj = item !== null && typeof item !== "object";
1832
- if (!top && prevNonObj && itemNonObj) result.t[result.t.length - 1] += `<!--!$-->`;
1833
- prevNonObj = itemNonObj;
1834
- resolveSSRNode(item, result);
2404
+ const slotLive = node.$slot && sharedConfig.context && sharedConfig.context.liveHoles;
2405
+ if (slotLive) slotLive.suppressed++;
2406
+ try {
2407
+ let prevNonObj = false;
2408
+ for (let i = 0, len = node.length; i < len; i++) {
2409
+ const item = node[i];
2410
+ const itemNonObj = item !== null && typeof item !== "object";
2411
+ if (!top && prevNonObj && itemNonObj) result.t[result.t.length - 1] += `<!--!$-->`;
2412
+ prevNonObj = itemNonObj;
2413
+ resolveSSRNode(item, result);
2414
+ }
2415
+ } finally {
2416
+ if (slotLive) slotLive.suppressed--;
1835
2417
  }
1836
2418
  } else if (t === "object") {
1837
2419
  if (node.h) {
@@ -1843,16 +2425,22 @@ function resolveSSRNode(node, result = {
1843
2425
  }
1844
2426
  } else if (node.t !== undefined) {
1845
2427
  result.t[result.t.length - 1] += node.t;
1846
- } else console.warn(`Unrecognized value. Skipped inserting`, node);
2428
+ } else ;
1847
2429
  } else if (t === "function") {
1848
- try {
1849
- resolveSSRNode(node(), result);
1850
- } catch (err) {
1851
- const wrap = buildAsyncWrap(err, node);
1852
- if (wrap) {
1853
- result.h.push(wrap.fn);
1854
- result.p.push(wrap.p);
1855
- result.t.push("");
2430
+ const live = sharedConfig.context && sharedConfig.context.liveHoles;
2431
+ let liveNode = null;
2432
+ if (live && (liveNode = live.content(node)) !== null) {
2433
+ if (typeof liveNode === "string") result.t[result.t.length - 1] += liveNode;else resolveSSRNode(liveNode, result);
2434
+ } else {
2435
+ try {
2436
+ resolveSSRNode(node(), result);
2437
+ } catch (err) {
2438
+ const wrap = buildAsyncWrap(err, node);
2439
+ if (wrap) {
2440
+ result.h.push(wrap.fn);
2441
+ result.p.push(wrap.p);
2442
+ result.t.push("");
2443
+ }
1856
2444
  }
1857
2445
  }
1858
2446
  }
@@ -1887,7 +2475,7 @@ function parseServerComponent(value, ctx) {
1887
2475
  address: ctx.parse(value[SERVER_COMPONENT_ADDRESS])
1888
2476
  };
1889
2477
  }
1890
- const ServerComponentPlugin = /*#__PURE__*/createPlugin({
2478
+ const ServerComponentPlugin = {
1891
2479
  tag: "dom-expressions/server-component",
1892
2480
  test(value) {
1893
2481
  return typeof value === "function" && SERVER_COMPONENT in value;
@@ -1911,18 +2499,17 @@ const ServerComponentPlugin = /*#__PURE__*/createPlugin({
1911
2499
  ctx.deserialize(node.address);
1912
2500
  return globalThis._$SC.r(id);
1913
2501
  }
1914
- });
2502
+ };
1915
2503
  function flightCodec(codec) {
1916
2504
  const plugins = codec && codec.plugins || [];
1917
- for (const plugin of plugins) {
1918
- if (plugin && plugin.tag === "dom-expressions/server-component") return codec;
1919
- }
2505
+ if (plugins.some(plugin => plugin && plugin.tag === ServerComponentPlugin.tag)) return codec;
1920
2506
  return {
1921
2507
  ...codec,
1922
2508
  plugins: [...plugins, ServerComponentPlugin]
1923
2509
  };
1924
2510
  }
1925
2511
 
2512
+ const scopeStamp = typeof creationStamp === "function" ? creationStamp : () => 0;
1926
2513
  function serverOwned(render) {
1927
2514
  return NoHydration ? NoHydration({
1928
2515
  get children() {
@@ -2147,6 +2734,26 @@ function createFrameSink(emit, frame) {
2147
2734
  html
2148
2735
  });
2149
2736
  },
2737
+ hole(key, html) {
2738
+ emit({
2739
+ type: "hole",
2740
+ id,
2741
+ version,
2742
+ key,
2743
+ html
2744
+ });
2745
+ },
2746
+ attr(key, attrs, removed) {
2747
+ const chunk = {
2748
+ type: "attr",
2749
+ id,
2750
+ version,
2751
+ key,
2752
+ attrs
2753
+ };
2754
+ if (removed && removed.length) chunk.removed = removed;
2755
+ emit(chunk);
2756
+ },
2150
2757
  openBinding(key, b) {
2151
2758
  bindings.set(key, b);
2152
2759
  },
@@ -2178,6 +2785,7 @@ function renderServerComponent(component, options = {}) {
2178
2785
  if (ctx) {
2179
2786
  ctx.commit = sink.commit;
2180
2787
  ctx.commitEpoch = () => sink.epoch;
2788
+ ctx.liveHoles = createLiveHoles(sink);
2181
2789
  }
2182
2790
  return serverComponentScope(() => component(props));
2183
2791
  };
@@ -2238,7 +2846,8 @@ function frameStream(makeCode, options) {
2238
2846
  }
2239
2847
  function slotRange(occurrence) {
2240
2848
  return {
2241
- t: `<!--slot:${occurrence}:start--><!--slot:${occurrence}:end-->`
2849
+ t: `<!--slot:${occurrence}:start--><!--slot:${occurrence}:end-->`,
2850
+ $slot: true
2242
2851
  };
2243
2852
  }
2244
2853
  const OCCURRENCE_UNSAFE = /[^A-Za-z0-9_.-]/g;
@@ -2286,14 +2895,28 @@ function tapFirstYield(iterable) {
2286
2895
  }
2287
2896
  };
2288
2897
  }
2898
+ function suppressedFill(render) {
2899
+ const live = sharedConfig.context && sharedConfig.context.liveHoles;
2900
+ if (!live) return render();
2901
+ live.suppressed++;
2902
+ try {
2903
+ return render();
2904
+ } finally {
2905
+ live.suppressed--;
2906
+ }
2907
+ }
2289
2908
  function createDocumentSlotProps(clientProps, frameId) {
2290
2909
  const counts = Object.create(null);
2291
2910
  const getters = new Map();
2292
- const range = (occurrence, content) => [{
2293
- t: `<!--slot:${occurrence}:start-->`
2294
- }, content, {
2295
- t: `<!--slot:${occurrence}:end-->`
2296
- }];
2911
+ const range = (occurrence, content) => {
2912
+ const r = [{
2913
+ t: `<!--slot:${occurrence}:start-->`
2914
+ }, content, {
2915
+ t: `<!--slot:${occurrence}:end-->`
2916
+ }];
2917
+ r.$slot = true;
2918
+ return r;
2919
+ };
2297
2920
  const zoneOwner = getOwner ? getOwner() : null;
2298
2921
  const scoped = (occurrence, render) => {
2299
2922
  const id = `sc-${frameId}-${occurrence}-`;
@@ -2316,27 +2939,68 @@ function createDocumentSlotProps(clientProps, frameId) {
2316
2939
  if (!fn) {
2317
2940
  fn = (...callArgs) => {
2318
2941
  if (callArgs.length === 0 || callArgs[0] === undefined) {
2319
- return scoped(prop, () => {
2942
+ return suppressedFill(() => scoped(prop, () => {
2320
2943
  const value = clientProps[prop];
2321
2944
  return range(prop, typeof value === "function" ? value() : value);
2322
- });
2945
+ }));
2323
2946
  }
2324
2947
  const raw = callArgs[0];
2325
2948
  const occurrence = occurrenceId(prop, raw, counts);
2326
2949
  const slot = clientProps[prop];
2327
2950
  if (typeof slot !== "function") return range(occurrence, undefined);
2328
2951
  const resolved = {};
2952
+ const liveArgs = sharedConfig.context && sharedConfig.context.live && sharedConfig.context.live.args;
2329
2953
  const vals = {};
2954
+ const evals = {};
2955
+ const states = {};
2956
+ const minted = {};
2330
2957
  for (const key of Object.keys(raw)) {
2331
2958
  if (key === "$key") continue;
2332
- let value = raw[key];
2333
- for (let d = 0; typeof value === "function" && d < 16; d++) value = value();
2959
+ const desc = Object.getOwnPropertyDescriptor(raw, key);
2960
+ let evaluate = null;
2961
+ let value;
2962
+ if (desc.get) {
2963
+ const get = desc.get;
2964
+ evaluate = () => unwrapThunks(get.call(raw));
2965
+ } else {
2966
+ value = desc.value;
2967
+ if (typeof value === "function") {
2968
+ const fn = value;
2969
+ evaluate = () => unwrapThunks(fn);
2970
+ }
2971
+ }
2972
+ if (evaluate) {
2973
+ evals[key] = evaluate;
2974
+ const stampBefore = scopeStamp();
2975
+ try {
2976
+ value = evaluate();
2977
+ states[key] = {
2978
+ settled: true,
2979
+ last: value
2980
+ };
2981
+ } catch (err) {
2982
+ const blocked = ssrHandleError && ssrHandleError(err);
2983
+ if (!blocked) throw err;
2984
+ const state = states[key] = {
2985
+ settled: false,
2986
+ last: undefined
2987
+ };
2988
+ value = retryArgUntilSettled(evaluate, blocked, key, occurrence, v => {
2989
+ state.settled = true;
2990
+ state.last = v;
2991
+ if (liveArgs) liveArgs.commit();
2992
+ });
2993
+ }
2994
+ if (scopeStamp() !== stampBefore) minted[key] = true;
2995
+ }
2334
2996
  vals[key] = value;
2335
2997
  }
2336
2998
  const regions = [];
2337
2999
  for (const key of Object.keys(vals)) {
2338
3000
  const value = vals[key];
2339
- if (isServerContent(value)) {
3001
+ if (isContainerTraced(value)) {
3002
+ resolved[key] = value;
3003
+ } else if (isServerContent(value)) {
2340
3004
  const childId = `${frameId}.${occurrence}.${key}`;
2341
3005
  const region = {
2342
3006
  key,
@@ -2375,7 +3039,7 @@ function createDocumentSlotProps(clientProps, frameId) {
2375
3039
  resolved[key] = value;
2376
3040
  }
2377
3041
  }
2378
- const out = scoped(occurrence, () => range(occurrence, slot(resolved)));
3042
+ const out = suppressedFill(() => scoped(occurrence, () => range(occurrence, slot(resolved))));
2379
3043
  const unused = regions.filter(r => !r.used);
2380
3044
  if (sharedConfig.context) {
2381
3045
  const args = {};
@@ -2388,17 +3052,33 @@ function createDocumentSlotProps(clientProps, frameId) {
2388
3052
  };
2389
3053
  continue;
2390
3054
  }
2391
- if (isServerContent(value)) continue;
2392
- args[key] = value;
3055
+ if (!isContainerTraced(value) && isServerContent(value)) continue;
3056
+ args[key] = envelopeContainerTraces(value);
2393
3057
  }
2394
- sharedConfig.context.serialize(`sc:slot:${frameId}:${occurrence}`, args);
3058
+ sharedConfig.context.serialize(`sc:slot:${frameId}:${occurrence}`, {
3059
+ ...args
3060
+ });
2395
3061
  for (const region of unused) {
2396
3062
  region.locked = true;
2397
3063
  sharedConfig.context.serialize(`sc:region:${region.childId}`, resolveRegionHtml(sharedConfig.context, region.value));
2398
3064
  }
3065
+ if (liveArgs) {
3066
+ for (const key of Object.keys(evals)) {
3067
+ if (regions.some(r => r.key === key)) continue;
3068
+ if (minted[key]) continue;
3069
+ const ledgerKey = `${frameId}:${occurrence}:${key}`;
3070
+ openArgBinding(liveArgs, ledgerKey, occurrence, key, evals[key], states[key], value => {
3071
+ args[key] = envelopeContainerTraces(value);
3072
+ liveArgs.slot(frameId, occurrence, {
3073
+ ...args
3074
+ });
3075
+ });
3076
+ }
3077
+ }
2399
3078
  }
2400
3079
  return out;
2401
3080
  };
3081
+ fn.$lhSkip = true;
2402
3082
  getters.set(prop, fn);
2403
3083
  }
2404
3084
  return fn;
@@ -2412,6 +3092,113 @@ function frameElementOpen(id) {
2412
3092
  return `<${FRAME_TAG} ${FRAME_ID_ATTR}="${escaped}" style="display:contents">`;
2413
3093
  }
2414
3094
  const FRAME_ELEMENT_CLOSE = `</${FRAME_TAG}>`;
3095
+ function armDocumentLiveHoles(ctx) {
3096
+ if (!ctx || ctx.liveHoles !== undefined) return;
3097
+ const live = ctx.live;
3098
+ if (live && live.holes !== undefined) {
3099
+ ctx.liveHoles = live.holes;
3100
+ if (live.holes) {
3101
+ ctx.commit = live.commit;
3102
+ ctx.commitEpoch = live.commitEpoch;
3103
+ }
3104
+ return;
3105
+ }
3106
+ if (!live || !ctx.async || ctx.noHydrate || !ctx.serialize || typeof ReadableStream !== "function") {
3107
+ ctx.liveHoles = null;
3108
+ if (live) live.holes = null;
3109
+ return;
3110
+ }
3111
+ const bindings = new Map();
3112
+ let epoch = 0;
3113
+ let sweepScheduled = false;
3114
+ let closed = false;
3115
+ const sweep = () => {
3116
+ epoch++;
3117
+ for (const b of [...bindings.values()]) {
3118
+ try {
3119
+ b.sweep();
3120
+ } catch (_) {
3121
+ }
3122
+ }
3123
+ };
3124
+ const scheduleSweep = () => {
3125
+ if (closed || sweepScheduled || !bindings.size) return;
3126
+ sweepScheduled = true;
3127
+ queueMicrotask(() => {
3128
+ sweepScheduled = false;
3129
+ if (!closed) sweep();
3130
+ });
3131
+ };
3132
+ let channel;
3133
+ ctx.serialize("sc:live", new ReadableStream({
3134
+ start(c) {
3135
+ channel = c;
3136
+ }
3137
+ }));
3138
+ const push = op => {
3139
+ if (!closed) channel.enqueue(op);
3140
+ };
3141
+ ctx.liveHoles = live.holes = createLiveHoles({
3142
+ openBinding(key, b) {
3143
+ bindings.set(key, b);
3144
+ },
3145
+ closeBinding(key) {
3146
+ bindings.delete(key);
3147
+ },
3148
+ hole(key, html) {
3149
+ push({
3150
+ type: "hole",
3151
+ key,
3152
+ html
3153
+ });
3154
+ },
3155
+ attr(key, attrs, removed) {
3156
+ const op = {
3157
+ type: "attr",
3158
+ key,
3159
+ attrs
3160
+ };
3161
+ if (removed && removed.length) op.removed = removed;
3162
+ push(op);
3163
+ },
3164
+ error(key, error) {
3165
+ push({
3166
+ type: "error",
3167
+ key,
3168
+ error
3169
+ });
3170
+ },
3171
+ commit: scheduleSweep,
3172
+ get epoch() {
3173
+ return epoch;
3174
+ }
3175
+ }, true);
3176
+ ctx.commit = live.commit = scheduleSweep;
3177
+ ctx.commitEpoch = live.commitEpoch = () => epoch;
3178
+ live.args = {
3179
+ openBinding(key, b) {
3180
+ bindings.set(key, b);
3181
+ },
3182
+ closeBinding(key) {
3183
+ bindings.delete(key);
3184
+ },
3185
+ slot(fid, occurrence, args) {
3186
+ push({
3187
+ type: "slot",
3188
+ fid,
3189
+ key: occurrence,
3190
+ args
3191
+ });
3192
+ },
3193
+ commit: scheduleSweep
3194
+ };
3195
+ live.end = () => {
3196
+ if (closed) return;
3197
+ if (bindings.size) sweep();
3198
+ closed = true;
3199
+ channel.close();
3200
+ };
3201
+ }
2415
3202
  function frameTransformDirectResult(value, {
2416
3203
  id,
2417
3204
  args
@@ -2422,6 +3209,7 @@ function frameTransformDirectResult(value, {
2422
3209
  t: frameElementOpen(id)
2423
3210
  },
2424
3211
  serverOwned(() => {
3212
+ armDocumentLiveHoles(sharedConfig.context);
2425
3213
  const slotProps = createDocumentSlotProps(props, id);
2426
3214
  return serverComponentScope(() => component(slotProps));
2427
3215
  }), {
@@ -2485,60 +3273,48 @@ function retryArgUntilSettled(evaluate, blocked, key, occurrence, onSettle) {
2485
3273
  blocked.then(retry, retry);
2486
3274
  });
2487
3275
  }
2488
- function openArgBinding(sink, ctx, occurrence, key, evaluate, args, state) {
3276
+ function openArgBinding(sink, ledgerKey, occurrence, key, evaluate, state, emit) {
2489
3277
  const owner = getOwner();
2490
- const ledgerKey = `${occurrence}:${key}`;
2491
- const reEmit = value => {
2492
- const ref = `arg:${occurrence}:${key}@${sink.nextArgRef(ledgerKey)}`;
2493
- sink.mintRef(ref);
2494
- ctx.serialize(ref, value);
2495
- args[key] = {
2496
- $ref: ref
2497
- };
2498
- sink.slot(occurrence, {
2499
- ...args
2500
- });
2501
- };
2502
- const binding = {
3278
+ sink.openBinding(ledgerKey, {
2503
3279
  sweep() {
2504
3280
  if (!state.settled) return;
2505
3281
  let value;
3282
+ const stampBefore = scopeStamp();
2506
3283
  try {
2507
3284
  value = owner ? runWithOwner(owner, evaluate) : evaluate();
2508
3285
  } catch (err) {
2509
3286
  const blocked = ssrHandleError && ssrHandleError(err);
2510
3287
  if (!blocked) {
2511
3288
  sink.closeBinding(ledgerKey);
2512
- reEmit(Promise.reject(err instanceof Error ? err : new Error(String(err))));
3289
+ emit(Promise.reject(err instanceof Error ? err : new Error(String(err))));
3290
+ return;
3291
+ }
3292
+ if (scopeStamp() !== stampBefore) {
3293
+ sink.closeBinding(ledgerKey);
2513
3294
  return;
2514
3295
  }
2515
3296
  state.settled = false;
2516
- reEmit(retryArgUntilSettled(evaluate, blocked, key, occurrence, v => {
3297
+ emit(retryArgUntilSettled(evaluate, blocked, key, occurrence, v => {
2517
3298
  state.settled = true;
2518
3299
  state.last = v;
2519
3300
  sink.commit();
2520
3301
  }));
2521
3302
  return;
2522
3303
  }
3304
+ if (scopeStamp() !== stampBefore) {
3305
+ sink.closeBinding(ledgerKey);
3306
+ return;
3307
+ }
2523
3308
  if (value === state.last) return;
2524
3309
  state.last = value;
2525
3310
  if (isServerContent(value)) {
2526
3311
  sink.closeBinding(ledgerKey);
2527
- reEmit(Promise.reject(contentArgError(key, occurrence)));
3312
+ emit(Promise.reject(contentArgError(key, occurrence)));
2528
3313
  return;
2529
3314
  }
2530
- const t = typeof value;
2531
- if (value == null || t === "string" || t === "number" || t === "boolean") {
2532
- args[key] = value;
2533
- sink.slot(occurrence, {
2534
- ...args
2535
- });
2536
- } else {
2537
- reEmit(value);
2538
- }
3315
+ emit(value);
2539
3316
  }
2540
- };
2541
- sink.openBinding(ledgerKey, binding);
3317
+ });
2542
3318
  }
2543
3319
  function createSlotProps(sink, frame) {
2544
3320
  const counts = Object.create(null);
@@ -2556,6 +3332,17 @@ function createSlotProps(sink, frame) {
2556
3332
  if (callArgs.length === 0 || callArgs[0] === undefined) {
2557
3333
  return slotRange(prop);
2558
3334
  }
3335
+ const live = sharedConfig.context && sharedConfig.context.liveHoles;
3336
+ if (live) {
3337
+ if (live.sweeping) {
3338
+ live.gateHit = true;
3339
+ return {
3340
+ t: "",
3341
+ $slot: true
3342
+ };
3343
+ }
3344
+ live.recordStamp++;
3345
+ }
2559
3346
  const raw = callArgs[0];
2560
3347
  const occurrence = occurrenceId(prop, raw, counts);
2561
3348
  const args = {};
@@ -2574,6 +3361,7 @@ function createSlotProps(sink, frame) {
2574
3361
  let evaluate = null;
2575
3362
  let value;
2576
3363
  let state = null;
3364
+ const stampBefore = scopeStamp();
2577
3365
  try {
2578
3366
  if (desc.get) {
2579
3367
  const get = desc.get;
@@ -2601,6 +3389,7 @@ function createSlotProps(sink, frame) {
2601
3389
  sink.commit();
2602
3390
  });
2603
3391
  }
3392
+ const mintedEval = scopeStamp() !== stampBefore;
2604
3393
  const t = typeof value;
2605
3394
  if (value == null || t === "string" || t === "number" || t === "boolean") {
2606
3395
  args[key] = value;
@@ -2608,7 +3397,7 @@ function createSlotProps(sink, frame) {
2608
3397
  settled: true,
2609
3398
  last: value
2610
3399
  };
2611
- } else if (isServerContent(value)) {
3400
+ } else if (!isContainerTraced(value) && isServerContent(value)) {
2612
3401
  const resolved = ctx.resolve(value);
2613
3402
  if (resolved.h.length) {
2614
3403
  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.");
@@ -2619,7 +3408,7 @@ function createSlotProps(sink, frame) {
2619
3408
  };
2620
3409
  } else {
2621
3410
  const ref = `arg:${occurrence}:${key}`;
2622
- ctx.serialize(ref, value);
3411
+ ctx.serialize(ref, envelopeContainerTraces(value));
2623
3412
  args[key] = {
2624
3413
  $ref: ref
2625
3414
  };
@@ -2628,7 +3417,7 @@ function createSlotProps(sink, frame) {
2628
3417
  last: value
2629
3418
  };
2630
3419
  }
2631
- if (evaluate && state) opened.push({
3420
+ if (evaluate && state && !mintedEval) opened.push({
2632
3421
  key,
2633
3422
  evaluate,
2634
3423
  state
@@ -2642,10 +3431,28 @@ function createSlotProps(sink, frame) {
2642
3431
  });
2643
3432
  const ctx = sharedConfig.context;
2644
3433
  for (const b of opened) {
2645
- openArgBinding(sink, ctx, occurrence, b.key, b.evaluate, args, b.state);
3434
+ const key = b.key;
3435
+ const ledgerKey = `${occurrence}:${key}`;
3436
+ openArgBinding(sink, ledgerKey, occurrence, key, b.evaluate, b.state, value => {
3437
+ const t = typeof value;
3438
+ if (value == null || t === "string" || t === "number" || t === "boolean") {
3439
+ args[key] = value;
3440
+ } else {
3441
+ const ref = `arg:${occurrence}:${key}@${sink.nextArgRef(ledgerKey)}`;
3442
+ sink.mintRef(ref);
3443
+ ctx.serialize(ref, envelopeContainerTraces(value));
3444
+ args[key] = {
3445
+ $ref: ref
3446
+ };
3447
+ }
3448
+ sink.slot(occurrence, {
3449
+ ...args
3450
+ });
3451
+ });
2646
3452
  }
2647
3453
  return slotRange(occurrence);
2648
3454
  };
3455
+ fn.$lhSkip = true;
2649
3456
  getters.set(prop, fn);
2650
3457
  }
2651
3458
  return fn;
@@ -2677,16 +3484,27 @@ function serverComponentResponse(component, options = {}, init = {}) {
2677
3484
  version
2678
3485
  }
2679
3486
  });
3487
+ let closed = false;
2680
3488
  const body = new ReadableStream({
2681
3489
  start(controller) {
2682
3490
  stream.pipe({
2683
3491
  write(chunk) {
2684
- controller.enqueue(createChunk(JSON.stringify(chunk)));
3492
+ if (closed) return;
3493
+ try {
3494
+ controller.enqueue(createChunk(JSON.stringify(chunk)));
3495
+ } catch (_) {
3496
+ closed = true;
3497
+ }
2685
3498
  },
2686
3499
  end() {
3500
+ if (closed) return;
3501
+ closed = true;
2687
3502
  controller.close();
2688
3503
  }
2689
3504
  });
3505
+ },
3506
+ cancel() {
3507
+ closed = true;
2690
3508
  }
2691
3509
  });
2692
3510
  return new Response(body, {
@@ -2770,9 +3588,17 @@ function frameFlightResponse({
2770
3588
  headers.set(FRAME_STREAM_HEADER, primary ? primary.id : "");
2771
3589
  headers.set("X-Content-Raw", "1");
2772
3590
  headers.set(SINGLE_FLIGHT_HEADER, "true");
3591
+ let closed = false;
2773
3592
  const body = new ReadableStream({
2774
3593
  async start(controller) {
2775
- const write = chunk => controller.enqueue(createChunk(JSON.stringify(chunk)));
3594
+ const write = chunk => {
3595
+ if (closed) return;
3596
+ try {
3597
+ controller.enqueue(createChunk(JSON.stringify(chunk)));
3598
+ } catch (_) {
3599
+ closed = true;
3600
+ }
3601
+ };
2776
3602
  try {
2777
3603
  for (const {
2778
3604
  id,
@@ -2799,10 +3625,19 @@ function frameFlightResponse({
2799
3625
  });
2800
3626
  }
2801
3627
  }
2802
- controller.close();
3628
+ if (!closed) {
3629
+ closed = true;
3630
+ controller.close();
3631
+ }
2803
3632
  } catch (err) {
2804
- controller.error(err);
3633
+ if (!closed) {
3634
+ closed = true;
3635
+ controller.error(err);
3636
+ }
2805
3637
  }
3638
+ },
3639
+ cancel() {
3640
+ closed = true;
2806
3641
  }
2807
3642
  });
2808
3643
  return new Response(body, {
@@ -2811,6 +3646,7 @@ function frameFlightResponse({
2811
3646
  });
2812
3647
  }
2813
3648
 
3649
+ setContainerTraceResolver(getProjectionTrace);
2814
3650
  function asyncArg(value) {
2815
3651
  return value;
2816
3652
  }