@solidjs/web 2.0.0-beta.30 → 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 (66) hide show
  1. package/README.md +1 -6
  2. package/dist/dev.cjs +284 -82
  3. package/dist/dev.js +271 -79
  4. package/dist/server.cjs +555 -135
  5. package/dist/server.js +544 -132
  6. package/dist/web.cjs +281 -79
  7. package/dist/web.js +268 -76
  8. package/frames/dist/client.cjs +413 -360
  9. package/frames/dist/client.dev.cjs +413 -360
  10. package/frames/dist/client.dev.js +414 -361
  11. package/frames/dist/client.js +414 -361
  12. package/frames/dist/server.cjs +604 -199
  13. package/frames/dist/server.js +605 -201
  14. package/package.json +56 -6
  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 +134 -11
  32. package/types/core.d.ts +3 -1
  33. package/types/frames/client.d.ts +24 -8
  34. package/types/frames/frame-client.d.ts +49 -7
  35. package/types/frames/frame-sink.d.ts +32 -6
  36. package/types/frames/frame-transport.d.ts +88 -62
  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/jsx.d.ts +3 -3
  41. package/types/response.d.ts +45 -0
  42. package/types/serializer.d.ts +173 -6
  43. package/types/server-functions/client.d.ts +1 -0
  44. package/types/server-functions/rich-args.d.ts +10 -0
  45. package/types/server-functions/server.d.ts +98 -0
  46. package/types/server-functions/shared.d.ts +22 -0
  47. package/types/server-mock.d.ts +171 -59
  48. package/types/server.d.ts +196 -42
  49. package/types-cjs/client.d.cts +134 -11
  50. package/types-cjs/core.d.cts +3 -1
  51. package/types-cjs/frames/client.d.cts +24 -8
  52. package/types-cjs/frames/frame-client.d.cts +49 -7
  53. package/types-cjs/frames/frame-sink.d.cts +32 -6
  54. package/types-cjs/frames/frame-transport.d.cts +88 -62
  55. package/types-cjs/frames/serializer.d.cts +173 -6
  56. package/types-cjs/frames/server.d.cts +22 -0
  57. package/types-cjs/index.d.cts +2 -3
  58. package/types-cjs/jsx.d.cts +3 -3
  59. package/types-cjs/response.d.cts +45 -0
  60. package/types-cjs/serializer.d.cts +173 -6
  61. package/types-cjs/server-functions/client.d.cts +1 -0
  62. package/types-cjs/server-functions/rich-args.d.cts +10 -0
  63. package/types-cjs/server-functions/server.d.cts +98 -0
  64. package/types-cjs/server-functions/shared.d.cts +22 -0
  65. package/types-cjs/server-mock.d.cts +171 -59
  66. package/types-cjs/server.d.cts +196 -42
@@ -83,98 +83,73 @@ function chunkToRecords(chunk) {
83
83
  }
84
84
  function createFrameHost(options = {}) {
85
85
  const frames = new Map();
86
- const pending = new Map();
87
- const retained = new Map();
88
- const deliver = (frame, chunk) => {
89
- if (chunk.type === "data") {
90
- options.applyData && options.applyData(chunk);
91
- return;
92
- }
93
- frame.apply({
94
- version: chunk.version,
95
- r: chunkToRecords(chunk)
86
+ const stores = new Map();
87
+ const storeFor = id => {
88
+ let store = stores.get(id);
89
+ if (!store) stores.set(id, store = {
90
+ version: undefined,
91
+ records: {}
96
92
  });
93
+ return store;
94
+ };
95
+ const write = (store, version, records) => {
96
+ if (store.version !== undefined && version < store.version) return false;
97
+ if (store.version === undefined || version > store.version) {
98
+ store.version = version;
99
+ clearStreamRecords(store.records);
100
+ }
101
+ Object.assign(store.records, records);
102
+ return true;
97
103
  };
98
104
  return {
99
105
  register(id, frame) {
100
106
  let set = frames.get(id);
101
107
  if (!set) frames.set(id, set = new Set());
102
- const sibling = set.size ? set.values().next().value : undefined;
103
108
  set.add(frame);
104
- if (sibling) {
109
+ const store = stores.get(id);
110
+ if (store && store.version !== undefined) {
105
111
  frame.apply({
106
- version: sibling.version ?? 0,
107
- r: sibling.store
108
- });
109
- if (sibling.version === undefined) frame.rebase && frame.rebase();
110
- return;
111
- }
112
- const kept = retained.get(id);
113
- if (kept) {
114
- retained.delete(id);
115
- frame.apply({
116
- version: kept.version,
117
- r: kept.records
112
+ version: store.version,
113
+ r: store.records
118
114
  });
119
115
  frame.rebase && frame.rebase();
120
116
  }
121
- const buffered = pending.get(id);
122
- if (buffered) {
123
- pending.delete(id);
124
- const records = {};
125
- let version;
126
- for (const chunk of buffered.chunks) {
127
- if (chunk.type === "data") {
128
- options.applyData && options.applyData(chunk);
129
- continue;
130
- }
131
- version = chunk.version;
132
- Object.assign(records, chunkToRecords(chunk));
133
- }
134
- if (version !== undefined) frame.apply({
135
- version,
136
- r: records
137
- });
138
- }
139
117
  },
140
118
  unregister(id, frame) {
141
119
  const set = frames.get(id);
142
120
  if (set && frame) set.delete(frame);
143
121
  if (!set || !frame || !set.size) {
144
- if (frame) {
145
- const kept = frame.snapshot && frame.snapshot();
146
- if (kept) retained.set(id, kept);
147
- } else {
148
- retained.delete(id);
149
- }
150
122
  frames.delete(id);
151
- pending.delete(id);
123
+ if (frame && frame.contentHTML) {
124
+ const store = storeFor(id);
125
+ if (!store.records[""]) {
126
+ const html = frame.contentHTML();
127
+ if (html != null) {
128
+ store.records[""] = {
129
+ kind: "html",
130
+ value: html
131
+ };
132
+ if (store.version === undefined) store.version = 0;
133
+ }
134
+ }
135
+ }
152
136
  }
137
+ if (!frame) stores.delete(id);
153
138
  },
154
139
  apply(chunk) {
155
140
  if (chunk.type === "data") {
156
141
  options.applyData && options.applyData(chunk);
157
142
  return;
158
143
  }
144
+ const records = chunkToRecords(chunk);
145
+ if (!write(storeFor(chunk.id), chunk.version, records)) return;
159
146
  const set = frames.get(chunk.id);
160
- if (set && set.size) {
161
- for (const frame of set) deliver(frame, chunk);
162
- return;
163
- }
164
- const buffered = pending.get(chunk.id);
165
- if (!buffered) {
166
- pending.set(chunk.id, {
147
+ if (set) {
148
+ for (const frame of set) frame.apply({
167
149
  version: chunk.version,
168
- chunks: [chunk]
150
+ r: records
169
151
  });
170
- return;
171
- }
172
- if (chunk.version < buffered.version) return;
173
- if (chunk.version > buffered.version) {
174
- buffered.version = chunk.version;
175
- buffered.chunks.length = 0;
176
152
  }
177
- buffered.chunks.push(chunk);
178
153
  },
179
154
  get(id) {
180
155
  const set = frames.get(id);
@@ -199,6 +174,7 @@ class FrameImpl {
199
174
  #store = Object.create(null);
200
175
  #appliedRootValue;
201
176
  #hasContent = false;
177
+ #errorNotified = false;
202
178
  #revealed = new Set();
203
179
  #fallbackShown = new Set();
204
180
  #slots;
@@ -210,6 +186,7 @@ class FrameImpl {
210
186
  #slotResolvedRefs = new Map();
211
187
  #slotNodes = new Map();
212
188
  #processedAssets = new Set();
189
+ #recordRefresh = null;
213
190
  #disposed = false;
214
191
  #styleFlush = () => {
215
192
  if (!this.#disposed) this.#flush();
@@ -217,10 +194,12 @@ class FrameImpl {
217
194
  #claimTree = (node, direct) => {
218
195
  const handlers = claimHandlers();
219
196
  if (!handlers) return;
220
- const run = () => direct ? claimNode(handlers, node) : claimTree(handlers, node);
221
- const scope = this.#options.ownerScope;
222
- scope ? scope(run) : run();
197
+ this.#scoped(() => direct ? claimNode(handlers, node) : claimTree(handlers, node));
223
198
  };
199
+ #scoped(fn) {
200
+ const scope = this.#options.ownerScope;
201
+ return scope ? scope(fn) : fn();
202
+ }
224
203
  constructor(element, start, end, options = {}) {
225
204
  this.#element = element;
226
205
  this.#start = start;
@@ -281,15 +260,9 @@ class FrameImpl {
281
260
  return;
282
261
  } else if (v > this.#version) {
283
262
  this.#version = v;
284
- this.#revealed.clear();
285
- this.#fallbackShown.clear();
286
- for (const key of Object.keys(this.#store)) {
287
- if (key.startsWith("seg:") || key === ":error") {
288
- delete this.#store[key];
289
- }
290
- }
263
+ this.#resetStreamState();
291
264
  }
292
- for (const key of Object.keys(write.r)) {
265
+ for (const key in write.r) {
293
266
  const incoming = write.r[key];
294
267
  if (incoming && incoming.kind === "slot" && key.charCodeAt(0) === 115 && key.startsWith("slot:")) {
295
268
  const existing = this.#store[key];
@@ -301,6 +274,12 @@ class FrameImpl {
301
274
  }
302
275
  this.#flush();
303
276
  }
277
+ #resetStreamState(root) {
278
+ this.#revealed.clear();
279
+ this.#fallbackShown.clear();
280
+ this.#errorNotified = false;
281
+ clearStreamRecords(this.#store, root);
282
+ }
304
283
  #flush() {
305
284
  if (this.#disposed) return;
306
285
  const version = this.#version;
@@ -311,10 +290,14 @@ class FrameImpl {
311
290
  this.#appliedRootValue = root.value;
312
291
  this.#applied(version, reason);
313
292
  }
293
+ if (this.#store[":error"] && !this.#errorNotified) {
294
+ this.#errorNotified = true;
295
+ this.#applied(version, "error");
296
+ }
314
297
  let progressed = true;
315
298
  while (progressed) {
316
299
  progressed = false;
317
- for (const key of Object.keys(this.#store)) {
300
+ for (const key in this.#store) {
318
301
  const name = segmentName(key);
319
302
  if (name === null || this.#revealed.has(name)) continue;
320
303
  if (this.#segmentReady(name)) {
@@ -323,7 +306,7 @@ class FrameImpl {
323
306
  progressed = true;
324
307
  }
325
308
  }
326
- for (const key of Object.keys(this.#store)) {
309
+ for (const key in this.#store) {
327
310
  const m = /^seg:([^:]+):fallback$/.exec(key);
328
311
  if (!m) continue;
329
312
  const name = m[1];
@@ -335,7 +318,7 @@ class FrameImpl {
335
318
  }
336
319
  }
337
320
  }
338
- for (const key of Object.keys(this.#store)) {
321
+ for (const key in this.#store) {
339
322
  if (this.#processedAssets.has(key) || !key.endsWith(":assets")) continue;
340
323
  this.#processedAssets.add(key);
341
324
  const record = this.#store[key];
@@ -355,7 +338,9 @@ class FrameImpl {
355
338
  }
356
339
  #removeSlotRecord(occurrence) {
357
340
  const key = `slot:${occurrence}`;
358
- if (key in this.#store) delete this.#store[key];else this.#options.removeSlotRecord?.(occurrence);
341
+ if (key in this.#store) {
342
+ if (!this.#mountedSlots.has(occurrence)) delete this.#store[key];
343
+ } else this.#options.removeSlotRecord?.(occurrence);
359
344
  }
360
345
  #syncSlots(root) {
361
346
  if (!this.#slots && !this.#options.resolveSlot) return;
@@ -365,6 +350,7 @@ class FrameImpl {
365
350
  const callback = this.#resolveSlot(propOf(occurrence));
366
351
  if (!callback) continue;
367
352
  const record = this.#resolveSlotRecord(occurrence);
353
+ if (record && record.kind === "slot" && this.#refsUnresolved(record.args)) continue;
368
354
  const prev = this.#slotNodes.get(occurrence);
369
355
  const prevFirst = Array.isArray(prev) ? prev[0] : prev;
370
356
  const zombie = this.#mountedSlots.has(occurrence) && prevFirst && !prevFirst.parentNode;
@@ -373,6 +359,15 @@ class FrameImpl {
373
359
  this.#runSlotCleanups(occurrence);
374
360
  }
375
361
  if (!this.#mountedSlots.has(occurrence)) {
362
+ if (record === undefined && !root && this.#options.adopt && this.#options.recordsPending?.()) {
363
+ this.#recordRefresh ??= setTimeout(() => {
364
+ this.#recordRefresh = null;
365
+ if (this.#disposed) return;
366
+ this.#options.drainRecords?.();
367
+ this.#syncSlots();
368
+ });
369
+ continue;
370
+ }
376
371
  if (this.#options.adopt) this.#discoverRegions(occurrence, start);
377
372
  const nodes = this.#invokeSlot(occurrence, callback, record, start, this.#options.adopt);
378
373
  if (nodes) this.#replaceRange(occurrence, start, nodes);
@@ -389,12 +384,6 @@ class FrameImpl {
389
384
  const update = this.#slotUpdaters.get(occurrence);
390
385
  if (update) {
391
386
  const props = this.#resolveArgs(occurrence, record.args);
392
- const regions = this.#slotRegions.get(occurrence);
393
- if (regions) {
394
- for (const [argKey, entry] of regions) {
395
- if (!(argKey in props)) props[argKey] = entry.element;
396
- }
397
- }
398
387
  this.#slotArgs.set(occurrence, record);
399
388
  update(props);
400
389
  this.#bindRegions(occurrence);
@@ -417,15 +406,7 @@ class FrameImpl {
417
406
  const cleanups = this.#slotCleanups.get(occurrence) ?? [];
418
407
  let existing = [];
419
408
  let end = null;
420
- if (start) {
421
- const endData = slotEnd(occurrence);
422
- let n = start.nextSibling;
423
- while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
424
- existing.push(n);
425
- n = n.nextSibling;
426
- }
427
- end = n;
428
- }
409
+ if (start) end = eachInRange(start, occurrence, n => existing.push(n));
429
410
  const ctx = {
430
411
  frame: this.#options.claimScope ?? this.#options.id,
431
412
  key: occurrence,
@@ -440,29 +421,16 @@ class FrameImpl {
440
421
  } : undefined
441
422
  };
442
423
  const props = record && record.kind === "slot" ? this.#resolveArgs(occurrence, record.args) : {};
443
- const regions = this.#slotRegions.get(occurrence);
444
- if (regions) {
445
- for (const [argKey, entry] of regions) {
446
- if (!(argKey in props)) props[argKey] = entry.element;
447
- }
448
- }
449
- const scope = this.#options.ownerScope;
450
- const content = scope ? scope(() => callback(props, ctx)) : callback(props, ctx);
424
+ const content = this.#scoped(() => callback(props, ctx));
451
425
  this.#slotArgs.set(occurrence, record);
452
426
  if (cleanups.length) this.#slotCleanups.set(occurrence, cleanups);
453
427
  if (content == null) return null;
454
428
  return Array.isArray(content) ? content : [content];
455
429
  }
456
430
  #replaceRange(key, start, nodes) {
457
- const end = slotEnd(key);
458
431
  const parent = start.parentNode;
459
- let n = start.nextSibling;
460
- while (n && !(n.nodeType === COMMENT_NODE && n.data === end)) {
461
- const next = n.nextSibling;
462
- parent.removeChild(n);
463
- n = next;
464
- }
465
- 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);
466
434
  }
467
435
  #unmountSlot(key) {
468
436
  this.#mountedSlots.delete(key);
@@ -474,9 +442,7 @@ class FrameImpl {
474
442
  this.#runSlotCleanups(key);
475
443
  const regions = this.#slotRegions.get(key);
476
444
  if (regions) {
477
- for (const {
478
- frame
479
- } of regions.values()) frame?.dispose();
445
+ disposeRegions(regions);
480
446
  this.#slotRegions.delete(key);
481
447
  }
482
448
  }
@@ -486,15 +452,26 @@ class FrameImpl {
486
452
  this.#slotCleanups.delete(key);
487
453
  for (const fn of cleanups) fn();
488
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
+ }
489
470
  #resolveArgs(slotKey, args) {
490
471
  const host = this.#options.host;
491
- let regions = this.#slotRegions.get(slotKey);
492
- if (!regions) {
493
- regions = new Map();
494
- this.#slotRegions.set(slotKey, regions);
495
- }
472
+ const regions = this.#regionsFor(slotKey);
496
473
  const props = {};
497
- for (const key of Object.keys(args)) {
474
+ for (const key in args) {
498
475
  const value = args[key];
499
476
  if (isDataRef(value)) {
500
477
  const resolved = host ? host.resolve(value, this.#options.id) : undefined;
@@ -524,18 +501,8 @@ class FrameImpl {
524
501
  }
525
502
  #discoverRegions(slotKey, start) {
526
503
  if (!start) return;
527
- let regions = this.#slotRegions.get(slotKey);
528
- if (!regions) {
529
- regions = new Map();
530
- this.#slotRegions.set(slotKey, regions);
531
- }
532
- const endData = slotEnd(slotKey);
533
- const prefix = `${this.#options.id}.`;
534
- let n = start.nextSibling;
535
- while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
536
- collectRegionElements(n, regions, prefix);
537
- n = n.nextSibling;
538
- }
504
+ const regions = this.#regionsFor(slotKey);
505
+ eachInRange(start, slotKey, n => collectRegionElements(n, regions));
539
506
  }
540
507
  #refArgsUnchanged(occurrence, record) {
541
508
  const old = this.#slotArgs.get(occurrence);
@@ -545,26 +512,17 @@ class FrameImpl {
545
512
  const b = record.args || {};
546
513
  const ka = Object.keys(a);
547
514
  const kb = Object.keys(b);
548
- if (kb.length < ka.length) return false;
549
- if (kb.length !== ka.length) {
550
- const regions = this.#slotRegions.get(occurrence);
551
- for (const key of kb) {
552
- if (key in a) continue;
553
- const vb = b[key];
554
- if (!vb || typeof vb !== "object" || typeof vb.$frame !== "string") return false;
555
- if (!regions || !regions.has(key)) return false;
556
- }
557
- }
515
+ if (kb.length !== ka.length) return false;
558
516
  const cache = this.#slotResolvedRefs.get(occurrence);
559
517
  for (const key of ka) {
560
518
  const va = a[key];
561
519
  const vb = b[key];
562
520
  if (va === vb) continue;
563
- if (!va || !vb || typeof va !== "object" || typeof vb !== "object") return false;
564
- if (typeof va.$frame === "string" && typeof vb.$frame === "string") continue;
565
- 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) {
566
523
  const host = this.#options.host;
567
524
  const next = host ? host.resolve(vb, this.#options.id) : undefined;
525
+ if (isAsyncLike(next) || isAsyncLike(cache[key])) return false;
568
526
  try {
569
527
  if (JSON.stringify(next) === JSON.stringify(cache[key])) continue;
570
528
  } catch (e) {
@@ -580,7 +538,7 @@ class FrameImpl {
580
538
  if (!args) return;
581
539
  const regions = this.#slotRegions.get(occurrence);
582
540
  if (!regions) return;
583
- for (const key of Object.keys(args)) {
541
+ for (const key in args) {
584
542
  const value = args[key];
585
543
  if (!isFrameRef(value)) continue;
586
544
  const entry = regions.get(key);
@@ -611,22 +569,9 @@ class FrameImpl {
611
569
  #findPlaceholder(name) {
612
570
  return findPlaceholder(this.#firstContent(), this.#end, placeholderId(name));
613
571
  }
614
- snapshot() {
615
- if (this.#disposed) return null;
616
- const records = {
617
- ...this.#store
618
- };
619
- if (!records[""] && this.#element && this.#hasContent) {
620
- records[""] = {
621
- kind: "html",
622
- value: this.#element.innerHTML
623
- };
624
- }
625
- if (!records[""] && this.#version === undefined) return null;
626
- return {
627
- version: this.#version ?? 0,
628
- records
629
- };
572
+ contentHTML() {
573
+ if (this.#disposed || !this.#element || !this.#hasContent) return null;
574
+ return this.#element.innerHTML;
630
575
  }
631
576
  rebind(id) {
632
577
  if (this.#disposed || id === this.#options.id) return;
@@ -643,11 +588,8 @@ class FrameImpl {
643
588
  this.#element.setAttribute(FRAME_ID_ATTR, id);
644
589
  }
645
590
  this.#version = undefined;
646
- this.#revealed.clear();
647
- this.#fallbackShown.clear();
648
- for (const key of Object.keys(this.#store)) {
649
- if (key.startsWith("seg:") || key === ":error") delete this.#store[key];
650
- }
591
+ this.#appliedRootValue = undefined;
592
+ this.#resetStreamState(true);
651
593
  if (host) host.register(id, this);
652
594
  }
653
595
  rebase() {
@@ -661,13 +603,13 @@ class FrameImpl {
661
603
  } = this.#options;
662
604
  if (host && id !== undefined) host.unregister(id, this);
663
605
  this.#disposed = true;
606
+ if (this.#recordRefresh) {
607
+ clearTimeout(this.#recordRefresh);
608
+ this.#recordRefresh = null;
609
+ }
664
610
  for (const key of [...this.#slotCleanups.keys()]) this.#runSlotCleanups(key);
665
611
  for (const key of this.#mountedSlots) this.#removeSlotRecord(key);
666
- for (const regions of this.#slotRegions.values()) {
667
- for (const {
668
- frame
669
- } of regions.values()) frame?.dispose();
670
- }
612
+ for (const regions of this.#slotRegions.values()) disposeRegions(regions);
671
613
  this.#slotRegions.clear();
672
614
  this.#mountedSlots.clear();
673
615
  }
@@ -683,18 +625,13 @@ class FrameImpl {
683
625
  const claim = claimHandlers() ? this.#claimTree : null;
684
626
  const ranges = new Map();
685
627
  this.#collectSlots(ranges);
686
- reconcileChildren(parent, fragment, this.#start, this.#end, claim, ranges);
687
- if (ranges.size) restoreDisplacedRanges(this.#firstContent(), this.#end, ranges);
628
+ const grafts = [];
629
+ reconcileChildren(parent, fragment, this.#start, this.#end, claim, ranges, grafts);
630
+ if (ranges.size) for (const root of grafts) flushGrafts(root, ranges);
688
631
  }
689
632
  }
690
633
  #clearContent() {
691
- const parent = this.#parent();
692
- let n = this.#firstContent();
693
- while (n && n !== this.#end) {
694
- const next = n.nextSibling;
695
- parent.removeChild(n);
696
- n = next;
697
- }
634
+ removeUntil(this.#parent(), this.#firstContent(), this.#end);
698
635
  }
699
636
  #claimContent() {
700
637
  if (!claimHandlers()) return;
@@ -711,9 +648,7 @@ class FrameImpl {
711
648
  const assets = this.#store[`seg:${name}:assets`];
712
649
  if (assets && assets.styles) {
713
650
  let ready = true;
714
- for (const entry of assets.styles) {
715
- if (!ensureStylesheet(entry, this.#styleFlush)) ready = false;
716
- }
651
+ for (const entry of assets.styles) ready = ensureStylesheet(entry, this.#styleFlush) && ready;
717
652
  if (!ready) return false;
718
653
  }
719
654
  if (!this.#findPlaceholder(name)) return false;
@@ -727,12 +662,7 @@ class FrameImpl {
727
662
  const content = this.#store[`seg:${name}`];
728
663
  const closing = rangeClose(tpl, placeholderId(name));
729
664
  const parent = tpl.parentNode;
730
- let n = tpl.nextSibling;
731
- while (n && n !== closing) {
732
- const next = n.nextSibling;
733
- parent.removeChild(n);
734
- n = next;
735
- }
665
+ removeUntil(parent, tpl.nextSibling, closing);
736
666
  if (this.#options.reveal) {
737
667
  const fallbackFrag = tpl.content.cloneNode(true);
738
668
  this.#claimTree(fallbackFrag);
@@ -781,9 +711,7 @@ function createFrameElement(options) {
781
711
  const frame = new FrameImpl(el, null, null, options);
782
712
  return {
783
713
  element: el,
784
- get frame() {
785
- return frame;
786
- },
714
+ frame,
787
715
  dispose() {
788
716
  frame.dispose();
789
717
  el.remove();
@@ -803,15 +731,30 @@ function segmentName(key) {
803
731
  const m = /^seg:([^:]+)$/.exec(key);
804
732
  return m ? m[1] : null;
805
733
  }
734
+ function isAsyncLike(v) {
735
+ return !!v && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
736
+ }
806
737
  function propOf(occurrence) {
807
738
  const hash = occurrence.indexOf("#");
808
739
  return hash === -1 ? occurrence : occurrence.slice(0, hash);
809
740
  }
810
741
  function isDataRef(value) {
811
- return typeof value === "object" && value !== null && typeof value.$ref === "string";
742
+ return !!value && typeof value.$ref === "string";
812
743
  }
813
744
  function isFrameRef(value) {
814
- 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
+ }
815
758
  }
816
759
  function parseFragment(html) {
817
760
  const template = document.createElement("template");
@@ -819,9 +762,8 @@ function parseFragment(html) {
819
762
  return template.content;
820
763
  }
821
764
  function findHeadElement(selector, attr, value) {
822
- const nodes = document.head.querySelectorAll(selector);
823
- for (let i = 0; i < nodes.length; i++) {
824
- 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;
825
767
  }
826
768
  return null;
827
769
  }
@@ -870,7 +812,7 @@ function applyInlineStyles(inlineStyles) {
870
812
  }
871
813
  }
872
814
  function isPlaceholderStart(node, id) {
873
- return node.nodeType === ELEMENT_NODE && node.tagName === "TEMPLATE" && node.getAttribute("id") === id;
815
+ return node.tagName === "TEMPLATE" && node.id === id;
874
816
  }
875
817
  function rangeClose(start, id) {
876
818
  let n = start.nextSibling;
@@ -903,11 +845,11 @@ function collectSlots(n, end, out) {
903
845
  n = n.nextSibling;
904
846
  }
905
847
  }
906
- function collectRegionElements(node, regions, prefix) {
848
+ function collectRegionElements(node, regions) {
907
849
  if (node.nodeType !== ELEMENT_NODE) return;
908
850
  if (isFrameElement(node)) {
909
851
  const childId = node.getAttribute(FRAME_ID_ATTR);
910
- if (childId && childId.startsWith(prefix)) {
852
+ if (childId && childId.includes(".")) {
911
853
  const argKey = childId.slice(childId.lastIndexOf(".") + 1);
912
854
  if (!regions.has(argKey)) {
913
855
  regions.set(argKey, {
@@ -920,12 +862,27 @@ function collectRegionElements(node, regions, prefix) {
920
862
  }
921
863
  return;
922
864
  }
923
- for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions, prefix);
865
+ for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions);
924
866
  }
925
867
  function renameRegion(entry, childId) {
926
868
  entry.childId = childId;
927
869
  if (entry.frame) entry.frame.rebind(childId);else entry.element.setAttribute(FRAME_ID_ATTR, childId);
928
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
+ }
929
886
  function argsEquivalent(a, b) {
930
887
  if (a === b) return true;
931
888
  if (!a || !b) return false;
@@ -936,9 +893,7 @@ function argsEquivalent(a, b) {
936
893
  const va = a[key];
937
894
  const vb = b[key];
938
895
  if (va === vb) continue;
939
- if (va && vb && typeof va === "object" && typeof vb === "object" && typeof va.$frame === "string" && va.$frame === vb.$frame) {
940
- continue;
941
- }
896
+ if (isFrameRef(va) && va.$frame === vb?.$frame) continue;
942
897
  return false;
943
898
  }
944
899
  return true;
@@ -988,11 +943,11 @@ function morphAttributes(oldEl, newEl, claim) {
988
943
  }
989
944
  if (claim && (reclaim || changed && oldEl.matches(CLAIMED_ELEMENTS))) claim(oldEl, true);
990
945
  }
991
- function morphNode(oldNode, newNode, claim, ranges) {
946
+ function morphNode(oldNode, newNode, claim, ranges, grafts) {
992
947
  if (oldNode.nodeType === ELEMENT_NODE) {
993
948
  if (oldNode.hasAttribute("data-preserve")) return;
994
949
  morphAttributes(oldNode, newNode, claim);
995
- reconcileChildren(oldNode, newNode, null, null, claim, ranges);
950
+ reconcileChildren(oldNode, newNode, null, null, claim, ranges, grafts);
996
951
  } else if (oldNode.data !== newNode.data) {
997
952
  oldNode.data = newNode.data;
998
953
  }
@@ -1026,6 +981,13 @@ function moveRangeBefore(parent, start, id, ref) {
1026
981
  n = next;
1027
982
  }
1028
983
  }
984
+ function placeRange(parent, range, id, ref) {
985
+ if (range.nodeType === 11 ) {
986
+ parent.insertBefore(range, ref);
987
+ } else {
988
+ moveRangeBefore(parent, range, id, ref);
989
+ }
990
+ }
1029
991
  function adoptRange(parent, start, id, ref, claim) {
1030
992
  const end = slotEnd(id);
1031
993
  let n = start;
@@ -1043,7 +1005,7 @@ function adoptRange(parent, start, id, ref, claim) {
1043
1005
  }
1044
1006
  return after;
1045
1007
  }
1046
- function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null) {
1008
+ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null, grafts = null) {
1047
1009
  let oldChild = boundStart ? boundStart.nextSibling : parent.firstChild;
1048
1010
  let newChild = source.firstChild;
1049
1011
  while (newChild) {
@@ -1059,11 +1021,7 @@ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, c
1059
1021
  const existing = displaced || findRangeStart(old, pid, boundEnd);
1060
1022
  if (existing) {
1061
1023
  if (ranges) ranges.delete(pid);
1062
- if (existing.nodeType === 11 ) {
1063
- parent.insertBefore(existing, old ?? boundEnd);
1064
- } else {
1065
- moveRangeBefore(parent, existing, pid, old ?? boundEnd);
1066
- }
1024
+ placeRange(parent, existing, pid, old ?? boundEnd);
1067
1025
  newChild = afterRange(newChild, pid);
1068
1026
  } else {
1069
1027
  newChild = adoptRange(parent, newChild, pid, old ?? boundEnd, claim);
@@ -1074,17 +1032,19 @@ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, c
1074
1032
  if (!old) {
1075
1033
  parent.insertBefore(newChild, boundEnd);
1076
1034
  if (claim) claim(newChild);
1035
+ if (grafts) grafts.push(newChild);
1077
1036
  newChild = nextNew;
1078
1037
  continue;
1079
1038
  }
1080
1039
  if (isSlotMarker(old)) {
1081
1040
  parent.insertBefore(newChild, old);
1082
1041
  if (claim) claim(newChild);
1042
+ if (grafts) grafts.push(newChild);
1083
1043
  newChild = nextNew;
1084
1044
  continue;
1085
1045
  }
1086
1046
  if (compatible(old, newChild)) {
1087
- morphNode(old, newChild, claim, ranges);
1047
+ morphNode(old, newChild, claim, ranges, grafts);
1088
1048
  oldChild = old.nextSibling;
1089
1049
  newChild = nextNew;
1090
1050
  continue;
@@ -1097,13 +1057,14 @@ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, c
1097
1057
  }
1098
1058
  if (ahead && ahead !== boundEnd) {
1099
1059
  parent.insertBefore(ahead, old);
1100
- morphNode(ahead, newChild, claim, ranges);
1060
+ morphNode(ahead, newChild, claim, ranges, grafts);
1101
1061
  newChild = nextNew;
1102
1062
  continue;
1103
1063
  }
1104
1064
  }
1105
1065
  parent.insertBefore(newChild, old);
1106
1066
  if (claim) claim(newChild);
1067
+ if (grafts) grafts.push(newChild);
1107
1068
  newChild = nextNew;
1108
1069
  }
1109
1070
  while (oldChild && oldChild !== boundEnd) {
@@ -1120,20 +1081,24 @@ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, c
1120
1081
  oldChild = next;
1121
1082
  }
1122
1083
  }
1123
- function restoreDisplacedRanges(first, end, ranges) {
1124
- const found = new Map();
1125
- collectSlots(first, end, found);
1126
- for (const [id, start] of found) {
1127
- const displaced = ranges.get(id);
1128
- if (!displaced || displaced === start) continue;
1129
- ranges.delete(id);
1130
- const parent = start.parentNode;
1131
- if (displaced.nodeType === 11 ) {
1132
- parent.insertBefore(displaced, start);
1133
- } else {
1134
- moveRangeBefore(parent, displaced, id, start);
1084
+ function flushGrafts(node, ranges) {
1085
+ if (node.nodeType !== ELEMENT_NODE || isFrameElement(node)) return;
1086
+ let n = node.firstChild;
1087
+ while (n) {
1088
+ const id = slotStartId(n);
1089
+ if (id !== null) {
1090
+ const next = afterRange(n, id);
1091
+ const displaced = ranges.get(id);
1092
+ if (displaced) {
1093
+ ranges.delete(id);
1094
+ placeRange(node, displaced, id, n);
1095
+ stashRange(document.createDocumentFragment(), n, id);
1096
+ }
1097
+ n = next;
1098
+ continue;
1135
1099
  }
1136
- stashRange(document.createDocumentFragment(), start, id);
1100
+ flushGrafts(n, ranges);
1101
+ n = n.nextSibling;
1137
1102
  }
1138
1103
  }
1139
1104
  function stashRange(frag, start, id) {
@@ -1165,7 +1130,7 @@ async function applyFrameResponse(response, host, options = {}) {
1165
1130
  if (chunk.type === "outcome") {
1166
1131
  if (options.onOutcome) options.onOutcome(chunk.payload);
1167
1132
  } else {
1168
- if (as !== undefined && chunk.id === rootId) chunk.id = as;else if (options.route) chunk.id = options.route(chunk.id);
1133
+ if (as !== undefined && chunk.id === rootId) chunk.id = as;
1169
1134
  if (perFrame) {
1170
1135
  let v = perFrame.get(chunk.id);
1171
1136
  if (v === undefined) perFrame.set(chunk.id, v = version(chunk.id));
@@ -1179,7 +1144,7 @@ async function applyFrameResponse(response, host, options = {}) {
1179
1144
  }
1180
1145
  const SERVER_COMPONENT = /*#__PURE__*/Symbol.for("dom-expressions.server-component");
1181
1146
  const SERVER_COMPONENT_ADDRESS = /*#__PURE__*/Symbol.for("dom-expressions.server-component-address");
1182
- const COMPONENT_HANDOFF = /*#__PURE__*/Symbol.for("dom-expressions.component-handoff");
1147
+ const COMPONENT_BINDING = /*#__PURE__*/Symbol.for("dom-expressions.component-binding");
1183
1148
  let resolveServerComponent;
1184
1149
  function parseServerComponent(value, ctx) {
1185
1150
  return {
@@ -1203,7 +1168,8 @@ const ServerComponentPlugin = /*#__PURE__*/seroval.createPlugin({
1203
1168
  stream: parseServerComponent
1204
1169
  },
1205
1170
  serialize(node, ctx) {
1206
- return "self._$SC.r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
1171
+ const registry = "self._$SC";
1172
+ return registry + ".r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
1207
1173
  },
1208
1174
  deserialize(node, ctx) {
1209
1175
  const id = ctx.deserialize(node.id);
@@ -1228,120 +1194,79 @@ function createServerComponentHandler({
1228
1194
  host,
1229
1195
  component,
1230
1196
  onStream,
1231
- documentComponent,
1232
1197
  intercept,
1233
1198
  consumer = client.getFlightDataConsumer,
1234
1199
  codec = client.getServerFunctionsCodec
1235
1200
  }) {
1236
- const byAddress = new Map();
1237
- const forwards = new Map();
1238
- const brand = (comp, fnId, frameId) => {
1239
- const brandable = typeof comp === "function" || typeof comp === "object" && comp !== null;
1240
- if (brandable && !comp[COMPONENT_HANDOFF]) {
1241
- comp[COMPONENT_HANDOFF] = {
1242
- fnId,
1243
- frameId,
1244
- take(prev) {
1245
- const meta = prev !== null && (typeof prev === "function" || typeof prev === "object") && prev[COMPONENT_HANDOFF];
1246
- if (!meta || meta.fnId !== fnId) return false;
1247
- const root = meta.frameId;
1248
- let cur = forwards.get(root) ?? root;
1249
- if (cur !== root && !host.get(cur)) {
1250
- forwards.delete(root);
1251
- cur = root;
1252
- }
1253
- if (cur === frameId) return true;
1254
- let frame = host.get(cur);
1255
- if (!frame) return false;
1256
- while (frame) {
1257
- frame.rebind(frameId);
1258
- frame = host.get(cur);
1259
- }
1260
- if (frameId === root) forwards.delete(root);else forwards.set(root, frameId);
1261
- return true;
1262
- }
1263
- };
1264
- }
1201
+ const byFn = new Map();
1202
+ const componentFor = fnId => {
1203
+ let comp = byFn.get(fnId);
1204
+ if (comp === undefined) byFn.set(fnId, comp = component(fnId));
1265
1205
  return comp;
1266
1206
  };
1267
- const boundaryFor = (address, fnId) => {
1268
- let entry = byAddress.get(address);
1269
- if (!entry) {
1270
- entry = {
1271
- frameId: address,
1272
- component: brand(component(address), fnId, address)
1207
+ const byAddress = new Map();
1208
+ const bindingFor = (address, fnId) => {
1209
+ let binding = byAddress.get(address);
1210
+ if (!binding) {
1211
+ const comp = componentFor(fnId);
1212
+ binding = props => comp(props, () => address);
1213
+ binding[COMPONENT_BINDING] = {
1214
+ component: comp,
1215
+ address
1273
1216
  };
1274
- byAddress.set(address, entry);
1217
+ byAddress.set(address, binding);
1275
1218
  }
1276
- return entry;
1219
+ return binding;
1277
1220
  };
1278
- const resolveAddress = (id, address) => boundaryFor(address, id).component;
1279
- resolveServerComponent = resolveAddress;
1221
+ resolveServerComponent = (id, address) => bindingFor(address, id);
1280
1222
  const versions = new Map();
1281
- const bump = frameId => {
1282
- const version = (versions.get(frameId) || 0) + 1;
1283
- versions.set(frameId, version);
1223
+ const bump = address => {
1224
+ const version = (versions.get(address) || 0) + 1;
1225
+ versions.set(address, version);
1284
1226
  return version;
1285
1227
  };
1286
1228
  return {
1287
1229
  intercept: intercept && (info => {
1288
1230
  const hit = intercept(info);
1289
- if (hit !== undefined) {
1290
- const address = client.frameAddress(info.id, info.args);
1291
- byAddress.set(address, {
1292
- frameId: info.id,
1293
- component: brand(hit, info.id, info.id)
1294
- });
1295
- }
1296
- return hit;
1231
+ if (hit === undefined) return undefined;
1232
+ return bindingFor(client.frameAddress(info.id, info.args), info.id);
1297
1233
  }),
1298
1234
  handle(response, ctx) {
1299
1235
  if (!isFrameStreamResponse(response)) return undefined;
1300
1236
  const address = client.frameAddress(ctx.id, ctx.args);
1301
- let entry = byAddress.get(address);
1302
- if (!entry) {
1303
- const adopted = documentComponent && documentComponent(ctx.id);
1304
- if (adopted) {
1305
- entry = {
1306
- frameId: ctx.id,
1307
- component: brand(adopted, ctx.id, ctx.id)
1308
- };
1309
- byAddress.set(address, entry);
1310
- } else {
1311
- entry = boundaryFor(address, ctx.id);
1312
- }
1313
- }
1237
+ const binding = bindingFor(address, ctx.id);
1314
1238
  if (response.headers.has(client.SINGLE_FLIGHT_HEADER)) {
1315
- return applyFlightResponse(response, entry);
1239
+ return applyFlightResponse(response, address, binding);
1316
1240
  }
1317
- const version = bump(entry.frameId);
1318
- if (onStream) onStream(entry.frameId, version, response);
1241
+ const version = bump(address);
1242
+ if (onStream) onStream(address, version, response);
1319
1243
  applyFrameResponse(response, host, {
1320
- as: entry.frameId,
1244
+ as: address,
1321
1245
  version
1322
1246
  }).catch(err => host.apply({
1323
1247
  type: "error",
1324
- id: entry.frameId,
1248
+ id: address,
1325
1249
  version,
1326
1250
  error: {
1327
1251
  message: String(err && err.message)
1328
1252
  }
1329
1253
  }));
1330
- return entry.component;
1254
+ return binding;
1331
1255
  },
1332
- showing(address, functionId, component) {
1333
- if (!byAddress.has(address)) {
1334
- byAddress.set(address, {
1335
- frameId: functionId,
1336
- component: brand(component, functionId, functionId),
1256
+ showing(address, functionId) {
1257
+ bindingFor(address, functionId);
1258
+ const comp = componentFor(functionId);
1259
+ if (comp && (typeof comp === "function" || typeof comp === "object") && !comp[COMPONENT_BINDING]) {
1260
+ comp[COMPONENT_BINDING] = {
1261
+ component: comp,
1337
1262
  address
1338
- });
1263
+ };
1339
1264
  }
1340
1265
  }
1341
1266
  };
1342
- async function applyFlightResponse(response, entry) {
1267
+ async function applyFlightResponse(response, address, binding) {
1343
1268
  const rootId = response.headers.get(FRAME_STREAM_HEADER) ?? "";
1344
- const as = rootId ? entry.frameId : undefined;
1269
+ const as = rootId ? address : undefined;
1345
1270
  let feed;
1346
1271
  const source = new ReadableStream({
1347
1272
  start(controller) {
@@ -1352,10 +1277,6 @@ function createServerComponentHandler({
1352
1277
  let carried = false;
1353
1278
  await applyFrameResponse(response, host, {
1354
1279
  as,
1355
- route: id => {
1356
- const local = byAddress.get(id);
1357
- return local ? local.frameId : id;
1358
- },
1359
1280
  version: frameId => {
1360
1281
  const version = bump(frameId);
1361
1282
  if (onStream) onStream(frameId, version, response);
@@ -1376,7 +1297,7 @@ function createServerComponentHandler({
1376
1297
  if (response.headers.has(client.ERROR_HEADER) && !response.headers.has("Location") && !response.headers.has(client.REVALIDATE_HEADER)) {
1377
1298
  throw envelope.value;
1378
1299
  }
1379
- return rootId ? entry.component : envelope.value;
1300
+ return rootId ? binding : envelope.value;
1380
1301
  }
1381
1302
  }
1382
1303
 
@@ -1427,6 +1348,9 @@ function createJSONDataTable(options) {
1427
1348
  };
1428
1349
  }
1429
1350
 
1351
+ function asyncArg(value) {
1352
+ return value;
1353
+ }
1430
1354
  let sharedHost;
1431
1355
  const tables = new Map();
1432
1356
  function tableFor(id) {
@@ -1503,8 +1427,26 @@ function claimRender(prefix, existing, render) {
1503
1427
  function liveSlotProps(initial, ctx) {
1504
1428
  const [args, setArgs] = solidJs.createSignal(initial);
1505
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();
1506
1438
  return new Proxy({}, {
1507
- 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
+ },
1508
1450
  has: (_, key) => key in args(),
1509
1451
  ownKeys: () => Reflect.ownKeys(args()),
1510
1452
  getOwnPropertyDescriptor: (_, key) => key in args() ? {
@@ -1522,6 +1464,7 @@ function isReactiveContent(value) {
1522
1464
  }
1523
1465
  function slotsFor(props) {
1524
1466
  const bindings = new Map();
1467
+ const fillScopes = new Map();
1525
1468
  return new Proxy({}, {
1526
1469
  get(_, prop) {
1527
1470
  if (typeof prop !== "string" || !(prop in props)) return undefined;
@@ -1532,6 +1475,19 @@ function slotsFor(props) {
1532
1475
  bindings.delete(key);
1533
1476
  prev.dispose();
1534
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
+ }
1535
1491
  const settle = out => {
1536
1492
  const existing = ctx && ctx.existing || [];
1537
1493
  if (existing.length) {
@@ -1544,26 +1500,18 @@ function slotsFor(props) {
1544
1500
  const evaluate = () => {
1545
1501
  const v = props[prop];
1546
1502
  if (typeof v === "function" && ctx && ctx.invoked) {
1547
- return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotProps);
1503
+ return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotArgsProxy(() => slotProps));
1548
1504
  }
1549
1505
  return v;
1550
1506
  };
1551
1507
  const adopted = !!(ctx && ctx.frame && ctx.adopted && ctx.existing && ctx.existing.length);
1552
1508
  const prefix = ctx && ctx.frame ? `sc-${ctx.frame}-${ctx.key}-` : "";
1553
- 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();
1554
1510
  if (!isReactiveContent(value)) {
1555
1511
  return settle(normalizeSlotContent(value));
1556
1512
  }
1557
1513
  if (ctx && ctx.range) {
1558
- let claim = adopted;
1559
1514
  const source = value;
1560
- const accessor = () => {
1561
- if (claim) {
1562
- claim = false;
1563
- return claimRender(prefix, ctx.existing, () => typeof source === "function" ? source() : source);
1564
- }
1565
- return typeof source === "function" ? source() : source;
1566
- };
1567
1515
  const owner = solidJs.createOwner();
1568
1516
  bindings.set(key, owner);
1569
1517
  ctx.onCleanup(() => {
@@ -1571,7 +1519,8 @@ function slotsFor(props) {
1571
1519
  owner.dispose();
1572
1520
  });
1573
1521
  const end = ctx.range.end;
1574
- solidJs.runWithOwner(owner, () => web$1.insert(end.parentNode, accessor, end, [...ctx.existing]));
1522
+ const bind = () => web$1.insert(end.parentNode, () => typeof source === "function" ? source() : source, end, [...ctx.existing]);
1523
+ solidJs.runWithOwner(owner, () => adopted ? claimRender(prefix, ctx.existing, bind) : bind());
1575
1524
  return undefined;
1576
1525
  }
1577
1526
  return settle(normalizeSlotContent(value));
@@ -1582,24 +1531,61 @@ function slotsFor(props) {
1582
1531
  function revealSeam(owner) {
1583
1532
  return seam => solidJs.runWithOwner(owner, () => web$1.insert(seam.before.parentNode, solidJs.createLoadingBoundary(() => seam.content(), () => seam.fallback), seam.before));
1584
1533
  }
1534
+ let streamInvoke = false;
1585
1535
  function boundaryScope(owner) {
1586
- return fn => solidJs.getOwner() ? fn() : solidJs.runWithOwner(owner, fn);
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
+ };
1587
1545
  }
1588
- function boundaryComponent(host, id) {
1589
- return props => {
1546
+ function boundaryComponent(host, fnId) {
1547
+ return (props, binding) => {
1590
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;
1591
1555
  const {
1592
1556
  element,
1557
+ frame,
1593
1558
  dispose
1594
1559
  } = createFrameElement({
1595
1560
  host,
1596
1561
  id,
1597
1562
  slots: slotsFor(props),
1598
1563
  ownerScope: boundaryScope(owner),
1599
- 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
+ }
1600
1573
  });
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
+ }
1601
1585
  solidJs.onCleanup(dispose);
1602
- return element;
1586
+ if (applied && !binding) return element;
1587
+ const gate = solidJs.createMemo(() => gatePromise());
1588
+ return solidJs.createMemo(() => (gate(), element));
1603
1589
  };
1604
1590
  }
1605
1591
  const claimedBoundaries = new Set();
@@ -1619,51 +1605,76 @@ function findBoundaryElement(id) {
1619
1605
  return boundaryIndex.get(id);
1620
1606
  }
1621
1607
  const boundaryWaiters = new Map();
1622
- function documentStreaming() {
1608
+ function boundaryMayArrive() {
1623
1609
  const hy = globalThis._$HY;
1624
- return !!hy && !hy.done;
1610
+ if (!hy) return false;
1611
+ return !hy.done || !!(hy.fr && hy.fr.pending());
1625
1612
  }
1626
1613
  function installRevealHook() {
1627
1614
  const hy = globalThis._$HY;
1628
- if (!hy || hy.$sc) return;
1615
+ if (!hy || hy.$sc || !hy.fr) return;
1629
1616
  hy.$sc = true;
1630
- const prev = hy.fe;
1631
- hy.fe = (fragmentId, parent) => {
1632
- if (prev) prev(fragmentId, parent);
1617
+ hy.fr.subscribe((_id, parent) => {
1633
1618
  if (!boundaryIndex) return;
1634
1619
  const root = parent || (typeof document !== "undefined" ? document.body : null);
1635
- if (!root) return;
1636
- indexBoundaries(root);
1620
+ if (root) indexBoundaries(root);
1621
+ if (!boundaryWaiters.size) return;
1622
+ const exhausted = hy.done && !hy.fr.pending();
1637
1623
  for (const [id, notify] of boundaryWaiters) {
1638
- const el = boundaryIndex.get(id);
1639
- if (!el) continue;
1624
+ const el = boundaryIndex && boundaryIndex.get(id);
1625
+ if (!el && !exhausted) continue;
1640
1626
  boundaryWaiters.delete(id);
1641
1627
  notify(el);
1642
1628
  }
1643
- };
1629
+ });
1644
1630
  }
1645
- function documentBoundary(host, id, props) {
1631
+ function documentBoundary(host, id, props, binding) {
1632
+ installRevealHook();
1646
1633
  const claimed = claimedBoundaries.has(id);
1647
1634
  const el = !claimed ? findBoundaryElement(id) : undefined;
1648
- if (el) return adoptBoundary(host, id, el, props);
1649
- if (!claimed && !boundaryWaiters.has(id) && documentStreaming()) {
1635
+ if (el) return adoptBoundary(host, id, el, props, binding);
1636
+ if (!claimed && !boundaryWaiters.has(id) && boundaryMayArrive()) {
1650
1637
  const owner = solidJs.getOwner();
1651
1638
  const arrival = new Promise(resolve => boundaryWaiters.set(id, resolve));
1652
1639
  solidJs.onCleanup(() => boundaryWaiters.delete(id));
1653
- return solidJs.createMemo(() => arrival.then(node => solidJs.runWithOwner(owner, () => adoptBoundary(host, id, node, props))));
1640
+ return solidJs.createMemo(() => arrival.then(node => solidJs.runWithOwner(owner, () =>
1641
+ node ? adoptBoundary(host, id, node, props, binding) : boundaryComponent(host, id)(props, binding))));
1654
1642
  }
1655
- return boundaryComponent(host, id)(props);
1643
+ return boundaryComponent(host, id)(props, binding);
1656
1644
  }
1657
- function adoptBoundary(host, id, el, props) {
1645
+ function documentAddress(id) {
1646
+ const records = globalThis._$SC?.a;
1647
+ if (records) {
1648
+ for (const address in records) if (records[address] === id) return address;
1649
+ }
1650
+ return id;
1651
+ }
1652
+ function adoptBoundary(host, id, el, props, binding) {
1658
1653
  claimedBoundaries.add(id);
1659
- const hy = globalThis._$HY;
1660
- if (hy && hy.r) {
1654
+ const address = binding ? binding() : documentAddress(id);
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
+ };
1667
+ const drainRecords = () => {
1668
+ const hy = globalThis._$HY;
1669
+ if (!hy || !hy.r) return;
1661
1670
  const slotPrefix = `sc:slot:${id}:`;
1662
1671
  for (const key of Object.keys(hy.r)) {
1672
+ if (appliedRecords.has(key)) continue;
1663
1673
  if (key.startsWith(slotPrefix)) {
1674
+ appliedRecords.add(key);
1664
1675
  host.apply({
1665
1676
  type: "slot",
1666
- id,
1677
+ id: address,
1667
1678
  version: 0,
1668
1679
  key: key.slice(slotPrefix.length),
1669
1680
  args: hy.r[key]
@@ -1671,6 +1682,7 @@ function adoptBoundary(host, id, el, props) {
1671
1682
  } else if (key.startsWith("sc:region:")) {
1672
1683
  const childId = key.slice("sc:region:".length);
1673
1684
  if (childId.startsWith(id + ".")) {
1685
+ appliedRecords.add(key);
1674
1686
  const val = hy.r[key];
1675
1687
  const apply = html => host.apply({
1676
1688
  type: "html",
@@ -1682,16 +1694,58 @@ function adoptBoundary(host, id, el, props) {
1682
1694
  }
1683
1695
  }
1684
1696
  }
1685
- }
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
+ });
1708
+ drainRecords();
1686
1709
  const owner = solidJs.getOwner();
1710
+ let release;
1711
+ let setGate;
1687
1712
  const frame = createFrame(el, {
1688
1713
  adopt: true,
1689
1714
  host,
1690
- id,
1715
+ id: address,
1691
1716
  slots: slotsFor(props),
1692
1717
  ownerScope: boundaryScope(owner),
1693
- reveal: revealSeam(owner)
1718
+ reveal: revealSeam(owner),
1719
+ onApply: () => {
1720
+ if (release) {
1721
+ release();
1722
+ release = undefined;
1723
+ }
1724
+ setGate && setGate(undefined);
1725
+ },
1726
+ ...{
1727
+ recordsPending: () => {
1728
+ if (document.readyState === "loading") return true;
1729
+ const hy = globalThis._$HY;
1730
+ return !!(hy && hy.fr && hy.fr.pending());
1731
+ },
1732
+ drainRecords,
1733
+ claimScope: id
1734
+ }
1694
1735
  });
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
+ }
1695
1749
  solidJs.onCleanup(() => frame.dispose());
1696
1750
  return el;
1697
1751
  }
@@ -1706,17 +1760,16 @@ function installServerComponents(host = getFrameHost()) {
1706
1760
  g._$SC.a[a] = i;
1707
1761
  g._$SC.reg && g._$SC.reg(a, i);
1708
1762
  }
1709
- return g._$SC.c[i] || (g._$SC.c[i] = p => g._$SC.impl(i, p));
1763
+ return g._$SC.c[i] || (g._$SC.c[i] = (p, b) => g._$SC.impl(i, p, b));
1710
1764
  }
1711
1765
  };
1712
1766
  }
1713
- g._$SC.impl = (id, props) => documentBoundary(host, id, props);
1767
+ g._$SC.impl = (id, props, binding) => documentBoundary(host, id, props, binding);
1714
1768
  installRevealHook();
1715
1769
  const handler = createServerComponentHandler({
1716
1770
  host,
1717
- component: frameId => boundaryComponent(host, frameId),
1718
- onStream: frameId => beginStream(frameId),
1719
- documentComponent: functionId => claimedBoundaries.has(functionId) ? undefined : g._$SC.c[functionId],
1771
+ component: fnId => g._$SC.r(fnId),
1772
+ onStream: address => beginStream(address),
1720
1773
  intercept: ({
1721
1774
  id
1722
1775
  }) => {
@@ -1724,7 +1777,7 @@ function installServerComponents(host = getFrameHost()) {
1724
1777
  return g._$SC.r(id);
1725
1778
  }
1726
1779
  });
1727
- const showing = (address, id) => handler.showing(address, id, g._$SC.r(id));
1780
+ const showing = (address, id) => handler.showing(address, id);
1728
1781
  const records = g._$SC.a || (g._$SC.a = {});
1729
1782
  for (const address in records) showing(address, records[address]);
1730
1783
  g._$SC.reg = showing;
@@ -1736,10 +1789,10 @@ function installServerComponents(host = getFrameHost()) {
1736
1789
  exports.FRAME_APPLIED_EVENT = FRAME_APPLIED_EVENT;
1737
1790
  exports.FRAME_STREAM_HEADER = FRAME_STREAM_HEADER;
1738
1791
  exports.applyFrameResponse = applyFrameResponse;
1792
+ exports.asyncArg = asyncArg;
1739
1793
  exports.createFrame = createFrame;
1740
1794
  exports.createFrameElement = createFrameElement;
1741
1795
  exports.createFrameHost = createFrameHost;
1742
- exports.createJSONDataTable = createJSONDataTable;
1743
1796
  exports.createServerComponentHandler = createServerComponentHandler;
1744
1797
  exports.getFrameHost = getFrameHost;
1745
1798
  exports.installServerComponents = installServerComponents;