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

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 (64) hide show
  1. package/README.md +1 -6
  2. package/dist/dev.cjs +234 -45
  3. package/dist/dev.js +221 -42
  4. package/dist/server.cjs +456 -123
  5. package/dist/server.js +445 -120
  6. package/dist/web.cjs +234 -45
  7. package/dist/web.js +221 -42
  8. package/frames/dist/client.cjs +217 -112
  9. package/frames/dist/client.dev.cjs +217 -112
  10. package/frames/dist/client.dev.js +218 -113
  11. package/frames/dist/client.js +218 -113
  12. package/frames/dist/server.cjs +488 -177
  13. package/frames/dist/server.js +489 -179
  14. package/package.json +55 -4
  15. package/serialization/dist/serialization.cjs +8 -0
  16. package/serialization/dist/serialization.js +1 -0
  17. package/serialization/types/index.d.ts +173 -6
  18. package/serialization/types-cjs/index.d.cts +173 -6
  19. package/server-functions/dist/client.cjs +46 -9
  20. package/server-functions/dist/client.js +47 -11
  21. package/server-functions/dist/rich-args.cjs +11 -0
  22. package/server-functions/dist/rich-args.js +9 -0
  23. package/server-functions/dist/server.cjs +275 -126
  24. package/server-functions/dist/server.dev.cjs +1053 -0
  25. package/server-functions/dist/server.dev.js +1021 -0
  26. package/server-functions/dist/server.js +273 -127
  27. package/server-functions/package.json +10 -0
  28. package/server-functions/rich-args/package.json +20 -0
  29. package/storage/types/index.d.ts +1 -1
  30. package/storage/types-cjs/index.d.cts +1 -1
  31. package/types/client.d.ts +127 -6
  32. package/types/core.d.ts +3 -1
  33. package/types/frames/client.d.ts +15 -1
  34. package/types/frames/frame-client.d.ts +37 -7
  35. package/types/frames/frame-sink.d.ts +26 -3
  36. package/types/frames/frame-transport.d.ts +39 -7
  37. package/types/frames/serializer.d.ts +173 -6
  38. package/types/frames/server.d.ts +22 -0
  39. package/types/index.d.ts +2 -3
  40. package/types/response.d.ts +45 -0
  41. package/types/serializer.d.ts +173 -6
  42. package/types/server-functions/client.d.ts +1 -0
  43. package/types/server-functions/rich-args.d.ts +10 -0
  44. package/types/server-functions/server.d.ts +98 -0
  45. package/types/server-functions/shared.d.ts +22 -0
  46. package/types/server-mock.d.ts +171 -59
  47. package/types/server.d.ts +188 -36
  48. package/types-cjs/client.d.cts +127 -6
  49. package/types-cjs/core.d.cts +3 -1
  50. package/types-cjs/frames/client.d.cts +15 -1
  51. package/types-cjs/frames/frame-client.d.cts +37 -7
  52. package/types-cjs/frames/frame-sink.d.cts +26 -3
  53. package/types-cjs/frames/frame-transport.d.cts +39 -7
  54. package/types-cjs/frames/serializer.d.cts +173 -6
  55. package/types-cjs/frames/server.d.cts +22 -0
  56. package/types-cjs/index.d.cts +2 -3
  57. package/types-cjs/response.d.cts +45 -0
  58. package/types-cjs/serializer.d.cts +173 -6
  59. package/types-cjs/server-functions/client.d.cts +1 -0
  60. package/types-cjs/server-functions/rich-args.d.cts +10 -0
  61. package/types-cjs/server-functions/server.d.cts +98 -0
  62. package/types-cjs/server-functions/shared.d.cts +22 -0
  63. package/types-cjs/server-mock.d.cts +171 -59
  64. package/types-cjs/server.d.cts +188 -36
@@ -96,9 +96,7 @@ function createFrameHost(options = {}) {
96
96
  if (store.version !== undefined && version < store.version) return false;
97
97
  if (store.version === undefined || version > store.version) {
98
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
- }
99
+ clearStreamRecords(store.records);
102
100
  }
103
101
  Object.assign(store.records, records);
104
102
  return true;
@@ -176,6 +174,7 @@ class FrameImpl {
176
174
  #store = Object.create(null);
177
175
  #appliedRootValue;
178
176
  #hasContent = false;
177
+ #errorNotified = false;
179
178
  #revealed = new Set();
180
179
  #fallbackShown = new Set();
181
180
  #slots;
@@ -195,10 +194,12 @@ class FrameImpl {
195
194
  #claimTree = (node, direct) => {
196
195
  const handlers = claimHandlers();
197
196
  if (!handlers) return;
198
- const run = () => direct ? claimNode(handlers, node) : claimTree(handlers, node);
199
- const scope = this.#options.ownerScope;
200
- scope ? scope(run) : run();
197
+ this.#scoped(() => direct ? claimNode(handlers, node) : claimTree(handlers, node));
201
198
  };
199
+ #scoped(fn) {
200
+ const scope = this.#options.ownerScope;
201
+ return scope ? scope(fn) : fn();
202
+ }
202
203
  constructor(element, start, end, options = {}) {
203
204
  this.#element = element;
204
205
  this.#start = start;
@@ -259,15 +260,9 @@ class FrameImpl {
259
260
  return;
260
261
  } else if (v > this.#version) {
261
262
  this.#version = v;
262
- this.#revealed.clear();
263
- this.#fallbackShown.clear();
264
- for (const key of Object.keys(this.#store)) {
265
- if (key.startsWith("seg:") || key === ":error") {
266
- delete this.#store[key];
267
- }
268
- }
263
+ this.#resetStreamState();
269
264
  }
270
- for (const key of Object.keys(write.r)) {
265
+ for (const key in write.r) {
271
266
  const incoming = write.r[key];
272
267
  if (incoming && incoming.kind === "slot" && key.charCodeAt(0) === 115 && key.startsWith("slot:")) {
273
268
  const existing = this.#store[key];
@@ -279,6 +274,12 @@ class FrameImpl {
279
274
  }
280
275
  this.#flush();
281
276
  }
277
+ #resetStreamState(root) {
278
+ this.#revealed.clear();
279
+ this.#fallbackShown.clear();
280
+ this.#errorNotified = false;
281
+ clearStreamRecords(this.#store, root);
282
+ }
282
283
  #flush() {
283
284
  if (this.#disposed) return;
284
285
  const version = this.#version;
@@ -289,10 +290,14 @@ class FrameImpl {
289
290
  this.#appliedRootValue = root.value;
290
291
  this.#applied(version, reason);
291
292
  }
293
+ if (this.#store[":error"] && !this.#errorNotified) {
294
+ this.#errorNotified = true;
295
+ this.#applied(version, "error");
296
+ }
292
297
  let progressed = true;
293
298
  while (progressed) {
294
299
  progressed = false;
295
- for (const key of Object.keys(this.#store)) {
300
+ for (const key in this.#store) {
296
301
  const name = segmentName(key);
297
302
  if (name === null || this.#revealed.has(name)) continue;
298
303
  if (this.#segmentReady(name)) {
@@ -301,7 +306,7 @@ class FrameImpl {
301
306
  progressed = true;
302
307
  }
303
308
  }
304
- for (const key of Object.keys(this.#store)) {
309
+ for (const key in this.#store) {
305
310
  const m = /^seg:([^:]+):fallback$/.exec(key);
306
311
  if (!m) continue;
307
312
  const name = m[1];
@@ -313,7 +318,7 @@ class FrameImpl {
313
318
  }
314
319
  }
315
320
  }
316
- for (const key of Object.keys(this.#store)) {
321
+ for (const key in this.#store) {
317
322
  if (this.#processedAssets.has(key) || !key.endsWith(":assets")) continue;
318
323
  this.#processedAssets.add(key);
319
324
  const record = this.#store[key];
@@ -345,6 +350,7 @@ class FrameImpl {
345
350
  const callback = this.#resolveSlot(propOf(occurrence));
346
351
  if (!callback) continue;
347
352
  const record = this.#resolveSlotRecord(occurrence);
353
+ if (record && record.kind === "slot" && this.#refsUnresolved(record.args)) continue;
348
354
  const prev = this.#slotNodes.get(occurrence);
349
355
  const prevFirst = Array.isArray(prev) ? prev[0] : prev;
350
356
  const zombie = this.#mountedSlots.has(occurrence) && prevFirst && !prevFirst.parentNode;
@@ -400,15 +406,7 @@ class FrameImpl {
400
406
  const cleanups = this.#slotCleanups.get(occurrence) ?? [];
401
407
  let existing = [];
402
408
  let end = null;
403
- if (start) {
404
- const endData = slotEnd(occurrence);
405
- let n = start.nextSibling;
406
- while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
407
- existing.push(n);
408
- n = n.nextSibling;
409
- }
410
- end = n;
411
- }
409
+ if (start) end = eachInRange(start, occurrence, n => existing.push(n));
412
410
  const ctx = {
413
411
  frame: this.#options.claimScope ?? this.#options.id,
414
412
  key: occurrence,
@@ -423,23 +421,16 @@ class FrameImpl {
423
421
  } : undefined
424
422
  };
425
423
  const props = record && record.kind === "slot" ? this.#resolveArgs(occurrence, record.args) : {};
426
- const scope = this.#options.ownerScope;
427
- const content = scope ? scope(() => callback(props, ctx)) : callback(props, ctx);
424
+ const content = this.#scoped(() => callback(props, ctx));
428
425
  this.#slotArgs.set(occurrence, record);
429
426
  if (cleanups.length) this.#slotCleanups.set(occurrence, cleanups);
430
427
  if (content == null) return null;
431
428
  return Array.isArray(content) ? content : [content];
432
429
  }
433
430
  #replaceRange(key, start, nodes) {
434
- const end = slotEnd(key);
435
431
  const parent = start.parentNode;
436
- let n = start.nextSibling;
437
- while (n && !(n.nodeType === COMMENT_NODE && n.data === end)) {
438
- const next = n.nextSibling;
439
- parent.removeChild(n);
440
- n = next;
441
- }
442
- for (const node of nodes) parent.insertBefore(node, n);
432
+ const end = eachInRange(start, key, n => parent.removeChild(n));
433
+ for (const node of nodes) parent.insertBefore(node, end);
443
434
  }
444
435
  #unmountSlot(key) {
445
436
  this.#mountedSlots.delete(key);
@@ -451,9 +442,7 @@ class FrameImpl {
451
442
  this.#runSlotCleanups(key);
452
443
  const regions = this.#slotRegions.get(key);
453
444
  if (regions) {
454
- for (const {
455
- frame
456
- } of regions.values()) frame?.dispose();
445
+ disposeRegions(regions);
457
446
  this.#slotRegions.delete(key);
458
447
  }
459
448
  }
@@ -463,15 +452,26 @@ class FrameImpl {
463
452
  this.#slotCleanups.delete(key);
464
453
  for (const fn of cleanups) fn();
465
454
  }
455
+ #refsUnresolved(args) {
456
+ const {
457
+ host,
458
+ id
459
+ } = this.#options;
460
+ if (host) for (const key in args) {
461
+ if (isDataRef(args[key]) && host.resolve(args[key], id) === undefined) return true;
462
+ }
463
+ return false;
464
+ }
465
+ #regionsFor(slotKey) {
466
+ let regions = this.#slotRegions.get(slotKey);
467
+ if (!regions) this.#slotRegions.set(slotKey, regions = new Map());
468
+ return regions;
469
+ }
466
470
  #resolveArgs(slotKey, args) {
467
471
  const host = this.#options.host;
468
- let regions = this.#slotRegions.get(slotKey);
469
- if (!regions) {
470
- regions = new Map();
471
- this.#slotRegions.set(slotKey, regions);
472
- }
472
+ const regions = this.#regionsFor(slotKey);
473
473
  const props = {};
474
- for (const key of Object.keys(args)) {
474
+ for (const key in args) {
475
475
  const value = args[key];
476
476
  if (isDataRef(value)) {
477
477
  const resolved = host ? host.resolve(value, this.#options.id) : undefined;
@@ -501,17 +501,8 @@ class FrameImpl {
501
501
  }
502
502
  #discoverRegions(slotKey, start) {
503
503
  if (!start) return;
504
- let regions = this.#slotRegions.get(slotKey);
505
- if (!regions) {
506
- regions = new Map();
507
- this.#slotRegions.set(slotKey, regions);
508
- }
509
- const endData = slotEnd(slotKey);
510
- let n = start.nextSibling;
511
- while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
512
- collectRegionElements(n, regions);
513
- n = n.nextSibling;
514
- }
504
+ const regions = this.#regionsFor(slotKey);
505
+ eachInRange(start, slotKey, n => collectRegionElements(n, regions));
515
506
  }
516
507
  #refArgsUnchanged(occurrence, record) {
517
508
  const old = this.#slotArgs.get(occurrence);
@@ -527,11 +518,11 @@ class FrameImpl {
527
518
  const va = a[key];
528
519
  const vb = b[key];
529
520
  if (va === vb) continue;
530
- if (!va || !vb || typeof va !== "object" || typeof vb !== "object") return false;
531
- if (typeof va.$frame === "string" && typeof vb.$frame === "string") continue;
532
- if (typeof va.$ref === "string" && typeof vb.$ref === "string" && cache && key in cache) {
521
+ if (isFrameRef(va) && isFrameRef(vb)) continue;
522
+ if (isDataRef(va) && isDataRef(vb) && cache && key in cache) {
533
523
  const host = this.#options.host;
534
524
  const next = host ? host.resolve(vb, this.#options.id) : undefined;
525
+ if (isAsyncLike(next) || isAsyncLike(cache[key])) return false;
535
526
  try {
536
527
  if (JSON.stringify(next) === JSON.stringify(cache[key])) continue;
537
528
  } catch (e) {
@@ -547,7 +538,7 @@ class FrameImpl {
547
538
  if (!args) return;
548
539
  const regions = this.#slotRegions.get(occurrence);
549
540
  if (!regions) return;
550
- for (const key of Object.keys(args)) {
541
+ for (const key in args) {
551
542
  const value = args[key];
552
543
  if (!isFrameRef(value)) continue;
553
544
  const entry = regions.get(key);
@@ -597,11 +588,8 @@ class FrameImpl {
597
588
  this.#element.setAttribute(FRAME_ID_ATTR, id);
598
589
  }
599
590
  this.#version = undefined;
600
- this.#revealed.clear();
601
- this.#fallbackShown.clear();
602
- for (const key of Object.keys(this.#store)) {
603
- if (key.startsWith("seg:") || key === ":error") delete this.#store[key];
604
- }
591
+ this.#appliedRootValue = undefined;
592
+ this.#resetStreamState(true);
605
593
  if (host) host.register(id, this);
606
594
  }
607
595
  rebase() {
@@ -621,11 +609,7 @@ class FrameImpl {
621
609
  }
622
610
  for (const key of [...this.#slotCleanups.keys()]) this.#runSlotCleanups(key);
623
611
  for (const key of this.#mountedSlots) this.#removeSlotRecord(key);
624
- for (const regions of this.#slotRegions.values()) {
625
- for (const {
626
- frame
627
- } of regions.values()) frame?.dispose();
628
- }
612
+ for (const regions of this.#slotRegions.values()) disposeRegions(regions);
629
613
  this.#slotRegions.clear();
630
614
  this.#mountedSlots.clear();
631
615
  }
@@ -647,13 +631,7 @@ class FrameImpl {
647
631
  }
648
632
  }
649
633
  #clearContent() {
650
- const parent = this.#parent();
651
- let n = this.#firstContent();
652
- while (n && n !== this.#end) {
653
- const next = n.nextSibling;
654
- parent.removeChild(n);
655
- n = next;
656
- }
634
+ removeUntil(this.#parent(), this.#firstContent(), this.#end);
657
635
  }
658
636
  #claimContent() {
659
637
  if (!claimHandlers()) return;
@@ -670,9 +648,7 @@ class FrameImpl {
670
648
  const assets = this.#store[`seg:${name}:assets`];
671
649
  if (assets && assets.styles) {
672
650
  let ready = true;
673
- for (const entry of assets.styles) {
674
- if (!ensureStylesheet(entry, this.#styleFlush)) ready = false;
675
- }
651
+ for (const entry of assets.styles) ready = ensureStylesheet(entry, this.#styleFlush) && ready;
676
652
  if (!ready) return false;
677
653
  }
678
654
  if (!this.#findPlaceholder(name)) return false;
@@ -686,12 +662,7 @@ class FrameImpl {
686
662
  const content = this.#store[`seg:${name}`];
687
663
  const closing = rangeClose(tpl, placeholderId(name));
688
664
  const parent = tpl.parentNode;
689
- let n = tpl.nextSibling;
690
- while (n && n !== closing) {
691
- const next = n.nextSibling;
692
- parent.removeChild(n);
693
- n = next;
694
- }
665
+ removeUntil(parent, tpl.nextSibling, closing);
695
666
  if (this.#options.reveal) {
696
667
  const fallbackFrag = tpl.content.cloneNode(true);
697
668
  this.#claimTree(fallbackFrag);
@@ -740,9 +711,7 @@ function createFrameElement(options) {
740
711
  const frame = new FrameImpl(el, null, null, options);
741
712
  return {
742
713
  element: el,
743
- get frame() {
744
- return frame;
745
- },
714
+ frame,
746
715
  dispose() {
747
716
  frame.dispose();
748
717
  el.remove();
@@ -762,15 +731,30 @@ function segmentName(key) {
762
731
  const m = /^seg:([^:]+)$/.exec(key);
763
732
  return m ? m[1] : null;
764
733
  }
734
+ function isAsyncLike(v) {
735
+ return !!v && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
736
+ }
765
737
  function propOf(occurrence) {
766
738
  const hash = occurrence.indexOf("#");
767
739
  return hash === -1 ? occurrence : occurrence.slice(0, hash);
768
740
  }
769
741
  function isDataRef(value) {
770
- return typeof value === "object" && value !== null && typeof value.$ref === "string";
742
+ return !!value && typeof value.$ref === "string";
771
743
  }
772
744
  function isFrameRef(value) {
773
- return typeof value === "object" && value !== null && typeof value.$frame === "string";
745
+ return !!value && typeof value.$frame === "string";
746
+ }
747
+ function disposeRegions(regions) {
748
+ for (const {
749
+ frame
750
+ } of regions.values()) frame?.dispose();
751
+ }
752
+ function removeUntil(parent, n, stop) {
753
+ while (n && n !== stop) {
754
+ const next = n.nextSibling;
755
+ parent.removeChild(n);
756
+ n = next;
757
+ }
774
758
  }
775
759
  function parseFragment(html) {
776
760
  const template = document.createElement("template");
@@ -778,9 +762,8 @@ function parseFragment(html) {
778
762
  return template.content;
779
763
  }
780
764
  function findHeadElement(selector, attr, value) {
781
- const nodes = document.head.querySelectorAll(selector);
782
- for (let i = 0; i < nodes.length; i++) {
783
- if (nodes[i].getAttribute(attr) === value) return nodes[i];
765
+ for (const node of document.head.querySelectorAll(selector)) {
766
+ if (node.getAttribute(attr) === value) return node;
784
767
  }
785
768
  return null;
786
769
  }
@@ -829,7 +812,7 @@ function applyInlineStyles(inlineStyles) {
829
812
  }
830
813
  }
831
814
  function isPlaceholderStart(node, id) {
832
- return node.nodeType === ELEMENT_NODE && node.tagName === "TEMPLATE" && node.getAttribute("id") === id;
815
+ return node.tagName === "TEMPLATE" && node.id === id;
833
816
  }
834
817
  function rangeClose(start, id) {
835
818
  let n = start.nextSibling;
@@ -885,6 +868,21 @@ function renameRegion(entry, childId) {
885
868
  entry.childId = childId;
886
869
  if (entry.frame) entry.frame.rebind(childId);else entry.element.setAttribute(FRAME_ID_ATTR, childId);
887
870
  }
871
+ function eachInRange(start, key, cb) {
872
+ const end = slotEnd(key);
873
+ let n = start.nextSibling;
874
+ while (n && !(n.nodeType === COMMENT_NODE && n.data === end)) {
875
+ const next = n.nextSibling;
876
+ cb(n);
877
+ n = next;
878
+ }
879
+ return n;
880
+ }
881
+ function clearStreamRecords(records, root) {
882
+ for (const key in records) {
883
+ if (key.startsWith("seg:") || key === ":error" || root && key === "") delete records[key];
884
+ }
885
+ }
888
886
  function argsEquivalent(a, b) {
889
887
  if (a === b) return true;
890
888
  if (!a || !b) return false;
@@ -895,9 +893,7 @@ function argsEquivalent(a, b) {
895
893
  const va = a[key];
896
894
  const vb = b[key];
897
895
  if (va === vb) continue;
898
- if (va && vb && typeof va === "object" && typeof vb === "object" && typeof va.$frame === "string" && va.$frame === vb.$frame) {
899
- continue;
900
- }
896
+ if (isFrameRef(va) && va.$frame === vb?.$frame) continue;
901
897
  return false;
902
898
  }
903
899
  return true;
@@ -1260,7 +1256,7 @@ function createServerComponentHandler({
1260
1256
  showing(address, functionId) {
1261
1257
  bindingFor(address, functionId);
1262
1258
  const comp = componentFor(functionId);
1263
- if ((typeof comp === "function" || typeof comp === "object" && comp !== null) && !comp[COMPONENT_BINDING]) {
1259
+ if (comp && (typeof comp === "function" || typeof comp === "object") && !comp[COMPONENT_BINDING]) {
1264
1260
  comp[COMPONENT_BINDING] = {
1265
1261
  component: comp,
1266
1262
  address
@@ -1352,6 +1348,9 @@ function createJSONDataTable(options) {
1352
1348
  };
1353
1349
  }
1354
1350
 
1351
+ function asyncArg(value) {
1352
+ return value;
1353
+ }
1355
1354
  let sharedHost;
1356
1355
  const tables = new Map();
1357
1356
  function tableFor(id) {
@@ -1428,8 +1427,26 @@ function claimRender(prefix, existing, render) {
1428
1427
  function liveSlotProps(initial, ctx) {
1429
1428
  const [args, setArgs] = solidJs.createSignal(initial);
1430
1429
  ctx.onUpdate(next => setArgs(() => next));
1430
+ return slotArgsProxy(args);
1431
+ }
1432
+ function isAsyncValue(v) {
1433
+ return v !== null && typeof v === "object" && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
1434
+ }
1435
+ function slotArgsProxy(args) {
1436
+ const owner = solidJs.getOwner();
1437
+ const asyncReads = new Map();
1431
1438
  return new Proxy({}, {
1432
- get: (_, key) => args()[key],
1439
+ get: (_, key) => {
1440
+ const v = args()[key];
1441
+ if (!isAsyncValue(v)) return v;
1442
+ let read = asyncReads.get(key);
1443
+ if (!read) {
1444
+ const make = () => solidJs.createMemo(() => args()[key]);
1445
+ read = owner ? solidJs.runWithOwner(owner, make) : make();
1446
+ asyncReads.set(key, read);
1447
+ }
1448
+ return read();
1449
+ },
1433
1450
  has: (_, key) => key in args(),
1434
1451
  ownKeys: () => Reflect.ownKeys(args()),
1435
1452
  getOwnPropertyDescriptor: (_, key) => key in args() ? {
@@ -1447,6 +1464,7 @@ function isReactiveContent(value) {
1447
1464
  }
1448
1465
  function slotsFor(props) {
1449
1466
  const bindings = new Map();
1467
+ const fillScopes = new Map();
1450
1468
  return new Proxy({}, {
1451
1469
  get(_, prop) {
1452
1470
  if (typeof prop !== "string" || !(prop in props)) return undefined;
@@ -1457,6 +1475,19 @@ function slotsFor(props) {
1457
1475
  bindings.delete(key);
1458
1476
  prev.dispose();
1459
1477
  }
1478
+ const prevFill = key !== undefined && fillScopes.get(key);
1479
+ if (prevFill) {
1480
+ fillScopes.delete(key);
1481
+ prevFill.dispose();
1482
+ }
1483
+ const fillOwner = streamInvoke ? solidJs.createOwner() : null;
1484
+ if (fillOwner && key !== undefined && ctx) {
1485
+ fillScopes.set(key, fillOwner);
1486
+ ctx.onCleanup(() => {
1487
+ if (fillScopes.get(key) === fillOwner) fillScopes.delete(key);
1488
+ fillOwner.dispose();
1489
+ });
1490
+ }
1460
1491
  const settle = out => {
1461
1492
  const existing = ctx && ctx.existing || [];
1462
1493
  if (existing.length) {
@@ -1469,13 +1500,13 @@ function slotsFor(props) {
1469
1500
  const evaluate = () => {
1470
1501
  const v = props[prop];
1471
1502
  if (typeof v === "function" && ctx && ctx.invoked) {
1472
- return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotProps);
1503
+ return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotArgsProxy(() => slotProps));
1473
1504
  }
1474
1505
  return v;
1475
1506
  };
1476
1507
  const adopted = !!(ctx && ctx.frame && ctx.adopted && ctx.existing && ctx.existing.length);
1477
1508
  const prefix = ctx && ctx.frame ? `sc-${ctx.frame}-${ctx.key}-` : "";
1478
- const value = adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
1509
+ const value = fillOwner ? solidJs.runWithOwner(fillOwner, () => adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate()) : adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
1479
1510
  if (!isReactiveContent(value)) {
1480
1511
  return settle(normalizeSlotContent(value));
1481
1512
  }
@@ -1500,29 +1531,61 @@ function slotsFor(props) {
1500
1531
  function revealSeam(owner) {
1501
1532
  return seam => solidJs.runWithOwner(owner, () => web$1.insert(seam.before.parentNode, solidJs.createLoadingBoundary(() => seam.content(), () => seam.fallback), seam.before));
1502
1533
  }
1534
+ let streamInvoke = false;
1503
1535
  function boundaryScope(owner) {
1504
- return fn => solidJs.getOwner() ? fn() : solidJs.runWithOwner(owner, fn);
1505
- }
1506
- function followBinding(frame, binding) {
1507
- solidJs.createRenderEffect(binding, address => frame.rebind(address));
1536
+ return fn => {
1537
+ if (solidJs.getOwner()) return fn();
1538
+ streamInvoke = true;
1539
+ try {
1540
+ return solidJs.runWithOwner(owner, fn);
1541
+ } finally {
1542
+ streamInvoke = false;
1543
+ }
1544
+ };
1508
1545
  }
1509
1546
  function boundaryComponent(host, fnId) {
1510
1547
  return (props, binding) => {
1511
1548
  const owner = solidJs.getOwner();
1549
+ const id = binding ? binding() : fnId;
1550
+ let applied = !tables.has(id);
1551
+ let release;
1552
+ const arm = () => new Promise(r => release = r);
1553
+ const mountGate = applied ? undefined : arm();
1554
+ let setGate;
1512
1555
  const {
1513
1556
  element,
1514
1557
  frame,
1515
1558
  dispose
1516
1559
  } = createFrameElement({
1517
1560
  host,
1518
- id: binding ? binding() : fnId,
1561
+ id,
1519
1562
  slots: slotsFor(props),
1520
1563
  ownerScope: boundaryScope(owner),
1521
- reveal: revealSeam(owner)
1564
+ reveal: revealSeam(owner),
1565
+ onApply: () => {
1566
+ applied = true;
1567
+ if (release) {
1568
+ release();
1569
+ release = undefined;
1570
+ }
1571
+ setGate && setGate(undefined);
1572
+ }
1522
1573
  });
1523
- if (binding) followBinding(frame, binding);
1574
+ const [gatePromise, setGatePromise] = solidJs.createSignal(applied ? undefined : mountGate);
1575
+ setGate = setGatePromise;
1576
+ if (binding) {
1577
+ solidJs.createRenderEffect(binding, (address, prev) => {
1578
+ if (prev !== undefined && address !== prev && tables.has(address)) {
1579
+ applied = false;
1580
+ setGatePromise(arm());
1581
+ }
1582
+ frame.rebind(address);
1583
+ });
1584
+ }
1524
1585
  solidJs.onCleanup(dispose);
1525
- return element;
1586
+ if (applied && !binding) return element;
1587
+ const gate = solidJs.createMemo(() => gatePromise());
1588
+ return solidJs.createMemo(() => (gate(), element));
1526
1589
  };
1527
1590
  }
1528
1591
  const claimedBoundaries = new Set();
@@ -1590,6 +1653,17 @@ function adoptBoundary(host, id, el, props, binding) {
1590
1653
  claimedBoundaries.add(id);
1591
1654
  const address = binding ? binding() : documentAddress(id);
1592
1655
  const appliedRecords = new Set();
1656
+ const claimedFragments = new Set();
1657
+ const claimRegionFragments = root => {
1658
+ const fr = globalThis._$HY?.fr;
1659
+ if (!fr || !fr.claim) return;
1660
+ root.querySelectorAll('template[id^="pl-"]').forEach(tpl => {
1661
+ const fragId = tpl.id.slice(3);
1662
+ if (claimedFragments.has(fragId)) return;
1663
+ claimedFragments.add(fragId);
1664
+ fr.claim(fragId);
1665
+ });
1666
+ };
1593
1667
  const drainRecords = () => {
1594
1668
  const hy = globalThis._$HY;
1595
1669
  if (!hy || !hy.r) return;
@@ -1621,8 +1695,20 @@ function adoptBoundary(host, id, el, props, binding) {
1621
1695
  }
1622
1696
  }
1623
1697
  };
1698
+ claimRegionFragments(el);
1699
+ const fr = globalThis._$HY?.fr;
1700
+ const unsubscribe = fr ? fr.subscribe((_fragId, parent) => {
1701
+ if (fr.claim && parent && el.contains(parent)) claimRegionFragments(parent);
1702
+ drainRecords();
1703
+ }) : undefined;
1704
+ solidJs.onCleanup(() => {
1705
+ unsubscribe && unsubscribe();
1706
+ if (fr && fr.release) for (const fragId of claimedFragments) fr.release(fragId);
1707
+ });
1624
1708
  drainRecords();
1625
1709
  const owner = solidJs.getOwner();
1710
+ let release;
1711
+ let setGate;
1626
1712
  const frame = createFrame(el, {
1627
1713
  adopt: true,
1628
1714
  host,
@@ -1630,6 +1716,13 @@ function adoptBoundary(host, id, el, props, binding) {
1630
1716
  slots: slotsFor(props),
1631
1717
  ownerScope: boundaryScope(owner),
1632
1718
  reveal: revealSeam(owner),
1719
+ onApply: () => {
1720
+ if (release) {
1721
+ release();
1722
+ release = undefined;
1723
+ }
1724
+ setGate && setGate(undefined);
1725
+ },
1633
1726
  ...{
1634
1727
  recordsPending: () => {
1635
1728
  if (document.readyState === "loading") return true;
@@ -1640,7 +1733,19 @@ function adoptBoundary(host, id, el, props, binding) {
1640
1733
  claimScope: id
1641
1734
  }
1642
1735
  });
1643
- if (binding) followBinding(frame, binding);
1736
+ if (binding) {
1737
+ const arm = () => new Promise(r => release = r);
1738
+ const [gatePromise, setGatePromise] = solidJs.createSignal(undefined);
1739
+ setGate = setGatePromise;
1740
+ const gate = solidJs.createMemo(() => gatePromise());
1741
+ solidJs.createRenderEffect(binding, (address, prev) => {
1742
+ if (prev !== undefined && address !== prev && tables.has(address)) {
1743
+ setGatePromise(arm());
1744
+ }
1745
+ frame.rebind(address);
1746
+ });
1747
+ solidJs.createRenderEffect(() => (gate(), undefined), () => {});
1748
+ }
1644
1749
  solidJs.onCleanup(() => frame.dispose());
1645
1750
  return el;
1646
1751
  }
@@ -1684,10 +1789,10 @@ function installServerComponents(host = getFrameHost()) {
1684
1789
  exports.FRAME_APPLIED_EVENT = FRAME_APPLIED_EVENT;
1685
1790
  exports.FRAME_STREAM_HEADER = FRAME_STREAM_HEADER;
1686
1791
  exports.applyFrameResponse = applyFrameResponse;
1792
+ exports.asyncArg = asyncArg;
1687
1793
  exports.createFrame = createFrame;
1688
1794
  exports.createFrameElement = createFrameElement;
1689
1795
  exports.createFrameHost = createFrameHost;
1690
- exports.createJSONDataTable = createJSONDataTable;
1691
1796
  exports.createServerComponentHandler = createServerComponentHandler;
1692
1797
  exports.getFrameHost = getFrameHost;
1693
1798
  exports.installServerComponents = installServerComponents;