@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;
@@ -730,12 +665,7 @@ class FrameImpl {
730
665
  console.error(`Frame fragment placeholder "${name}" is missing its closing comment ` + `(<!--${placeholderId(name)}-->); revealed content will be appended at the end of ` + `its parent instead of in place. Likely an HTML-rewriting layer stripped the ` + `comment, or invalid nesting split the placeholder range.`, tpl);
731
666
  }
732
667
  const parent = tpl.parentNode;
733
- let n = tpl.nextSibling;
734
- while (n && n !== closing) {
735
- const next = n.nextSibling;
736
- parent.removeChild(n);
737
- n = next;
738
- }
668
+ removeUntil(parent, tpl.nextSibling, closing);
739
669
  if (this.#options.reveal) {
740
670
  const fallbackFrag = tpl.content.cloneNode(true);
741
671
  this.#claimTree(fallbackFrag);
@@ -784,9 +714,7 @@ function createFrameElement(options) {
784
714
  const frame = new FrameImpl(el, null, null, options);
785
715
  return {
786
716
  element: el,
787
- get frame() {
788
- return frame;
789
- },
717
+ frame,
790
718
  dispose() {
791
719
  frame.dispose();
792
720
  el.remove();
@@ -806,15 +734,30 @@ function segmentName(key) {
806
734
  const m = /^seg:([^:]+)$/.exec(key);
807
735
  return m ? m[1] : null;
808
736
  }
737
+ function isAsyncLike(v) {
738
+ return !!v && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
739
+ }
809
740
  function propOf(occurrence) {
810
741
  const hash = occurrence.indexOf("#");
811
742
  return hash === -1 ? occurrence : occurrence.slice(0, hash);
812
743
  }
813
744
  function isDataRef(value) {
814
- return typeof value === "object" && value !== null && typeof value.$ref === "string";
745
+ return !!value && typeof value.$ref === "string";
815
746
  }
816
747
  function isFrameRef(value) {
817
- return typeof value === "object" && value !== null && typeof value.$frame === "string";
748
+ return !!value && typeof value.$frame === "string";
749
+ }
750
+ function disposeRegions(regions) {
751
+ for (const {
752
+ frame
753
+ } of regions.values()) frame?.dispose();
754
+ }
755
+ function removeUntil(parent, n, stop) {
756
+ while (n && n !== stop) {
757
+ const next = n.nextSibling;
758
+ parent.removeChild(n);
759
+ n = next;
760
+ }
818
761
  }
819
762
  function parseFragment(html) {
820
763
  const template = document.createElement("template");
@@ -822,9 +765,8 @@ function parseFragment(html) {
822
765
  return template.content;
823
766
  }
824
767
  function findHeadElement(selector, attr, value) {
825
- const nodes = document.head.querySelectorAll(selector);
826
- for (let i = 0; i < nodes.length; i++) {
827
- if (nodes[i].getAttribute(attr) === value) return nodes[i];
768
+ for (const node of document.head.querySelectorAll(selector)) {
769
+ if (node.getAttribute(attr) === value) return node;
828
770
  }
829
771
  return null;
830
772
  }
@@ -873,7 +815,7 @@ function applyInlineStyles(inlineStyles) {
873
815
  }
874
816
  }
875
817
  function isPlaceholderStart(node, id) {
876
- return node.nodeType === ELEMENT_NODE && node.tagName === "TEMPLATE" && node.getAttribute("id") === id;
818
+ return node.tagName === "TEMPLATE" && node.id === id;
877
819
  }
878
820
  function rangeClose(start, id) {
879
821
  let n = start.nextSibling;
@@ -907,11 +849,11 @@ function collectSlots(n, end, out) {
907
849
  n = n.nextSibling;
908
850
  }
909
851
  }
910
- function collectRegionElements(node, regions, prefix) {
852
+ function collectRegionElements(node, regions) {
911
853
  if (node.nodeType !== ELEMENT_NODE) return;
912
854
  if (isFrameElement(node)) {
913
855
  const childId = node.getAttribute(FRAME_ID_ATTR);
914
- if (childId && childId.startsWith(prefix)) {
856
+ if (childId && childId.includes(".")) {
915
857
  const argKey = childId.slice(childId.lastIndexOf(".") + 1);
916
858
  if (!regions.has(argKey)) {
917
859
  regions.set(argKey, {
@@ -924,12 +866,27 @@ function collectRegionElements(node, regions, prefix) {
924
866
  }
925
867
  return;
926
868
  }
927
- for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions, prefix);
869
+ for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions);
928
870
  }
929
871
  function renameRegion(entry, childId) {
930
872
  entry.childId = childId;
931
873
  if (entry.frame) entry.frame.rebind(childId);else entry.element.setAttribute(FRAME_ID_ATTR, childId);
932
874
  }
875
+ function eachInRange(start, key, cb) {
876
+ const end = slotEnd(key);
877
+ let n = start.nextSibling;
878
+ while (n && !(n.nodeType === COMMENT_NODE && n.data === end)) {
879
+ const next = n.nextSibling;
880
+ cb(n);
881
+ n = next;
882
+ }
883
+ return n;
884
+ }
885
+ function clearStreamRecords(records, root) {
886
+ for (const key in records) {
887
+ if (key.startsWith("seg:") || key === ":error" || root && key === "") delete records[key];
888
+ }
889
+ }
933
890
  function argsEquivalent(a, b) {
934
891
  if (a === b) return true;
935
892
  if (!a || !b) return false;
@@ -940,9 +897,7 @@ function argsEquivalent(a, b) {
940
897
  const va = a[key];
941
898
  const vb = b[key];
942
899
  if (va === vb) continue;
943
- if (va && vb && typeof va === "object" && typeof vb === "object" && typeof va.$frame === "string" && va.$frame === vb.$frame) {
944
- continue;
945
- }
900
+ if (isFrameRef(va) && va.$frame === vb?.$frame) continue;
946
901
  return false;
947
902
  }
948
903
  return true;
@@ -992,11 +947,11 @@ function morphAttributes(oldEl, newEl, claim) {
992
947
  }
993
948
  if (claim && (reclaim || changed && oldEl.matches(CLAIMED_ELEMENTS))) claim(oldEl, true);
994
949
  }
995
- function morphNode(oldNode, newNode, claim, ranges) {
950
+ function morphNode(oldNode, newNode, claim, ranges, grafts) {
996
951
  if (oldNode.nodeType === ELEMENT_NODE) {
997
952
  if (oldNode.hasAttribute("data-preserve")) return;
998
953
  morphAttributes(oldNode, newNode, claim);
999
- reconcileChildren(oldNode, newNode, null, null, claim, ranges);
954
+ reconcileChildren(oldNode, newNode, null, null, claim, ranges, grafts);
1000
955
  } else if (oldNode.data !== newNode.data) {
1001
956
  oldNode.data = newNode.data;
1002
957
  }
@@ -1039,6 +994,13 @@ function moveRangeBefore(parent, start, id, ref) {
1039
994
  n = next;
1040
995
  }
1041
996
  }
997
+ function placeRange(parent, range, id, ref) {
998
+ if (range.nodeType === 11 ) {
999
+ parent.insertBefore(range, ref);
1000
+ } else {
1001
+ moveRangeBefore(parent, range, id, ref);
1002
+ }
1003
+ }
1042
1004
  function adoptRange(parent, start, id, ref, claim) {
1043
1005
  const end = slotEnd(id);
1044
1006
  let n = start;
@@ -1056,7 +1018,7 @@ function adoptRange(parent, start, id, ref, claim) {
1056
1018
  }
1057
1019
  return after;
1058
1020
  }
1059
- function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null) {
1021
+ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null, grafts = null) {
1060
1022
  let oldChild = boundStart ? boundStart.nextSibling : parent.firstChild;
1061
1023
  let newChild = source.firstChild;
1062
1024
  while (newChild) {
@@ -1072,11 +1034,7 @@ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, c
1072
1034
  const existing = displaced || findRangeStart(old, pid, boundEnd);
1073
1035
  if (existing) {
1074
1036
  if (ranges) ranges.delete(pid);
1075
- if (existing.nodeType === 11 ) {
1076
- parent.insertBefore(existing, old ?? boundEnd);
1077
- } else {
1078
- moveRangeBefore(parent, existing, pid, old ?? boundEnd);
1079
- }
1037
+ placeRange(parent, existing, pid, old ?? boundEnd);
1080
1038
  newChild = afterRange(newChild, pid);
1081
1039
  } else {
1082
1040
  newChild = adoptRange(parent, newChild, pid, old ?? boundEnd, claim);
@@ -1087,17 +1045,19 @@ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, c
1087
1045
  if (!old) {
1088
1046
  parent.insertBefore(newChild, boundEnd);
1089
1047
  if (claim) claim(newChild);
1048
+ if (grafts) grafts.push(newChild);
1090
1049
  newChild = nextNew;
1091
1050
  continue;
1092
1051
  }
1093
1052
  if (isSlotMarker(old)) {
1094
1053
  parent.insertBefore(newChild, old);
1095
1054
  if (claim) claim(newChild);
1055
+ if (grafts) grafts.push(newChild);
1096
1056
  newChild = nextNew;
1097
1057
  continue;
1098
1058
  }
1099
1059
  if (compatible(old, newChild)) {
1100
- morphNode(old, newChild, claim, ranges);
1060
+ morphNode(old, newChild, claim, ranges, grafts);
1101
1061
  oldChild = old.nextSibling;
1102
1062
  newChild = nextNew;
1103
1063
  continue;
@@ -1110,13 +1070,14 @@ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, c
1110
1070
  }
1111
1071
  if (ahead && ahead !== boundEnd) {
1112
1072
  parent.insertBefore(ahead, old);
1113
- morphNode(ahead, newChild, claim, ranges);
1073
+ morphNode(ahead, newChild, claim, ranges, grafts);
1114
1074
  newChild = nextNew;
1115
1075
  continue;
1116
1076
  }
1117
1077
  }
1118
1078
  parent.insertBefore(newChild, old);
1119
1079
  if (claim) claim(newChild);
1080
+ if (grafts) grafts.push(newChild);
1120
1081
  newChild = nextNew;
1121
1082
  }
1122
1083
  while (oldChild && oldChild !== boundEnd) {
@@ -1133,20 +1094,24 @@ function reconcileChildren(parent, source, boundStart = null, boundEnd = null, c
1133
1094
  oldChild = next;
1134
1095
  }
1135
1096
  }
1136
- function restoreDisplacedRanges(first, end, ranges) {
1137
- const found = new Map();
1138
- collectSlots(first, end, found);
1139
- for (const [id, start] of found) {
1140
- const displaced = ranges.get(id);
1141
- if (!displaced || displaced === start) continue;
1142
- ranges.delete(id);
1143
- const parent = start.parentNode;
1144
- if (displaced.nodeType === 11 ) {
1145
- parent.insertBefore(displaced, start);
1146
- } else {
1147
- moveRangeBefore(parent, displaced, id, start);
1097
+ function flushGrafts(node, ranges) {
1098
+ if (node.nodeType !== ELEMENT_NODE || isFrameElement(node)) return;
1099
+ let n = node.firstChild;
1100
+ while (n) {
1101
+ const id = slotStartId(n);
1102
+ if (id !== null) {
1103
+ const next = afterRange(n, id);
1104
+ const displaced = ranges.get(id);
1105
+ if (displaced) {
1106
+ ranges.delete(id);
1107
+ placeRange(node, displaced, id, n);
1108
+ stashRange(document.createDocumentFragment(), n, id);
1109
+ }
1110
+ n = next;
1111
+ continue;
1148
1112
  }
1149
- stashRange(document.createDocumentFragment(), start, id);
1113
+ flushGrafts(n, ranges);
1114
+ n = n.nextSibling;
1150
1115
  }
1151
1116
  }
1152
1117
  function stashRange(frag, start, id) {
@@ -1178,7 +1143,7 @@ async function applyFrameResponse(response, host, options = {}) {
1178
1143
  if (chunk.type === "outcome") {
1179
1144
  if (options.onOutcome) options.onOutcome(chunk.payload);
1180
1145
  } else {
1181
- if (as !== undefined && chunk.id === rootId) chunk.id = as;else if (options.route) chunk.id = options.route(chunk.id);
1146
+ if (as !== undefined && chunk.id === rootId) chunk.id = as;
1182
1147
  if (perFrame) {
1183
1148
  let v = perFrame.get(chunk.id);
1184
1149
  if (v === undefined) perFrame.set(chunk.id, v = version(chunk.id));
@@ -1192,7 +1157,7 @@ async function applyFrameResponse(response, host, options = {}) {
1192
1157
  }
1193
1158
  const SERVER_COMPONENT = /*#__PURE__*/Symbol.for("dom-expressions.server-component");
1194
1159
  const SERVER_COMPONENT_ADDRESS = /*#__PURE__*/Symbol.for("dom-expressions.server-component-address");
1195
- const COMPONENT_HANDOFF = /*#__PURE__*/Symbol.for("dom-expressions.component-handoff");
1160
+ const COMPONENT_BINDING = /*#__PURE__*/Symbol.for("dom-expressions.component-binding");
1196
1161
  let resolveServerComponent;
1197
1162
  function parseServerComponent(value, ctx) {
1198
1163
  return {
@@ -1216,7 +1181,8 @@ const ServerComponentPlugin = /*#__PURE__*/seroval.createPlugin({
1216
1181
  stream: parseServerComponent
1217
1182
  },
1218
1183
  serialize(node, ctx) {
1219
- return "self._$SC.r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
1184
+ const registry = "self._$SC";
1185
+ return registry + ".r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
1220
1186
  },
1221
1187
  deserialize(node, ctx) {
1222
1188
  const id = ctx.deserialize(node.id);
@@ -1241,120 +1207,79 @@ function createServerComponentHandler({
1241
1207
  host,
1242
1208
  component,
1243
1209
  onStream,
1244
- documentComponent,
1245
1210
  intercept,
1246
1211
  consumer = client.getFlightDataConsumer,
1247
1212
  codec = client.getServerFunctionsCodec
1248
1213
  }) {
1249
- const byAddress = new Map();
1250
- const forwards = new Map();
1251
- const brand = (comp, fnId, frameId) => {
1252
- const brandable = typeof comp === "function" || typeof comp === "object" && comp !== null;
1253
- if (brandable && !comp[COMPONENT_HANDOFF]) {
1254
- comp[COMPONENT_HANDOFF] = {
1255
- fnId,
1256
- frameId,
1257
- take(prev) {
1258
- const meta = prev !== null && (typeof prev === "function" || typeof prev === "object") && prev[COMPONENT_HANDOFF];
1259
- if (!meta || meta.fnId !== fnId) return false;
1260
- const root = meta.frameId;
1261
- let cur = forwards.get(root) ?? root;
1262
- if (cur !== root && !host.get(cur)) {
1263
- forwards.delete(root);
1264
- cur = root;
1265
- }
1266
- if (cur === frameId) return true;
1267
- let frame = host.get(cur);
1268
- if (!frame) return false;
1269
- while (frame) {
1270
- frame.rebind(frameId);
1271
- frame = host.get(cur);
1272
- }
1273
- if (frameId === root) forwards.delete(root);else forwards.set(root, frameId);
1274
- return true;
1275
- }
1276
- };
1277
- }
1214
+ const byFn = new Map();
1215
+ const componentFor = fnId => {
1216
+ let comp = byFn.get(fnId);
1217
+ if (comp === undefined) byFn.set(fnId, comp = component(fnId));
1278
1218
  return comp;
1279
1219
  };
1280
- const boundaryFor = (address, fnId) => {
1281
- let entry = byAddress.get(address);
1282
- if (!entry) {
1283
- entry = {
1284
- frameId: address,
1285
- component: brand(component(address), fnId, address)
1220
+ const byAddress = new Map();
1221
+ const bindingFor = (address, fnId) => {
1222
+ let binding = byAddress.get(address);
1223
+ if (!binding) {
1224
+ const comp = componentFor(fnId);
1225
+ binding = props => comp(props, () => address);
1226
+ binding[COMPONENT_BINDING] = {
1227
+ component: comp,
1228
+ address
1286
1229
  };
1287
- byAddress.set(address, entry);
1230
+ byAddress.set(address, binding);
1288
1231
  }
1289
- return entry;
1232
+ return binding;
1290
1233
  };
1291
- const resolveAddress = (id, address) => boundaryFor(address, id).component;
1292
- resolveServerComponent = resolveAddress;
1234
+ resolveServerComponent = (id, address) => bindingFor(address, id);
1293
1235
  const versions = new Map();
1294
- const bump = frameId => {
1295
- const version = (versions.get(frameId) || 0) + 1;
1296
- versions.set(frameId, version);
1236
+ const bump = address => {
1237
+ const version = (versions.get(address) || 0) + 1;
1238
+ versions.set(address, version);
1297
1239
  return version;
1298
1240
  };
1299
1241
  return {
1300
1242
  intercept: intercept && (info => {
1301
1243
  const hit = intercept(info);
1302
- if (hit !== undefined) {
1303
- const address = client.frameAddress(info.id, info.args);
1304
- byAddress.set(address, {
1305
- frameId: info.id,
1306
- component: brand(hit, info.id, info.id)
1307
- });
1308
- }
1309
- return hit;
1244
+ if (hit === undefined) return undefined;
1245
+ return bindingFor(client.frameAddress(info.id, info.args), info.id);
1310
1246
  }),
1311
1247
  handle(response, ctx) {
1312
1248
  if (!isFrameStreamResponse(response)) return undefined;
1313
1249
  const address = client.frameAddress(ctx.id, ctx.args);
1314
- let entry = byAddress.get(address);
1315
- if (!entry) {
1316
- const adopted = documentComponent && documentComponent(ctx.id);
1317
- if (adopted) {
1318
- entry = {
1319
- frameId: ctx.id,
1320
- component: brand(adopted, ctx.id, ctx.id)
1321
- };
1322
- byAddress.set(address, entry);
1323
- } else {
1324
- entry = boundaryFor(address, ctx.id);
1325
- }
1326
- }
1250
+ const binding = bindingFor(address, ctx.id);
1327
1251
  if (response.headers.has(client.SINGLE_FLIGHT_HEADER)) {
1328
- return applyFlightResponse(response, entry);
1252
+ return applyFlightResponse(response, address, binding);
1329
1253
  }
1330
- const version = bump(entry.frameId);
1331
- if (onStream) onStream(entry.frameId, version, response);
1254
+ const version = bump(address);
1255
+ if (onStream) onStream(address, version, response);
1332
1256
  applyFrameResponse(response, host, {
1333
- as: entry.frameId,
1257
+ as: address,
1334
1258
  version
1335
1259
  }).catch(err => host.apply({
1336
1260
  type: "error",
1337
- id: entry.frameId,
1261
+ id: address,
1338
1262
  version,
1339
1263
  error: {
1340
1264
  message: String(err && err.message)
1341
1265
  }
1342
1266
  }));
1343
- return entry.component;
1267
+ return binding;
1344
1268
  },
1345
- showing(address, functionId, component) {
1346
- if (!byAddress.has(address)) {
1347
- byAddress.set(address, {
1348
- frameId: functionId,
1349
- component: brand(component, functionId, functionId),
1269
+ showing(address, functionId) {
1270
+ bindingFor(address, functionId);
1271
+ const comp = componentFor(functionId);
1272
+ if (comp && (typeof comp === "function" || typeof comp === "object") && !comp[COMPONENT_BINDING]) {
1273
+ comp[COMPONENT_BINDING] = {
1274
+ component: comp,
1350
1275
  address
1351
- });
1276
+ };
1352
1277
  }
1353
1278
  }
1354
1279
  };
1355
- async function applyFlightResponse(response, entry) {
1280
+ async function applyFlightResponse(response, address, binding) {
1356
1281
  const rootId = response.headers.get(FRAME_STREAM_HEADER) ?? "";
1357
- const as = rootId ? entry.frameId : undefined;
1282
+ const as = rootId ? address : undefined;
1358
1283
  let feed;
1359
1284
  const source = new ReadableStream({
1360
1285
  start(controller) {
@@ -1365,10 +1290,6 @@ function createServerComponentHandler({
1365
1290
  let carried = false;
1366
1291
  await applyFrameResponse(response, host, {
1367
1292
  as,
1368
- route: id => {
1369
- const local = byAddress.get(id);
1370
- return local ? local.frameId : id;
1371
- },
1372
1293
  version: frameId => {
1373
1294
  const version = bump(frameId);
1374
1295
  if (onStream) onStream(frameId, version, response);
@@ -1389,7 +1310,7 @@ function createServerComponentHandler({
1389
1310
  if (response.headers.has(client.ERROR_HEADER) && !response.headers.has("Location") && !response.headers.has(client.REVALIDATE_HEADER)) {
1390
1311
  throw envelope.value;
1391
1312
  }
1392
- return rootId ? entry.component : envelope.value;
1313
+ return rootId ? binding : envelope.value;
1393
1314
  }
1394
1315
  }
1395
1316
 
@@ -1440,6 +1361,9 @@ function createJSONDataTable(options) {
1440
1361
  };
1441
1362
  }
1442
1363
 
1364
+ function asyncArg(value) {
1365
+ return value;
1366
+ }
1443
1367
  let sharedHost;
1444
1368
  const tables = new Map();
1445
1369
  function tableFor(id) {
@@ -1516,8 +1440,26 @@ function claimRender(prefix, existing, render) {
1516
1440
  function liveSlotProps(initial, ctx) {
1517
1441
  const [args, setArgs] = solidJs.createSignal(initial);
1518
1442
  ctx.onUpdate(next => setArgs(() => next));
1443
+ return slotArgsProxy(args);
1444
+ }
1445
+ function isAsyncValue(v) {
1446
+ return v !== null && typeof v === "object" && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
1447
+ }
1448
+ function slotArgsProxy(args) {
1449
+ const owner = solidJs.getOwner();
1450
+ const asyncReads = new Map();
1519
1451
  return new Proxy({}, {
1520
- get: (_, key) => args()[key],
1452
+ get: (_, key) => {
1453
+ const v = args()[key];
1454
+ if (!isAsyncValue(v)) return v;
1455
+ let read = asyncReads.get(key);
1456
+ if (!read) {
1457
+ const make = () => solidJs.createMemo(() => args()[key]);
1458
+ read = owner ? solidJs.runWithOwner(owner, make) : make();
1459
+ asyncReads.set(key, read);
1460
+ }
1461
+ return read();
1462
+ },
1521
1463
  has: (_, key) => key in args(),
1522
1464
  ownKeys: () => Reflect.ownKeys(args()),
1523
1465
  getOwnPropertyDescriptor: (_, key) => key in args() ? {
@@ -1535,6 +1477,7 @@ function isReactiveContent(value) {
1535
1477
  }
1536
1478
  function slotsFor(props) {
1537
1479
  const bindings = new Map();
1480
+ const fillScopes = new Map();
1538
1481
  return new Proxy({}, {
1539
1482
  get(_, prop) {
1540
1483
  if (typeof prop !== "string" || !(prop in props)) return undefined;
@@ -1545,6 +1488,19 @@ function slotsFor(props) {
1545
1488
  bindings.delete(key);
1546
1489
  prev.dispose();
1547
1490
  }
1491
+ const prevFill = key !== undefined && fillScopes.get(key);
1492
+ if (prevFill) {
1493
+ fillScopes.delete(key);
1494
+ prevFill.dispose();
1495
+ }
1496
+ const fillOwner = streamInvoke ? solidJs.createOwner() : null;
1497
+ if (fillOwner && key !== undefined && ctx) {
1498
+ fillScopes.set(key, fillOwner);
1499
+ ctx.onCleanup(() => {
1500
+ if (fillScopes.get(key) === fillOwner) fillScopes.delete(key);
1501
+ fillOwner.dispose();
1502
+ });
1503
+ }
1548
1504
  const settle = out => {
1549
1505
  const existing = ctx && ctx.existing || [];
1550
1506
  if (existing.length) {
@@ -1557,26 +1513,18 @@ function slotsFor(props) {
1557
1513
  const evaluate = () => {
1558
1514
  const v = props[prop];
1559
1515
  if (typeof v === "function" && ctx && ctx.invoked) {
1560
- return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotProps);
1516
+ return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotArgsProxy(() => slotProps));
1561
1517
  }
1562
1518
  return v;
1563
1519
  };
1564
1520
  const adopted = !!(ctx && ctx.frame && ctx.adopted && ctx.existing && ctx.existing.length);
1565
1521
  const prefix = ctx && ctx.frame ? `sc-${ctx.frame}-${ctx.key}-` : "";
1566
- const value = adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
1522
+ const value = fillOwner ? solidJs.runWithOwner(fillOwner, () => adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate()) : adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
1567
1523
  if (!isReactiveContent(value)) {
1568
1524
  return settle(normalizeSlotContent(value));
1569
1525
  }
1570
1526
  if (ctx && ctx.range) {
1571
- let claim = adopted;
1572
1527
  const source = value;
1573
- const accessor = () => {
1574
- if (claim) {
1575
- claim = false;
1576
- return claimRender(prefix, ctx.existing, () => typeof source === "function" ? source() : source);
1577
- }
1578
- return typeof source === "function" ? source() : source;
1579
- };
1580
1528
  const owner = solidJs.createOwner();
1581
1529
  bindings.set(key, owner);
1582
1530
  ctx.onCleanup(() => {
@@ -1584,7 +1532,8 @@ function slotsFor(props) {
1584
1532
  owner.dispose();
1585
1533
  });
1586
1534
  const end = ctx.range.end;
1587
- solidJs.runWithOwner(owner, () => web$1.insert(end.parentNode, accessor, end, [...ctx.existing]));
1535
+ const bind = () => web$1.insert(end.parentNode, () => typeof source === "function" ? source() : source, end, [...ctx.existing]);
1536
+ solidJs.runWithOwner(owner, () => adopted ? claimRender(prefix, ctx.existing, bind) : bind());
1588
1537
  return undefined;
1589
1538
  }
1590
1539
  return settle(normalizeSlotContent(value));
@@ -1595,24 +1544,61 @@ function slotsFor(props) {
1595
1544
  function revealSeam(owner) {
1596
1545
  return seam => solidJs.runWithOwner(owner, () => web$1.insert(seam.before.parentNode, solidJs.createLoadingBoundary(() => seam.content(), () => seam.fallback), seam.before));
1597
1546
  }
1547
+ let streamInvoke = false;
1598
1548
  function boundaryScope(owner) {
1599
- return fn => solidJs.getOwner() ? fn() : solidJs.runWithOwner(owner, fn);
1549
+ return fn => {
1550
+ if (solidJs.getOwner()) return fn();
1551
+ streamInvoke = true;
1552
+ try {
1553
+ return solidJs.runWithOwner(owner, fn);
1554
+ } finally {
1555
+ streamInvoke = false;
1556
+ }
1557
+ };
1600
1558
  }
1601
- function boundaryComponent(host, id) {
1602
- return props => {
1559
+ function boundaryComponent(host, fnId) {
1560
+ return (props, binding) => {
1603
1561
  const owner = solidJs.getOwner();
1562
+ const id = binding ? binding() : fnId;
1563
+ let applied = !tables.has(id);
1564
+ let release;
1565
+ const arm = () => new Promise(r => release = r);
1566
+ const mountGate = applied ? undefined : arm();
1567
+ let setGate;
1604
1568
  const {
1605
1569
  element,
1570
+ frame,
1606
1571
  dispose
1607
1572
  } = createFrameElement({
1608
1573
  host,
1609
1574
  id,
1610
1575
  slots: slotsFor(props),
1611
1576
  ownerScope: boundaryScope(owner),
1612
- reveal: revealSeam(owner)
1577
+ reveal: revealSeam(owner),
1578
+ onApply: () => {
1579
+ applied = true;
1580
+ if (release) {
1581
+ release();
1582
+ release = undefined;
1583
+ }
1584
+ setGate && setGate(undefined);
1585
+ }
1613
1586
  });
1587
+ const [gatePromise, setGatePromise] = solidJs.createSignal(applied ? undefined : mountGate);
1588
+ setGate = setGatePromise;
1589
+ if (binding) {
1590
+ solidJs.createRenderEffect(binding, (address, prev) => {
1591
+ if (prev !== undefined && address !== prev && tables.has(address)) {
1592
+ applied = false;
1593
+ setGatePromise(arm());
1594
+ }
1595
+ frame.rebind(address);
1596
+ });
1597
+ }
1614
1598
  solidJs.onCleanup(dispose);
1615
- return element;
1599
+ if (applied && !binding) return element;
1600
+ const gate = solidJs.createMemo(() => gatePromise());
1601
+ return solidJs.createMemo(() => (gate(), element));
1616
1602
  };
1617
1603
  }
1618
1604
  const claimedBoundaries = new Set();
@@ -1632,51 +1618,76 @@ function findBoundaryElement(id) {
1632
1618
  return boundaryIndex.get(id);
1633
1619
  }
1634
1620
  const boundaryWaiters = new Map();
1635
- function documentStreaming() {
1621
+ function boundaryMayArrive() {
1636
1622
  const hy = globalThis._$HY;
1637
- return !!hy && !hy.done;
1623
+ if (!hy) return false;
1624
+ return !hy.done || !!(hy.fr && hy.fr.pending());
1638
1625
  }
1639
1626
  function installRevealHook() {
1640
1627
  const hy = globalThis._$HY;
1641
- if (!hy || hy.$sc) return;
1628
+ if (!hy || hy.$sc || !hy.fr) return;
1642
1629
  hy.$sc = true;
1643
- const prev = hy.fe;
1644
- hy.fe = (fragmentId, parent) => {
1645
- if (prev) prev(fragmentId, parent);
1630
+ hy.fr.subscribe((_id, parent) => {
1646
1631
  if (!boundaryIndex) return;
1647
1632
  const root = parent || (typeof document !== "undefined" ? document.body : null);
1648
- if (!root) return;
1649
- indexBoundaries(root);
1633
+ if (root) indexBoundaries(root);
1634
+ if (!boundaryWaiters.size) return;
1635
+ const exhausted = hy.done && !hy.fr.pending();
1650
1636
  for (const [id, notify] of boundaryWaiters) {
1651
- const el = boundaryIndex.get(id);
1652
- if (!el) continue;
1637
+ const el = boundaryIndex && boundaryIndex.get(id);
1638
+ if (!el && !exhausted) continue;
1653
1639
  boundaryWaiters.delete(id);
1654
1640
  notify(el);
1655
1641
  }
1656
- };
1642
+ });
1657
1643
  }
1658
- function documentBoundary(host, id, props) {
1644
+ function documentBoundary(host, id, props, binding) {
1645
+ installRevealHook();
1659
1646
  const claimed = claimedBoundaries.has(id);
1660
1647
  const el = !claimed ? findBoundaryElement(id) : undefined;
1661
- if (el) return adoptBoundary(host, id, el, props);
1662
- if (!claimed && !boundaryWaiters.has(id) && documentStreaming()) {
1648
+ if (el) return adoptBoundary(host, id, el, props, binding);
1649
+ if (!claimed && !boundaryWaiters.has(id) && boundaryMayArrive()) {
1663
1650
  const owner = solidJs.getOwner();
1664
1651
  const arrival = new Promise(resolve => boundaryWaiters.set(id, resolve));
1665
1652
  solidJs.onCleanup(() => boundaryWaiters.delete(id));
1666
- return solidJs.createMemo(() => arrival.then(node => solidJs.runWithOwner(owner, () => adoptBoundary(host, id, node, props))));
1653
+ return solidJs.createMemo(() => arrival.then(node => solidJs.runWithOwner(owner, () =>
1654
+ node ? adoptBoundary(host, id, node, props, binding) : boundaryComponent(host, id)(props, binding))));
1667
1655
  }
1668
- return boundaryComponent(host, id)(props);
1656
+ return boundaryComponent(host, id)(props, binding);
1669
1657
  }
1670
- function adoptBoundary(host, id, el, props) {
1658
+ function documentAddress(id) {
1659
+ const records = globalThis._$SC?.a;
1660
+ if (records) {
1661
+ for (const address in records) if (records[address] === id) return address;
1662
+ }
1663
+ return id;
1664
+ }
1665
+ function adoptBoundary(host, id, el, props, binding) {
1671
1666
  claimedBoundaries.add(id);
1672
- const hy = globalThis._$HY;
1673
- if (hy && hy.r) {
1667
+ const address = binding ? binding() : documentAddress(id);
1668
+ const appliedRecords = new Set();
1669
+ const claimedFragments = new Set();
1670
+ const claimRegionFragments = root => {
1671
+ const fr = globalThis._$HY?.fr;
1672
+ if (!fr || !fr.claim) return;
1673
+ root.querySelectorAll('template[id^="pl-"]').forEach(tpl => {
1674
+ const fragId = tpl.id.slice(3);
1675
+ if (claimedFragments.has(fragId)) return;
1676
+ claimedFragments.add(fragId);
1677
+ fr.claim(fragId);
1678
+ });
1679
+ };
1680
+ const drainRecords = () => {
1681
+ const hy = globalThis._$HY;
1682
+ if (!hy || !hy.r) return;
1674
1683
  const slotPrefix = `sc:slot:${id}:`;
1675
1684
  for (const key of Object.keys(hy.r)) {
1685
+ if (appliedRecords.has(key)) continue;
1676
1686
  if (key.startsWith(slotPrefix)) {
1687
+ appliedRecords.add(key);
1677
1688
  host.apply({
1678
1689
  type: "slot",
1679
- id,
1690
+ id: address,
1680
1691
  version: 0,
1681
1692
  key: key.slice(slotPrefix.length),
1682
1693
  args: hy.r[key]
@@ -1684,6 +1695,7 @@ function adoptBoundary(host, id, el, props) {
1684
1695
  } else if (key.startsWith("sc:region:")) {
1685
1696
  const childId = key.slice("sc:region:".length);
1686
1697
  if (childId.startsWith(id + ".")) {
1698
+ appliedRecords.add(key);
1687
1699
  const val = hy.r[key];
1688
1700
  const apply = html => host.apply({
1689
1701
  type: "html",
@@ -1695,16 +1707,58 @@ function adoptBoundary(host, id, el, props) {
1695
1707
  }
1696
1708
  }
1697
1709
  }
1698
- }
1710
+ };
1711
+ claimRegionFragments(el);
1712
+ const fr = globalThis._$HY?.fr;
1713
+ const unsubscribe = fr ? fr.subscribe((_fragId, parent) => {
1714
+ if (fr.claim && parent && el.contains(parent)) claimRegionFragments(parent);
1715
+ drainRecords();
1716
+ }) : undefined;
1717
+ solidJs.onCleanup(() => {
1718
+ unsubscribe && unsubscribe();
1719
+ if (fr && fr.release) for (const fragId of claimedFragments) fr.release(fragId);
1720
+ });
1721
+ drainRecords();
1699
1722
  const owner = solidJs.getOwner();
1723
+ let release;
1724
+ let setGate;
1700
1725
  const frame = createFrame(el, {
1701
1726
  adopt: true,
1702
1727
  host,
1703
- id,
1728
+ id: address,
1704
1729
  slots: slotsFor(props),
1705
1730
  ownerScope: boundaryScope(owner),
1706
- reveal: revealSeam(owner)
1731
+ reveal: revealSeam(owner),
1732
+ onApply: () => {
1733
+ if (release) {
1734
+ release();
1735
+ release = undefined;
1736
+ }
1737
+ setGate && setGate(undefined);
1738
+ },
1739
+ ...{
1740
+ recordsPending: () => {
1741
+ if (document.readyState === "loading") return true;
1742
+ const hy = globalThis._$HY;
1743
+ return !!(hy && hy.fr && hy.fr.pending());
1744
+ },
1745
+ drainRecords,
1746
+ claimScope: id
1747
+ }
1707
1748
  });
1749
+ if (binding) {
1750
+ const arm = () => new Promise(r => release = r);
1751
+ const [gatePromise, setGatePromise] = solidJs.createSignal(undefined);
1752
+ setGate = setGatePromise;
1753
+ const gate = solidJs.createMemo(() => gatePromise());
1754
+ solidJs.createRenderEffect(binding, (address, prev) => {
1755
+ if (prev !== undefined && address !== prev && tables.has(address)) {
1756
+ setGatePromise(arm());
1757
+ }
1758
+ frame.rebind(address);
1759
+ });
1760
+ solidJs.createRenderEffect(() => (gate(), undefined), () => {});
1761
+ }
1708
1762
  solidJs.onCleanup(() => frame.dispose());
1709
1763
  return el;
1710
1764
  }
@@ -1719,17 +1773,16 @@ function installServerComponents(host = getFrameHost()) {
1719
1773
  g._$SC.a[a] = i;
1720
1774
  g._$SC.reg && g._$SC.reg(a, i);
1721
1775
  }
1722
- return g._$SC.c[i] || (g._$SC.c[i] = p => g._$SC.impl(i, p));
1776
+ return g._$SC.c[i] || (g._$SC.c[i] = (p, b) => g._$SC.impl(i, p, b));
1723
1777
  }
1724
1778
  };
1725
1779
  }
1726
- g._$SC.impl = (id, props) => documentBoundary(host, id, props);
1780
+ g._$SC.impl = (id, props, binding) => documentBoundary(host, id, props, binding);
1727
1781
  installRevealHook();
1728
1782
  const handler = createServerComponentHandler({
1729
1783
  host,
1730
- component: frameId => boundaryComponent(host, frameId),
1731
- onStream: frameId => beginStream(frameId),
1732
- documentComponent: functionId => claimedBoundaries.has(functionId) ? undefined : g._$SC.c[functionId],
1784
+ component: fnId => g._$SC.r(fnId),
1785
+ onStream: address => beginStream(address),
1733
1786
  intercept: ({
1734
1787
  id
1735
1788
  }) => {
@@ -1737,7 +1790,7 @@ function installServerComponents(host = getFrameHost()) {
1737
1790
  return g._$SC.r(id);
1738
1791
  }
1739
1792
  });
1740
- const showing = (address, id) => handler.showing(address, id, g._$SC.r(id));
1793
+ const showing = (address, id) => handler.showing(address, id);
1741
1794
  const records = g._$SC.a || (g._$SC.a = {});
1742
1795
  for (const address in records) showing(address, records[address]);
1743
1796
  g._$SC.reg = showing;
@@ -1749,10 +1802,10 @@ function installServerComponents(host = getFrameHost()) {
1749
1802
  exports.FRAME_APPLIED_EVENT = FRAME_APPLIED_EVENT;
1750
1803
  exports.FRAME_STREAM_HEADER = FRAME_STREAM_HEADER;
1751
1804
  exports.applyFrameResponse = applyFrameResponse;
1805
+ exports.asyncArg = asyncArg;
1752
1806
  exports.createFrame = createFrame;
1753
1807
  exports.createFrameElement = createFrameElement;
1754
1808
  exports.createFrameHost = createFrameHost;
1755
- exports.createJSONDataTable = createJSONDataTable;
1756
1809
  exports.createServerComponentHandler = createServerComponentHandler;
1757
1810
  exports.getFrameHost = getFrameHost;
1758
1811
  exports.installServerComponents = installServerComponents;