@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
|
@@ -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,25 @@ 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
|
+
console.error(`Live hole ${key.slice(5, -6)} failed on the server; latched:`, record);
|
|
345
|
+
} else if (this.#applyHole(key.slice(5), record.value)) {
|
|
346
|
+
this.#appliedHoles.set(key, record);
|
|
347
|
+
this.#applied(version, "morph");
|
|
348
|
+
}
|
|
349
|
+
} else if (key.startsWith("attr:")) {
|
|
350
|
+
if (this.#applyAttrs(key.slice(5), record.value, record.removed)) {
|
|
351
|
+
this.#appliedHoles.set(key, record);
|
|
352
|
+
this.#applied(version, "morph");
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
for (const key in this.#store) {
|
|
315
357
|
if (this.#processedAssets.has(key) || !key.endsWith(":assets")) continue;
|
|
316
358
|
this.#processedAssets.add(key);
|
|
317
359
|
const record = this.#store[key];
|
|
@@ -343,6 +385,7 @@ class FrameImpl {
|
|
|
343
385
|
const callback = this.#resolveSlot(propOf(occurrence));
|
|
344
386
|
if (!callback) continue;
|
|
345
387
|
const record = this.#resolveSlotRecord(occurrence);
|
|
388
|
+
if (record && record.kind === "slot" && this.#refsUnresolved(record.args)) continue;
|
|
346
389
|
const prev = this.#slotNodes.get(occurrence);
|
|
347
390
|
const prevFirst = Array.isArray(prev) ? prev[0] : prev;
|
|
348
391
|
const zombie = this.#mountedSlots.has(occurrence) && prevFirst && !prevFirst.parentNode;
|
|
@@ -398,15 +441,7 @@ class FrameImpl {
|
|
|
398
441
|
const cleanups = this.#slotCleanups.get(occurrence) ?? [];
|
|
399
442
|
let existing = [];
|
|
400
443
|
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
|
-
}
|
|
444
|
+
if (start) end = eachInRange(start, occurrence, n => existing.push(n));
|
|
410
445
|
const ctx = {
|
|
411
446
|
frame: this.#options.claimScope ?? this.#options.id,
|
|
412
447
|
key: occurrence,
|
|
@@ -421,23 +456,16 @@ class FrameImpl {
|
|
|
421
456
|
} : undefined
|
|
422
457
|
};
|
|
423
458
|
const props = record && record.kind === "slot" ? this.#resolveArgs(occurrence, record.args) : {};
|
|
424
|
-
const
|
|
425
|
-
const content = scope ? scope(() => callback(props, ctx)) : callback(props, ctx);
|
|
459
|
+
const content = this.#scoped(() => callback(props, ctx));
|
|
426
460
|
this.#slotArgs.set(occurrence, record);
|
|
427
461
|
if (cleanups.length) this.#slotCleanups.set(occurrence, cleanups);
|
|
428
462
|
if (content == null) return null;
|
|
429
463
|
return Array.isArray(content) ? content : [content];
|
|
430
464
|
}
|
|
431
465
|
#replaceRange(key, start, nodes) {
|
|
432
|
-
const end = slotEnd(key);
|
|
433
466
|
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);
|
|
467
|
+
const end = eachInRange(start, key, n => parent.removeChild(n));
|
|
468
|
+
for (const node of nodes) parent.insertBefore(node, end);
|
|
441
469
|
}
|
|
442
470
|
#unmountSlot(key) {
|
|
443
471
|
this.#mountedSlots.delete(key);
|
|
@@ -449,9 +477,7 @@ class FrameImpl {
|
|
|
449
477
|
this.#runSlotCleanups(key);
|
|
450
478
|
const regions = this.#slotRegions.get(key);
|
|
451
479
|
if (regions) {
|
|
452
|
-
|
|
453
|
-
frame
|
|
454
|
-
} of regions.values()) frame?.dispose();
|
|
480
|
+
disposeRegions(regions);
|
|
455
481
|
this.#slotRegions.delete(key);
|
|
456
482
|
}
|
|
457
483
|
}
|
|
@@ -461,15 +487,26 @@ class FrameImpl {
|
|
|
461
487
|
this.#slotCleanups.delete(key);
|
|
462
488
|
for (const fn of cleanups) fn();
|
|
463
489
|
}
|
|
490
|
+
#refsUnresolved(args) {
|
|
491
|
+
const {
|
|
492
|
+
host,
|
|
493
|
+
id
|
|
494
|
+
} = this.#options;
|
|
495
|
+
if (host) for (const key in args) {
|
|
496
|
+
if (isDataRef(args[key]) && host.resolve(args[key], id) === undefined) return true;
|
|
497
|
+
}
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
#regionsFor(slotKey) {
|
|
501
|
+
let regions = this.#slotRegions.get(slotKey);
|
|
502
|
+
if (!regions) this.#slotRegions.set(slotKey, regions = new Map());
|
|
503
|
+
return regions;
|
|
504
|
+
}
|
|
464
505
|
#resolveArgs(slotKey, args) {
|
|
465
506
|
const host = this.#options.host;
|
|
466
|
-
|
|
467
|
-
if (!regions) {
|
|
468
|
-
regions = new Map();
|
|
469
|
-
this.#slotRegions.set(slotKey, regions);
|
|
470
|
-
}
|
|
507
|
+
const regions = this.#regionsFor(slotKey);
|
|
471
508
|
const props = {};
|
|
472
|
-
for (const key
|
|
509
|
+
for (const key in args) {
|
|
473
510
|
const value = args[key];
|
|
474
511
|
if (isDataRef(value)) {
|
|
475
512
|
const resolved = host ? host.resolve(value, this.#options.id) : undefined;
|
|
@@ -492,24 +529,15 @@ class FrameImpl {
|
|
|
492
529
|
}
|
|
493
530
|
props[key] = entry.element;
|
|
494
531
|
} else {
|
|
495
|
-
props[key] = value;
|
|
532
|
+
props[key] = host && host.revive ? host.revive(value) : value;
|
|
496
533
|
}
|
|
497
534
|
}
|
|
498
535
|
return props;
|
|
499
536
|
}
|
|
500
537
|
#discoverRegions(slotKey, start) {
|
|
501
538
|
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
|
-
}
|
|
539
|
+
const regions = this.#regionsFor(slotKey);
|
|
540
|
+
eachInRange(start, slotKey, n => collectRegionElements(n, regions));
|
|
513
541
|
}
|
|
514
542
|
#refArgsUnchanged(occurrence, record) {
|
|
515
543
|
const old = this.#slotArgs.get(occurrence);
|
|
@@ -525,11 +553,15 @@ class FrameImpl {
|
|
|
525
553
|
const va = a[key];
|
|
526
554
|
const vb = b[key];
|
|
527
555
|
if (va === vb) continue;
|
|
528
|
-
if (
|
|
529
|
-
if (
|
|
530
|
-
if (typeof va.$ref === "string" && typeof vb.$ref === "string" && cache && key in cache) {
|
|
556
|
+
if (isFrameRef(va) && isFrameRef(vb)) continue;
|
|
557
|
+
if (isDataRef(va) && isDataRef(vb) && cache && key in cache) {
|
|
531
558
|
const host = this.#options.host;
|
|
532
559
|
const next = host ? host.resolve(vb, this.#options.id) : undefined;
|
|
560
|
+
if (host && host.isContainer && (host.isContainer(next) || host.isContainer(cache[key]))) {
|
|
561
|
+
if (next === cache[key]) continue;
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
if (isAsyncLike(next) || isAsyncLike(cache[key])) return false;
|
|
533
565
|
try {
|
|
534
566
|
if (JSON.stringify(next) === JSON.stringify(cache[key])) continue;
|
|
535
567
|
} catch (e) {
|
|
@@ -545,7 +577,7 @@ class FrameImpl {
|
|
|
545
577
|
if (!args) return;
|
|
546
578
|
const regions = this.#slotRegions.get(occurrence);
|
|
547
579
|
if (!regions) return;
|
|
548
|
-
for (const key
|
|
580
|
+
for (const key in args) {
|
|
549
581
|
const value = args[key];
|
|
550
582
|
if (!isFrameRef(value)) continue;
|
|
551
583
|
const entry = regions.get(key);
|
|
@@ -595,11 +627,8 @@ class FrameImpl {
|
|
|
595
627
|
this.#element.setAttribute(FRAME_ID_ATTR, id);
|
|
596
628
|
}
|
|
597
629
|
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
|
-
}
|
|
630
|
+
this.#appliedRootValue = undefined;
|
|
631
|
+
this.#resetStreamState(true);
|
|
603
632
|
if (host) host.register(id, this);
|
|
604
633
|
}
|
|
605
634
|
rebase() {
|
|
@@ -619,11 +648,7 @@ class FrameImpl {
|
|
|
619
648
|
}
|
|
620
649
|
for (const key of [...this.#slotCleanups.keys()]) this.#runSlotCleanups(key);
|
|
621
650
|
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
|
-
}
|
|
651
|
+
for (const regions of this.#slotRegions.values()) disposeRegions(regions);
|
|
627
652
|
this.#slotRegions.clear();
|
|
628
653
|
this.#mountedSlots.clear();
|
|
629
654
|
}
|
|
@@ -644,14 +669,40 @@ class FrameImpl {
|
|
|
644
669
|
if (ranges.size) for (const root of grafts) flushGrafts(root, ranges);
|
|
645
670
|
}
|
|
646
671
|
}
|
|
647
|
-
#
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
672
|
+
#applyHole(marker, html) {
|
|
673
|
+
if (!this.#hasContent) return false;
|
|
674
|
+
const open = findLiveTarget(this.#firstContent(), this.#end, n => n.nodeType === COMMENT_NODE && n.data === marker);
|
|
675
|
+
if (!open) return false;
|
|
676
|
+
const close = rangeClose(open, "lh:/" + marker.slice(3));
|
|
677
|
+
if (!close) {
|
|
678
|
+
{
|
|
679
|
+
console.error(`Live hole "${marker}" is missing its closing comment; update dropped. ` + `Likely an HTML-rewriting layer stripped it.`, open);
|
|
680
|
+
}
|
|
681
|
+
return false;
|
|
682
|
+
}
|
|
683
|
+
const claim = claimHandlers() ? this.#claimTree : null;
|
|
684
|
+
reconcileChildren(open.parentNode, parseFragment(html), open, close, claim);
|
|
685
|
+
return true;
|
|
686
|
+
}
|
|
687
|
+
#applyAttrs(addr, text, removed) {
|
|
688
|
+
if (!this.#hasContent) return false;
|
|
689
|
+
const el = findLiveTarget(this.#firstContent(), this.#end, n => n.nodeType === ELEMENT_NODE && n.getAttribute("data-lha") === addr);
|
|
690
|
+
if (!el) return false;
|
|
691
|
+
const parsed = parseFragment(`<i${text}></i>`).firstChild;
|
|
692
|
+
if (parsed) {
|
|
693
|
+
for (let i = 0; i < parsed.attributes.length; i++) {
|
|
694
|
+
const {
|
|
695
|
+
name,
|
|
696
|
+
value
|
|
697
|
+
} = parsed.attributes[i];
|
|
698
|
+
if (el.getAttribute(name) !== value) el.setAttribute(name, value);
|
|
699
|
+
}
|
|
654
700
|
}
|
|
701
|
+
if (removed) for (const name of removed) el.removeAttribute(name);
|
|
702
|
+
return true;
|
|
703
|
+
}
|
|
704
|
+
#clearContent() {
|
|
705
|
+
removeUntil(this.#parent(), this.#firstContent(), this.#end);
|
|
655
706
|
}
|
|
656
707
|
#claimContent() {
|
|
657
708
|
if (!claimHandlers()) return;
|
|
@@ -668,9 +719,7 @@ class FrameImpl {
|
|
|
668
719
|
const assets = this.#store[`seg:${name}:assets`];
|
|
669
720
|
if (assets && assets.styles) {
|
|
670
721
|
let ready = true;
|
|
671
|
-
for (const entry of assets.styles)
|
|
672
|
-
if (!ensureStylesheet(entry, this.#styleFlush)) ready = false;
|
|
673
|
-
}
|
|
722
|
+
for (const entry of assets.styles) ready = ensureStylesheet(entry, this.#styleFlush) && ready;
|
|
674
723
|
if (!ready) return false;
|
|
675
724
|
}
|
|
676
725
|
if (!this.#findPlaceholder(name)) return false;
|
|
@@ -687,12 +736,7 @@ class FrameImpl {
|
|
|
687
736
|
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
737
|
}
|
|
689
738
|
const parent = tpl.parentNode;
|
|
690
|
-
|
|
691
|
-
while (n && n !== closing) {
|
|
692
|
-
const next = n.nextSibling;
|
|
693
|
-
parent.removeChild(n);
|
|
694
|
-
n = next;
|
|
695
|
-
}
|
|
739
|
+
removeUntil(parent, tpl.nextSibling, closing);
|
|
696
740
|
if (this.#options.reveal) {
|
|
697
741
|
const fallbackFrag = tpl.content.cloneNode(true);
|
|
698
742
|
this.#claimTree(fallbackFrag);
|
|
@@ -741,9 +785,7 @@ function createFrameElement(options) {
|
|
|
741
785
|
const frame = new FrameImpl(el, null, null, options);
|
|
742
786
|
return {
|
|
743
787
|
element: el,
|
|
744
|
-
|
|
745
|
-
return frame;
|
|
746
|
-
},
|
|
788
|
+
frame,
|
|
747
789
|
dispose() {
|
|
748
790
|
frame.dispose();
|
|
749
791
|
el.remove();
|
|
@@ -763,15 +805,30 @@ function segmentName(key) {
|
|
|
763
805
|
const m = /^seg:([^:]+)$/.exec(key);
|
|
764
806
|
return m ? m[1] : null;
|
|
765
807
|
}
|
|
808
|
+
function isAsyncLike(v) {
|
|
809
|
+
return !!v && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
|
|
810
|
+
}
|
|
766
811
|
function propOf(occurrence) {
|
|
767
812
|
const hash = occurrence.indexOf("#");
|
|
768
813
|
return hash === -1 ? occurrence : occurrence.slice(0, hash);
|
|
769
814
|
}
|
|
770
815
|
function isDataRef(value) {
|
|
771
|
-
return
|
|
816
|
+
return !!value && typeof value.$ref === "string";
|
|
772
817
|
}
|
|
773
818
|
function isFrameRef(value) {
|
|
774
|
-
return
|
|
819
|
+
return !!value && typeof value.$frame === "string";
|
|
820
|
+
}
|
|
821
|
+
function disposeRegions(regions) {
|
|
822
|
+
for (const {
|
|
823
|
+
frame
|
|
824
|
+
} of regions.values()) frame?.dispose();
|
|
825
|
+
}
|
|
826
|
+
function removeUntil(parent, n, stop) {
|
|
827
|
+
while (n && n !== stop) {
|
|
828
|
+
const next = n.nextSibling;
|
|
829
|
+
parent.removeChild(n);
|
|
830
|
+
n = next;
|
|
831
|
+
}
|
|
775
832
|
}
|
|
776
833
|
function parseFragment(html) {
|
|
777
834
|
const template = document.createElement("template");
|
|
@@ -779,9 +836,8 @@ function parseFragment(html) {
|
|
|
779
836
|
return template.content;
|
|
780
837
|
}
|
|
781
838
|
function findHeadElement(selector, attr, value) {
|
|
782
|
-
const
|
|
783
|
-
|
|
784
|
-
if (nodes[i].getAttribute(attr) === value) return nodes[i];
|
|
839
|
+
for (const node of document.head.querySelectorAll(selector)) {
|
|
840
|
+
if (node.getAttribute(attr) === value) return node;
|
|
785
841
|
}
|
|
786
842
|
return null;
|
|
787
843
|
}
|
|
@@ -830,7 +886,7 @@ function applyInlineStyles(inlineStyles) {
|
|
|
830
886
|
}
|
|
831
887
|
}
|
|
832
888
|
function isPlaceholderStart(node, id) {
|
|
833
|
-
return node.
|
|
889
|
+
return node.tagName === "TEMPLATE" && node.id === id;
|
|
834
890
|
}
|
|
835
891
|
function rangeClose(start, id) {
|
|
836
892
|
let n = start.nextSibling;
|
|
@@ -840,6 +896,20 @@ function rangeClose(start, id) {
|
|
|
840
896
|
}
|
|
841
897
|
return null;
|
|
842
898
|
}
|
|
899
|
+
function findLiveTarget(n, end, test) {
|
|
900
|
+
while (n && n !== end) {
|
|
901
|
+
if (n.nodeType === ELEMENT_NODE) {
|
|
902
|
+
const fid = isFrameElement(n) ? n.getAttribute(FRAME_ID_ATTR) : null;
|
|
903
|
+
if (fid === null || fid.includes(".")) {
|
|
904
|
+
if (test(n)) return n;
|
|
905
|
+
const found = findLiveTarget(n.firstChild, null, test);
|
|
906
|
+
if (found) return found;
|
|
907
|
+
}
|
|
908
|
+
} else if (test(n)) return n;
|
|
909
|
+
n = n.nextSibling;
|
|
910
|
+
}
|
|
911
|
+
return null;
|
|
912
|
+
}
|
|
843
913
|
function findPlaceholder(n, end, id) {
|
|
844
914
|
while (n && n !== end) {
|
|
845
915
|
if (isPlaceholderStart(n, id)) return n;
|
|
@@ -887,6 +957,23 @@ function renameRegion(entry, childId) {
|
|
|
887
957
|
entry.childId = childId;
|
|
888
958
|
if (entry.frame) entry.frame.rebind(childId);else entry.element.setAttribute(FRAME_ID_ATTR, childId);
|
|
889
959
|
}
|
|
960
|
+
function eachInRange(start, key, cb) {
|
|
961
|
+
const end = slotEnd(key);
|
|
962
|
+
let n = start.nextSibling;
|
|
963
|
+
while (n && !(n.nodeType === COMMENT_NODE && n.data === end)) {
|
|
964
|
+
const next = n.nextSibling;
|
|
965
|
+
cb(n);
|
|
966
|
+
n = next;
|
|
967
|
+
}
|
|
968
|
+
return n;
|
|
969
|
+
}
|
|
970
|
+
function clearStreamRecords(records, root) {
|
|
971
|
+
for (const key in records) {
|
|
972
|
+
if (/^(seg|hole|attr):/.test(key) || key === ":error" || root && key === "") {
|
|
973
|
+
delete records[key];
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
}
|
|
890
977
|
function argsEquivalent(a, b) {
|
|
891
978
|
if (a === b) return true;
|
|
892
979
|
if (!a || !b) return false;
|
|
@@ -897,9 +984,7 @@ function argsEquivalent(a, b) {
|
|
|
897
984
|
const va = a[key];
|
|
898
985
|
const vb = b[key];
|
|
899
986
|
if (va === vb) continue;
|
|
900
|
-
if (va &&
|
|
901
|
-
continue;
|
|
902
|
-
}
|
|
987
|
+
if (isFrameRef(va) && va.$frame === vb?.$frame) continue;
|
|
903
988
|
return false;
|
|
904
989
|
}
|
|
905
990
|
return true;
|
|
@@ -1151,6 +1236,7 @@ async function applyFrameResponse(response, host, options = {}) {
|
|
|
1151
1236
|
if (v === undefined) perFrame.set(chunk.id, v = version(chunk.id));
|
|
1152
1237
|
chunk.version = v;
|
|
1153
1238
|
} else if (version !== undefined) chunk.version = version;
|
|
1239
|
+
if (chunk.type === "data" && host.prepareData) await host.prepareData();
|
|
1154
1240
|
host.apply(chunk);
|
|
1155
1241
|
}
|
|
1156
1242
|
result = await reader.next();
|
|
@@ -1167,7 +1253,7 @@ function parseServerComponent(value, ctx) {
|
|
|
1167
1253
|
address: ctx.parse(value[SERVER_COMPONENT_ADDRESS])
|
|
1168
1254
|
};
|
|
1169
1255
|
}
|
|
1170
|
-
const ServerComponentPlugin =
|
|
1256
|
+
const ServerComponentPlugin = {
|
|
1171
1257
|
tag: "dom-expressions/server-component",
|
|
1172
1258
|
test(value) {
|
|
1173
1259
|
return typeof value === "function" && SERVER_COMPONENT in value;
|
|
@@ -1194,12 +1280,10 @@ const ServerComponentPlugin = /*#__PURE__*/createPlugin({
|
|
|
1194
1280
|
}
|
|
1195
1281
|
return globalThis._$SC.r(id);
|
|
1196
1282
|
}
|
|
1197
|
-
}
|
|
1283
|
+
};
|
|
1198
1284
|
function flightCodec(codec) {
|
|
1199
1285
|
const plugins = codec && codec.plugins || [];
|
|
1200
|
-
|
|
1201
|
-
if (plugin && plugin.tag === "dom-expressions/server-component") return codec;
|
|
1202
|
-
}
|
|
1286
|
+
if (plugins.some(plugin => plugin && plugin.tag === ServerComponentPlugin.tag)) return codec;
|
|
1203
1287
|
return {
|
|
1204
1288
|
...codec,
|
|
1205
1289
|
plugins: [...plugins, ServerComponentPlugin]
|
|
@@ -1271,7 +1355,7 @@ function createServerComponentHandler({
|
|
|
1271
1355
|
showing(address, functionId) {
|
|
1272
1356
|
bindingFor(address, functionId);
|
|
1273
1357
|
const comp = componentFor(functionId);
|
|
1274
|
-
if ((typeof comp === "function" || typeof comp === "object"
|
|
1358
|
+
if (comp && (typeof comp === "function" || typeof comp === "object") && !comp[COMPONENT_BINDING]) {
|
|
1275
1359
|
comp[COMPONENT_BINDING] = {
|
|
1276
1360
|
component: comp,
|
|
1277
1361
|
address
|
|
@@ -1316,69 +1400,74 @@ function createServerComponentHandler({
|
|
|
1316
1400
|
}
|
|
1317
1401
|
}
|
|
1318
1402
|
|
|
1319
|
-
|
|
1320
|
-
const
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
const JSON_CODEC_DISABLED_FEATURES = Feature.RegExp;
|
|
1327
|
-
const JSON_CODEC_DEPTH_LIMIT = 64;
|
|
1328
|
-
function resolveCodecOptions({
|
|
1329
|
-
plugins,
|
|
1330
|
-
disabledFeatures,
|
|
1331
|
-
depthLimit
|
|
1332
|
-
} = {}) {
|
|
1333
|
-
return {
|
|
1334
|
-
plugins: resolveSerializerPlugins(plugins),
|
|
1335
|
-
disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
|
|
1336
|
-
depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
|
|
1337
|
-
};
|
|
1403
|
+
const STATE = Symbol.for("dom-expressions.container-trace-state");
|
|
1404
|
+
const state = globalThis[STATE] || (globalThis[STATE] = {
|
|
1405
|
+
materialized: new WeakMap(),
|
|
1406
|
+
materializedValues: new WeakSet()
|
|
1407
|
+
});
|
|
1408
|
+
function setContainerTraceMaterializer(fn) {
|
|
1409
|
+
state.materializeTrace = fn;
|
|
1338
1410
|
}
|
|
1339
|
-
function
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
};
|
|
1411
|
+
function materialize(marker) {
|
|
1412
|
+
let value = state.materialized.get(marker.$tr);
|
|
1413
|
+
if (value === undefined) {
|
|
1414
|
+
value = state.materializeTrace(marker);
|
|
1415
|
+
state.materialized.set(marker.$tr, value);
|
|
1416
|
+
if (value !== null && typeof value === "object") state.materializedValues.add(value);
|
|
1417
|
+
}
|
|
1418
|
+
return value;
|
|
1348
1419
|
}
|
|
1349
|
-
function
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1420
|
+
function isMaterializedContainer(value) {
|
|
1421
|
+
return value !== null && typeof value === "object" && state.materializedValues.has(value);
|
|
1422
|
+
}
|
|
1423
|
+
function isContainerTraceMarker(value) {
|
|
1424
|
+
return value != null && typeof value === "object" && value.$tr != null && typeof value.$tr[Symbol.asyncIterator] === "function";
|
|
1425
|
+
}
|
|
1426
|
+
function reviveContainerTraces(value) {
|
|
1427
|
+
if (!state.materializeTrace || value == null || typeof value !== "object") return value;
|
|
1428
|
+
if (isContainerTraceMarker(value)) return materialize(value);
|
|
1429
|
+
if (Array.isArray(value)) {
|
|
1430
|
+
for (let i = 0; i < value.length; i++) value[i] = reviveContainerTraces(value[i]);
|
|
1431
|
+
} else if (Object.getPrototypeOf(value) === Object.prototype) {
|
|
1432
|
+
for (const key of Object.keys(value)) value[key] = reviveContainerTraces(value[key]);
|
|
1433
|
+
}
|
|
1434
|
+
return value;
|
|
1364
1435
|
}
|
|
1365
1436
|
|
|
1437
|
+
setContainerTraceMaterializer(materializeContainerTrace);
|
|
1438
|
+
function asyncArg(value) {
|
|
1439
|
+
return value;
|
|
1440
|
+
}
|
|
1366
1441
|
let sharedHost;
|
|
1442
|
+
let codec;
|
|
1443
|
+
let codecLoading;
|
|
1444
|
+
function loadCodec() {
|
|
1445
|
+
return codecLoading ??= import('@solidjs/web/serialization/decode').then(m => {
|
|
1446
|
+
codec = m;
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1367
1449
|
const tables = new Map();
|
|
1450
|
+
function ensureTable(root) {
|
|
1451
|
+
let table = tables.get(root);
|
|
1452
|
+
if (!table && codec) tables.set(root, table = codec.createJSONDataTable());
|
|
1453
|
+
return table;
|
|
1454
|
+
}
|
|
1368
1455
|
function tableFor(id) {
|
|
1369
|
-
|
|
1370
|
-
if (
|
|
1371
|
-
for (const [root, t] of tables) if (id.startsWith(root + ".")) return t;
|
|
1456
|
+
if (tables.has(id)) return ensureTable(id);
|
|
1457
|
+
for (const root of tables.keys()) if (id.startsWith(root + ".")) return ensureTable(root);
|
|
1372
1458
|
return undefined;
|
|
1373
1459
|
}
|
|
1374
1460
|
function beginStream(frameId) {
|
|
1375
|
-
tables.set(frameId,
|
|
1461
|
+
tables.set(frameId, undefined);
|
|
1376
1462
|
}
|
|
1377
1463
|
function getFrameHost() {
|
|
1378
1464
|
if (!sharedHost) {
|
|
1379
1465
|
sharedHost = createFrameHost({
|
|
1466
|
+
prepareData: loadCodec,
|
|
1380
1467
|
applyData: c => tableFor(c.id)?.apply(c),
|
|
1381
|
-
resolve: (ref, id) => tableFor(id)?.resolve(ref)
|
|
1468
|
+
resolve: (ref, id) => tableFor(id)?.resolve(ref),
|
|
1469
|
+
revive: reviveContainerTraces,
|
|
1470
|
+
isContainer: isMaterializedContainer
|
|
1382
1471
|
});
|
|
1383
1472
|
}
|
|
1384
1473
|
return sharedHost;
|
|
@@ -1439,8 +1528,27 @@ function claimRender(prefix, existing, render) {
|
|
|
1439
1528
|
function liveSlotProps(initial, ctx) {
|
|
1440
1529
|
const [args, setArgs] = createSignal(initial);
|
|
1441
1530
|
ctx.onUpdate(next => setArgs(() => next));
|
|
1531
|
+
return slotArgsProxy(args);
|
|
1532
|
+
}
|
|
1533
|
+
function isAsyncValue(v) {
|
|
1534
|
+
return v !== null && typeof v === "object" && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
|
|
1535
|
+
}
|
|
1536
|
+
function slotArgsProxy(args) {
|
|
1537
|
+
const owner = getOwner();
|
|
1538
|
+
const asyncReads = new Map();
|
|
1442
1539
|
return new Proxy({}, {
|
|
1443
|
-
get: (_, key) =>
|
|
1540
|
+
get: (_, key) => {
|
|
1541
|
+
const v = args()[key];
|
|
1542
|
+
if (isMaterializedContainer(v)) return v;
|
|
1543
|
+
if (!isAsyncValue(v)) return v;
|
|
1544
|
+
let read = asyncReads.get(key);
|
|
1545
|
+
if (!read) {
|
|
1546
|
+
const make = () => createMemo(() => args()[key]);
|
|
1547
|
+
read = owner ? runWithOwner(owner, make) : make();
|
|
1548
|
+
asyncReads.set(key, read);
|
|
1549
|
+
}
|
|
1550
|
+
return read();
|
|
1551
|
+
},
|
|
1444
1552
|
has: (_, key) => key in args(),
|
|
1445
1553
|
ownKeys: () => Reflect.ownKeys(args()),
|
|
1446
1554
|
getOwnPropertyDescriptor: (_, key) => key in args() ? {
|
|
@@ -1458,6 +1566,7 @@ function isReactiveContent(value) {
|
|
|
1458
1566
|
}
|
|
1459
1567
|
function slotsFor(props) {
|
|
1460
1568
|
const bindings = new Map();
|
|
1569
|
+
const fillScopes = new Map();
|
|
1461
1570
|
return new Proxy({}, {
|
|
1462
1571
|
get(_, prop) {
|
|
1463
1572
|
if (typeof prop !== "string" || !(prop in props)) return undefined;
|
|
@@ -1468,6 +1577,19 @@ function slotsFor(props) {
|
|
|
1468
1577
|
bindings.delete(key);
|
|
1469
1578
|
prev.dispose();
|
|
1470
1579
|
}
|
|
1580
|
+
const prevFill = key !== undefined && fillScopes.get(key);
|
|
1581
|
+
if (prevFill) {
|
|
1582
|
+
fillScopes.delete(key);
|
|
1583
|
+
prevFill.dispose();
|
|
1584
|
+
}
|
|
1585
|
+
const fillOwner = streamInvoke ? createOwner() : null;
|
|
1586
|
+
if (fillOwner && key !== undefined && ctx) {
|
|
1587
|
+
fillScopes.set(key, fillOwner);
|
|
1588
|
+
ctx.onCleanup(() => {
|
|
1589
|
+
if (fillScopes.get(key) === fillOwner) fillScopes.delete(key);
|
|
1590
|
+
fillOwner.dispose();
|
|
1591
|
+
});
|
|
1592
|
+
}
|
|
1471
1593
|
const settle = out => {
|
|
1472
1594
|
const existing = ctx && ctx.existing || [];
|
|
1473
1595
|
if (existing.length) {
|
|
@@ -1480,13 +1602,13 @@ function slotsFor(props) {
|
|
|
1480
1602
|
const evaluate = () => {
|
|
1481
1603
|
const v = props[prop];
|
|
1482
1604
|
if (typeof v === "function" && ctx && ctx.invoked) {
|
|
1483
|
-
return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotProps);
|
|
1605
|
+
return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotArgsProxy(() => slotProps));
|
|
1484
1606
|
}
|
|
1485
1607
|
return v;
|
|
1486
1608
|
};
|
|
1487
1609
|
const adopted = !!(ctx && ctx.frame && ctx.adopted && ctx.existing && ctx.existing.length);
|
|
1488
1610
|
const prefix = ctx && ctx.frame ? `sc-${ctx.frame}-${ctx.key}-` : "";
|
|
1489
|
-
const value = adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
|
|
1611
|
+
const value = fillOwner ? runWithOwner(fillOwner, () => adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate()) : adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
|
|
1490
1612
|
if (!isReactiveContent(value)) {
|
|
1491
1613
|
return settle(normalizeSlotContent(value));
|
|
1492
1614
|
}
|
|
@@ -1511,32 +1633,82 @@ function slotsFor(props) {
|
|
|
1511
1633
|
function revealSeam(owner) {
|
|
1512
1634
|
return seam => runWithOwner(owner, () => insert(seam.before.parentNode, createLoadingBoundary(() => seam.content(), () => seam.fallback), seam.before));
|
|
1513
1635
|
}
|
|
1636
|
+
let streamInvoke = false;
|
|
1514
1637
|
function boundaryScope(owner) {
|
|
1515
|
-
return fn =>
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1638
|
+
return fn => {
|
|
1639
|
+
if (getOwner()) return fn();
|
|
1640
|
+
streamInvoke = true;
|
|
1641
|
+
try {
|
|
1642
|
+
return runWithOwner(owner, fn);
|
|
1643
|
+
} finally {
|
|
1644
|
+
streamInvoke = false;
|
|
1645
|
+
}
|
|
1646
|
+
};
|
|
1519
1647
|
}
|
|
1520
1648
|
function boundaryComponent(host, fnId) {
|
|
1521
1649
|
return (props, binding) => {
|
|
1522
1650
|
const owner = getOwner();
|
|
1651
|
+
const id = binding ? binding() : fnId;
|
|
1652
|
+
let applied = !tables.has(id);
|
|
1653
|
+
let release;
|
|
1654
|
+
const arm = () => new Promise(r => release = r);
|
|
1655
|
+
const mountGate = applied ? undefined : arm();
|
|
1656
|
+
let setGate;
|
|
1523
1657
|
const {
|
|
1524
1658
|
element,
|
|
1525
1659
|
frame,
|
|
1526
1660
|
dispose
|
|
1527
1661
|
} = createFrameElement({
|
|
1528
1662
|
host,
|
|
1529
|
-
id
|
|
1663
|
+
id,
|
|
1530
1664
|
slots: slotsFor(props),
|
|
1531
1665
|
ownerScope: boundaryScope(owner),
|
|
1532
|
-
reveal: revealSeam(owner)
|
|
1666
|
+
reveal: revealSeam(owner),
|
|
1667
|
+
onApply: () => {
|
|
1668
|
+
applied = true;
|
|
1669
|
+
if (release) {
|
|
1670
|
+
release();
|
|
1671
|
+
release = undefined;
|
|
1672
|
+
}
|
|
1673
|
+
setGate && setGate(undefined);
|
|
1674
|
+
}
|
|
1533
1675
|
});
|
|
1534
|
-
|
|
1676
|
+
const [gatePromise, setGatePromise] = createSignal(applied ? undefined : mountGate);
|
|
1677
|
+
setGate = setGatePromise;
|
|
1678
|
+
if (binding) {
|
|
1679
|
+
createRenderEffect(binding, (address, prev) => {
|
|
1680
|
+
if (prev !== undefined && address !== prev && tables.has(address)) {
|
|
1681
|
+
applied = false;
|
|
1682
|
+
setGatePromise(arm());
|
|
1683
|
+
}
|
|
1684
|
+
frame.rebind(address);
|
|
1685
|
+
});
|
|
1686
|
+
}
|
|
1535
1687
|
onCleanup(dispose);
|
|
1536
|
-
return element;
|
|
1688
|
+
if (applied && !binding) return element;
|
|
1689
|
+
const gate = createMemo(() => gatePromise());
|
|
1690
|
+
return createMemo(() => (gate(), element));
|
|
1537
1691
|
};
|
|
1538
1692
|
}
|
|
1539
1693
|
const claimedBoundaries = new Set();
|
|
1694
|
+
const liveOps = new Map();
|
|
1695
|
+
const liveAppliers = new Set();
|
|
1696
|
+
let livePumped = null;
|
|
1697
|
+
function pumpLiveChannel() {
|
|
1698
|
+
const stream = globalThis._$HY?.r?.["sc:live"];
|
|
1699
|
+
if (!stream || stream === livePumped || typeof stream.getReader !== "function") return;
|
|
1700
|
+
livePumped = stream;
|
|
1701
|
+
const reader = stream.getReader();
|
|
1702
|
+
const pump = () => reader.read().then(r => {
|
|
1703
|
+
if (r.done) return;
|
|
1704
|
+
const op = r.value;
|
|
1705
|
+
liveOps.set(`${op.type}:${op.fid || ""}:${op.key || ""}`, op);
|
|
1706
|
+
for (const apply of liveAppliers) apply(op);
|
|
1707
|
+
return pump();
|
|
1708
|
+
});
|
|
1709
|
+
pump().catch(() => {
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1540
1712
|
let boundaryIndex = null;
|
|
1541
1713
|
const isBoundaryId = id => !id.includes(".");
|
|
1542
1714
|
function indexBoundaries(root) {
|
|
@@ -1601,9 +1773,21 @@ function adoptBoundary(host, id, el, props, binding) {
|
|
|
1601
1773
|
claimedBoundaries.add(id);
|
|
1602
1774
|
const address = binding ? binding() : documentAddress(id);
|
|
1603
1775
|
const appliedRecords = new Set();
|
|
1776
|
+
const claimedFragments = new Set();
|
|
1777
|
+
const claimRegionFragments = root => {
|
|
1778
|
+
const fr = globalThis._$HY?.fr;
|
|
1779
|
+
if (!fr || !fr.claim) return;
|
|
1780
|
+
root.querySelectorAll('template[id^="pl-"]').forEach(tpl => {
|
|
1781
|
+
const fragId = tpl.id.slice(3);
|
|
1782
|
+
if (claimedFragments.has(fragId)) return;
|
|
1783
|
+
claimedFragments.add(fragId);
|
|
1784
|
+
fr.claim(fragId);
|
|
1785
|
+
});
|
|
1786
|
+
};
|
|
1604
1787
|
const drainRecords = () => {
|
|
1605
1788
|
const hy = globalThis._$HY;
|
|
1606
1789
|
if (!hy || !hy.r) return;
|
|
1790
|
+
pumpLiveChannel();
|
|
1607
1791
|
const slotPrefix = `sc:slot:${id}:`;
|
|
1608
1792
|
for (const key of Object.keys(hy.r)) {
|
|
1609
1793
|
if (appliedRecords.has(key)) continue;
|
|
@@ -1632,8 +1816,31 @@ function adoptBoundary(host, id, el, props, binding) {
|
|
|
1632
1816
|
}
|
|
1633
1817
|
}
|
|
1634
1818
|
};
|
|
1819
|
+
claimRegionFragments(el);
|
|
1820
|
+
const fr = globalThis._$HY?.fr;
|
|
1821
|
+
const unsubscribe = fr ? fr.subscribe((_fragId, parent) => {
|
|
1822
|
+
if (fr.claim && parent && el.contains(parent)) claimRegionFragments(parent);
|
|
1823
|
+
drainRecords();
|
|
1824
|
+
}) : undefined;
|
|
1825
|
+
const applyLiveOp = op => {
|
|
1826
|
+
if (op.type === "slot" && op.fid !== id) return;
|
|
1827
|
+
host.apply({
|
|
1828
|
+
...op,
|
|
1829
|
+
id: address,
|
|
1830
|
+
version: 0
|
|
1831
|
+
});
|
|
1832
|
+
};
|
|
1833
|
+
liveAppliers.add(applyLiveOp);
|
|
1834
|
+
onCleanup(() => {
|
|
1835
|
+
liveAppliers.delete(applyLiveOp);
|
|
1836
|
+
unsubscribe && unsubscribe();
|
|
1837
|
+
if (fr && fr.release) for (const fragId of claimedFragments) fr.release(fragId);
|
|
1838
|
+
});
|
|
1635
1839
|
drainRecords();
|
|
1840
|
+
for (const op of liveOps.values()) applyLiveOp(op);
|
|
1636
1841
|
const owner = getOwner();
|
|
1842
|
+
let release;
|
|
1843
|
+
let setGate;
|
|
1637
1844
|
const frame = createFrame(el, {
|
|
1638
1845
|
adopt: true,
|
|
1639
1846
|
host,
|
|
@@ -1641,6 +1848,13 @@ function adoptBoundary(host, id, el, props, binding) {
|
|
|
1641
1848
|
slots: slotsFor(props),
|
|
1642
1849
|
ownerScope: boundaryScope(owner),
|
|
1643
1850
|
reveal: revealSeam(owner),
|
|
1851
|
+
onApply: () => {
|
|
1852
|
+
if (release) {
|
|
1853
|
+
release();
|
|
1854
|
+
release = undefined;
|
|
1855
|
+
}
|
|
1856
|
+
setGate && setGate(undefined);
|
|
1857
|
+
},
|
|
1644
1858
|
...{
|
|
1645
1859
|
recordsPending: () => {
|
|
1646
1860
|
if (document.readyState === "loading") return true;
|
|
@@ -1651,7 +1865,19 @@ function adoptBoundary(host, id, el, props, binding) {
|
|
|
1651
1865
|
claimScope: id
|
|
1652
1866
|
}
|
|
1653
1867
|
});
|
|
1654
|
-
if (binding)
|
|
1868
|
+
if (binding) {
|
|
1869
|
+
const arm = () => new Promise(r => release = r);
|
|
1870
|
+
const [gatePromise, setGatePromise] = createSignal(undefined);
|
|
1871
|
+
setGate = setGatePromise;
|
|
1872
|
+
const gate = createMemo(() => gatePromise());
|
|
1873
|
+
createRenderEffect(binding, (address, prev) => {
|
|
1874
|
+
if (prev !== undefined && address !== prev && tables.has(address)) {
|
|
1875
|
+
setGatePromise(arm());
|
|
1876
|
+
}
|
|
1877
|
+
frame.rebind(address);
|
|
1878
|
+
});
|
|
1879
|
+
createRenderEffect(() => (gate(), undefined), () => {});
|
|
1880
|
+
}
|
|
1655
1881
|
onCleanup(() => frame.dispose());
|
|
1656
1882
|
return el;
|
|
1657
1883
|
}
|
|
@@ -1692,4 +1918,4 @@ function installServerComponents(host = getFrameHost()) {
|
|
|
1692
1918
|
});
|
|
1693
1919
|
}
|
|
1694
1920
|
|
|
1695
|
-
export { FRAME_APPLIED_EVENT, FRAME_STREAM_HEADER, applyFrameResponse, createFrame, createFrameElement, createFrameHost,
|
|
1921
|
+
export { FRAME_APPLIED_EVENT, FRAME_STREAM_HEADER, applyFrameResponse, asyncArg, createFrame, createFrameElement, createFrameHost, createServerComponentHandler, getFrameHost, installServerComponents, isFrameStreamResponse };
|