@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;
@@ -689,12 +665,7 @@ class FrameImpl {
689
665
  console.error(`Frame fragment placeholder "${name}" is missing its closing comment ` + `(<!--${placeholderId(name)}-->); revealed content will be appended at the end of ` + `its parent instead of in place. Likely an HTML-rewriting layer stripped the ` + `comment, or invalid nesting split the placeholder range.`, tpl);
690
666
  }
691
667
  const parent = tpl.parentNode;
692
- let n = tpl.nextSibling;
693
- while (n && n !== closing) {
694
- const next = n.nextSibling;
695
- parent.removeChild(n);
696
- n = next;
697
- }
668
+ removeUntil(parent, tpl.nextSibling, closing);
698
669
  if (this.#options.reveal) {
699
670
  const fallbackFrag = tpl.content.cloneNode(true);
700
671
  this.#claimTree(fallbackFrag);
@@ -743,9 +714,7 @@ function createFrameElement(options) {
743
714
  const frame = new FrameImpl(el, null, null, options);
744
715
  return {
745
716
  element: el,
746
- get frame() {
747
- return frame;
748
- },
717
+ frame,
749
718
  dispose() {
750
719
  frame.dispose();
751
720
  el.remove();
@@ -765,15 +734,30 @@ function segmentName(key) {
765
734
  const m = /^seg:([^:]+)$/.exec(key);
766
735
  return m ? m[1] : null;
767
736
  }
737
+ function isAsyncLike(v) {
738
+ return !!v && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
739
+ }
768
740
  function propOf(occurrence) {
769
741
  const hash = occurrence.indexOf("#");
770
742
  return hash === -1 ? occurrence : occurrence.slice(0, hash);
771
743
  }
772
744
  function isDataRef(value) {
773
- return typeof value === "object" && value !== null && typeof value.$ref === "string";
745
+ return !!value && typeof value.$ref === "string";
774
746
  }
775
747
  function isFrameRef(value) {
776
- return typeof value === "object" && value !== null && typeof value.$frame === "string";
748
+ return !!value && typeof value.$frame === "string";
749
+ }
750
+ function disposeRegions(regions) {
751
+ for (const {
752
+ frame
753
+ } of regions.values()) frame?.dispose();
754
+ }
755
+ function removeUntil(parent, n, stop) {
756
+ while (n && n !== stop) {
757
+ const next = n.nextSibling;
758
+ parent.removeChild(n);
759
+ n = next;
760
+ }
777
761
  }
778
762
  function parseFragment(html) {
779
763
  const template = document.createElement("template");
@@ -781,9 +765,8 @@ function parseFragment(html) {
781
765
  return template.content;
782
766
  }
783
767
  function findHeadElement(selector, attr, value) {
784
- const nodes = document.head.querySelectorAll(selector);
785
- for (let i = 0; i < nodes.length; i++) {
786
- if (nodes[i].getAttribute(attr) === value) return nodes[i];
768
+ for (const node of document.head.querySelectorAll(selector)) {
769
+ if (node.getAttribute(attr) === value) return node;
787
770
  }
788
771
  return null;
789
772
  }
@@ -832,7 +815,7 @@ function applyInlineStyles(inlineStyles) {
832
815
  }
833
816
  }
834
817
  function isPlaceholderStart(node, id) {
835
- return node.nodeType === ELEMENT_NODE && node.tagName === "TEMPLATE" && node.getAttribute("id") === id;
818
+ return node.tagName === "TEMPLATE" && node.id === id;
836
819
  }
837
820
  function rangeClose(start, id) {
838
821
  let n = start.nextSibling;
@@ -889,6 +872,21 @@ function renameRegion(entry, childId) {
889
872
  entry.childId = childId;
890
873
  if (entry.frame) entry.frame.rebind(childId);else entry.element.setAttribute(FRAME_ID_ATTR, childId);
891
874
  }
875
+ function eachInRange(start, key, cb) {
876
+ const end = slotEnd(key);
877
+ let n = start.nextSibling;
878
+ while (n && !(n.nodeType === COMMENT_NODE && n.data === end)) {
879
+ const next = n.nextSibling;
880
+ cb(n);
881
+ n = next;
882
+ }
883
+ return n;
884
+ }
885
+ function clearStreamRecords(records, root) {
886
+ for (const key in records) {
887
+ if (key.startsWith("seg:") || key === ":error" || root && key === "") delete records[key];
888
+ }
889
+ }
892
890
  function argsEquivalent(a, b) {
893
891
  if (a === b) return true;
894
892
  if (!a || !b) return false;
@@ -899,9 +897,7 @@ function argsEquivalent(a, b) {
899
897
  const va = a[key];
900
898
  const vb = b[key];
901
899
  if (va === vb) continue;
902
- if (va && vb && typeof va === "object" && typeof vb === "object" && typeof va.$frame === "string" && va.$frame === vb.$frame) {
903
- continue;
904
- }
900
+ if (isFrameRef(va) && va.$frame === vb?.$frame) continue;
905
901
  return false;
906
902
  }
907
903
  return true;
@@ -1273,7 +1269,7 @@ function createServerComponentHandler({
1273
1269
  showing(address, functionId) {
1274
1270
  bindingFor(address, functionId);
1275
1271
  const comp = componentFor(functionId);
1276
- if ((typeof comp === "function" || typeof comp === "object" && comp !== null) && !comp[COMPONENT_BINDING]) {
1272
+ if (comp && (typeof comp === "function" || typeof comp === "object") && !comp[COMPONENT_BINDING]) {
1277
1273
  comp[COMPONENT_BINDING] = {
1278
1274
  component: comp,
1279
1275
  address
@@ -1365,6 +1361,9 @@ function createJSONDataTable(options) {
1365
1361
  };
1366
1362
  }
1367
1363
 
1364
+ function asyncArg(value) {
1365
+ return value;
1366
+ }
1368
1367
  let sharedHost;
1369
1368
  const tables = new Map();
1370
1369
  function tableFor(id) {
@@ -1441,8 +1440,26 @@ function claimRender(prefix, existing, render) {
1441
1440
  function liveSlotProps(initial, ctx) {
1442
1441
  const [args, setArgs] = solidJs.createSignal(initial);
1443
1442
  ctx.onUpdate(next => setArgs(() => next));
1443
+ return slotArgsProxy(args);
1444
+ }
1445
+ function isAsyncValue(v) {
1446
+ return v !== null && typeof v === "object" && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
1447
+ }
1448
+ function slotArgsProxy(args) {
1449
+ const owner = solidJs.getOwner();
1450
+ const asyncReads = new Map();
1444
1451
  return new Proxy({}, {
1445
- get: (_, key) => args()[key],
1452
+ get: (_, key) => {
1453
+ const v = args()[key];
1454
+ if (!isAsyncValue(v)) return v;
1455
+ let read = asyncReads.get(key);
1456
+ if (!read) {
1457
+ const make = () => solidJs.createMemo(() => args()[key]);
1458
+ read = owner ? solidJs.runWithOwner(owner, make) : make();
1459
+ asyncReads.set(key, read);
1460
+ }
1461
+ return read();
1462
+ },
1446
1463
  has: (_, key) => key in args(),
1447
1464
  ownKeys: () => Reflect.ownKeys(args()),
1448
1465
  getOwnPropertyDescriptor: (_, key) => key in args() ? {
@@ -1460,6 +1477,7 @@ function isReactiveContent(value) {
1460
1477
  }
1461
1478
  function slotsFor(props) {
1462
1479
  const bindings = new Map();
1480
+ const fillScopes = new Map();
1463
1481
  return new Proxy({}, {
1464
1482
  get(_, prop) {
1465
1483
  if (typeof prop !== "string" || !(prop in props)) return undefined;
@@ -1470,6 +1488,19 @@ function slotsFor(props) {
1470
1488
  bindings.delete(key);
1471
1489
  prev.dispose();
1472
1490
  }
1491
+ const prevFill = key !== undefined && fillScopes.get(key);
1492
+ if (prevFill) {
1493
+ fillScopes.delete(key);
1494
+ prevFill.dispose();
1495
+ }
1496
+ const fillOwner = streamInvoke ? solidJs.createOwner() : null;
1497
+ if (fillOwner && key !== undefined && ctx) {
1498
+ fillScopes.set(key, fillOwner);
1499
+ ctx.onCleanup(() => {
1500
+ if (fillScopes.get(key) === fillOwner) fillScopes.delete(key);
1501
+ fillOwner.dispose();
1502
+ });
1503
+ }
1473
1504
  const settle = out => {
1474
1505
  const existing = ctx && ctx.existing || [];
1475
1506
  if (existing.length) {
@@ -1482,13 +1513,13 @@ function slotsFor(props) {
1482
1513
  const evaluate = () => {
1483
1514
  const v = props[prop];
1484
1515
  if (typeof v === "function" && ctx && ctx.invoked) {
1485
- return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotProps);
1516
+ return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotArgsProxy(() => slotProps));
1486
1517
  }
1487
1518
  return v;
1488
1519
  };
1489
1520
  const adopted = !!(ctx && ctx.frame && ctx.adopted && ctx.existing && ctx.existing.length);
1490
1521
  const prefix = ctx && ctx.frame ? `sc-${ctx.frame}-${ctx.key}-` : "";
1491
- const value = adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
1522
+ const value = fillOwner ? solidJs.runWithOwner(fillOwner, () => adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate()) : adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
1492
1523
  if (!isReactiveContent(value)) {
1493
1524
  return settle(normalizeSlotContent(value));
1494
1525
  }
@@ -1513,29 +1544,61 @@ function slotsFor(props) {
1513
1544
  function revealSeam(owner) {
1514
1545
  return seam => solidJs.runWithOwner(owner, () => web$1.insert(seam.before.parentNode, solidJs.createLoadingBoundary(() => seam.content(), () => seam.fallback), seam.before));
1515
1546
  }
1547
+ let streamInvoke = false;
1516
1548
  function boundaryScope(owner) {
1517
- return fn => solidJs.getOwner() ? fn() : solidJs.runWithOwner(owner, fn);
1518
- }
1519
- function followBinding(frame, binding) {
1520
- solidJs.createRenderEffect(binding, address => frame.rebind(address));
1549
+ return fn => {
1550
+ if (solidJs.getOwner()) return fn();
1551
+ streamInvoke = true;
1552
+ try {
1553
+ return solidJs.runWithOwner(owner, fn);
1554
+ } finally {
1555
+ streamInvoke = false;
1556
+ }
1557
+ };
1521
1558
  }
1522
1559
  function boundaryComponent(host, fnId) {
1523
1560
  return (props, binding) => {
1524
1561
  const owner = solidJs.getOwner();
1562
+ const id = binding ? binding() : fnId;
1563
+ let applied = !tables.has(id);
1564
+ let release;
1565
+ const arm = () => new Promise(r => release = r);
1566
+ const mountGate = applied ? undefined : arm();
1567
+ let setGate;
1525
1568
  const {
1526
1569
  element,
1527
1570
  frame,
1528
1571
  dispose
1529
1572
  } = createFrameElement({
1530
1573
  host,
1531
- id: binding ? binding() : fnId,
1574
+ id,
1532
1575
  slots: slotsFor(props),
1533
1576
  ownerScope: boundaryScope(owner),
1534
- reveal: revealSeam(owner)
1577
+ reveal: revealSeam(owner),
1578
+ onApply: () => {
1579
+ applied = true;
1580
+ if (release) {
1581
+ release();
1582
+ release = undefined;
1583
+ }
1584
+ setGate && setGate(undefined);
1585
+ }
1535
1586
  });
1536
- if (binding) followBinding(frame, binding);
1587
+ const [gatePromise, setGatePromise] = solidJs.createSignal(applied ? undefined : mountGate);
1588
+ setGate = setGatePromise;
1589
+ if (binding) {
1590
+ solidJs.createRenderEffect(binding, (address, prev) => {
1591
+ if (prev !== undefined && address !== prev && tables.has(address)) {
1592
+ applied = false;
1593
+ setGatePromise(arm());
1594
+ }
1595
+ frame.rebind(address);
1596
+ });
1597
+ }
1537
1598
  solidJs.onCleanup(dispose);
1538
- return element;
1599
+ if (applied && !binding) return element;
1600
+ const gate = solidJs.createMemo(() => gatePromise());
1601
+ return solidJs.createMemo(() => (gate(), element));
1539
1602
  };
1540
1603
  }
1541
1604
  const claimedBoundaries = new Set();
@@ -1603,6 +1666,17 @@ function adoptBoundary(host, id, el, props, binding) {
1603
1666
  claimedBoundaries.add(id);
1604
1667
  const address = binding ? binding() : documentAddress(id);
1605
1668
  const appliedRecords = new Set();
1669
+ const claimedFragments = new Set();
1670
+ const claimRegionFragments = root => {
1671
+ const fr = globalThis._$HY?.fr;
1672
+ if (!fr || !fr.claim) return;
1673
+ root.querySelectorAll('template[id^="pl-"]').forEach(tpl => {
1674
+ const fragId = tpl.id.slice(3);
1675
+ if (claimedFragments.has(fragId)) return;
1676
+ claimedFragments.add(fragId);
1677
+ fr.claim(fragId);
1678
+ });
1679
+ };
1606
1680
  const drainRecords = () => {
1607
1681
  const hy = globalThis._$HY;
1608
1682
  if (!hy || !hy.r) return;
@@ -1634,8 +1708,20 @@ function adoptBoundary(host, id, el, props, binding) {
1634
1708
  }
1635
1709
  }
1636
1710
  };
1711
+ claimRegionFragments(el);
1712
+ const fr = globalThis._$HY?.fr;
1713
+ const unsubscribe = fr ? fr.subscribe((_fragId, parent) => {
1714
+ if (fr.claim && parent && el.contains(parent)) claimRegionFragments(parent);
1715
+ drainRecords();
1716
+ }) : undefined;
1717
+ solidJs.onCleanup(() => {
1718
+ unsubscribe && unsubscribe();
1719
+ if (fr && fr.release) for (const fragId of claimedFragments) fr.release(fragId);
1720
+ });
1637
1721
  drainRecords();
1638
1722
  const owner = solidJs.getOwner();
1723
+ let release;
1724
+ let setGate;
1639
1725
  const frame = createFrame(el, {
1640
1726
  adopt: true,
1641
1727
  host,
@@ -1643,6 +1729,13 @@ function adoptBoundary(host, id, el, props, binding) {
1643
1729
  slots: slotsFor(props),
1644
1730
  ownerScope: boundaryScope(owner),
1645
1731
  reveal: revealSeam(owner),
1732
+ onApply: () => {
1733
+ if (release) {
1734
+ release();
1735
+ release = undefined;
1736
+ }
1737
+ setGate && setGate(undefined);
1738
+ },
1646
1739
  ...{
1647
1740
  recordsPending: () => {
1648
1741
  if (document.readyState === "loading") return true;
@@ -1653,7 +1746,19 @@ function adoptBoundary(host, id, el, props, binding) {
1653
1746
  claimScope: id
1654
1747
  }
1655
1748
  });
1656
- if (binding) followBinding(frame, binding);
1749
+ if (binding) {
1750
+ const arm = () => new Promise(r => release = r);
1751
+ const [gatePromise, setGatePromise] = solidJs.createSignal(undefined);
1752
+ setGate = setGatePromise;
1753
+ const gate = solidJs.createMemo(() => gatePromise());
1754
+ solidJs.createRenderEffect(binding, (address, prev) => {
1755
+ if (prev !== undefined && address !== prev && tables.has(address)) {
1756
+ setGatePromise(arm());
1757
+ }
1758
+ frame.rebind(address);
1759
+ });
1760
+ solidJs.createRenderEffect(() => (gate(), undefined), () => {});
1761
+ }
1657
1762
  solidJs.onCleanup(() => frame.dispose());
1658
1763
  return el;
1659
1764
  }
@@ -1697,10 +1802,10 @@ function installServerComponents(host = getFrameHost()) {
1697
1802
  exports.FRAME_APPLIED_EVENT = FRAME_APPLIED_EVENT;
1698
1803
  exports.FRAME_STREAM_HEADER = FRAME_STREAM_HEADER;
1699
1804
  exports.applyFrameResponse = applyFrameResponse;
1805
+ exports.asyncArg = asyncArg;
1700
1806
  exports.createFrame = createFrame;
1701
1807
  exports.createFrameElement = createFrameElement;
1702
1808
  exports.createFrameHost = createFrameHost;
1703
- exports.createJSONDataTable = createJSONDataTable;
1704
1809
  exports.createServerComponentHandler = createServerComponentHandler;
1705
1810
  exports.getFrameHost = getFrameHost;
1706
1811
  exports.installServerComponents = installServerComponents;