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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +1 -6
  2. package/dist/dev.cjs +285 -60
  3. package/dist/dev.js +267 -57
  4. package/dist/server.cjs +1148 -176
  5. package/dist/server.js +1133 -175
  6. package/dist/web.cjs +285 -60
  7. package/dist/web.js +267 -57
  8. package/frames/dist/client.cjs +397 -175
  9. package/frames/dist/client.dev.cjs +401 -175
  10. package/frames/dist/client.dev.js +399 -173
  11. package/frames/dist/client.js +395 -173
  12. package/frames/dist/server.cjs +1424 -277
  13. package/frames/dist/server.js +1426 -280
  14. package/package.json +69 -7
  15. package/serialization/decode/package.json +20 -0
  16. package/serialization/dist/decode.cjs +110 -0
  17. package/serialization/dist/decode.js +104 -0
  18. package/serialization/dist/serialization.cjs +106 -43
  19. package/serialization/dist/serialization.js +100 -44
  20. package/serialization/types/index.d.ts +85 -60
  21. package/serialization/types/serializer-decode.d.ts +182 -0
  22. package/serialization/types-cjs/index.d.cts +85 -60
  23. package/serialization/types-cjs/serializer-decode.d.cts +182 -0
  24. package/server-functions/dist/client.cjs +131 -98
  25. package/server-functions/dist/client.js +131 -99
  26. package/server-functions/dist/rich-args.cjs +11 -0
  27. package/server-functions/dist/rich-args.js +9 -0
  28. package/server-functions/dist/server.cjs +367 -194
  29. package/server-functions/dist/server.dev.cjs +1077 -0
  30. package/server-functions/dist/server.dev.js +1045 -0
  31. package/server-functions/dist/server.js +365 -195
  32. package/server-functions/package.json +10 -0
  33. package/server-functions/rich-args/package.json +20 -0
  34. package/storage/types/index.d.ts +1 -1
  35. package/storage/types-cjs/index.d.cts +1 -1
  36. package/types/client.d.ts +149 -6
  37. package/types/cookies.d.ts +93 -0
  38. package/types/core.d.ts +4 -2
  39. package/types/frames/client.d.ts +15 -1
  40. package/types/frames/frame-client.d.ts +63 -7
  41. package/types/frames/frame-sink.d.ts +26 -3
  42. package/types/frames/frame-transport.d.ts +40 -8
  43. package/types/frames/serializer.d.ts +85 -60
  44. package/types/frames/server.d.ts +22 -0
  45. package/types/index.d.ts +2 -3
  46. package/types/response.d.ts +45 -0
  47. package/types/serializer-decode.d.ts +182 -0
  48. package/types/serializer.d.ts +85 -60
  49. package/types/server-functions/client.d.ts +2 -1
  50. package/types/server-functions/rich-args.d.ts +10 -0
  51. package/types/server-functions/server.d.ts +99 -1
  52. package/types/server-functions/shared.d.ts +79 -1
  53. package/types/server-mock.d.ts +171 -59
  54. package/types/server.d.ts +209 -37
  55. package/types-cjs/client.d.cts +149 -6
  56. package/types-cjs/cookies.d.cts +93 -0
  57. package/types-cjs/core.d.cts +4 -2
  58. package/types-cjs/frames/client.d.cts +15 -1
  59. package/types-cjs/frames/frame-client.d.cts +63 -7
  60. package/types-cjs/frames/frame-sink.d.cts +26 -3
  61. package/types-cjs/frames/frame-transport.d.cts +40 -8
  62. package/types-cjs/frames/serializer.d.cts +85 -60
  63. package/types-cjs/frames/server.d.cts +22 -0
  64. package/types-cjs/index.d.cts +2 -3
  65. package/types-cjs/response.d.cts +45 -0
  66. package/types-cjs/serializer-decode.d.cts +182 -0
  67. package/types-cjs/serializer.d.cts +85 -60
  68. package/types-cjs/server-functions/client.d.cts +2 -1
  69. package/types-cjs/server-functions/rich-args.d.cts +10 -0
  70. package/types-cjs/server-functions/server.d.cts +99 -1
  71. package/types-cjs/server-functions/shared.d.cts +79 -1
  72. package/types-cjs/server-mock.d.cts +171 -59
  73. package/types-cjs/server.d.cts +209 -37
@@ -1,8 +1,6 @@
1
- import { getOwner, onCleanup, createMemo, runWithOwner, createLoadingBoundary, createOwner, createRenderEffect, sharedConfig, createSignal } from 'solid-js';
1
+ import { getOwner, onCleanup, createMemo, runWithOwner, createSignal, createRenderEffect, createLoadingBoundary, createOwner, sharedConfig, materializeContainerTrace } from 'solid-js';
2
2
  import { insert } from '@solidjs/web';
3
- import { createPlugin, fromCrossJSON, Feature } from 'seroval';
4
3
  import { ChunkReader, frameAddress, SINGLE_FLIGHT_HEADER, deserializeStream, getServerFunctionsCodec, createChunk, getFlightDataConsumer, ERROR_HEADER, REVALIDATE_HEADER, configureServerFunctionsClient } from '@solidjs/web/server-functions/client';
5
- import { AbortSignalPlugin, CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin } from 'seroval-plugins/web';
6
4
 
7
5
  const ELEMENT_NODE = 1;
8
6
  const TEXT_NODE = 3;
@@ -65,16 +63,32 @@ function chunkToRecords(chunk) {
65
63
  args: chunk.args
66
64
  }
67
65
  };
66
+ case "hole":
67
+ return {
68
+ [`hole:${chunk.key}`]: {
69
+ kind: "html",
70
+ value: chunk.html
71
+ }
72
+ };
73
+ case "attr":
74
+ return {
75
+ [`attr:${chunk.key}`]: {
76
+ kind: "attrs",
77
+ value: chunk.attrs,
78
+ removed: chunk.removed
79
+ }
80
+ };
68
81
  case "complete":
69
82
  return {
70
83
  ":complete": true
71
84
  };
72
85
  case "error":
73
- return chunk.key ? {
74
- [`seg:${chunk.key}:error`]: chunk.error
75
- } : {
86
+ if (!chunk.key) return {
76
87
  ":error": chunk.error
77
88
  };
89
+ return {
90
+ [`${/^lha?:/.test(chunk.key) ? "hole" : "seg"}:${chunk.key}:error`]: chunk.error
91
+ };
78
92
  default:
79
93
  return {};
80
94
  }
@@ -94,9 +108,7 @@ function createFrameHost(options = {}) {
94
108
  if (store.version !== undefined && version < store.version) return false;
95
109
  if (store.version === undefined || version > store.version) {
96
110
  store.version = version;
97
- for (const key of Object.keys(store.records)) {
98
- if (key.startsWith("seg:") || key === ":error") delete store.records[key];
99
- }
111
+ clearStreamRecords(store.records);
100
112
  }
101
113
  Object.assign(store.records, records);
102
114
  return true;
@@ -161,7 +173,10 @@ function createFrameHost(options = {}) {
161
173
  },
162
174
  resolve(ref, frameId) {
163
175
  return options.resolve ? options.resolve(ref, frameId) : undefined;
164
- }
176
+ },
177
+ revive: options.revive,
178
+ isContainer: options.isContainer,
179
+ prepareData: options.prepareData
165
180
  };
166
181
  }
167
182
  const FRAME_APPLIED_EVENT = "frame:applied";
@@ -174,8 +189,10 @@ class FrameImpl {
174
189
  #store = Object.create(null);
175
190
  #appliedRootValue;
176
191
  #hasContent = false;
192
+ #errorNotified = false;
177
193
  #revealed = new Set();
178
194
  #fallbackShown = new Set();
195
+ #appliedHoles = new Map();
179
196
  #slots;
180
197
  #mountedSlots = new Set();
181
198
  #slotCleanups = new Map();
@@ -193,10 +210,12 @@ class FrameImpl {
193
210
  #claimTree = (node, direct) => {
194
211
  const handlers = claimHandlers();
195
212
  if (!handlers) return;
196
- const run = () => direct ? claimNode(handlers, node) : claimTree(handlers, node);
197
- const scope = this.#options.ownerScope;
198
- scope ? scope(run) : run();
213
+ this.#scoped(() => direct ? claimNode(handlers, node) : claimTree(handlers, node));
199
214
  };
215
+ #scoped(fn) {
216
+ const scope = this.#options.ownerScope;
217
+ return scope ? scope(fn) : fn();
218
+ }
200
219
  constructor(element, start, end, options = {}) {
201
220
  this.#element = element;
202
221
  this.#start = start;
@@ -257,15 +276,9 @@ class FrameImpl {
257
276
  return;
258
277
  } else if (v > this.#version) {
259
278
  this.#version = v;
260
- this.#revealed.clear();
261
- this.#fallbackShown.clear();
262
- for (const key of Object.keys(this.#store)) {
263
- if (key.startsWith("seg:") || key === ":error") {
264
- delete this.#store[key];
265
- }
266
- }
279
+ this.#resetStreamState();
267
280
  }
268
- for (const key of Object.keys(write.r)) {
281
+ for (const key in write.r) {
269
282
  const incoming = write.r[key];
270
283
  if (incoming && incoming.kind === "slot" && key.charCodeAt(0) === 115 && key.startsWith("slot:")) {
271
284
  const existing = this.#store[key];
@@ -277,6 +290,13 @@ class FrameImpl {
277
290
  }
278
291
  this.#flush();
279
292
  }
293
+ #resetStreamState(root) {
294
+ this.#revealed.clear();
295
+ this.#fallbackShown.clear();
296
+ this.#appliedHoles.clear();
297
+ this.#errorNotified = false;
298
+ clearStreamRecords(this.#store, root);
299
+ }
280
300
  #flush() {
281
301
  if (this.#disposed) return;
282
302
  const version = this.#version;
@@ -287,10 +307,14 @@ class FrameImpl {
287
307
  this.#appliedRootValue = root.value;
288
308
  this.#applied(version, reason);
289
309
  }
310
+ if (this.#store[":error"] && !this.#errorNotified) {
311
+ this.#errorNotified = true;
312
+ this.#applied(version, "error");
313
+ }
290
314
  let progressed = true;
291
315
  while (progressed) {
292
316
  progressed = false;
293
- for (const key of Object.keys(this.#store)) {
317
+ for (const key in this.#store) {
294
318
  const name = segmentName(key);
295
319
  if (name === null || this.#revealed.has(name)) continue;
296
320
  if (this.#segmentReady(name)) {
@@ -299,7 +323,7 @@ class FrameImpl {
299
323
  progressed = true;
300
324
  }
301
325
  }
302
- for (const key of Object.keys(this.#store)) {
326
+ for (const key in this.#store) {
303
327
  const m = /^seg:([^:]+):fallback$/.exec(key);
304
328
  if (!m) continue;
305
329
  const name = m[1];
@@ -311,7 +335,24 @@ class FrameImpl {
311
335
  }
312
336
  }
313
337
  }
314
- for (const key of Object.keys(this.#store)) {
338
+ for (const key in this.#store) {
339
+ const record = this.#store[key];
340
+ if (!record || this.#appliedHoles.get(key) === record) continue;
341
+ if (key.startsWith("hole:")) {
342
+ if (key.endsWith(":error")) {
343
+ this.#appliedHoles.set(key, record);
344
+ } else if (this.#applyHole(key.slice(5), record.value)) {
345
+ this.#appliedHoles.set(key, record);
346
+ this.#applied(version, "morph");
347
+ }
348
+ } else if (key.startsWith("attr:")) {
349
+ if (this.#applyAttrs(key.slice(5), record.value, record.removed)) {
350
+ this.#appliedHoles.set(key, record);
351
+ this.#applied(version, "morph");
352
+ }
353
+ }
354
+ }
355
+ for (const key in this.#store) {
315
356
  if (this.#processedAssets.has(key) || !key.endsWith(":assets")) continue;
316
357
  this.#processedAssets.add(key);
317
358
  const record = this.#store[key];
@@ -343,6 +384,7 @@ class FrameImpl {
343
384
  const callback = this.#resolveSlot(propOf(occurrence));
344
385
  if (!callback) continue;
345
386
  const record = this.#resolveSlotRecord(occurrence);
387
+ if (record && record.kind === "slot" && this.#refsUnresolved(record.args)) continue;
346
388
  const prev = this.#slotNodes.get(occurrence);
347
389
  const prevFirst = Array.isArray(prev) ? prev[0] : prev;
348
390
  const zombie = this.#mountedSlots.has(occurrence) && prevFirst && !prevFirst.parentNode;
@@ -398,15 +440,7 @@ class FrameImpl {
398
440
  const cleanups = this.#slotCleanups.get(occurrence) ?? [];
399
441
  let existing = [];
400
442
  let end = null;
401
- if (start) {
402
- const endData = slotEnd(occurrence);
403
- let n = start.nextSibling;
404
- while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
405
- existing.push(n);
406
- n = n.nextSibling;
407
- }
408
- end = n;
409
- }
443
+ if (start) end = eachInRange(start, occurrence, n => existing.push(n));
410
444
  const ctx = {
411
445
  frame: this.#options.claimScope ?? this.#options.id,
412
446
  key: occurrence,
@@ -421,23 +455,16 @@ class FrameImpl {
421
455
  } : undefined
422
456
  };
423
457
  const props = record && record.kind === "slot" ? this.#resolveArgs(occurrence, record.args) : {};
424
- const scope = this.#options.ownerScope;
425
- const content = scope ? scope(() => callback(props, ctx)) : callback(props, ctx);
458
+ const content = this.#scoped(() => callback(props, ctx));
426
459
  this.#slotArgs.set(occurrence, record);
427
460
  if (cleanups.length) this.#slotCleanups.set(occurrence, cleanups);
428
461
  if (content == null) return null;
429
462
  return Array.isArray(content) ? content : [content];
430
463
  }
431
464
  #replaceRange(key, start, nodes) {
432
- const end = slotEnd(key);
433
465
  const parent = start.parentNode;
434
- let n = start.nextSibling;
435
- while (n && !(n.nodeType === COMMENT_NODE && n.data === end)) {
436
- const next = n.nextSibling;
437
- parent.removeChild(n);
438
- n = next;
439
- }
440
- for (const node of nodes) parent.insertBefore(node, n);
466
+ const end = eachInRange(start, key, n => parent.removeChild(n));
467
+ for (const node of nodes) parent.insertBefore(node, end);
441
468
  }
442
469
  #unmountSlot(key) {
443
470
  this.#mountedSlots.delete(key);
@@ -449,9 +476,7 @@ class FrameImpl {
449
476
  this.#runSlotCleanups(key);
450
477
  const regions = this.#slotRegions.get(key);
451
478
  if (regions) {
452
- for (const {
453
- frame
454
- } of regions.values()) frame?.dispose();
479
+ disposeRegions(regions);
455
480
  this.#slotRegions.delete(key);
456
481
  }
457
482
  }
@@ -461,15 +486,26 @@ class FrameImpl {
461
486
  this.#slotCleanups.delete(key);
462
487
  for (const fn of cleanups) fn();
463
488
  }
489
+ #refsUnresolved(args) {
490
+ const {
491
+ host,
492
+ id
493
+ } = this.#options;
494
+ if (host) for (const key in args) {
495
+ if (isDataRef(args[key]) && host.resolve(args[key], id) === undefined) return true;
496
+ }
497
+ return false;
498
+ }
499
+ #regionsFor(slotKey) {
500
+ let regions = this.#slotRegions.get(slotKey);
501
+ if (!regions) this.#slotRegions.set(slotKey, regions = new Map());
502
+ return regions;
503
+ }
464
504
  #resolveArgs(slotKey, args) {
465
505
  const host = this.#options.host;
466
- let regions = this.#slotRegions.get(slotKey);
467
- if (!regions) {
468
- regions = new Map();
469
- this.#slotRegions.set(slotKey, regions);
470
- }
506
+ const regions = this.#regionsFor(slotKey);
471
507
  const props = {};
472
- for (const key of Object.keys(args)) {
508
+ for (const key in args) {
473
509
  const value = args[key];
474
510
  if (isDataRef(value)) {
475
511
  const resolved = host ? host.resolve(value, this.#options.id) : undefined;
@@ -492,24 +528,15 @@ class FrameImpl {
492
528
  }
493
529
  props[key] = entry.element;
494
530
  } else {
495
- props[key] = value;
531
+ props[key] = host && host.revive ? host.revive(value) : value;
496
532
  }
497
533
  }
498
534
  return props;
499
535
  }
500
536
  #discoverRegions(slotKey, start) {
501
537
  if (!start) return;
502
- let regions = this.#slotRegions.get(slotKey);
503
- if (!regions) {
504
- regions = new Map();
505
- this.#slotRegions.set(slotKey, regions);
506
- }
507
- const endData = slotEnd(slotKey);
508
- let n = start.nextSibling;
509
- while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
510
- collectRegionElements(n, regions);
511
- n = n.nextSibling;
512
- }
538
+ const regions = this.#regionsFor(slotKey);
539
+ eachInRange(start, slotKey, n => collectRegionElements(n, regions));
513
540
  }
514
541
  #refArgsUnchanged(occurrence, record) {
515
542
  const old = this.#slotArgs.get(occurrence);
@@ -525,11 +552,15 @@ class FrameImpl {
525
552
  const va = a[key];
526
553
  const vb = b[key];
527
554
  if (va === vb) continue;
528
- if (!va || !vb || typeof va !== "object" || typeof vb !== "object") return false;
529
- if (typeof va.$frame === "string" && typeof vb.$frame === "string") continue;
530
- if (typeof va.$ref === "string" && typeof vb.$ref === "string" && cache && key in cache) {
555
+ if (isFrameRef(va) && isFrameRef(vb)) continue;
556
+ if (isDataRef(va) && isDataRef(vb) && cache && key in cache) {
531
557
  const host = this.#options.host;
532
558
  const next = host ? host.resolve(vb, this.#options.id) : undefined;
559
+ if (host && host.isContainer && (host.isContainer(next) || host.isContainer(cache[key]))) {
560
+ if (next === cache[key]) continue;
561
+ return false;
562
+ }
563
+ if (isAsyncLike(next) || isAsyncLike(cache[key])) return false;
533
564
  try {
534
565
  if (JSON.stringify(next) === JSON.stringify(cache[key])) continue;
535
566
  } catch (e) {
@@ -545,7 +576,7 @@ class FrameImpl {
545
576
  if (!args) return;
546
577
  const regions = this.#slotRegions.get(occurrence);
547
578
  if (!regions) return;
548
- for (const key of Object.keys(args)) {
579
+ for (const key in args) {
549
580
  const value = args[key];
550
581
  if (!isFrameRef(value)) continue;
551
582
  const entry = regions.get(key);
@@ -595,11 +626,8 @@ class FrameImpl {
595
626
  this.#element.setAttribute(FRAME_ID_ATTR, id);
596
627
  }
597
628
  this.#version = undefined;
598
- this.#revealed.clear();
599
- this.#fallbackShown.clear();
600
- for (const key of Object.keys(this.#store)) {
601
- if (key.startsWith("seg:") || key === ":error") delete this.#store[key];
602
- }
629
+ this.#appliedRootValue = undefined;
630
+ this.#resetStreamState(true);
603
631
  if (host) host.register(id, this);
604
632
  }
605
633
  rebase() {
@@ -619,11 +647,7 @@ class FrameImpl {
619
647
  }
620
648
  for (const key of [...this.#slotCleanups.keys()]) this.#runSlotCleanups(key);
621
649
  for (const key of this.#mountedSlots) this.#removeSlotRecord(key);
622
- for (const regions of this.#slotRegions.values()) {
623
- for (const {
624
- frame
625
- } of regions.values()) frame?.dispose();
626
- }
650
+ for (const regions of this.#slotRegions.values()) disposeRegions(regions);
627
651
  this.#slotRegions.clear();
628
652
  this.#mountedSlots.clear();
629
653
  }
@@ -644,14 +668,37 @@ class FrameImpl {
644
668
  if (ranges.size) for (const root of grafts) flushGrafts(root, ranges);
645
669
  }
646
670
  }
647
- #clearContent() {
648
- const parent = this.#parent();
649
- let n = this.#firstContent();
650
- while (n && n !== this.#end) {
651
- const next = n.nextSibling;
652
- parent.removeChild(n);
653
- n = next;
671
+ #applyHole(marker, html) {
672
+ if (!this.#hasContent) return false;
673
+ const open = findLiveTarget(this.#firstContent(), this.#end, n => n.nodeType === COMMENT_NODE && n.data === marker);
674
+ if (!open) return false;
675
+ const close = rangeClose(open, "lh:/" + marker.slice(3));
676
+ if (!close) {
677
+ return false;
678
+ }
679
+ const claim = claimHandlers() ? this.#claimTree : null;
680
+ reconcileChildren(open.parentNode, parseFragment(html), open, close, claim);
681
+ return true;
682
+ }
683
+ #applyAttrs(addr, text, removed) {
684
+ if (!this.#hasContent) return false;
685
+ const el = findLiveTarget(this.#firstContent(), this.#end, n => n.nodeType === ELEMENT_NODE && n.getAttribute("data-lha") === addr);
686
+ if (!el) return false;
687
+ const parsed = parseFragment(`<i${text}></i>`).firstChild;
688
+ if (parsed) {
689
+ for (let i = 0; i < parsed.attributes.length; i++) {
690
+ const {
691
+ name,
692
+ value
693
+ } = parsed.attributes[i];
694
+ if (el.getAttribute(name) !== value) el.setAttribute(name, value);
695
+ }
654
696
  }
697
+ if (removed) for (const name of removed) el.removeAttribute(name);
698
+ return true;
699
+ }
700
+ #clearContent() {
701
+ removeUntil(this.#parent(), this.#firstContent(), this.#end);
655
702
  }
656
703
  #claimContent() {
657
704
  if (!claimHandlers()) return;
@@ -668,9 +715,7 @@ class FrameImpl {
668
715
  const assets = this.#store[`seg:${name}:assets`];
669
716
  if (assets && assets.styles) {
670
717
  let ready = true;
671
- for (const entry of assets.styles) {
672
- if (!ensureStylesheet(entry, this.#styleFlush)) ready = false;
673
- }
718
+ for (const entry of assets.styles) ready = ensureStylesheet(entry, this.#styleFlush) && ready;
674
719
  if (!ready) return false;
675
720
  }
676
721
  if (!this.#findPlaceholder(name)) return false;
@@ -684,12 +729,7 @@ class FrameImpl {
684
729
  const content = this.#store[`seg:${name}`];
685
730
  const closing = rangeClose(tpl, placeholderId(name));
686
731
  const parent = tpl.parentNode;
687
- let n = tpl.nextSibling;
688
- while (n && n !== closing) {
689
- const next = n.nextSibling;
690
- parent.removeChild(n);
691
- n = next;
692
- }
732
+ removeUntil(parent, tpl.nextSibling, closing);
693
733
  if (this.#options.reveal) {
694
734
  const fallbackFrag = tpl.content.cloneNode(true);
695
735
  this.#claimTree(fallbackFrag);
@@ -738,9 +778,7 @@ function createFrameElement(options) {
738
778
  const frame = new FrameImpl(el, null, null, options);
739
779
  return {
740
780
  element: el,
741
- get frame() {
742
- return frame;
743
- },
781
+ frame,
744
782
  dispose() {
745
783
  frame.dispose();
746
784
  el.remove();
@@ -760,15 +798,30 @@ function segmentName(key) {
760
798
  const m = /^seg:([^:]+)$/.exec(key);
761
799
  return m ? m[1] : null;
762
800
  }
801
+ function isAsyncLike(v) {
802
+ return !!v && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
803
+ }
763
804
  function propOf(occurrence) {
764
805
  const hash = occurrence.indexOf("#");
765
806
  return hash === -1 ? occurrence : occurrence.slice(0, hash);
766
807
  }
767
808
  function isDataRef(value) {
768
- return typeof value === "object" && value !== null && typeof value.$ref === "string";
809
+ return !!value && typeof value.$ref === "string";
769
810
  }
770
811
  function isFrameRef(value) {
771
- return typeof value === "object" && value !== null && typeof value.$frame === "string";
812
+ return !!value && typeof value.$frame === "string";
813
+ }
814
+ function disposeRegions(regions) {
815
+ for (const {
816
+ frame
817
+ } of regions.values()) frame?.dispose();
818
+ }
819
+ function removeUntil(parent, n, stop) {
820
+ while (n && n !== stop) {
821
+ const next = n.nextSibling;
822
+ parent.removeChild(n);
823
+ n = next;
824
+ }
772
825
  }
773
826
  function parseFragment(html) {
774
827
  const template = document.createElement("template");
@@ -776,9 +829,8 @@ function parseFragment(html) {
776
829
  return template.content;
777
830
  }
778
831
  function findHeadElement(selector, attr, value) {
779
- const nodes = document.head.querySelectorAll(selector);
780
- for (let i = 0; i < nodes.length; i++) {
781
- if (nodes[i].getAttribute(attr) === value) return nodes[i];
832
+ for (const node of document.head.querySelectorAll(selector)) {
833
+ if (node.getAttribute(attr) === value) return node;
782
834
  }
783
835
  return null;
784
836
  }
@@ -827,7 +879,7 @@ function applyInlineStyles(inlineStyles) {
827
879
  }
828
880
  }
829
881
  function isPlaceholderStart(node, id) {
830
- return node.nodeType === ELEMENT_NODE && node.tagName === "TEMPLATE" && node.getAttribute("id") === id;
882
+ return node.tagName === "TEMPLATE" && node.id === id;
831
883
  }
832
884
  function rangeClose(start, id) {
833
885
  let n = start.nextSibling;
@@ -837,6 +889,20 @@ function rangeClose(start, id) {
837
889
  }
838
890
  return null;
839
891
  }
892
+ function findLiveTarget(n, end, test) {
893
+ while (n && n !== end) {
894
+ if (n.nodeType === ELEMENT_NODE) {
895
+ const fid = isFrameElement(n) ? n.getAttribute(FRAME_ID_ATTR) : null;
896
+ if (fid === null || fid.includes(".")) {
897
+ if (test(n)) return n;
898
+ const found = findLiveTarget(n.firstChild, null, test);
899
+ if (found) return found;
900
+ }
901
+ } else if (test(n)) return n;
902
+ n = n.nextSibling;
903
+ }
904
+ return null;
905
+ }
840
906
  function findPlaceholder(n, end, id) {
841
907
  while (n && n !== end) {
842
908
  if (isPlaceholderStart(n, id)) return n;
@@ -883,6 +949,23 @@ function renameRegion(entry, childId) {
883
949
  entry.childId = childId;
884
950
  if (entry.frame) entry.frame.rebind(childId);else entry.element.setAttribute(FRAME_ID_ATTR, childId);
885
951
  }
952
+ function eachInRange(start, key, cb) {
953
+ const end = slotEnd(key);
954
+ let n = start.nextSibling;
955
+ while (n && !(n.nodeType === COMMENT_NODE && n.data === end)) {
956
+ const next = n.nextSibling;
957
+ cb(n);
958
+ n = next;
959
+ }
960
+ return n;
961
+ }
962
+ function clearStreamRecords(records, root) {
963
+ for (const key in records) {
964
+ if (/^(seg|hole|attr):/.test(key) || key === ":error" || root && key === "") {
965
+ delete records[key];
966
+ }
967
+ }
968
+ }
886
969
  function argsEquivalent(a, b) {
887
970
  if (a === b) return true;
888
971
  if (!a || !b) return false;
@@ -893,9 +976,7 @@ function argsEquivalent(a, b) {
893
976
  const va = a[key];
894
977
  const vb = b[key];
895
978
  if (va === vb) continue;
896
- if (va && vb && typeof va === "object" && typeof vb === "object" && typeof va.$frame === "string" && va.$frame === vb.$frame) {
897
- continue;
898
- }
979
+ if (isFrameRef(va) && va.$frame === vb?.$frame) continue;
899
980
  return false;
900
981
  }
901
982
  return true;
@@ -1138,6 +1219,7 @@ async function applyFrameResponse(response, host, options = {}) {
1138
1219
  if (v === undefined) perFrame.set(chunk.id, v = version(chunk.id));
1139
1220
  chunk.version = v;
1140
1221
  } else if (version !== undefined) chunk.version = version;
1222
+ if (chunk.type === "data" && host.prepareData) await host.prepareData();
1141
1223
  host.apply(chunk);
1142
1224
  }
1143
1225
  result = await reader.next();
@@ -1154,7 +1236,7 @@ function parseServerComponent(value, ctx) {
1154
1236
  address: ctx.parse(value[SERVER_COMPONENT_ADDRESS])
1155
1237
  };
1156
1238
  }
1157
- const ServerComponentPlugin = /*#__PURE__*/createPlugin({
1239
+ const ServerComponentPlugin = {
1158
1240
  tag: "dom-expressions/server-component",
1159
1241
  test(value) {
1160
1242
  return typeof value === "function" && SERVER_COMPONENT in value;
@@ -1181,12 +1263,10 @@ const ServerComponentPlugin = /*#__PURE__*/createPlugin({
1181
1263
  }
1182
1264
  return globalThis._$SC.r(id);
1183
1265
  }
1184
- });
1266
+ };
1185
1267
  function flightCodec(codec) {
1186
1268
  const plugins = codec && codec.plugins || [];
1187
- for (const plugin of plugins) {
1188
- if (plugin && plugin.tag === "dom-expressions/server-component") return codec;
1189
- }
1269
+ if (plugins.some(plugin => plugin && plugin.tag === ServerComponentPlugin.tag)) return codec;
1190
1270
  return {
1191
1271
  ...codec,
1192
1272
  plugins: [...plugins, ServerComponentPlugin]
@@ -1258,7 +1338,7 @@ function createServerComponentHandler({
1258
1338
  showing(address, functionId) {
1259
1339
  bindingFor(address, functionId);
1260
1340
  const comp = componentFor(functionId);
1261
- if ((typeof comp === "function" || typeof comp === "object" && comp !== null) && !comp[COMPONENT_BINDING]) {
1341
+ if (comp && (typeof comp === "function" || typeof comp === "object") && !comp[COMPONENT_BINDING]) {
1262
1342
  comp[COMPONENT_BINDING] = {
1263
1343
  component: comp,
1264
1344
  address
@@ -1303,69 +1383,74 @@ function createServerComponentHandler({
1303
1383
  }
1304
1384
  }
1305
1385
 
1306
- Feature.AggregateError | Feature.BigIntTypedArray;
1307
- const DEFAULT_WEB_PLUGINS = Object.freeze([AbortSignalPlugin,
1308
- CustomEventPlugin, DOMExceptionPlugin, EventPlugin,
1309
- FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin]);
1310
- function resolveSerializerPlugins(customPlugins) {
1311
- return customPlugins ? [...customPlugins, ...DEFAULT_WEB_PLUGINS] : [...DEFAULT_WEB_PLUGINS];
1312
- }
1313
- const JSON_CODEC_DISABLED_FEATURES = Feature.RegExp;
1314
- const JSON_CODEC_DEPTH_LIMIT = 64;
1315
- function resolveCodecOptions({
1316
- plugins,
1317
- disabledFeatures,
1318
- depthLimit
1319
- } = {}) {
1320
- return {
1321
- plugins: resolveSerializerPlugins(plugins),
1322
- disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
1323
- depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
1324
- };
1386
+ const STATE = Symbol.for("dom-expressions.container-trace-state");
1387
+ const state = globalThis[STATE] || (globalThis[STATE] = {
1388
+ materialized: new WeakMap(),
1389
+ materializedValues: new WeakSet()
1390
+ });
1391
+ function setContainerTraceMaterializer(fn) {
1392
+ state.materializeTrace = fn;
1325
1393
  }
1326
- function createJSONDeserializer(options) {
1327
- const refs = new Map();
1328
- const resolved = resolveCodecOptions(options);
1329
- return function deserializeJSONChunk(node) {
1330
- return fromCrossJSON(node, {
1331
- refs,
1332
- ...resolved
1333
- });
1334
- };
1394
+ function materialize(marker) {
1395
+ let value = state.materialized.get(marker.$tr);
1396
+ if (value === undefined) {
1397
+ value = state.materializeTrace(marker);
1398
+ state.materialized.set(marker.$tr, value);
1399
+ if (value !== null && typeof value === "object") state.materializedValues.add(value);
1400
+ }
1401
+ return value;
1335
1402
  }
1336
- function createJSONDataTable(options) {
1337
- const deserialize = createJSONDeserializer(options);
1338
- const table = new Map();
1339
- return {
1340
- apply(record) {
1341
- const value = deserialize(record.node);
1342
- if (record.initial) table.set(record.key, value);
1343
- },
1344
- get(key) {
1345
- return table.get(key);
1346
- },
1347
- resolve(ref) {
1348
- return table.get(ref.$ref);
1349
- }
1350
- };
1403
+ function isMaterializedContainer(value) {
1404
+ return value !== null && typeof value === "object" && state.materializedValues.has(value);
1405
+ }
1406
+ function isContainerTraceMarker(value) {
1407
+ return value != null && typeof value === "object" && value.$tr != null && typeof value.$tr[Symbol.asyncIterator] === "function";
1408
+ }
1409
+ function reviveContainerTraces(value) {
1410
+ if (!state.materializeTrace || value == null || typeof value !== "object") return value;
1411
+ if (isContainerTraceMarker(value)) return materialize(value);
1412
+ if (Array.isArray(value)) {
1413
+ for (let i = 0; i < value.length; i++) value[i] = reviveContainerTraces(value[i]);
1414
+ } else if (Object.getPrototypeOf(value) === Object.prototype) {
1415
+ for (const key of Object.keys(value)) value[key] = reviveContainerTraces(value[key]);
1416
+ }
1417
+ return value;
1351
1418
  }
1352
1419
 
1420
+ setContainerTraceMaterializer(materializeContainerTrace);
1421
+ function asyncArg(value) {
1422
+ return value;
1423
+ }
1353
1424
  let sharedHost;
1425
+ let codec;
1426
+ let codecLoading;
1427
+ function loadCodec() {
1428
+ return codecLoading ??= import('@solidjs/web/serialization/decode').then(m => {
1429
+ codec = m;
1430
+ });
1431
+ }
1354
1432
  const tables = new Map();
1433
+ function ensureTable(root) {
1434
+ let table = tables.get(root);
1435
+ if (!table && codec) tables.set(root, table = codec.createJSONDataTable());
1436
+ return table;
1437
+ }
1355
1438
  function tableFor(id) {
1356
- const table = tables.get(id);
1357
- if (table) return table;
1358
- for (const [root, t] of tables) if (id.startsWith(root + ".")) return t;
1439
+ if (tables.has(id)) return ensureTable(id);
1440
+ for (const root of tables.keys()) if (id.startsWith(root + ".")) return ensureTable(root);
1359
1441
  return undefined;
1360
1442
  }
1361
1443
  function beginStream(frameId) {
1362
- tables.set(frameId, createJSONDataTable());
1444
+ tables.set(frameId, undefined);
1363
1445
  }
1364
1446
  function getFrameHost() {
1365
1447
  if (!sharedHost) {
1366
1448
  sharedHost = createFrameHost({
1449
+ prepareData: loadCodec,
1367
1450
  applyData: c => tableFor(c.id)?.apply(c),
1368
- resolve: (ref, id) => tableFor(id)?.resolve(ref)
1451
+ resolve: (ref, id) => tableFor(id)?.resolve(ref),
1452
+ revive: reviveContainerTraces,
1453
+ isContainer: isMaterializedContainer
1369
1454
  });
1370
1455
  }
1371
1456
  return sharedHost;
@@ -1426,8 +1511,27 @@ function claimRender(prefix, existing, render) {
1426
1511
  function liveSlotProps(initial, ctx) {
1427
1512
  const [args, setArgs] = createSignal(initial);
1428
1513
  ctx.onUpdate(next => setArgs(() => next));
1514
+ return slotArgsProxy(args);
1515
+ }
1516
+ function isAsyncValue(v) {
1517
+ return v !== null && typeof v === "object" && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
1518
+ }
1519
+ function slotArgsProxy(args) {
1520
+ const owner = getOwner();
1521
+ const asyncReads = new Map();
1429
1522
  return new Proxy({}, {
1430
- get: (_, key) => args()[key],
1523
+ get: (_, key) => {
1524
+ const v = args()[key];
1525
+ if (isMaterializedContainer(v)) return v;
1526
+ if (!isAsyncValue(v)) return v;
1527
+ let read = asyncReads.get(key);
1528
+ if (!read) {
1529
+ const make = () => createMemo(() => args()[key]);
1530
+ read = owner ? runWithOwner(owner, make) : make();
1531
+ asyncReads.set(key, read);
1532
+ }
1533
+ return read();
1534
+ },
1431
1535
  has: (_, key) => key in args(),
1432
1536
  ownKeys: () => Reflect.ownKeys(args()),
1433
1537
  getOwnPropertyDescriptor: (_, key) => key in args() ? {
@@ -1445,6 +1549,7 @@ function isReactiveContent(value) {
1445
1549
  }
1446
1550
  function slotsFor(props) {
1447
1551
  const bindings = new Map();
1552
+ const fillScopes = new Map();
1448
1553
  return new Proxy({}, {
1449
1554
  get(_, prop) {
1450
1555
  if (typeof prop !== "string" || !(prop in props)) return undefined;
@@ -1455,6 +1560,19 @@ function slotsFor(props) {
1455
1560
  bindings.delete(key);
1456
1561
  prev.dispose();
1457
1562
  }
1563
+ const prevFill = key !== undefined && fillScopes.get(key);
1564
+ if (prevFill) {
1565
+ fillScopes.delete(key);
1566
+ prevFill.dispose();
1567
+ }
1568
+ const fillOwner = streamInvoke ? createOwner() : null;
1569
+ if (fillOwner && key !== undefined && ctx) {
1570
+ fillScopes.set(key, fillOwner);
1571
+ ctx.onCleanup(() => {
1572
+ if (fillScopes.get(key) === fillOwner) fillScopes.delete(key);
1573
+ fillOwner.dispose();
1574
+ });
1575
+ }
1458
1576
  const settle = out => {
1459
1577
  const existing = ctx && ctx.existing || [];
1460
1578
  if (existing.length) {
@@ -1467,13 +1585,13 @@ function slotsFor(props) {
1467
1585
  const evaluate = () => {
1468
1586
  const v = props[prop];
1469
1587
  if (typeof v === "function" && ctx && ctx.invoked) {
1470
- return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotProps);
1588
+ return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotArgsProxy(() => slotProps));
1471
1589
  }
1472
1590
  return v;
1473
1591
  };
1474
1592
  const adopted = !!(ctx && ctx.frame && ctx.adopted && ctx.existing && ctx.existing.length);
1475
1593
  const prefix = ctx && ctx.frame ? `sc-${ctx.frame}-${ctx.key}-` : "";
1476
- const value = adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
1594
+ const value = fillOwner ? runWithOwner(fillOwner, () => adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate()) : adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
1477
1595
  if (!isReactiveContent(value)) {
1478
1596
  return settle(normalizeSlotContent(value));
1479
1597
  }
@@ -1498,32 +1616,82 @@ function slotsFor(props) {
1498
1616
  function revealSeam(owner) {
1499
1617
  return seam => runWithOwner(owner, () => insert(seam.before.parentNode, createLoadingBoundary(() => seam.content(), () => seam.fallback), seam.before));
1500
1618
  }
1619
+ let streamInvoke = false;
1501
1620
  function boundaryScope(owner) {
1502
- return fn => getOwner() ? fn() : runWithOwner(owner, fn);
1503
- }
1504
- function followBinding(frame, binding) {
1505
- createRenderEffect(binding, address => frame.rebind(address));
1621
+ return fn => {
1622
+ if (getOwner()) return fn();
1623
+ streamInvoke = true;
1624
+ try {
1625
+ return runWithOwner(owner, fn);
1626
+ } finally {
1627
+ streamInvoke = false;
1628
+ }
1629
+ };
1506
1630
  }
1507
1631
  function boundaryComponent(host, fnId) {
1508
1632
  return (props, binding) => {
1509
1633
  const owner = getOwner();
1634
+ const id = binding ? binding() : fnId;
1635
+ let applied = !tables.has(id);
1636
+ let release;
1637
+ const arm = () => new Promise(r => release = r);
1638
+ const mountGate = applied ? undefined : arm();
1639
+ let setGate;
1510
1640
  const {
1511
1641
  element,
1512
1642
  frame,
1513
1643
  dispose
1514
1644
  } = createFrameElement({
1515
1645
  host,
1516
- id: binding ? binding() : fnId,
1646
+ id,
1517
1647
  slots: slotsFor(props),
1518
1648
  ownerScope: boundaryScope(owner),
1519
- reveal: revealSeam(owner)
1649
+ reveal: revealSeam(owner),
1650
+ onApply: () => {
1651
+ applied = true;
1652
+ if (release) {
1653
+ release();
1654
+ release = undefined;
1655
+ }
1656
+ setGate && setGate(undefined);
1657
+ }
1520
1658
  });
1521
- if (binding) followBinding(frame, binding);
1659
+ const [gatePromise, setGatePromise] = createSignal(applied ? undefined : mountGate);
1660
+ setGate = setGatePromise;
1661
+ if (binding) {
1662
+ createRenderEffect(binding, (address, prev) => {
1663
+ if (prev !== undefined && address !== prev && tables.has(address)) {
1664
+ applied = false;
1665
+ setGatePromise(arm());
1666
+ }
1667
+ frame.rebind(address);
1668
+ });
1669
+ }
1522
1670
  onCleanup(dispose);
1523
- return element;
1671
+ if (applied && !binding) return element;
1672
+ const gate = createMemo(() => gatePromise());
1673
+ return createMemo(() => (gate(), element));
1524
1674
  };
1525
1675
  }
1526
1676
  const claimedBoundaries = new Set();
1677
+ const liveOps = new Map();
1678
+ const liveAppliers = new Set();
1679
+ let livePumped = null;
1680
+ function pumpLiveChannel() {
1681
+ const stream = globalThis._$HY?.r?.["sc:live"];
1682
+ if (!stream || stream === livePumped || typeof stream.getReader !== "function") return;
1683
+ livePumped = stream;
1684
+ const reader = stream.getReader();
1685
+ const pump = () => reader.read().then(r => {
1686
+ if (r.done) return;
1687
+ const op = r.value;
1688
+ liveOps.set(`${op.type}:${op.fid || ""}:${op.key || ""}`, op);
1689
+ for (const apply of liveAppliers) apply(op);
1690
+ return pump();
1691
+ });
1692
+ pump().catch(() => {
1693
+ });
1694
+ }
1527
1695
  let boundaryIndex = null;
1528
1696
  const isBoundaryId = id => !id.includes(".");
1529
1697
  function indexBoundaries(root) {
@@ -1588,9 +1756,21 @@ function adoptBoundary(host, id, el, props, binding) {
1588
1756
  claimedBoundaries.add(id);
1589
1757
  const address = binding ? binding() : documentAddress(id);
1590
1758
  const appliedRecords = new Set();
1759
+ const claimedFragments = new Set();
1760
+ const claimRegionFragments = root => {
1761
+ const fr = globalThis._$HY?.fr;
1762
+ if (!fr || !fr.claim) return;
1763
+ root.querySelectorAll('template[id^="pl-"]').forEach(tpl => {
1764
+ const fragId = tpl.id.slice(3);
1765
+ if (claimedFragments.has(fragId)) return;
1766
+ claimedFragments.add(fragId);
1767
+ fr.claim(fragId);
1768
+ });
1769
+ };
1591
1770
  const drainRecords = () => {
1592
1771
  const hy = globalThis._$HY;
1593
1772
  if (!hy || !hy.r) return;
1773
+ pumpLiveChannel();
1594
1774
  const slotPrefix = `sc:slot:${id}:`;
1595
1775
  for (const key of Object.keys(hy.r)) {
1596
1776
  if (appliedRecords.has(key)) continue;
@@ -1619,8 +1799,31 @@ function adoptBoundary(host, id, el, props, binding) {
1619
1799
  }
1620
1800
  }
1621
1801
  };
1802
+ claimRegionFragments(el);
1803
+ const fr = globalThis._$HY?.fr;
1804
+ const unsubscribe = fr ? fr.subscribe((_fragId, parent) => {
1805
+ if (fr.claim && parent && el.contains(parent)) claimRegionFragments(parent);
1806
+ drainRecords();
1807
+ }) : undefined;
1808
+ const applyLiveOp = op => {
1809
+ if (op.type === "slot" && op.fid !== id) return;
1810
+ host.apply({
1811
+ ...op,
1812
+ id: address,
1813
+ version: 0
1814
+ });
1815
+ };
1816
+ liveAppliers.add(applyLiveOp);
1817
+ onCleanup(() => {
1818
+ liveAppliers.delete(applyLiveOp);
1819
+ unsubscribe && unsubscribe();
1820
+ if (fr && fr.release) for (const fragId of claimedFragments) fr.release(fragId);
1821
+ });
1622
1822
  drainRecords();
1823
+ for (const op of liveOps.values()) applyLiveOp(op);
1623
1824
  const owner = getOwner();
1825
+ let release;
1826
+ let setGate;
1624
1827
  const frame = createFrame(el, {
1625
1828
  adopt: true,
1626
1829
  host,
@@ -1628,6 +1831,13 @@ function adoptBoundary(host, id, el, props, binding) {
1628
1831
  slots: slotsFor(props),
1629
1832
  ownerScope: boundaryScope(owner),
1630
1833
  reveal: revealSeam(owner),
1834
+ onApply: () => {
1835
+ if (release) {
1836
+ release();
1837
+ release = undefined;
1838
+ }
1839
+ setGate && setGate(undefined);
1840
+ },
1631
1841
  ...{
1632
1842
  recordsPending: () => {
1633
1843
  if (document.readyState === "loading") return true;
@@ -1638,7 +1848,19 @@ function adoptBoundary(host, id, el, props, binding) {
1638
1848
  claimScope: id
1639
1849
  }
1640
1850
  });
1641
- if (binding) followBinding(frame, binding);
1851
+ if (binding) {
1852
+ const arm = () => new Promise(r => release = r);
1853
+ const [gatePromise, setGatePromise] = createSignal(undefined);
1854
+ setGate = setGatePromise;
1855
+ const gate = createMemo(() => gatePromise());
1856
+ createRenderEffect(binding, (address, prev) => {
1857
+ if (prev !== undefined && address !== prev && tables.has(address)) {
1858
+ setGatePromise(arm());
1859
+ }
1860
+ frame.rebind(address);
1861
+ });
1862
+ createRenderEffect(() => (gate(), undefined), () => {});
1863
+ }
1642
1864
  onCleanup(() => frame.dispose());
1643
1865
  return el;
1644
1866
  }
@@ -1679,4 +1901,4 @@ function installServerComponents(host = getFrameHost()) {
1679
1901
  });
1680
1902
  }
1681
1903
 
1682
- export { FRAME_APPLIED_EVENT, FRAME_STREAM_HEADER, applyFrameResponse, createFrame, createFrameElement, createFrameHost, createJSONDataTable, createServerComponentHandler, getFrameHost, installServerComponents, isFrameStreamResponse };
1904
+ export { FRAME_APPLIED_EVENT, FRAME_STREAM_HEADER, applyFrameResponse, asyncArg, createFrame, createFrameElement, createFrameHost, createServerComponentHandler, getFrameHost, installServerComponents, isFrameStreamResponse };