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