@solidjs/web 2.0.0-beta.31 → 2.0.0-beta.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -6
- package/dist/dev.cjs +234 -45
- package/dist/dev.js +221 -42
- package/dist/server.cjs +456 -123
- package/dist/server.js +445 -120
- package/dist/web.cjs +234 -45
- package/dist/web.js +221 -42
- package/frames/dist/client.cjs +217 -112
- package/frames/dist/client.dev.cjs +217 -112
- package/frames/dist/client.dev.js +218 -113
- package/frames/dist/client.js +218 -113
- package/frames/dist/server.cjs +488 -177
- package/frames/dist/server.js +489 -179
- package/package.json +55 -4
- package/serialization/dist/serialization.cjs +8 -0
- package/serialization/dist/serialization.js +1 -0
- package/serialization/types/index.d.ts +173 -6
- package/serialization/types-cjs/index.d.cts +173 -6
- package/server-functions/dist/client.cjs +46 -9
- package/server-functions/dist/client.js +47 -11
- package/server-functions/dist/rich-args.cjs +11 -0
- package/server-functions/dist/rich-args.js +9 -0
- package/server-functions/dist/server.cjs +275 -126
- package/server-functions/dist/server.dev.cjs +1053 -0
- package/server-functions/dist/server.dev.js +1021 -0
- package/server-functions/dist/server.js +273 -127
- package/server-functions/package.json +10 -0
- package/server-functions/rich-args/package.json +20 -0
- package/storage/types/index.d.ts +1 -1
- package/storage/types-cjs/index.d.cts +1 -1
- package/types/client.d.ts +127 -6
- package/types/core.d.ts +3 -1
- package/types/frames/client.d.ts +15 -1
- package/types/frames/frame-client.d.ts +37 -7
- package/types/frames/frame-sink.d.ts +26 -3
- package/types/frames/frame-transport.d.ts +39 -7
- package/types/frames/serializer.d.ts +173 -6
- package/types/frames/server.d.ts +22 -0
- package/types/index.d.ts +2 -3
- package/types/response.d.ts +45 -0
- package/types/serializer.d.ts +173 -6
- package/types/server-functions/client.d.ts +1 -0
- package/types/server-functions/rich-args.d.ts +10 -0
- package/types/server-functions/server.d.ts +98 -0
- package/types/server-functions/shared.d.ts +22 -0
- package/types/server-mock.d.ts +171 -59
- package/types/server.d.ts +188 -36
- package/types-cjs/client.d.cts +127 -6
- package/types-cjs/core.d.cts +3 -1
- package/types-cjs/frames/client.d.cts +15 -1
- package/types-cjs/frames/frame-client.d.cts +37 -7
- package/types-cjs/frames/frame-sink.d.cts +26 -3
- package/types-cjs/frames/frame-transport.d.cts +39 -7
- package/types-cjs/frames/serializer.d.cts +173 -6
- package/types-cjs/frames/server.d.cts +22 -0
- package/types-cjs/index.d.cts +2 -3
- package/types-cjs/response.d.cts +45 -0
- package/types-cjs/serializer.d.cts +173 -6
- package/types-cjs/server-functions/client.d.cts +1 -0
- package/types-cjs/server-functions/rich-args.d.cts +10 -0
- package/types-cjs/server-functions/server.d.cts +98 -0
- package/types-cjs/server-functions/shared.d.cts +22 -0
- package/types-cjs/server-mock.d.cts +171 -59
- package/types-cjs/server.d.cts +188 -36
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getOwner, onCleanup, createMemo, runWithOwner,
|
|
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';
|
|
@@ -94,9 +94,7 @@ function createFrameHost(options = {}) {
|
|
|
94
94
|
if (store.version !== undefined && version < store.version) return false;
|
|
95
95
|
if (store.version === undefined || version > store.version) {
|
|
96
96
|
store.version = version;
|
|
97
|
-
|
|
98
|
-
if (key.startsWith("seg:") || key === ":error") delete store.records[key];
|
|
99
|
-
}
|
|
97
|
+
clearStreamRecords(store.records);
|
|
100
98
|
}
|
|
101
99
|
Object.assign(store.records, records);
|
|
102
100
|
return true;
|
|
@@ -174,6 +172,7 @@ class FrameImpl {
|
|
|
174
172
|
#store = Object.create(null);
|
|
175
173
|
#appliedRootValue;
|
|
176
174
|
#hasContent = false;
|
|
175
|
+
#errorNotified = false;
|
|
177
176
|
#revealed = new Set();
|
|
178
177
|
#fallbackShown = new Set();
|
|
179
178
|
#slots;
|
|
@@ -193,10 +192,12 @@ class FrameImpl {
|
|
|
193
192
|
#claimTree = (node, direct) => {
|
|
194
193
|
const handlers = claimHandlers();
|
|
195
194
|
if (!handlers) return;
|
|
196
|
-
|
|
197
|
-
const scope = this.#options.ownerScope;
|
|
198
|
-
scope ? scope(run) : run();
|
|
195
|
+
this.#scoped(() => direct ? claimNode(handlers, node) : claimTree(handlers, node));
|
|
199
196
|
};
|
|
197
|
+
#scoped(fn) {
|
|
198
|
+
const scope = this.#options.ownerScope;
|
|
199
|
+
return scope ? scope(fn) : fn();
|
|
200
|
+
}
|
|
200
201
|
constructor(element, start, end, options = {}) {
|
|
201
202
|
this.#element = element;
|
|
202
203
|
this.#start = start;
|
|
@@ -257,15 +258,9 @@ class FrameImpl {
|
|
|
257
258
|
return;
|
|
258
259
|
} else if (v > this.#version) {
|
|
259
260
|
this.#version = v;
|
|
260
|
-
this.#
|
|
261
|
-
this.#fallbackShown.clear();
|
|
262
|
-
for (const key of Object.keys(this.#store)) {
|
|
263
|
-
if (key.startsWith("seg:") || key === ":error") {
|
|
264
|
-
delete this.#store[key];
|
|
265
|
-
}
|
|
266
|
-
}
|
|
261
|
+
this.#resetStreamState();
|
|
267
262
|
}
|
|
268
|
-
for (const key
|
|
263
|
+
for (const key in write.r) {
|
|
269
264
|
const incoming = write.r[key];
|
|
270
265
|
if (incoming && incoming.kind === "slot" && key.charCodeAt(0) === 115 && key.startsWith("slot:")) {
|
|
271
266
|
const existing = this.#store[key];
|
|
@@ -277,6 +272,12 @@ class FrameImpl {
|
|
|
277
272
|
}
|
|
278
273
|
this.#flush();
|
|
279
274
|
}
|
|
275
|
+
#resetStreamState(root) {
|
|
276
|
+
this.#revealed.clear();
|
|
277
|
+
this.#fallbackShown.clear();
|
|
278
|
+
this.#errorNotified = false;
|
|
279
|
+
clearStreamRecords(this.#store, root);
|
|
280
|
+
}
|
|
280
281
|
#flush() {
|
|
281
282
|
if (this.#disposed) return;
|
|
282
283
|
const version = this.#version;
|
|
@@ -287,10 +288,14 @@ class FrameImpl {
|
|
|
287
288
|
this.#appliedRootValue = root.value;
|
|
288
289
|
this.#applied(version, reason);
|
|
289
290
|
}
|
|
291
|
+
if (this.#store[":error"] && !this.#errorNotified) {
|
|
292
|
+
this.#errorNotified = true;
|
|
293
|
+
this.#applied(version, "error");
|
|
294
|
+
}
|
|
290
295
|
let progressed = true;
|
|
291
296
|
while (progressed) {
|
|
292
297
|
progressed = false;
|
|
293
|
-
for (const key
|
|
298
|
+
for (const key in this.#store) {
|
|
294
299
|
const name = segmentName(key);
|
|
295
300
|
if (name === null || this.#revealed.has(name)) continue;
|
|
296
301
|
if (this.#segmentReady(name)) {
|
|
@@ -299,7 +304,7 @@ class FrameImpl {
|
|
|
299
304
|
progressed = true;
|
|
300
305
|
}
|
|
301
306
|
}
|
|
302
|
-
for (const key
|
|
307
|
+
for (const key in this.#store) {
|
|
303
308
|
const m = /^seg:([^:]+):fallback$/.exec(key);
|
|
304
309
|
if (!m) continue;
|
|
305
310
|
const name = m[1];
|
|
@@ -311,7 +316,7 @@ class FrameImpl {
|
|
|
311
316
|
}
|
|
312
317
|
}
|
|
313
318
|
}
|
|
314
|
-
for (const key
|
|
319
|
+
for (const key in this.#store) {
|
|
315
320
|
if (this.#processedAssets.has(key) || !key.endsWith(":assets")) continue;
|
|
316
321
|
this.#processedAssets.add(key);
|
|
317
322
|
const record = this.#store[key];
|
|
@@ -343,6 +348,7 @@ class FrameImpl {
|
|
|
343
348
|
const callback = this.#resolveSlot(propOf(occurrence));
|
|
344
349
|
if (!callback) continue;
|
|
345
350
|
const record = this.#resolveSlotRecord(occurrence);
|
|
351
|
+
if (record && record.kind === "slot" && this.#refsUnresolved(record.args)) continue;
|
|
346
352
|
const prev = this.#slotNodes.get(occurrence);
|
|
347
353
|
const prevFirst = Array.isArray(prev) ? prev[0] : prev;
|
|
348
354
|
const zombie = this.#mountedSlots.has(occurrence) && prevFirst && !prevFirst.parentNode;
|
|
@@ -398,15 +404,7 @@ class FrameImpl {
|
|
|
398
404
|
const cleanups = this.#slotCleanups.get(occurrence) ?? [];
|
|
399
405
|
let existing = [];
|
|
400
406
|
let end = null;
|
|
401
|
-
if (start)
|
|
402
|
-
const endData = slotEnd(occurrence);
|
|
403
|
-
let n = start.nextSibling;
|
|
404
|
-
while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
|
|
405
|
-
existing.push(n);
|
|
406
|
-
n = n.nextSibling;
|
|
407
|
-
}
|
|
408
|
-
end = n;
|
|
409
|
-
}
|
|
407
|
+
if (start) end = eachInRange(start, occurrence, n => existing.push(n));
|
|
410
408
|
const ctx = {
|
|
411
409
|
frame: this.#options.claimScope ?? this.#options.id,
|
|
412
410
|
key: occurrence,
|
|
@@ -421,23 +419,16 @@ class FrameImpl {
|
|
|
421
419
|
} : undefined
|
|
422
420
|
};
|
|
423
421
|
const props = record && record.kind === "slot" ? this.#resolveArgs(occurrence, record.args) : {};
|
|
424
|
-
const
|
|
425
|
-
const content = scope ? scope(() => callback(props, ctx)) : callback(props, ctx);
|
|
422
|
+
const content = this.#scoped(() => callback(props, ctx));
|
|
426
423
|
this.#slotArgs.set(occurrence, record);
|
|
427
424
|
if (cleanups.length) this.#slotCleanups.set(occurrence, cleanups);
|
|
428
425
|
if (content == null) return null;
|
|
429
426
|
return Array.isArray(content) ? content : [content];
|
|
430
427
|
}
|
|
431
428
|
#replaceRange(key, start, nodes) {
|
|
432
|
-
const end = slotEnd(key);
|
|
433
429
|
const parent = start.parentNode;
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
const next = n.nextSibling;
|
|
437
|
-
parent.removeChild(n);
|
|
438
|
-
n = next;
|
|
439
|
-
}
|
|
440
|
-
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);
|
|
441
432
|
}
|
|
442
433
|
#unmountSlot(key) {
|
|
443
434
|
this.#mountedSlots.delete(key);
|
|
@@ -449,9 +440,7 @@ class FrameImpl {
|
|
|
449
440
|
this.#runSlotCleanups(key);
|
|
450
441
|
const regions = this.#slotRegions.get(key);
|
|
451
442
|
if (regions) {
|
|
452
|
-
|
|
453
|
-
frame
|
|
454
|
-
} of regions.values()) frame?.dispose();
|
|
443
|
+
disposeRegions(regions);
|
|
455
444
|
this.#slotRegions.delete(key);
|
|
456
445
|
}
|
|
457
446
|
}
|
|
@@ -461,15 +450,26 @@ class FrameImpl {
|
|
|
461
450
|
this.#slotCleanups.delete(key);
|
|
462
451
|
for (const fn of cleanups) fn();
|
|
463
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
|
+
}
|
|
464
468
|
#resolveArgs(slotKey, args) {
|
|
465
469
|
const host = this.#options.host;
|
|
466
|
-
|
|
467
|
-
if (!regions) {
|
|
468
|
-
regions = new Map();
|
|
469
|
-
this.#slotRegions.set(slotKey, regions);
|
|
470
|
-
}
|
|
470
|
+
const regions = this.#regionsFor(slotKey);
|
|
471
471
|
const props = {};
|
|
472
|
-
for (const key
|
|
472
|
+
for (const key in args) {
|
|
473
473
|
const value = args[key];
|
|
474
474
|
if (isDataRef(value)) {
|
|
475
475
|
const resolved = host ? host.resolve(value, this.#options.id) : undefined;
|
|
@@ -499,17 +499,8 @@ class FrameImpl {
|
|
|
499
499
|
}
|
|
500
500
|
#discoverRegions(slotKey, start) {
|
|
501
501
|
if (!start) return;
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
regions = new Map();
|
|
505
|
-
this.#slotRegions.set(slotKey, regions);
|
|
506
|
-
}
|
|
507
|
-
const endData = slotEnd(slotKey);
|
|
508
|
-
let n = start.nextSibling;
|
|
509
|
-
while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
|
|
510
|
-
collectRegionElements(n, regions);
|
|
511
|
-
n = n.nextSibling;
|
|
512
|
-
}
|
|
502
|
+
const regions = this.#regionsFor(slotKey);
|
|
503
|
+
eachInRange(start, slotKey, n => collectRegionElements(n, regions));
|
|
513
504
|
}
|
|
514
505
|
#refArgsUnchanged(occurrence, record) {
|
|
515
506
|
const old = this.#slotArgs.get(occurrence);
|
|
@@ -525,11 +516,11 @@ class FrameImpl {
|
|
|
525
516
|
const va = a[key];
|
|
526
517
|
const vb = b[key];
|
|
527
518
|
if (va === vb) continue;
|
|
528
|
-
if (
|
|
529
|
-
if (
|
|
530
|
-
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) {
|
|
531
521
|
const host = this.#options.host;
|
|
532
522
|
const next = host ? host.resolve(vb, this.#options.id) : undefined;
|
|
523
|
+
if (isAsyncLike(next) || isAsyncLike(cache[key])) return false;
|
|
533
524
|
try {
|
|
534
525
|
if (JSON.stringify(next) === JSON.stringify(cache[key])) continue;
|
|
535
526
|
} catch (e) {
|
|
@@ -545,7 +536,7 @@ class FrameImpl {
|
|
|
545
536
|
if (!args) return;
|
|
546
537
|
const regions = this.#slotRegions.get(occurrence);
|
|
547
538
|
if (!regions) return;
|
|
548
|
-
for (const key
|
|
539
|
+
for (const key in args) {
|
|
549
540
|
const value = args[key];
|
|
550
541
|
if (!isFrameRef(value)) continue;
|
|
551
542
|
const entry = regions.get(key);
|
|
@@ -595,11 +586,8 @@ class FrameImpl {
|
|
|
595
586
|
this.#element.setAttribute(FRAME_ID_ATTR, id);
|
|
596
587
|
}
|
|
597
588
|
this.#version = undefined;
|
|
598
|
-
this.#
|
|
599
|
-
this.#
|
|
600
|
-
for (const key of Object.keys(this.#store)) {
|
|
601
|
-
if (key.startsWith("seg:") || key === ":error") delete this.#store[key];
|
|
602
|
-
}
|
|
589
|
+
this.#appliedRootValue = undefined;
|
|
590
|
+
this.#resetStreamState(true);
|
|
603
591
|
if (host) host.register(id, this);
|
|
604
592
|
}
|
|
605
593
|
rebase() {
|
|
@@ -619,11 +607,7 @@ class FrameImpl {
|
|
|
619
607
|
}
|
|
620
608
|
for (const key of [...this.#slotCleanups.keys()]) this.#runSlotCleanups(key);
|
|
621
609
|
for (const key of this.#mountedSlots) this.#removeSlotRecord(key);
|
|
622
|
-
for (const regions of this.#slotRegions.values())
|
|
623
|
-
for (const {
|
|
624
|
-
frame
|
|
625
|
-
} of regions.values()) frame?.dispose();
|
|
626
|
-
}
|
|
610
|
+
for (const regions of this.#slotRegions.values()) disposeRegions(regions);
|
|
627
611
|
this.#slotRegions.clear();
|
|
628
612
|
this.#mountedSlots.clear();
|
|
629
613
|
}
|
|
@@ -645,13 +629,7 @@ class FrameImpl {
|
|
|
645
629
|
}
|
|
646
630
|
}
|
|
647
631
|
#clearContent() {
|
|
648
|
-
|
|
649
|
-
let n = this.#firstContent();
|
|
650
|
-
while (n && n !== this.#end) {
|
|
651
|
-
const next = n.nextSibling;
|
|
652
|
-
parent.removeChild(n);
|
|
653
|
-
n = next;
|
|
654
|
-
}
|
|
632
|
+
removeUntil(this.#parent(), this.#firstContent(), this.#end);
|
|
655
633
|
}
|
|
656
634
|
#claimContent() {
|
|
657
635
|
if (!claimHandlers()) return;
|
|
@@ -668,9 +646,7 @@ class FrameImpl {
|
|
|
668
646
|
const assets = this.#store[`seg:${name}:assets`];
|
|
669
647
|
if (assets && assets.styles) {
|
|
670
648
|
let ready = true;
|
|
671
|
-
for (const entry of assets.styles)
|
|
672
|
-
if (!ensureStylesheet(entry, this.#styleFlush)) ready = false;
|
|
673
|
-
}
|
|
649
|
+
for (const entry of assets.styles) ready = ensureStylesheet(entry, this.#styleFlush) && ready;
|
|
674
650
|
if (!ready) return false;
|
|
675
651
|
}
|
|
676
652
|
if (!this.#findPlaceholder(name)) return false;
|
|
@@ -687,12 +663,7 @@ class FrameImpl {
|
|
|
687
663
|
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);
|
|
688
664
|
}
|
|
689
665
|
const parent = tpl.parentNode;
|
|
690
|
-
|
|
691
|
-
while (n && n !== closing) {
|
|
692
|
-
const next = n.nextSibling;
|
|
693
|
-
parent.removeChild(n);
|
|
694
|
-
n = next;
|
|
695
|
-
}
|
|
666
|
+
removeUntil(parent, tpl.nextSibling, closing);
|
|
696
667
|
if (this.#options.reveal) {
|
|
697
668
|
const fallbackFrag = tpl.content.cloneNode(true);
|
|
698
669
|
this.#claimTree(fallbackFrag);
|
|
@@ -741,9 +712,7 @@ function createFrameElement(options) {
|
|
|
741
712
|
const frame = new FrameImpl(el, null, null, options);
|
|
742
713
|
return {
|
|
743
714
|
element: el,
|
|
744
|
-
|
|
745
|
-
return frame;
|
|
746
|
-
},
|
|
715
|
+
frame,
|
|
747
716
|
dispose() {
|
|
748
717
|
frame.dispose();
|
|
749
718
|
el.remove();
|
|
@@ -763,15 +732,30 @@ function segmentName(key) {
|
|
|
763
732
|
const m = /^seg:([^:]+)$/.exec(key);
|
|
764
733
|
return m ? m[1] : null;
|
|
765
734
|
}
|
|
735
|
+
function isAsyncLike(v) {
|
|
736
|
+
return !!v && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
|
|
737
|
+
}
|
|
766
738
|
function propOf(occurrence) {
|
|
767
739
|
const hash = occurrence.indexOf("#");
|
|
768
740
|
return hash === -1 ? occurrence : occurrence.slice(0, hash);
|
|
769
741
|
}
|
|
770
742
|
function isDataRef(value) {
|
|
771
|
-
return
|
|
743
|
+
return !!value && typeof value.$ref === "string";
|
|
772
744
|
}
|
|
773
745
|
function isFrameRef(value) {
|
|
774
|
-
return
|
|
746
|
+
return !!value && typeof value.$frame === "string";
|
|
747
|
+
}
|
|
748
|
+
function disposeRegions(regions) {
|
|
749
|
+
for (const {
|
|
750
|
+
frame
|
|
751
|
+
} of regions.values()) frame?.dispose();
|
|
752
|
+
}
|
|
753
|
+
function removeUntil(parent, n, stop) {
|
|
754
|
+
while (n && n !== stop) {
|
|
755
|
+
const next = n.nextSibling;
|
|
756
|
+
parent.removeChild(n);
|
|
757
|
+
n = next;
|
|
758
|
+
}
|
|
775
759
|
}
|
|
776
760
|
function parseFragment(html) {
|
|
777
761
|
const template = document.createElement("template");
|
|
@@ -779,9 +763,8 @@ function parseFragment(html) {
|
|
|
779
763
|
return template.content;
|
|
780
764
|
}
|
|
781
765
|
function findHeadElement(selector, attr, value) {
|
|
782
|
-
const
|
|
783
|
-
|
|
784
|
-
if (nodes[i].getAttribute(attr) === value) return nodes[i];
|
|
766
|
+
for (const node of document.head.querySelectorAll(selector)) {
|
|
767
|
+
if (node.getAttribute(attr) === value) return node;
|
|
785
768
|
}
|
|
786
769
|
return null;
|
|
787
770
|
}
|
|
@@ -830,7 +813,7 @@ function applyInlineStyles(inlineStyles) {
|
|
|
830
813
|
}
|
|
831
814
|
}
|
|
832
815
|
function isPlaceholderStart(node, id) {
|
|
833
|
-
return node.
|
|
816
|
+
return node.tagName === "TEMPLATE" && node.id === id;
|
|
834
817
|
}
|
|
835
818
|
function rangeClose(start, id) {
|
|
836
819
|
let n = start.nextSibling;
|
|
@@ -887,6 +870,21 @@ function renameRegion(entry, childId) {
|
|
|
887
870
|
entry.childId = childId;
|
|
888
871
|
if (entry.frame) entry.frame.rebind(childId);else entry.element.setAttribute(FRAME_ID_ATTR, childId);
|
|
889
872
|
}
|
|
873
|
+
function eachInRange(start, key, cb) {
|
|
874
|
+
const end = slotEnd(key);
|
|
875
|
+
let n = start.nextSibling;
|
|
876
|
+
while (n && !(n.nodeType === COMMENT_NODE && n.data === end)) {
|
|
877
|
+
const next = n.nextSibling;
|
|
878
|
+
cb(n);
|
|
879
|
+
n = next;
|
|
880
|
+
}
|
|
881
|
+
return n;
|
|
882
|
+
}
|
|
883
|
+
function clearStreamRecords(records, root) {
|
|
884
|
+
for (const key in records) {
|
|
885
|
+
if (key.startsWith("seg:") || key === ":error" || root && key === "") delete records[key];
|
|
886
|
+
}
|
|
887
|
+
}
|
|
890
888
|
function argsEquivalent(a, b) {
|
|
891
889
|
if (a === b) return true;
|
|
892
890
|
if (!a || !b) return false;
|
|
@@ -897,9 +895,7 @@ function argsEquivalent(a, b) {
|
|
|
897
895
|
const va = a[key];
|
|
898
896
|
const vb = b[key];
|
|
899
897
|
if (va === vb) continue;
|
|
900
|
-
if (va &&
|
|
901
|
-
continue;
|
|
902
|
-
}
|
|
898
|
+
if (isFrameRef(va) && va.$frame === vb?.$frame) continue;
|
|
903
899
|
return false;
|
|
904
900
|
}
|
|
905
901
|
return true;
|
|
@@ -1271,7 +1267,7 @@ function createServerComponentHandler({
|
|
|
1271
1267
|
showing(address, functionId) {
|
|
1272
1268
|
bindingFor(address, functionId);
|
|
1273
1269
|
const comp = componentFor(functionId);
|
|
1274
|
-
if ((typeof comp === "function" || typeof comp === "object"
|
|
1270
|
+
if (comp && (typeof comp === "function" || typeof comp === "object") && !comp[COMPONENT_BINDING]) {
|
|
1275
1271
|
comp[COMPONENT_BINDING] = {
|
|
1276
1272
|
component: comp,
|
|
1277
1273
|
address
|
|
@@ -1363,6 +1359,9 @@ function createJSONDataTable(options) {
|
|
|
1363
1359
|
};
|
|
1364
1360
|
}
|
|
1365
1361
|
|
|
1362
|
+
function asyncArg(value) {
|
|
1363
|
+
return value;
|
|
1364
|
+
}
|
|
1366
1365
|
let sharedHost;
|
|
1367
1366
|
const tables = new Map();
|
|
1368
1367
|
function tableFor(id) {
|
|
@@ -1439,8 +1438,26 @@ function claimRender(prefix, existing, render) {
|
|
|
1439
1438
|
function liveSlotProps(initial, ctx) {
|
|
1440
1439
|
const [args, setArgs] = createSignal(initial);
|
|
1441
1440
|
ctx.onUpdate(next => setArgs(() => next));
|
|
1441
|
+
return slotArgsProxy(args);
|
|
1442
|
+
}
|
|
1443
|
+
function isAsyncValue(v) {
|
|
1444
|
+
return v !== null && typeof v === "object" && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
|
|
1445
|
+
}
|
|
1446
|
+
function slotArgsProxy(args) {
|
|
1447
|
+
const owner = getOwner();
|
|
1448
|
+
const asyncReads = new Map();
|
|
1442
1449
|
return new Proxy({}, {
|
|
1443
|
-
get: (_, key) =>
|
|
1450
|
+
get: (_, key) => {
|
|
1451
|
+
const v = args()[key];
|
|
1452
|
+
if (!isAsyncValue(v)) return v;
|
|
1453
|
+
let read = asyncReads.get(key);
|
|
1454
|
+
if (!read) {
|
|
1455
|
+
const make = () => createMemo(() => args()[key]);
|
|
1456
|
+
read = owner ? runWithOwner(owner, make) : make();
|
|
1457
|
+
asyncReads.set(key, read);
|
|
1458
|
+
}
|
|
1459
|
+
return read();
|
|
1460
|
+
},
|
|
1444
1461
|
has: (_, key) => key in args(),
|
|
1445
1462
|
ownKeys: () => Reflect.ownKeys(args()),
|
|
1446
1463
|
getOwnPropertyDescriptor: (_, key) => key in args() ? {
|
|
@@ -1458,6 +1475,7 @@ function isReactiveContent(value) {
|
|
|
1458
1475
|
}
|
|
1459
1476
|
function slotsFor(props) {
|
|
1460
1477
|
const bindings = new Map();
|
|
1478
|
+
const fillScopes = new Map();
|
|
1461
1479
|
return new Proxy({}, {
|
|
1462
1480
|
get(_, prop) {
|
|
1463
1481
|
if (typeof prop !== "string" || !(prop in props)) return undefined;
|
|
@@ -1468,6 +1486,19 @@ function slotsFor(props) {
|
|
|
1468
1486
|
bindings.delete(key);
|
|
1469
1487
|
prev.dispose();
|
|
1470
1488
|
}
|
|
1489
|
+
const prevFill = key !== undefined && fillScopes.get(key);
|
|
1490
|
+
if (prevFill) {
|
|
1491
|
+
fillScopes.delete(key);
|
|
1492
|
+
prevFill.dispose();
|
|
1493
|
+
}
|
|
1494
|
+
const fillOwner = streamInvoke ? createOwner() : null;
|
|
1495
|
+
if (fillOwner && key !== undefined && ctx) {
|
|
1496
|
+
fillScopes.set(key, fillOwner);
|
|
1497
|
+
ctx.onCleanup(() => {
|
|
1498
|
+
if (fillScopes.get(key) === fillOwner) fillScopes.delete(key);
|
|
1499
|
+
fillOwner.dispose();
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1471
1502
|
const settle = out => {
|
|
1472
1503
|
const existing = ctx && ctx.existing || [];
|
|
1473
1504
|
if (existing.length) {
|
|
@@ -1480,13 +1511,13 @@ function slotsFor(props) {
|
|
|
1480
1511
|
const evaluate = () => {
|
|
1481
1512
|
const v = props[prop];
|
|
1482
1513
|
if (typeof v === "function" && ctx && ctx.invoked) {
|
|
1483
|
-
return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotProps);
|
|
1514
|
+
return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotArgsProxy(() => slotProps));
|
|
1484
1515
|
}
|
|
1485
1516
|
return v;
|
|
1486
1517
|
};
|
|
1487
1518
|
const adopted = !!(ctx && ctx.frame && ctx.adopted && ctx.existing && ctx.existing.length);
|
|
1488
1519
|
const prefix = ctx && ctx.frame ? `sc-${ctx.frame}-${ctx.key}-` : "";
|
|
1489
|
-
const value = adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
|
|
1520
|
+
const value = fillOwner ? runWithOwner(fillOwner, () => adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate()) : adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
|
|
1490
1521
|
if (!isReactiveContent(value)) {
|
|
1491
1522
|
return settle(normalizeSlotContent(value));
|
|
1492
1523
|
}
|
|
@@ -1511,29 +1542,61 @@ function slotsFor(props) {
|
|
|
1511
1542
|
function revealSeam(owner) {
|
|
1512
1543
|
return seam => runWithOwner(owner, () => insert(seam.before.parentNode, createLoadingBoundary(() => seam.content(), () => seam.fallback), seam.before));
|
|
1513
1544
|
}
|
|
1545
|
+
let streamInvoke = false;
|
|
1514
1546
|
function boundaryScope(owner) {
|
|
1515
|
-
return fn =>
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1547
|
+
return fn => {
|
|
1548
|
+
if (getOwner()) return fn();
|
|
1549
|
+
streamInvoke = true;
|
|
1550
|
+
try {
|
|
1551
|
+
return runWithOwner(owner, fn);
|
|
1552
|
+
} finally {
|
|
1553
|
+
streamInvoke = false;
|
|
1554
|
+
}
|
|
1555
|
+
};
|
|
1519
1556
|
}
|
|
1520
1557
|
function boundaryComponent(host, fnId) {
|
|
1521
1558
|
return (props, binding) => {
|
|
1522
1559
|
const owner = getOwner();
|
|
1560
|
+
const id = binding ? binding() : fnId;
|
|
1561
|
+
let applied = !tables.has(id);
|
|
1562
|
+
let release;
|
|
1563
|
+
const arm = () => new Promise(r => release = r);
|
|
1564
|
+
const mountGate = applied ? undefined : arm();
|
|
1565
|
+
let setGate;
|
|
1523
1566
|
const {
|
|
1524
1567
|
element,
|
|
1525
1568
|
frame,
|
|
1526
1569
|
dispose
|
|
1527
1570
|
} = createFrameElement({
|
|
1528
1571
|
host,
|
|
1529
|
-
id
|
|
1572
|
+
id,
|
|
1530
1573
|
slots: slotsFor(props),
|
|
1531
1574
|
ownerScope: boundaryScope(owner),
|
|
1532
|
-
reveal: revealSeam(owner)
|
|
1575
|
+
reveal: revealSeam(owner),
|
|
1576
|
+
onApply: () => {
|
|
1577
|
+
applied = true;
|
|
1578
|
+
if (release) {
|
|
1579
|
+
release();
|
|
1580
|
+
release = undefined;
|
|
1581
|
+
}
|
|
1582
|
+
setGate && setGate(undefined);
|
|
1583
|
+
}
|
|
1533
1584
|
});
|
|
1534
|
-
|
|
1585
|
+
const [gatePromise, setGatePromise] = createSignal(applied ? undefined : mountGate);
|
|
1586
|
+
setGate = setGatePromise;
|
|
1587
|
+
if (binding) {
|
|
1588
|
+
createRenderEffect(binding, (address, prev) => {
|
|
1589
|
+
if (prev !== undefined && address !== prev && tables.has(address)) {
|
|
1590
|
+
applied = false;
|
|
1591
|
+
setGatePromise(arm());
|
|
1592
|
+
}
|
|
1593
|
+
frame.rebind(address);
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1535
1596
|
onCleanup(dispose);
|
|
1536
|
-
return element;
|
|
1597
|
+
if (applied && !binding) return element;
|
|
1598
|
+
const gate = createMemo(() => gatePromise());
|
|
1599
|
+
return createMemo(() => (gate(), element));
|
|
1537
1600
|
};
|
|
1538
1601
|
}
|
|
1539
1602
|
const claimedBoundaries = new Set();
|
|
@@ -1601,6 +1664,17 @@ function adoptBoundary(host, id, el, props, binding) {
|
|
|
1601
1664
|
claimedBoundaries.add(id);
|
|
1602
1665
|
const address = binding ? binding() : documentAddress(id);
|
|
1603
1666
|
const appliedRecords = new Set();
|
|
1667
|
+
const claimedFragments = new Set();
|
|
1668
|
+
const claimRegionFragments = root => {
|
|
1669
|
+
const fr = globalThis._$HY?.fr;
|
|
1670
|
+
if (!fr || !fr.claim) return;
|
|
1671
|
+
root.querySelectorAll('template[id^="pl-"]').forEach(tpl => {
|
|
1672
|
+
const fragId = tpl.id.slice(3);
|
|
1673
|
+
if (claimedFragments.has(fragId)) return;
|
|
1674
|
+
claimedFragments.add(fragId);
|
|
1675
|
+
fr.claim(fragId);
|
|
1676
|
+
});
|
|
1677
|
+
};
|
|
1604
1678
|
const drainRecords = () => {
|
|
1605
1679
|
const hy = globalThis._$HY;
|
|
1606
1680
|
if (!hy || !hy.r) return;
|
|
@@ -1632,8 +1706,20 @@ function adoptBoundary(host, id, el, props, binding) {
|
|
|
1632
1706
|
}
|
|
1633
1707
|
}
|
|
1634
1708
|
};
|
|
1709
|
+
claimRegionFragments(el);
|
|
1710
|
+
const fr = globalThis._$HY?.fr;
|
|
1711
|
+
const unsubscribe = fr ? fr.subscribe((_fragId, parent) => {
|
|
1712
|
+
if (fr.claim && parent && el.contains(parent)) claimRegionFragments(parent);
|
|
1713
|
+
drainRecords();
|
|
1714
|
+
}) : undefined;
|
|
1715
|
+
onCleanup(() => {
|
|
1716
|
+
unsubscribe && unsubscribe();
|
|
1717
|
+
if (fr && fr.release) for (const fragId of claimedFragments) fr.release(fragId);
|
|
1718
|
+
});
|
|
1635
1719
|
drainRecords();
|
|
1636
1720
|
const owner = getOwner();
|
|
1721
|
+
let release;
|
|
1722
|
+
let setGate;
|
|
1637
1723
|
const frame = createFrame(el, {
|
|
1638
1724
|
adopt: true,
|
|
1639
1725
|
host,
|
|
@@ -1641,6 +1727,13 @@ function adoptBoundary(host, id, el, props, binding) {
|
|
|
1641
1727
|
slots: slotsFor(props),
|
|
1642
1728
|
ownerScope: boundaryScope(owner),
|
|
1643
1729
|
reveal: revealSeam(owner),
|
|
1730
|
+
onApply: () => {
|
|
1731
|
+
if (release) {
|
|
1732
|
+
release();
|
|
1733
|
+
release = undefined;
|
|
1734
|
+
}
|
|
1735
|
+
setGate && setGate(undefined);
|
|
1736
|
+
},
|
|
1644
1737
|
...{
|
|
1645
1738
|
recordsPending: () => {
|
|
1646
1739
|
if (document.readyState === "loading") return true;
|
|
@@ -1651,7 +1744,19 @@ function adoptBoundary(host, id, el, props, binding) {
|
|
|
1651
1744
|
claimScope: id
|
|
1652
1745
|
}
|
|
1653
1746
|
});
|
|
1654
|
-
if (binding)
|
|
1747
|
+
if (binding) {
|
|
1748
|
+
const arm = () => new Promise(r => release = r);
|
|
1749
|
+
const [gatePromise, setGatePromise] = createSignal(undefined);
|
|
1750
|
+
setGate = setGatePromise;
|
|
1751
|
+
const gate = createMemo(() => gatePromise());
|
|
1752
|
+
createRenderEffect(binding, (address, prev) => {
|
|
1753
|
+
if (prev !== undefined && address !== prev && tables.has(address)) {
|
|
1754
|
+
setGatePromise(arm());
|
|
1755
|
+
}
|
|
1756
|
+
frame.rebind(address);
|
|
1757
|
+
});
|
|
1758
|
+
createRenderEffect(() => (gate(), undefined), () => {});
|
|
1759
|
+
}
|
|
1655
1760
|
onCleanup(() => frame.dispose());
|
|
1656
1761
|
return el;
|
|
1657
1762
|
}
|
|
@@ -1692,4 +1797,4 @@ function installServerComponents(host = getFrameHost()) {
|
|
|
1692
1797
|
});
|
|
1693
1798
|
}
|
|
1694
1799
|
|
|
1695
|
-
export { FRAME_APPLIED_EVENT, FRAME_STREAM_HEADER, applyFrameResponse, createFrame, createFrameElement, createFrameHost,
|
|
1800
|
+
export { FRAME_APPLIED_EVENT, FRAME_STREAM_HEADER, applyFrameResponse, asyncArg, createFrame, createFrameElement, createFrameHost, createServerComponentHandler, getFrameHost, installServerComponents, isFrameStreamResponse };
|