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

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.
@@ -83,98 +83,75 @@ function chunkToRecords(chunk) {
83
83
  }
84
84
  function createFrameHost(options = {}) {
85
85
  const frames = new Map();
86
- const pending = new Map();
87
- const retained = new Map();
88
- const deliver = (frame, chunk) => {
89
- if (chunk.type === "data") {
90
- options.applyData && options.applyData(chunk);
91
- return;
92
- }
93
- frame.apply({
94
- version: chunk.version,
95
- r: chunkToRecords(chunk)
86
+ const stores = new Map();
87
+ const storeFor = id => {
88
+ let store = stores.get(id);
89
+ if (!store) stores.set(id, store = {
90
+ version: undefined,
91
+ records: {}
96
92
  });
93
+ return store;
94
+ };
95
+ const write = (store, version, records) => {
96
+ if (store.version !== undefined && version < store.version) return false;
97
+ if (store.version === undefined || version > store.version) {
98
+ store.version = version;
99
+ for (const key of Object.keys(store.records)) {
100
+ if (key.startsWith("seg:") || key === ":error") delete store.records[key];
101
+ }
102
+ }
103
+ Object.assign(store.records, records);
104
+ return true;
97
105
  };
98
106
  return {
99
107
  register(id, frame) {
100
108
  let set = frames.get(id);
101
109
  if (!set) frames.set(id, set = new Set());
102
- const sibling = set.size ? set.values().next().value : undefined;
103
110
  set.add(frame);
104
- if (sibling) {
111
+ const store = stores.get(id);
112
+ if (store && store.version !== undefined) {
105
113
  frame.apply({
106
- version: sibling.version ?? 0,
107
- r: sibling.store
108
- });
109
- if (sibling.version === undefined) frame.rebase && frame.rebase();
110
- return;
111
- }
112
- const kept = retained.get(id);
113
- if (kept) {
114
- retained.delete(id);
115
- frame.apply({
116
- version: kept.version,
117
- r: kept.records
114
+ version: store.version,
115
+ r: store.records
118
116
  });
119
117
  frame.rebase && frame.rebase();
120
118
  }
121
- const buffered = pending.get(id);
122
- if (buffered) {
123
- pending.delete(id);
124
- const records = {};
125
- let version;
126
- for (const chunk of buffered.chunks) {
127
- if (chunk.type === "data") {
128
- options.applyData && options.applyData(chunk);
129
- continue;
130
- }
131
- version = chunk.version;
132
- Object.assign(records, chunkToRecords(chunk));
133
- }
134
- if (version !== undefined) frame.apply({
135
- version,
136
- r: records
137
- });
138
- }
139
119
  },
140
120
  unregister(id, frame) {
141
121
  const set = frames.get(id);
142
122
  if (set && frame) set.delete(frame);
143
123
  if (!set || !frame || !set.size) {
144
- if (frame) {
145
- const kept = frame.snapshot && frame.snapshot();
146
- if (kept) retained.set(id, kept);
147
- } else {
148
- retained.delete(id);
149
- }
150
124
  frames.delete(id);
151
- pending.delete(id);
125
+ if (frame && frame.contentHTML) {
126
+ const store = storeFor(id);
127
+ if (!store.records[""]) {
128
+ const html = frame.contentHTML();
129
+ if (html != null) {
130
+ store.records[""] = {
131
+ kind: "html",
132
+ value: html
133
+ };
134
+ if (store.version === undefined) store.version = 0;
135
+ }
136
+ }
137
+ }
152
138
  }
139
+ if (!frame) stores.delete(id);
153
140
  },
154
141
  apply(chunk) {
155
142
  if (chunk.type === "data") {
156
143
  options.applyData && options.applyData(chunk);
157
144
  return;
158
145
  }
146
+ const records = chunkToRecords(chunk);
147
+ if (!write(storeFor(chunk.id), chunk.version, records)) return;
159
148
  const set = frames.get(chunk.id);
160
- if (set && set.size) {
161
- for (const frame of set) deliver(frame, chunk);
162
- return;
163
- }
164
- const buffered = pending.get(chunk.id);
165
- if (!buffered) {
166
- pending.set(chunk.id, {
149
+ if (set) {
150
+ for (const frame of set) frame.apply({
167
151
  version: chunk.version,
168
- chunks: [chunk]
152
+ r: records
169
153
  });
170
- return;
171
- }
172
- if (chunk.version < buffered.version) return;
173
- if (chunk.version > buffered.version) {
174
- buffered.version = chunk.version;
175
- buffered.chunks.length = 0;
176
154
  }
177
- buffered.chunks.push(chunk);
178
155
  },
179
156
  get(id) {
180
157
  const set = frames.get(id);
@@ -210,6 +187,7 @@ class FrameImpl {
210
187
  #slotResolvedRefs = new Map();
211
188
  #slotNodes = new Map();
212
189
  #processedAssets = new Set();
190
+ #recordRefresh = null;
213
191
  #disposed = false;
214
192
  #styleFlush = () => {
215
193
  if (!this.#disposed) this.#flush();
@@ -355,7 +333,9 @@ class FrameImpl {
355
333
  }
356
334
  #removeSlotRecord(occurrence) {
357
335
  const key = `slot:${occurrence}`;
358
- if (key in this.#store) delete this.#store[key];else this.#options.removeSlotRecord?.(occurrence);
336
+ if (key in this.#store) {
337
+ if (!this.#mountedSlots.has(occurrence)) delete this.#store[key];
338
+ } else this.#options.removeSlotRecord?.(occurrence);
359
339
  }
360
340
  #syncSlots(root) {
361
341
  if (!this.#slots && !this.#options.resolveSlot) return;
@@ -373,6 +353,15 @@ class FrameImpl {
373
353
  this.#runSlotCleanups(occurrence);
374
354
  }
375
355
  if (!this.#mountedSlots.has(occurrence)) {
356
+ if (record === undefined && !root && this.#options.adopt && this.#options.recordsPending?.()) {
357
+ this.#recordRefresh ??= setTimeout(() => {
358
+ this.#recordRefresh = null;
359
+ if (this.#disposed) return;
360
+ this.#options.drainRecords?.();
361
+ this.#syncSlots();
362
+ });
363
+ continue;
364
+ }
376
365
  if (this.#options.adopt) this.#discoverRegions(occurrence, start);
377
366
  const nodes = this.#invokeSlot(occurrence, callback, record, start, this.#options.adopt);
378
367
  if (nodes) this.#replaceRange(occurrence, start, nodes);
@@ -389,12 +378,6 @@ class FrameImpl {
389
378
  const update = this.#slotUpdaters.get(occurrence);
390
379
  if (update) {
391
380
  const props = this.#resolveArgs(occurrence, record.args);
392
- const regions = this.#slotRegions.get(occurrence);
393
- if (regions) {
394
- for (const [argKey, entry] of regions) {
395
- if (!(argKey in props)) props[argKey] = entry.element;
396
- }
397
- }
398
381
  this.#slotArgs.set(occurrence, record);
399
382
  update(props);
400
383
  this.#bindRegions(occurrence);
@@ -440,12 +423,6 @@ class FrameImpl {
440
423
  } : undefined
441
424
  };
442
425
  const props = record && record.kind === "slot" ? this.#resolveArgs(occurrence, record.args) : {};
443
- const regions = this.#slotRegions.get(occurrence);
444
- if (regions) {
445
- for (const [argKey, entry] of regions) {
446
- if (!(argKey in props)) props[argKey] = entry.element;
447
- }
448
- }
449
426
  const scope = this.#options.ownerScope;
450
427
  const content = scope ? scope(() => callback(props, ctx)) : callback(props, ctx);
451
428
  this.#slotArgs.set(occurrence, record);
@@ -530,10 +507,9 @@ class FrameImpl {
530
507
  this.#slotRegions.set(slotKey, regions);
531
508
  }
532
509
  const endData = slotEnd(slotKey);
533
- const prefix = `${this.#options.id}.`;
534
510
  let n = start.nextSibling;
535
511
  while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
536
- collectRegionElements(n, regions, prefix);
512
+ collectRegionElements(n, regions);
537
513
  n = n.nextSibling;
538
514
  }
539
515
  }
@@ -545,16 +521,7 @@ class FrameImpl {
545
521
  const b = record.args || {};
546
522
  const ka = Object.keys(a);
547
523
  const kb = Object.keys(b);
548
- if (kb.length < ka.length) return false;
549
- if (kb.length !== ka.length) {
550
- const regions = this.#slotRegions.get(occurrence);
551
- for (const key of kb) {
552
- if (key in a) continue;
553
- const vb = b[key];
554
- if (!vb || typeof vb !== "object" || typeof vb.$frame !== "string") return false;
555
- if (!regions || !regions.has(key)) return false;
556
- }
557
- }
524
+ if (kb.length !== ka.length) return false;
558
525
  const cache = this.#slotResolvedRefs.get(occurrence);
559
526
  for (const key of ka) {
560
527
  const va = a[key];
@@ -611,22 +578,9 @@ class FrameImpl {
611
578
  #findPlaceholder(name) {
612
579
  return findPlaceholder(this.#firstContent(), this.#end, placeholderId(name));
613
580
  }
614
- snapshot() {
615
- if (this.#disposed) return null;
616
- const records = {
617
- ...this.#store
618
- };
619
- if (!records[""] && this.#element && this.#hasContent) {
620
- records[""] = {
621
- kind: "html",
622
- value: this.#element.innerHTML
623
- };
624
- }
625
- if (!records[""] && this.#version === undefined) return null;
626
- return {
627
- version: this.#version ?? 0,
628
- records
629
- };
581
+ contentHTML() {
582
+ if (this.#disposed || !this.#element || !this.#hasContent) return null;
583
+ return this.#element.innerHTML;
630
584
  }
631
585
  rebind(id) {
632
586
  if (this.#disposed || id === this.#options.id) return;
@@ -661,6 +615,10 @@ class FrameImpl {
661
615
  } = this.#options;
662
616
  if (host && id !== undefined) host.unregister(id, this);
663
617
  this.#disposed = true;
618
+ if (this.#recordRefresh) {
619
+ clearTimeout(this.#recordRefresh);
620
+ this.#recordRefresh = null;
621
+ }
664
622
  for (const key of [...this.#slotCleanups.keys()]) this.#runSlotCleanups(key);
665
623
  for (const key of this.#mountedSlots) this.#removeSlotRecord(key);
666
624
  for (const regions of this.#slotRegions.values()) {
@@ -683,8 +641,9 @@ class FrameImpl {
683
641
  const claim = claimHandlers() ? this.#claimTree : null;
684
642
  const ranges = new Map();
685
643
  this.#collectSlots(ranges);
686
- reconcileChildren(parent, fragment, this.#start, this.#end, claim, ranges);
687
- if (ranges.size) restoreDisplacedRanges(this.#firstContent(), this.#end, ranges);
644
+ const grafts = [];
645
+ reconcileChildren(parent, fragment, this.#start, this.#end, claim, ranges, grafts);
646
+ if (ranges.size) for (const root of grafts) flushGrafts(root, ranges);
688
647
  }
689
648
  }
690
649
  #clearContent() {
@@ -903,11 +862,11 @@ function collectSlots(n, end, out) {
903
862
  n = n.nextSibling;
904
863
  }
905
864
  }
906
- function collectRegionElements(node, regions, prefix) {
865
+ function collectRegionElements(node, regions) {
907
866
  if (node.nodeType !== ELEMENT_NODE) return;
908
867
  if (isFrameElement(node)) {
909
868
  const childId = node.getAttribute(FRAME_ID_ATTR);
910
- if (childId && childId.startsWith(prefix)) {
869
+ if (childId && childId.includes(".")) {
911
870
  const argKey = childId.slice(childId.lastIndexOf(".") + 1);
912
871
  if (!regions.has(argKey)) {
913
872
  regions.set(argKey, {
@@ -920,7 +879,7 @@ function collectRegionElements(node, regions, prefix) {
920
879
  }
921
880
  return;
922
881
  }
923
- for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions, prefix);
882
+ for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions);
924
883
  }
925
884
  function renameRegion(entry, childId) {
926
885
  entry.childId = childId;
@@ -988,11 +947,11 @@ function morphAttributes(oldEl, newEl, claim) {
988
947
  }
989
948
  if (claim && (reclaim || changed && oldEl.matches(CLAIMED_ELEMENTS))) claim(oldEl, true);
990
949
  }
991
- function morphNode(oldNode, newNode, claim, ranges) {
950
+ function morphNode(oldNode, newNode, claim, ranges, grafts) {
992
951
  if (oldNode.nodeType === ELEMENT_NODE) {
993
952
  if (oldNode.hasAttribute("data-preserve")) return;
994
953
  morphAttributes(oldNode, newNode, claim);
995
- reconcileChildren(oldNode, newNode, null, null, claim, ranges);
954
+ reconcileChildren(oldNode, newNode, null, null, claim, ranges, grafts);
996
955
  } else if (oldNode.data !== newNode.data) {
997
956
  oldNode.data = newNode.data;
998
957
  }
@@ -1026,6 +985,13 @@ function moveRangeBefore(parent, start, id, ref) {
1026
985
  n = next;
1027
986
  }
1028
987
  }
988
+ function placeRange(parent, range, id, ref) {
989
+ if (range.nodeType === 11 ) {
990
+ parent.insertBefore(range, ref);
991
+ } else {
992
+ moveRangeBefore(parent, range, id, ref);
993
+ }
994
+ }
1029
995
  function adoptRange(parent, start, id, ref, claim) {
1030
996
  const end = slotEnd(id);
1031
997
  let n = start;
@@ -1043,7 +1009,7 @@ function adoptRange(parent, start, id, ref, claim) {
1043
1009
  }
1044
1010
  return after;
1045
1011
  }
1046
- function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null) {
1012
+ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null, grafts = null) {
1047
1013
  let oldChild = boundStart ? boundStart.nextSibling : parent.firstChild;
1048
1014
  let newChild = source.firstChild;
1049
1015
  while (newChild) {
@@ -1059,11 +1025,7 @@ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, c
1059
1025
  const existing = displaced || findRangeStart(old, pid, boundEnd);
1060
1026
  if (existing) {
1061
1027
  if (ranges) ranges.delete(pid);
1062
- if (existing.nodeType === 11 ) {
1063
- parent.insertBefore(existing, old ?? boundEnd);
1064
- } else {
1065
- moveRangeBefore(parent, existing, pid, old ?? boundEnd);
1066
- }
1028
+ placeRange(parent, existing, pid, old ?? boundEnd);
1067
1029
  newChild = afterRange(newChild, pid);
1068
1030
  } else {
1069
1031
  newChild = adoptRange(parent, newChild, pid, old ?? boundEnd, claim);
@@ -1074,17 +1036,19 @@ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, c
1074
1036
  if (!old) {
1075
1037
  parent.insertBefore(newChild, boundEnd);
1076
1038
  if (claim) claim(newChild);
1039
+ if (grafts) grafts.push(newChild);
1077
1040
  newChild = nextNew;
1078
1041
  continue;
1079
1042
  }
1080
1043
  if (isSlotMarker(old)) {
1081
1044
  parent.insertBefore(newChild, old);
1082
1045
  if (claim) claim(newChild);
1046
+ if (grafts) grafts.push(newChild);
1083
1047
  newChild = nextNew;
1084
1048
  continue;
1085
1049
  }
1086
1050
  if (compatible(old, newChild)) {
1087
- morphNode(old, newChild, claim, ranges);
1051
+ morphNode(old, newChild, claim, ranges, grafts);
1088
1052
  oldChild = old.nextSibling;
1089
1053
  newChild = nextNew;
1090
1054
  continue;
@@ -1097,13 +1061,14 @@ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, c
1097
1061
  }
1098
1062
  if (ahead && ahead !== boundEnd) {
1099
1063
  parent.insertBefore(ahead, old);
1100
- morphNode(ahead, newChild, claim, ranges);
1064
+ morphNode(ahead, newChild, claim, ranges, grafts);
1101
1065
  newChild = nextNew;
1102
1066
  continue;
1103
1067
  }
1104
1068
  }
1105
1069
  parent.insertBefore(newChild, old);
1106
1070
  if (claim) claim(newChild);
1071
+ if (grafts) grafts.push(newChild);
1107
1072
  newChild = nextNew;
1108
1073
  }
1109
1074
  while (oldChild && oldChild !== boundEnd) {
@@ -1120,20 +1085,24 @@ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, c
1120
1085
  oldChild = next;
1121
1086
  }
1122
1087
  }
1123
- function restoreDisplacedRanges(first, end, ranges) {
1124
- const found = new Map();
1125
- collectSlots(first, end, found);
1126
- for (const [id, start] of found) {
1127
- const displaced = ranges.get(id);
1128
- if (!displaced || displaced === start) continue;
1129
- ranges.delete(id);
1130
- const parent = start.parentNode;
1131
- if (displaced.nodeType === 11 ) {
1132
- parent.insertBefore(displaced, start);
1133
- } else {
1134
- moveRangeBefore(parent, displaced, id, start);
1088
+ function flushGrafts(node, ranges) {
1089
+ if (node.nodeType !== ELEMENT_NODE || isFrameElement(node)) return;
1090
+ let n = node.firstChild;
1091
+ while (n) {
1092
+ const id = slotStartId(n);
1093
+ if (id !== null) {
1094
+ const next = afterRange(n, id);
1095
+ const displaced = ranges.get(id);
1096
+ if (displaced) {
1097
+ ranges.delete(id);
1098
+ placeRange(node, displaced, id, n);
1099
+ stashRange(document.createDocumentFragment(), n, id);
1100
+ }
1101
+ n = next;
1102
+ continue;
1135
1103
  }
1136
- stashRange(document.createDocumentFragment(), start, id);
1104
+ flushGrafts(n, ranges);
1105
+ n = n.nextSibling;
1137
1106
  }
1138
1107
  }
1139
1108
  function stashRange(frag, start, id) {
@@ -1165,7 +1134,7 @@ async function applyFrameResponse(response, host, options = {}) {
1165
1134
  if (chunk.type === "outcome") {
1166
1135
  if (options.onOutcome) options.onOutcome(chunk.payload);
1167
1136
  } else {
1168
- if (as !== undefined && chunk.id === rootId) chunk.id = as;else if (options.route) chunk.id = options.route(chunk.id);
1137
+ if (as !== undefined && chunk.id === rootId) chunk.id = as;
1169
1138
  if (perFrame) {
1170
1139
  let v = perFrame.get(chunk.id);
1171
1140
  if (v === undefined) perFrame.set(chunk.id, v = version(chunk.id));
@@ -1179,7 +1148,7 @@ async function applyFrameResponse(response, host, options = {}) {
1179
1148
  }
1180
1149
  const SERVER_COMPONENT = /*#__PURE__*/Symbol.for("dom-expressions.server-component");
1181
1150
  const SERVER_COMPONENT_ADDRESS = /*#__PURE__*/Symbol.for("dom-expressions.server-component-address");
1182
- const COMPONENT_HANDOFF = /*#__PURE__*/Symbol.for("dom-expressions.component-handoff");
1151
+ const COMPONENT_BINDING = /*#__PURE__*/Symbol.for("dom-expressions.component-binding");
1183
1152
  let resolveServerComponent;
1184
1153
  function parseServerComponent(value, ctx) {
1185
1154
  return {
@@ -1203,7 +1172,8 @@ const ServerComponentPlugin = /*#__PURE__*/seroval.createPlugin({
1203
1172
  stream: parseServerComponent
1204
1173
  },
1205
1174
  serialize(node, ctx) {
1206
- return "self._$SC.r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
1175
+ const registry = "self._$SC";
1176
+ return registry + ".r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
1207
1177
  },
1208
1178
  deserialize(node, ctx) {
1209
1179
  const id = ctx.deserialize(node.id);
@@ -1228,120 +1198,79 @@ function createServerComponentHandler({
1228
1198
  host,
1229
1199
  component,
1230
1200
  onStream,
1231
- documentComponent,
1232
1201
  intercept,
1233
1202
  consumer = client.getFlightDataConsumer,
1234
1203
  codec = client.getServerFunctionsCodec
1235
1204
  }) {
1236
- const byAddress = new Map();
1237
- const forwards = new Map();
1238
- const brand = (comp, fnId, frameId) => {
1239
- const brandable = typeof comp === "function" || typeof comp === "object" && comp !== null;
1240
- if (brandable && !comp[COMPONENT_HANDOFF]) {
1241
- comp[COMPONENT_HANDOFF] = {
1242
- fnId,
1243
- frameId,
1244
- take(prev) {
1245
- const meta = prev !== null && (typeof prev === "function" || typeof prev === "object") && prev[COMPONENT_HANDOFF];
1246
- if (!meta || meta.fnId !== fnId) return false;
1247
- const root = meta.frameId;
1248
- let cur = forwards.get(root) ?? root;
1249
- if (cur !== root && !host.get(cur)) {
1250
- forwards.delete(root);
1251
- cur = root;
1252
- }
1253
- if (cur === frameId) return true;
1254
- let frame = host.get(cur);
1255
- if (!frame) return false;
1256
- while (frame) {
1257
- frame.rebind(frameId);
1258
- frame = host.get(cur);
1259
- }
1260
- if (frameId === root) forwards.delete(root);else forwards.set(root, frameId);
1261
- return true;
1262
- }
1263
- };
1264
- }
1205
+ const byFn = new Map();
1206
+ const componentFor = fnId => {
1207
+ let comp = byFn.get(fnId);
1208
+ if (comp === undefined) byFn.set(fnId, comp = component(fnId));
1265
1209
  return comp;
1266
1210
  };
1267
- const boundaryFor = (address, fnId) => {
1268
- let entry = byAddress.get(address);
1269
- if (!entry) {
1270
- entry = {
1271
- frameId: address,
1272
- component: brand(component(address), fnId, address)
1211
+ const byAddress = new Map();
1212
+ const bindingFor = (address, fnId) => {
1213
+ let binding = byAddress.get(address);
1214
+ if (!binding) {
1215
+ const comp = componentFor(fnId);
1216
+ binding = props => comp(props, () => address);
1217
+ binding[COMPONENT_BINDING] = {
1218
+ component: comp,
1219
+ address
1273
1220
  };
1274
- byAddress.set(address, entry);
1221
+ byAddress.set(address, binding);
1275
1222
  }
1276
- return entry;
1223
+ return binding;
1277
1224
  };
1278
- const resolveAddress = (id, address) => boundaryFor(address, id).component;
1279
- resolveServerComponent = resolveAddress;
1225
+ resolveServerComponent = (id, address) => bindingFor(address, id);
1280
1226
  const versions = new Map();
1281
- const bump = frameId => {
1282
- const version = (versions.get(frameId) || 0) + 1;
1283
- versions.set(frameId, version);
1227
+ const bump = address => {
1228
+ const version = (versions.get(address) || 0) + 1;
1229
+ versions.set(address, version);
1284
1230
  return version;
1285
1231
  };
1286
1232
  return {
1287
1233
  intercept: intercept && (info => {
1288
1234
  const hit = intercept(info);
1289
- if (hit !== undefined) {
1290
- const address = client.frameAddress(info.id, info.args);
1291
- byAddress.set(address, {
1292
- frameId: info.id,
1293
- component: brand(hit, info.id, info.id)
1294
- });
1295
- }
1296
- return hit;
1235
+ if (hit === undefined) return undefined;
1236
+ return bindingFor(client.frameAddress(info.id, info.args), info.id);
1297
1237
  }),
1298
1238
  handle(response, ctx) {
1299
1239
  if (!isFrameStreamResponse(response)) return undefined;
1300
1240
  const address = client.frameAddress(ctx.id, ctx.args);
1301
- let entry = byAddress.get(address);
1302
- if (!entry) {
1303
- const adopted = documentComponent && documentComponent(ctx.id);
1304
- if (adopted) {
1305
- entry = {
1306
- frameId: ctx.id,
1307
- component: brand(adopted, ctx.id, ctx.id)
1308
- };
1309
- byAddress.set(address, entry);
1310
- } else {
1311
- entry = boundaryFor(address, ctx.id);
1312
- }
1313
- }
1241
+ const binding = bindingFor(address, ctx.id);
1314
1242
  if (response.headers.has(client.SINGLE_FLIGHT_HEADER)) {
1315
- return applyFlightResponse(response, entry);
1243
+ return applyFlightResponse(response, address, binding);
1316
1244
  }
1317
- const version = bump(entry.frameId);
1318
- if (onStream) onStream(entry.frameId, version, response);
1245
+ const version = bump(address);
1246
+ if (onStream) onStream(address, version, response);
1319
1247
  applyFrameResponse(response, host, {
1320
- as: entry.frameId,
1248
+ as: address,
1321
1249
  version
1322
1250
  }).catch(err => host.apply({
1323
1251
  type: "error",
1324
- id: entry.frameId,
1252
+ id: address,
1325
1253
  version,
1326
1254
  error: {
1327
1255
  message: String(err && err.message)
1328
1256
  }
1329
1257
  }));
1330
- return entry.component;
1258
+ return binding;
1331
1259
  },
1332
- showing(address, functionId, component) {
1333
- if (!byAddress.has(address)) {
1334
- byAddress.set(address, {
1335
- frameId: functionId,
1336
- component: brand(component, functionId, functionId),
1260
+ showing(address, functionId) {
1261
+ bindingFor(address, functionId);
1262
+ const comp = componentFor(functionId);
1263
+ if ((typeof comp === "function" || typeof comp === "object" && comp !== null) && !comp[COMPONENT_BINDING]) {
1264
+ comp[COMPONENT_BINDING] = {
1265
+ component: comp,
1337
1266
  address
1338
- });
1267
+ };
1339
1268
  }
1340
1269
  }
1341
1270
  };
1342
- async function applyFlightResponse(response, entry) {
1271
+ async function applyFlightResponse(response, address, binding) {
1343
1272
  const rootId = response.headers.get(FRAME_STREAM_HEADER) ?? "";
1344
- const as = rootId ? entry.frameId : undefined;
1273
+ const as = rootId ? address : undefined;
1345
1274
  let feed;
1346
1275
  const source = new ReadableStream({
1347
1276
  start(controller) {
@@ -1352,10 +1281,6 @@ function createServerComponentHandler({
1352
1281
  let carried = false;
1353
1282
  await applyFrameResponse(response, host, {
1354
1283
  as,
1355
- route: id => {
1356
- const local = byAddress.get(id);
1357
- return local ? local.frameId : id;
1358
- },
1359
1284
  version: frameId => {
1360
1285
  const version = bump(frameId);
1361
1286
  if (onStream) onStream(frameId, version, response);
@@ -1376,7 +1301,7 @@ function createServerComponentHandler({
1376
1301
  if (response.headers.has(client.ERROR_HEADER) && !response.headers.has("Location") && !response.headers.has(client.REVALIDATE_HEADER)) {
1377
1302
  throw envelope.value;
1378
1303
  }
1379
- return rootId ? entry.component : envelope.value;
1304
+ return rootId ? binding : envelope.value;
1380
1305
  }
1381
1306
  }
1382
1307
 
@@ -1555,15 +1480,7 @@ function slotsFor(props) {
1555
1480
  return settle(normalizeSlotContent(value));
1556
1481
  }
1557
1482
  if (ctx && ctx.range) {
1558
- let claim = adopted;
1559
1483
  const source = value;
1560
- const accessor = () => {
1561
- if (claim) {
1562
- claim = false;
1563
- return claimRender(prefix, ctx.existing, () => typeof source === "function" ? source() : source);
1564
- }
1565
- return typeof source === "function" ? source() : source;
1566
- };
1567
1484
  const owner = solidJs.createOwner();
1568
1485
  bindings.set(key, owner);
1569
1486
  ctx.onCleanup(() => {
@@ -1571,7 +1488,8 @@ function slotsFor(props) {
1571
1488
  owner.dispose();
1572
1489
  });
1573
1490
  const end = ctx.range.end;
1574
- solidJs.runWithOwner(owner, () => web$1.insert(end.parentNode, accessor, end, [...ctx.existing]));
1491
+ const bind = () => web$1.insert(end.parentNode, () => typeof source === "function" ? source() : source, end, [...ctx.existing]);
1492
+ solidJs.runWithOwner(owner, () => adopted ? claimRender(prefix, ctx.existing, bind) : bind());
1575
1493
  return undefined;
1576
1494
  }
1577
1495
  return settle(normalizeSlotContent(value));
@@ -1585,19 +1503,24 @@ function revealSeam(owner) {
1585
1503
  function boundaryScope(owner) {
1586
1504
  return fn => solidJs.getOwner() ? fn() : solidJs.runWithOwner(owner, fn);
1587
1505
  }
1588
- function boundaryComponent(host, id) {
1589
- return props => {
1506
+ function followBinding(frame, binding) {
1507
+ solidJs.createRenderEffect(binding, address => frame.rebind(address));
1508
+ }
1509
+ function boundaryComponent(host, fnId) {
1510
+ return (props, binding) => {
1590
1511
  const owner = solidJs.getOwner();
1591
1512
  const {
1592
1513
  element,
1514
+ frame,
1593
1515
  dispose
1594
1516
  } = createFrameElement({
1595
1517
  host,
1596
- id,
1518
+ id: binding ? binding() : fnId,
1597
1519
  slots: slotsFor(props),
1598
1520
  ownerScope: boundaryScope(owner),
1599
1521
  reveal: revealSeam(owner)
1600
1522
  });
1523
+ if (binding) followBinding(frame, binding);
1601
1524
  solidJs.onCleanup(dispose);
1602
1525
  return element;
1603
1526
  };
@@ -1619,51 +1542,65 @@ function findBoundaryElement(id) {
1619
1542
  return boundaryIndex.get(id);
1620
1543
  }
1621
1544
  const boundaryWaiters = new Map();
1622
- function documentStreaming() {
1545
+ function boundaryMayArrive() {
1623
1546
  const hy = globalThis._$HY;
1624
- return !!hy && !hy.done;
1547
+ if (!hy) return false;
1548
+ return !hy.done || !!(hy.fr && hy.fr.pending());
1625
1549
  }
1626
1550
  function installRevealHook() {
1627
1551
  const hy = globalThis._$HY;
1628
- if (!hy || hy.$sc) return;
1552
+ if (!hy || hy.$sc || !hy.fr) return;
1629
1553
  hy.$sc = true;
1630
- const prev = hy.fe;
1631
- hy.fe = (fragmentId, parent) => {
1632
- if (prev) prev(fragmentId, parent);
1554
+ hy.fr.subscribe((_id, parent) => {
1633
1555
  if (!boundaryIndex) return;
1634
1556
  const root = parent || (typeof document !== "undefined" ? document.body : null);
1635
- if (!root) return;
1636
- indexBoundaries(root);
1557
+ if (root) indexBoundaries(root);
1558
+ if (!boundaryWaiters.size) return;
1559
+ const exhausted = hy.done && !hy.fr.pending();
1637
1560
  for (const [id, notify] of boundaryWaiters) {
1638
- const el = boundaryIndex.get(id);
1639
- if (!el) continue;
1561
+ const el = boundaryIndex && boundaryIndex.get(id);
1562
+ if (!el && !exhausted) continue;
1640
1563
  boundaryWaiters.delete(id);
1641
1564
  notify(el);
1642
1565
  }
1643
- };
1566
+ });
1644
1567
  }
1645
- function documentBoundary(host, id, props) {
1568
+ function documentBoundary(host, id, props, binding) {
1569
+ installRevealHook();
1646
1570
  const claimed = claimedBoundaries.has(id);
1647
1571
  const el = !claimed ? findBoundaryElement(id) : undefined;
1648
- if (el) return adoptBoundary(host, id, el, props);
1649
- if (!claimed && !boundaryWaiters.has(id) && documentStreaming()) {
1572
+ if (el) return adoptBoundary(host, id, el, props, binding);
1573
+ if (!claimed && !boundaryWaiters.has(id) && boundaryMayArrive()) {
1650
1574
  const owner = solidJs.getOwner();
1651
1575
  const arrival = new Promise(resolve => boundaryWaiters.set(id, resolve));
1652
1576
  solidJs.onCleanup(() => boundaryWaiters.delete(id));
1653
- return solidJs.createMemo(() => arrival.then(node => solidJs.runWithOwner(owner, () => adoptBoundary(host, id, node, props))));
1577
+ return solidJs.createMemo(() => arrival.then(node => solidJs.runWithOwner(owner, () =>
1578
+ node ? adoptBoundary(host, id, node, props, binding) : boundaryComponent(host, id)(props, binding))));
1579
+ }
1580
+ return boundaryComponent(host, id)(props, binding);
1581
+ }
1582
+ function documentAddress(id) {
1583
+ const records = globalThis._$SC?.a;
1584
+ if (records) {
1585
+ for (const address in records) if (records[address] === id) return address;
1654
1586
  }
1655
- return boundaryComponent(host, id)(props);
1587
+ return id;
1656
1588
  }
1657
- function adoptBoundary(host, id, el, props) {
1589
+ function adoptBoundary(host, id, el, props, binding) {
1658
1590
  claimedBoundaries.add(id);
1659
- const hy = globalThis._$HY;
1660
- if (hy && hy.r) {
1591
+ const address = binding ? binding() : documentAddress(id);
1592
+ const appliedRecords = new Set();
1593
+ const drainRecords = () => {
1594
+ const hy = globalThis._$HY;
1595
+ if (!hy || !hy.r) return;
1661
1596
  const slotPrefix = `sc:slot:${id}:`;
1662
1597
  for (const key of Object.keys(hy.r)) {
1598
+ if (appliedRecords.has(key)) continue;
1663
1599
  if (key.startsWith(slotPrefix)) {
1600
+ appliedRecords.add(key);
1664
1601
  host.apply({
1665
1602
  type: "slot",
1666
- id,
1603
+ id: address,
1667
1604
  version: 0,
1668
1605
  key: key.slice(slotPrefix.length),
1669
1606
  args: hy.r[key]
@@ -1671,6 +1608,7 @@ function adoptBoundary(host, id, el, props) {
1671
1608
  } else if (key.startsWith("sc:region:")) {
1672
1609
  const childId = key.slice("sc:region:".length);
1673
1610
  if (childId.startsWith(id + ".")) {
1611
+ appliedRecords.add(key);
1674
1612
  const val = hy.r[key];
1675
1613
  const apply = html => host.apply({
1676
1614
  type: "html",
@@ -1682,16 +1620,27 @@ function adoptBoundary(host, id, el, props) {
1682
1620
  }
1683
1621
  }
1684
1622
  }
1685
- }
1623
+ };
1624
+ drainRecords();
1686
1625
  const owner = solidJs.getOwner();
1687
1626
  const frame = createFrame(el, {
1688
1627
  adopt: true,
1689
1628
  host,
1690
- id,
1629
+ id: address,
1691
1630
  slots: slotsFor(props),
1692
1631
  ownerScope: boundaryScope(owner),
1693
- reveal: revealSeam(owner)
1632
+ reveal: revealSeam(owner),
1633
+ ...{
1634
+ recordsPending: () => {
1635
+ if (document.readyState === "loading") return true;
1636
+ const hy = globalThis._$HY;
1637
+ return !!(hy && hy.fr && hy.fr.pending());
1638
+ },
1639
+ drainRecords,
1640
+ claimScope: id
1641
+ }
1694
1642
  });
1643
+ if (binding) followBinding(frame, binding);
1695
1644
  solidJs.onCleanup(() => frame.dispose());
1696
1645
  return el;
1697
1646
  }
@@ -1706,17 +1655,16 @@ function installServerComponents(host = getFrameHost()) {
1706
1655
  g._$SC.a[a] = i;
1707
1656
  g._$SC.reg && g._$SC.reg(a, i);
1708
1657
  }
1709
- return g._$SC.c[i] || (g._$SC.c[i] = p => g._$SC.impl(i, p));
1658
+ return g._$SC.c[i] || (g._$SC.c[i] = (p, b) => g._$SC.impl(i, p, b));
1710
1659
  }
1711
1660
  };
1712
1661
  }
1713
- g._$SC.impl = (id, props) => documentBoundary(host, id, props);
1662
+ g._$SC.impl = (id, props, binding) => documentBoundary(host, id, props, binding);
1714
1663
  installRevealHook();
1715
1664
  const handler = createServerComponentHandler({
1716
1665
  host,
1717
- component: frameId => boundaryComponent(host, frameId),
1718
- onStream: frameId => beginStream(frameId),
1719
- documentComponent: functionId => claimedBoundaries.has(functionId) ? undefined : g._$SC.c[functionId],
1666
+ component: fnId => g._$SC.r(fnId),
1667
+ onStream: address => beginStream(address),
1720
1668
  intercept: ({
1721
1669
  id
1722
1670
  }) => {
@@ -1724,7 +1672,7 @@ function installServerComponents(host = getFrameHost()) {
1724
1672
  return g._$SC.r(id);
1725
1673
  }
1726
1674
  });
1727
- const showing = (address, id) => handler.showing(address, id, g._$SC.r(id));
1675
+ const showing = (address, id) => handler.showing(address, id);
1728
1676
  const records = g._$SC.a || (g._$SC.a = {});
1729
1677
  for (const address in records) showing(address, records[address]);
1730
1678
  g._$SC.reg = showing;