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