@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,10 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var solidJs = require('solid-js');
|
|
4
|
-
var web
|
|
5
|
-
var seroval = require('seroval');
|
|
4
|
+
var web = require('@solidjs/web');
|
|
6
5
|
var client = require('@solidjs/web/server-functions/client');
|
|
7
|
-
var web = require('seroval-plugins/web');
|
|
8
6
|
|
|
9
7
|
const ELEMENT_NODE = 1;
|
|
10
8
|
const TEXT_NODE = 3;
|
|
@@ -67,16 +65,32 @@ function chunkToRecords(chunk) {
|
|
|
67
65
|
args: chunk.args
|
|
68
66
|
}
|
|
69
67
|
};
|
|
68
|
+
case "hole":
|
|
69
|
+
return {
|
|
70
|
+
[`hole:${chunk.key}`]: {
|
|
71
|
+
kind: "html",
|
|
72
|
+
value: chunk.html
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
case "attr":
|
|
76
|
+
return {
|
|
77
|
+
[`attr:${chunk.key}`]: {
|
|
78
|
+
kind: "attrs",
|
|
79
|
+
value: chunk.attrs,
|
|
80
|
+
removed: chunk.removed
|
|
81
|
+
}
|
|
82
|
+
};
|
|
70
83
|
case "complete":
|
|
71
84
|
return {
|
|
72
85
|
":complete": true
|
|
73
86
|
};
|
|
74
87
|
case "error":
|
|
75
|
-
|
|
76
|
-
[`seg:${chunk.key}:error`]: chunk.error
|
|
77
|
-
} : {
|
|
88
|
+
if (!chunk.key) return {
|
|
78
89
|
":error": chunk.error
|
|
79
90
|
};
|
|
91
|
+
return {
|
|
92
|
+
[`${/^lha?:/.test(chunk.key) ? "hole" : "seg"}:${chunk.key}:error`]: chunk.error
|
|
93
|
+
};
|
|
80
94
|
default:
|
|
81
95
|
return {};
|
|
82
96
|
}
|
|
@@ -96,9 +110,7 @@ function createFrameHost(options = {}) {
|
|
|
96
110
|
if (store.version !== undefined && version < store.version) return false;
|
|
97
111
|
if (store.version === undefined || version > store.version) {
|
|
98
112
|
store.version = version;
|
|
99
|
-
|
|
100
|
-
if (key.startsWith("seg:") || key === ":error") delete store.records[key];
|
|
101
|
-
}
|
|
113
|
+
clearStreamRecords(store.records);
|
|
102
114
|
}
|
|
103
115
|
Object.assign(store.records, records);
|
|
104
116
|
return true;
|
|
@@ -163,7 +175,10 @@ function createFrameHost(options = {}) {
|
|
|
163
175
|
},
|
|
164
176
|
resolve(ref, frameId) {
|
|
165
177
|
return options.resolve ? options.resolve(ref, frameId) : undefined;
|
|
166
|
-
}
|
|
178
|
+
},
|
|
179
|
+
revive: options.revive,
|
|
180
|
+
isContainer: options.isContainer,
|
|
181
|
+
prepareData: options.prepareData
|
|
167
182
|
};
|
|
168
183
|
}
|
|
169
184
|
const FRAME_APPLIED_EVENT = "frame:applied";
|
|
@@ -176,8 +191,10 @@ class FrameImpl {
|
|
|
176
191
|
#store = Object.create(null);
|
|
177
192
|
#appliedRootValue;
|
|
178
193
|
#hasContent = false;
|
|
194
|
+
#errorNotified = false;
|
|
179
195
|
#revealed = new Set();
|
|
180
196
|
#fallbackShown = new Set();
|
|
197
|
+
#appliedHoles = new Map();
|
|
181
198
|
#slots;
|
|
182
199
|
#mountedSlots = new Set();
|
|
183
200
|
#slotCleanups = new Map();
|
|
@@ -195,10 +212,12 @@ class FrameImpl {
|
|
|
195
212
|
#claimTree = (node, direct) => {
|
|
196
213
|
const handlers = claimHandlers();
|
|
197
214
|
if (!handlers) return;
|
|
198
|
-
|
|
199
|
-
const scope = this.#options.ownerScope;
|
|
200
|
-
scope ? scope(run) : run();
|
|
215
|
+
this.#scoped(() => direct ? claimNode(handlers, node) : claimTree(handlers, node));
|
|
201
216
|
};
|
|
217
|
+
#scoped(fn) {
|
|
218
|
+
const scope = this.#options.ownerScope;
|
|
219
|
+
return scope ? scope(fn) : fn();
|
|
220
|
+
}
|
|
202
221
|
constructor(element, start, end, options = {}) {
|
|
203
222
|
this.#element = element;
|
|
204
223
|
this.#start = start;
|
|
@@ -259,15 +278,9 @@ class FrameImpl {
|
|
|
259
278
|
return;
|
|
260
279
|
} else if (v > this.#version) {
|
|
261
280
|
this.#version = v;
|
|
262
|
-
this.#
|
|
263
|
-
this.#fallbackShown.clear();
|
|
264
|
-
for (const key of Object.keys(this.#store)) {
|
|
265
|
-
if (key.startsWith("seg:") || key === ":error") {
|
|
266
|
-
delete this.#store[key];
|
|
267
|
-
}
|
|
268
|
-
}
|
|
281
|
+
this.#resetStreamState();
|
|
269
282
|
}
|
|
270
|
-
for (const key
|
|
283
|
+
for (const key in write.r) {
|
|
271
284
|
const incoming = write.r[key];
|
|
272
285
|
if (incoming && incoming.kind === "slot" && key.charCodeAt(0) === 115 && key.startsWith("slot:")) {
|
|
273
286
|
const existing = this.#store[key];
|
|
@@ -279,6 +292,13 @@ class FrameImpl {
|
|
|
279
292
|
}
|
|
280
293
|
this.#flush();
|
|
281
294
|
}
|
|
295
|
+
#resetStreamState(root) {
|
|
296
|
+
this.#revealed.clear();
|
|
297
|
+
this.#fallbackShown.clear();
|
|
298
|
+
this.#appliedHoles.clear();
|
|
299
|
+
this.#errorNotified = false;
|
|
300
|
+
clearStreamRecords(this.#store, root);
|
|
301
|
+
}
|
|
282
302
|
#flush() {
|
|
283
303
|
if (this.#disposed) return;
|
|
284
304
|
const version = this.#version;
|
|
@@ -289,10 +309,14 @@ class FrameImpl {
|
|
|
289
309
|
this.#appliedRootValue = root.value;
|
|
290
310
|
this.#applied(version, reason);
|
|
291
311
|
}
|
|
312
|
+
if (this.#store[":error"] && !this.#errorNotified) {
|
|
313
|
+
this.#errorNotified = true;
|
|
314
|
+
this.#applied(version, "error");
|
|
315
|
+
}
|
|
292
316
|
let progressed = true;
|
|
293
317
|
while (progressed) {
|
|
294
318
|
progressed = false;
|
|
295
|
-
for (const key
|
|
319
|
+
for (const key in this.#store) {
|
|
296
320
|
const name = segmentName(key);
|
|
297
321
|
if (name === null || this.#revealed.has(name)) continue;
|
|
298
322
|
if (this.#segmentReady(name)) {
|
|
@@ -301,7 +325,7 @@ class FrameImpl {
|
|
|
301
325
|
progressed = true;
|
|
302
326
|
}
|
|
303
327
|
}
|
|
304
|
-
for (const key
|
|
328
|
+
for (const key in this.#store) {
|
|
305
329
|
const m = /^seg:([^:]+):fallback$/.exec(key);
|
|
306
330
|
if (!m) continue;
|
|
307
331
|
const name = m[1];
|
|
@@ -313,7 +337,25 @@ class FrameImpl {
|
|
|
313
337
|
}
|
|
314
338
|
}
|
|
315
339
|
}
|
|
316
|
-
for (const key
|
|
340
|
+
for (const key in this.#store) {
|
|
341
|
+
const record = this.#store[key];
|
|
342
|
+
if (!record || this.#appliedHoles.get(key) === record) continue;
|
|
343
|
+
if (key.startsWith("hole:")) {
|
|
344
|
+
if (key.endsWith(":error")) {
|
|
345
|
+
this.#appliedHoles.set(key, record);
|
|
346
|
+
console.error(`Live hole ${key.slice(5, -6)} failed on the server; latched:`, record);
|
|
347
|
+
} else if (this.#applyHole(key.slice(5), record.value)) {
|
|
348
|
+
this.#appliedHoles.set(key, record);
|
|
349
|
+
this.#applied(version, "morph");
|
|
350
|
+
}
|
|
351
|
+
} else if (key.startsWith("attr:")) {
|
|
352
|
+
if (this.#applyAttrs(key.slice(5), record.value, record.removed)) {
|
|
353
|
+
this.#appliedHoles.set(key, record);
|
|
354
|
+
this.#applied(version, "morph");
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
for (const key in this.#store) {
|
|
317
359
|
if (this.#processedAssets.has(key) || !key.endsWith(":assets")) continue;
|
|
318
360
|
this.#processedAssets.add(key);
|
|
319
361
|
const record = this.#store[key];
|
|
@@ -345,6 +387,7 @@ class FrameImpl {
|
|
|
345
387
|
const callback = this.#resolveSlot(propOf(occurrence));
|
|
346
388
|
if (!callback) continue;
|
|
347
389
|
const record = this.#resolveSlotRecord(occurrence);
|
|
390
|
+
if (record && record.kind === "slot" && this.#refsUnresolved(record.args)) continue;
|
|
348
391
|
const prev = this.#slotNodes.get(occurrence);
|
|
349
392
|
const prevFirst = Array.isArray(prev) ? prev[0] : prev;
|
|
350
393
|
const zombie = this.#mountedSlots.has(occurrence) && prevFirst && !prevFirst.parentNode;
|
|
@@ -400,15 +443,7 @@ class FrameImpl {
|
|
|
400
443
|
const cleanups = this.#slotCleanups.get(occurrence) ?? [];
|
|
401
444
|
let existing = [];
|
|
402
445
|
let end = null;
|
|
403
|
-
if (start)
|
|
404
|
-
const endData = slotEnd(occurrence);
|
|
405
|
-
let n = start.nextSibling;
|
|
406
|
-
while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
|
|
407
|
-
existing.push(n);
|
|
408
|
-
n = n.nextSibling;
|
|
409
|
-
}
|
|
410
|
-
end = n;
|
|
411
|
-
}
|
|
446
|
+
if (start) end = eachInRange(start, occurrence, n => existing.push(n));
|
|
412
447
|
const ctx = {
|
|
413
448
|
frame: this.#options.claimScope ?? this.#options.id,
|
|
414
449
|
key: occurrence,
|
|
@@ -423,23 +458,16 @@ class FrameImpl {
|
|
|
423
458
|
} : undefined
|
|
424
459
|
};
|
|
425
460
|
const props = record && record.kind === "slot" ? this.#resolveArgs(occurrence, record.args) : {};
|
|
426
|
-
const
|
|
427
|
-
const content = scope ? scope(() => callback(props, ctx)) : callback(props, ctx);
|
|
461
|
+
const content = this.#scoped(() => callback(props, ctx));
|
|
428
462
|
this.#slotArgs.set(occurrence, record);
|
|
429
463
|
if (cleanups.length) this.#slotCleanups.set(occurrence, cleanups);
|
|
430
464
|
if (content == null) return null;
|
|
431
465
|
return Array.isArray(content) ? content : [content];
|
|
432
466
|
}
|
|
433
467
|
#replaceRange(key, start, nodes) {
|
|
434
|
-
const end = slotEnd(key);
|
|
435
468
|
const parent = start.parentNode;
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
const next = n.nextSibling;
|
|
439
|
-
parent.removeChild(n);
|
|
440
|
-
n = next;
|
|
441
|
-
}
|
|
442
|
-
for (const node of nodes) parent.insertBefore(node, n);
|
|
469
|
+
const end = eachInRange(start, key, n => parent.removeChild(n));
|
|
470
|
+
for (const node of nodes) parent.insertBefore(node, end);
|
|
443
471
|
}
|
|
444
472
|
#unmountSlot(key) {
|
|
445
473
|
this.#mountedSlots.delete(key);
|
|
@@ -451,9 +479,7 @@ class FrameImpl {
|
|
|
451
479
|
this.#runSlotCleanups(key);
|
|
452
480
|
const regions = this.#slotRegions.get(key);
|
|
453
481
|
if (regions) {
|
|
454
|
-
|
|
455
|
-
frame
|
|
456
|
-
} of regions.values()) frame?.dispose();
|
|
482
|
+
disposeRegions(regions);
|
|
457
483
|
this.#slotRegions.delete(key);
|
|
458
484
|
}
|
|
459
485
|
}
|
|
@@ -463,15 +489,26 @@ class FrameImpl {
|
|
|
463
489
|
this.#slotCleanups.delete(key);
|
|
464
490
|
for (const fn of cleanups) fn();
|
|
465
491
|
}
|
|
492
|
+
#refsUnresolved(args) {
|
|
493
|
+
const {
|
|
494
|
+
host,
|
|
495
|
+
id
|
|
496
|
+
} = this.#options;
|
|
497
|
+
if (host) for (const key in args) {
|
|
498
|
+
if (isDataRef(args[key]) && host.resolve(args[key], id) === undefined) return true;
|
|
499
|
+
}
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
#regionsFor(slotKey) {
|
|
503
|
+
let regions = this.#slotRegions.get(slotKey);
|
|
504
|
+
if (!regions) this.#slotRegions.set(slotKey, regions = new Map());
|
|
505
|
+
return regions;
|
|
506
|
+
}
|
|
466
507
|
#resolveArgs(slotKey, args) {
|
|
467
508
|
const host = this.#options.host;
|
|
468
|
-
|
|
469
|
-
if (!regions) {
|
|
470
|
-
regions = new Map();
|
|
471
|
-
this.#slotRegions.set(slotKey, regions);
|
|
472
|
-
}
|
|
509
|
+
const regions = this.#regionsFor(slotKey);
|
|
473
510
|
const props = {};
|
|
474
|
-
for (const key
|
|
511
|
+
for (const key in args) {
|
|
475
512
|
const value = args[key];
|
|
476
513
|
if (isDataRef(value)) {
|
|
477
514
|
const resolved = host ? host.resolve(value, this.#options.id) : undefined;
|
|
@@ -494,24 +531,15 @@ class FrameImpl {
|
|
|
494
531
|
}
|
|
495
532
|
props[key] = entry.element;
|
|
496
533
|
} else {
|
|
497
|
-
props[key] = value;
|
|
534
|
+
props[key] = host && host.revive ? host.revive(value) : value;
|
|
498
535
|
}
|
|
499
536
|
}
|
|
500
537
|
return props;
|
|
501
538
|
}
|
|
502
539
|
#discoverRegions(slotKey, start) {
|
|
503
540
|
if (!start) return;
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
regions = new Map();
|
|
507
|
-
this.#slotRegions.set(slotKey, regions);
|
|
508
|
-
}
|
|
509
|
-
const endData = slotEnd(slotKey);
|
|
510
|
-
let n = start.nextSibling;
|
|
511
|
-
while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
|
|
512
|
-
collectRegionElements(n, regions);
|
|
513
|
-
n = n.nextSibling;
|
|
514
|
-
}
|
|
541
|
+
const regions = this.#regionsFor(slotKey);
|
|
542
|
+
eachInRange(start, slotKey, n => collectRegionElements(n, regions));
|
|
515
543
|
}
|
|
516
544
|
#refArgsUnchanged(occurrence, record) {
|
|
517
545
|
const old = this.#slotArgs.get(occurrence);
|
|
@@ -527,11 +555,15 @@ class FrameImpl {
|
|
|
527
555
|
const va = a[key];
|
|
528
556
|
const vb = b[key];
|
|
529
557
|
if (va === vb) continue;
|
|
530
|
-
if (
|
|
531
|
-
if (
|
|
532
|
-
if (typeof va.$ref === "string" && typeof vb.$ref === "string" && cache && key in cache) {
|
|
558
|
+
if (isFrameRef(va) && isFrameRef(vb)) continue;
|
|
559
|
+
if (isDataRef(va) && isDataRef(vb) && cache && key in cache) {
|
|
533
560
|
const host = this.#options.host;
|
|
534
561
|
const next = host ? host.resolve(vb, this.#options.id) : undefined;
|
|
562
|
+
if (host && host.isContainer && (host.isContainer(next) || host.isContainer(cache[key]))) {
|
|
563
|
+
if (next === cache[key]) continue;
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
if (isAsyncLike(next) || isAsyncLike(cache[key])) return false;
|
|
535
567
|
try {
|
|
536
568
|
if (JSON.stringify(next) === JSON.stringify(cache[key])) continue;
|
|
537
569
|
} catch (e) {
|
|
@@ -547,7 +579,7 @@ class FrameImpl {
|
|
|
547
579
|
if (!args) return;
|
|
548
580
|
const regions = this.#slotRegions.get(occurrence);
|
|
549
581
|
if (!regions) return;
|
|
550
|
-
for (const key
|
|
582
|
+
for (const key in args) {
|
|
551
583
|
const value = args[key];
|
|
552
584
|
if (!isFrameRef(value)) continue;
|
|
553
585
|
const entry = regions.get(key);
|
|
@@ -597,11 +629,8 @@ class FrameImpl {
|
|
|
597
629
|
this.#element.setAttribute(FRAME_ID_ATTR, id);
|
|
598
630
|
}
|
|
599
631
|
this.#version = undefined;
|
|
600
|
-
this.#
|
|
601
|
-
this.#
|
|
602
|
-
for (const key of Object.keys(this.#store)) {
|
|
603
|
-
if (key.startsWith("seg:") || key === ":error") delete this.#store[key];
|
|
604
|
-
}
|
|
632
|
+
this.#appliedRootValue = undefined;
|
|
633
|
+
this.#resetStreamState(true);
|
|
605
634
|
if (host) host.register(id, this);
|
|
606
635
|
}
|
|
607
636
|
rebase() {
|
|
@@ -621,11 +650,7 @@ class FrameImpl {
|
|
|
621
650
|
}
|
|
622
651
|
for (const key of [...this.#slotCleanups.keys()]) this.#runSlotCleanups(key);
|
|
623
652
|
for (const key of this.#mountedSlots) this.#removeSlotRecord(key);
|
|
624
|
-
for (const regions of this.#slotRegions.values())
|
|
625
|
-
for (const {
|
|
626
|
-
frame
|
|
627
|
-
} of regions.values()) frame?.dispose();
|
|
628
|
-
}
|
|
653
|
+
for (const regions of this.#slotRegions.values()) disposeRegions(regions);
|
|
629
654
|
this.#slotRegions.clear();
|
|
630
655
|
this.#mountedSlots.clear();
|
|
631
656
|
}
|
|
@@ -646,14 +671,40 @@ class FrameImpl {
|
|
|
646
671
|
if (ranges.size) for (const root of grafts) flushGrafts(root, ranges);
|
|
647
672
|
}
|
|
648
673
|
}
|
|
649
|
-
#
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
674
|
+
#applyHole(marker, html) {
|
|
675
|
+
if (!this.#hasContent) return false;
|
|
676
|
+
const open = findLiveTarget(this.#firstContent(), this.#end, n => n.nodeType === COMMENT_NODE && n.data === marker);
|
|
677
|
+
if (!open) return false;
|
|
678
|
+
const close = rangeClose(open, "lh:/" + marker.slice(3));
|
|
679
|
+
if (!close) {
|
|
680
|
+
{
|
|
681
|
+
console.error(`Live hole "${marker}" is missing its closing comment; update dropped. ` + `Likely an HTML-rewriting layer stripped it.`, open);
|
|
682
|
+
}
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
const claim = claimHandlers() ? this.#claimTree : null;
|
|
686
|
+
reconcileChildren(open.parentNode, parseFragment(html), open, close, claim);
|
|
687
|
+
return true;
|
|
688
|
+
}
|
|
689
|
+
#applyAttrs(addr, text, removed) {
|
|
690
|
+
if (!this.#hasContent) return false;
|
|
691
|
+
const el = findLiveTarget(this.#firstContent(), this.#end, n => n.nodeType === ELEMENT_NODE && n.getAttribute("data-lha") === addr);
|
|
692
|
+
if (!el) return false;
|
|
693
|
+
const parsed = parseFragment(`<i${text}></i>`).firstChild;
|
|
694
|
+
if (parsed) {
|
|
695
|
+
for (let i = 0; i < parsed.attributes.length; i++) {
|
|
696
|
+
const {
|
|
697
|
+
name,
|
|
698
|
+
value
|
|
699
|
+
} = parsed.attributes[i];
|
|
700
|
+
if (el.getAttribute(name) !== value) el.setAttribute(name, value);
|
|
701
|
+
}
|
|
656
702
|
}
|
|
703
|
+
if (removed) for (const name of removed) el.removeAttribute(name);
|
|
704
|
+
return true;
|
|
705
|
+
}
|
|
706
|
+
#clearContent() {
|
|
707
|
+
removeUntil(this.#parent(), this.#firstContent(), this.#end);
|
|
657
708
|
}
|
|
658
709
|
#claimContent() {
|
|
659
710
|
if (!claimHandlers()) return;
|
|
@@ -670,9 +721,7 @@ class FrameImpl {
|
|
|
670
721
|
const assets = this.#store[`seg:${name}:assets`];
|
|
671
722
|
if (assets && assets.styles) {
|
|
672
723
|
let ready = true;
|
|
673
|
-
for (const entry of assets.styles)
|
|
674
|
-
if (!ensureStylesheet(entry, this.#styleFlush)) ready = false;
|
|
675
|
-
}
|
|
724
|
+
for (const entry of assets.styles) ready = ensureStylesheet(entry, this.#styleFlush) && ready;
|
|
676
725
|
if (!ready) return false;
|
|
677
726
|
}
|
|
678
727
|
if (!this.#findPlaceholder(name)) return false;
|
|
@@ -689,12 +738,7 @@ class FrameImpl {
|
|
|
689
738
|
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);
|
|
690
739
|
}
|
|
691
740
|
const parent = tpl.parentNode;
|
|
692
|
-
|
|
693
|
-
while (n && n !== closing) {
|
|
694
|
-
const next = n.nextSibling;
|
|
695
|
-
parent.removeChild(n);
|
|
696
|
-
n = next;
|
|
697
|
-
}
|
|
741
|
+
removeUntil(parent, tpl.nextSibling, closing);
|
|
698
742
|
if (this.#options.reveal) {
|
|
699
743
|
const fallbackFrag = tpl.content.cloneNode(true);
|
|
700
744
|
this.#claimTree(fallbackFrag);
|
|
@@ -743,9 +787,7 @@ function createFrameElement(options) {
|
|
|
743
787
|
const frame = new FrameImpl(el, null, null, options);
|
|
744
788
|
return {
|
|
745
789
|
element: el,
|
|
746
|
-
|
|
747
|
-
return frame;
|
|
748
|
-
},
|
|
790
|
+
frame,
|
|
749
791
|
dispose() {
|
|
750
792
|
frame.dispose();
|
|
751
793
|
el.remove();
|
|
@@ -765,15 +807,30 @@ function segmentName(key) {
|
|
|
765
807
|
const m = /^seg:([^:]+)$/.exec(key);
|
|
766
808
|
return m ? m[1] : null;
|
|
767
809
|
}
|
|
810
|
+
function isAsyncLike(v) {
|
|
811
|
+
return !!v && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
|
|
812
|
+
}
|
|
768
813
|
function propOf(occurrence) {
|
|
769
814
|
const hash = occurrence.indexOf("#");
|
|
770
815
|
return hash === -1 ? occurrence : occurrence.slice(0, hash);
|
|
771
816
|
}
|
|
772
817
|
function isDataRef(value) {
|
|
773
|
-
return
|
|
818
|
+
return !!value && typeof value.$ref === "string";
|
|
774
819
|
}
|
|
775
820
|
function isFrameRef(value) {
|
|
776
|
-
return
|
|
821
|
+
return !!value && typeof value.$frame === "string";
|
|
822
|
+
}
|
|
823
|
+
function disposeRegions(regions) {
|
|
824
|
+
for (const {
|
|
825
|
+
frame
|
|
826
|
+
} of regions.values()) frame?.dispose();
|
|
827
|
+
}
|
|
828
|
+
function removeUntil(parent, n, stop) {
|
|
829
|
+
while (n && n !== stop) {
|
|
830
|
+
const next = n.nextSibling;
|
|
831
|
+
parent.removeChild(n);
|
|
832
|
+
n = next;
|
|
833
|
+
}
|
|
777
834
|
}
|
|
778
835
|
function parseFragment(html) {
|
|
779
836
|
const template = document.createElement("template");
|
|
@@ -781,9 +838,8 @@ function parseFragment(html) {
|
|
|
781
838
|
return template.content;
|
|
782
839
|
}
|
|
783
840
|
function findHeadElement(selector, attr, value) {
|
|
784
|
-
const
|
|
785
|
-
|
|
786
|
-
if (nodes[i].getAttribute(attr) === value) return nodes[i];
|
|
841
|
+
for (const node of document.head.querySelectorAll(selector)) {
|
|
842
|
+
if (node.getAttribute(attr) === value) return node;
|
|
787
843
|
}
|
|
788
844
|
return null;
|
|
789
845
|
}
|
|
@@ -832,7 +888,7 @@ function applyInlineStyles(inlineStyles) {
|
|
|
832
888
|
}
|
|
833
889
|
}
|
|
834
890
|
function isPlaceholderStart(node, id) {
|
|
835
|
-
return node.
|
|
891
|
+
return node.tagName === "TEMPLATE" && node.id === id;
|
|
836
892
|
}
|
|
837
893
|
function rangeClose(start, id) {
|
|
838
894
|
let n = start.nextSibling;
|
|
@@ -842,6 +898,20 @@ function rangeClose(start, id) {
|
|
|
842
898
|
}
|
|
843
899
|
return null;
|
|
844
900
|
}
|
|
901
|
+
function findLiveTarget(n, end, test) {
|
|
902
|
+
while (n && n !== end) {
|
|
903
|
+
if (n.nodeType === ELEMENT_NODE) {
|
|
904
|
+
const fid = isFrameElement(n) ? n.getAttribute(FRAME_ID_ATTR) : null;
|
|
905
|
+
if (fid === null || fid.includes(".")) {
|
|
906
|
+
if (test(n)) return n;
|
|
907
|
+
const found = findLiveTarget(n.firstChild, null, test);
|
|
908
|
+
if (found) return found;
|
|
909
|
+
}
|
|
910
|
+
} else if (test(n)) return n;
|
|
911
|
+
n = n.nextSibling;
|
|
912
|
+
}
|
|
913
|
+
return null;
|
|
914
|
+
}
|
|
845
915
|
function findPlaceholder(n, end, id) {
|
|
846
916
|
while (n && n !== end) {
|
|
847
917
|
if (isPlaceholderStart(n, id)) return n;
|
|
@@ -889,6 +959,23 @@ function renameRegion(entry, childId) {
|
|
|
889
959
|
entry.childId = childId;
|
|
890
960
|
if (entry.frame) entry.frame.rebind(childId);else entry.element.setAttribute(FRAME_ID_ATTR, childId);
|
|
891
961
|
}
|
|
962
|
+
function eachInRange(start, key, cb) {
|
|
963
|
+
const end = slotEnd(key);
|
|
964
|
+
let n = start.nextSibling;
|
|
965
|
+
while (n && !(n.nodeType === COMMENT_NODE && n.data === end)) {
|
|
966
|
+
const next = n.nextSibling;
|
|
967
|
+
cb(n);
|
|
968
|
+
n = next;
|
|
969
|
+
}
|
|
970
|
+
return n;
|
|
971
|
+
}
|
|
972
|
+
function clearStreamRecords(records, root) {
|
|
973
|
+
for (const key in records) {
|
|
974
|
+
if (/^(seg|hole|attr):/.test(key) || key === ":error" || root && key === "") {
|
|
975
|
+
delete records[key];
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
892
979
|
function argsEquivalent(a, b) {
|
|
893
980
|
if (a === b) return true;
|
|
894
981
|
if (!a || !b) return false;
|
|
@@ -899,9 +986,7 @@ function argsEquivalent(a, b) {
|
|
|
899
986
|
const va = a[key];
|
|
900
987
|
const vb = b[key];
|
|
901
988
|
if (va === vb) continue;
|
|
902
|
-
if (va &&
|
|
903
|
-
continue;
|
|
904
|
-
}
|
|
989
|
+
if (isFrameRef(va) && va.$frame === vb?.$frame) continue;
|
|
905
990
|
return false;
|
|
906
991
|
}
|
|
907
992
|
return true;
|
|
@@ -1153,6 +1238,7 @@ async function applyFrameResponse(response, host, options = {}) {
|
|
|
1153
1238
|
if (v === undefined) perFrame.set(chunk.id, v = version(chunk.id));
|
|
1154
1239
|
chunk.version = v;
|
|
1155
1240
|
} else if (version !== undefined) chunk.version = version;
|
|
1241
|
+
if (chunk.type === "data" && host.prepareData) await host.prepareData();
|
|
1156
1242
|
host.apply(chunk);
|
|
1157
1243
|
}
|
|
1158
1244
|
result = await reader.next();
|
|
@@ -1169,7 +1255,7 @@ function parseServerComponent(value, ctx) {
|
|
|
1169
1255
|
address: ctx.parse(value[SERVER_COMPONENT_ADDRESS])
|
|
1170
1256
|
};
|
|
1171
1257
|
}
|
|
1172
|
-
const ServerComponentPlugin =
|
|
1258
|
+
const ServerComponentPlugin = {
|
|
1173
1259
|
tag: "dom-expressions/server-component",
|
|
1174
1260
|
test(value) {
|
|
1175
1261
|
return typeof value === "function" && SERVER_COMPONENT in value;
|
|
@@ -1196,12 +1282,10 @@ const ServerComponentPlugin = /*#__PURE__*/seroval.createPlugin({
|
|
|
1196
1282
|
}
|
|
1197
1283
|
return globalThis._$SC.r(id);
|
|
1198
1284
|
}
|
|
1199
|
-
}
|
|
1285
|
+
};
|
|
1200
1286
|
function flightCodec(codec) {
|
|
1201
1287
|
const plugins = codec && codec.plugins || [];
|
|
1202
|
-
|
|
1203
|
-
if (plugin && plugin.tag === "dom-expressions/server-component") return codec;
|
|
1204
|
-
}
|
|
1288
|
+
if (plugins.some(plugin => plugin && plugin.tag === ServerComponentPlugin.tag)) return codec;
|
|
1205
1289
|
return {
|
|
1206
1290
|
...codec,
|
|
1207
1291
|
plugins: [...plugins, ServerComponentPlugin]
|
|
@@ -1273,7 +1357,7 @@ function createServerComponentHandler({
|
|
|
1273
1357
|
showing(address, functionId) {
|
|
1274
1358
|
bindingFor(address, functionId);
|
|
1275
1359
|
const comp = componentFor(functionId);
|
|
1276
|
-
if ((typeof comp === "function" || typeof comp === "object"
|
|
1360
|
+
if (comp && (typeof comp === "function" || typeof comp === "object") && !comp[COMPONENT_BINDING]) {
|
|
1277
1361
|
comp[COMPONENT_BINDING] = {
|
|
1278
1362
|
component: comp,
|
|
1279
1363
|
address
|
|
@@ -1318,69 +1402,74 @@ function createServerComponentHandler({
|
|
|
1318
1402
|
}
|
|
1319
1403
|
}
|
|
1320
1404
|
|
|
1321
|
-
|
|
1322
|
-
const
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
const JSON_CODEC_DISABLED_FEATURES = seroval.Feature.RegExp;
|
|
1329
|
-
const JSON_CODEC_DEPTH_LIMIT = 64;
|
|
1330
|
-
function resolveCodecOptions({
|
|
1331
|
-
plugins,
|
|
1332
|
-
disabledFeatures,
|
|
1333
|
-
depthLimit
|
|
1334
|
-
} = {}) {
|
|
1335
|
-
return {
|
|
1336
|
-
plugins: resolveSerializerPlugins(plugins),
|
|
1337
|
-
disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
|
|
1338
|
-
depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
|
|
1339
|
-
};
|
|
1405
|
+
const STATE = Symbol.for("dom-expressions.container-trace-state");
|
|
1406
|
+
const state = globalThis[STATE] || (globalThis[STATE] = {
|
|
1407
|
+
materialized: new WeakMap(),
|
|
1408
|
+
materializedValues: new WeakSet()
|
|
1409
|
+
});
|
|
1410
|
+
function setContainerTraceMaterializer(fn) {
|
|
1411
|
+
state.materializeTrace = fn;
|
|
1340
1412
|
}
|
|
1341
|
-
function
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
};
|
|
1413
|
+
function materialize(marker) {
|
|
1414
|
+
let value = state.materialized.get(marker.$tr);
|
|
1415
|
+
if (value === undefined) {
|
|
1416
|
+
value = state.materializeTrace(marker);
|
|
1417
|
+
state.materialized.set(marker.$tr, value);
|
|
1418
|
+
if (value !== null && typeof value === "object") state.materializedValues.add(value);
|
|
1419
|
+
}
|
|
1420
|
+
return value;
|
|
1350
1421
|
}
|
|
1351
|
-
function
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1422
|
+
function isMaterializedContainer(value) {
|
|
1423
|
+
return value !== null && typeof value === "object" && state.materializedValues.has(value);
|
|
1424
|
+
}
|
|
1425
|
+
function isContainerTraceMarker(value) {
|
|
1426
|
+
return value != null && typeof value === "object" && value.$tr != null && typeof value.$tr[Symbol.asyncIterator] === "function";
|
|
1427
|
+
}
|
|
1428
|
+
function reviveContainerTraces(value) {
|
|
1429
|
+
if (!state.materializeTrace || value == null || typeof value !== "object") return value;
|
|
1430
|
+
if (isContainerTraceMarker(value)) return materialize(value);
|
|
1431
|
+
if (Array.isArray(value)) {
|
|
1432
|
+
for (let i = 0; i < value.length; i++) value[i] = reviveContainerTraces(value[i]);
|
|
1433
|
+
} else if (Object.getPrototypeOf(value) === Object.prototype) {
|
|
1434
|
+
for (const key of Object.keys(value)) value[key] = reviveContainerTraces(value[key]);
|
|
1435
|
+
}
|
|
1436
|
+
return value;
|
|
1366
1437
|
}
|
|
1367
1438
|
|
|
1439
|
+
setContainerTraceMaterializer(solidJs.materializeContainerTrace);
|
|
1440
|
+
function asyncArg(value) {
|
|
1441
|
+
return value;
|
|
1442
|
+
}
|
|
1368
1443
|
let sharedHost;
|
|
1444
|
+
let codec;
|
|
1445
|
+
let codecLoading;
|
|
1446
|
+
function loadCodec() {
|
|
1447
|
+
return codecLoading ??= import('@solidjs/web/serialization/decode').then(m => {
|
|
1448
|
+
codec = m;
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
1369
1451
|
const tables = new Map();
|
|
1452
|
+
function ensureTable(root) {
|
|
1453
|
+
let table = tables.get(root);
|
|
1454
|
+
if (!table && codec) tables.set(root, table = codec.createJSONDataTable());
|
|
1455
|
+
return table;
|
|
1456
|
+
}
|
|
1370
1457
|
function tableFor(id) {
|
|
1371
|
-
|
|
1372
|
-
if (
|
|
1373
|
-
for (const [root, t] of tables) if (id.startsWith(root + ".")) return t;
|
|
1458
|
+
if (tables.has(id)) return ensureTable(id);
|
|
1459
|
+
for (const root of tables.keys()) if (id.startsWith(root + ".")) return ensureTable(root);
|
|
1374
1460
|
return undefined;
|
|
1375
1461
|
}
|
|
1376
1462
|
function beginStream(frameId) {
|
|
1377
|
-
tables.set(frameId,
|
|
1463
|
+
tables.set(frameId, undefined);
|
|
1378
1464
|
}
|
|
1379
1465
|
function getFrameHost() {
|
|
1380
1466
|
if (!sharedHost) {
|
|
1381
1467
|
sharedHost = createFrameHost({
|
|
1468
|
+
prepareData: loadCodec,
|
|
1382
1469
|
applyData: c => tableFor(c.id)?.apply(c),
|
|
1383
|
-
resolve: (ref, id) => tableFor(id)?.resolve(ref)
|
|
1470
|
+
resolve: (ref, id) => tableFor(id)?.resolve(ref),
|
|
1471
|
+
revive: reviveContainerTraces,
|
|
1472
|
+
isContainer: isMaterializedContainer
|
|
1384
1473
|
});
|
|
1385
1474
|
}
|
|
1386
1475
|
return sharedHost;
|
|
@@ -1441,8 +1530,27 @@ function claimRender(prefix, existing, render) {
|
|
|
1441
1530
|
function liveSlotProps(initial, ctx) {
|
|
1442
1531
|
const [args, setArgs] = solidJs.createSignal(initial);
|
|
1443
1532
|
ctx.onUpdate(next => setArgs(() => next));
|
|
1533
|
+
return slotArgsProxy(args);
|
|
1534
|
+
}
|
|
1535
|
+
function isAsyncValue(v) {
|
|
1536
|
+
return v !== null && typeof v === "object" && (typeof v.then === "function" || typeof v[Symbol.asyncIterator] === "function");
|
|
1537
|
+
}
|
|
1538
|
+
function slotArgsProxy(args) {
|
|
1539
|
+
const owner = solidJs.getOwner();
|
|
1540
|
+
const asyncReads = new Map();
|
|
1444
1541
|
return new Proxy({}, {
|
|
1445
|
-
get: (_, key) =>
|
|
1542
|
+
get: (_, key) => {
|
|
1543
|
+
const v = args()[key];
|
|
1544
|
+
if (isMaterializedContainer(v)) return v;
|
|
1545
|
+
if (!isAsyncValue(v)) return v;
|
|
1546
|
+
let read = asyncReads.get(key);
|
|
1547
|
+
if (!read) {
|
|
1548
|
+
const make = () => solidJs.createMemo(() => args()[key]);
|
|
1549
|
+
read = owner ? solidJs.runWithOwner(owner, make) : make();
|
|
1550
|
+
asyncReads.set(key, read);
|
|
1551
|
+
}
|
|
1552
|
+
return read();
|
|
1553
|
+
},
|
|
1446
1554
|
has: (_, key) => key in args(),
|
|
1447
1555
|
ownKeys: () => Reflect.ownKeys(args()),
|
|
1448
1556
|
getOwnPropertyDescriptor: (_, key) => key in args() ? {
|
|
@@ -1460,6 +1568,7 @@ function isReactiveContent(value) {
|
|
|
1460
1568
|
}
|
|
1461
1569
|
function slotsFor(props) {
|
|
1462
1570
|
const bindings = new Map();
|
|
1571
|
+
const fillScopes = new Map();
|
|
1463
1572
|
return new Proxy({}, {
|
|
1464
1573
|
get(_, prop) {
|
|
1465
1574
|
if (typeof prop !== "string" || !(prop in props)) return undefined;
|
|
@@ -1470,6 +1579,19 @@ function slotsFor(props) {
|
|
|
1470
1579
|
bindings.delete(key);
|
|
1471
1580
|
prev.dispose();
|
|
1472
1581
|
}
|
|
1582
|
+
const prevFill = key !== undefined && fillScopes.get(key);
|
|
1583
|
+
if (prevFill) {
|
|
1584
|
+
fillScopes.delete(key);
|
|
1585
|
+
prevFill.dispose();
|
|
1586
|
+
}
|
|
1587
|
+
const fillOwner = streamInvoke ? solidJs.createOwner() : null;
|
|
1588
|
+
if (fillOwner && key !== undefined && ctx) {
|
|
1589
|
+
fillScopes.set(key, fillOwner);
|
|
1590
|
+
ctx.onCleanup(() => {
|
|
1591
|
+
if (fillScopes.get(key) === fillOwner) fillScopes.delete(key);
|
|
1592
|
+
fillOwner.dispose();
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1473
1595
|
const settle = out => {
|
|
1474
1596
|
const existing = ctx && ctx.existing || [];
|
|
1475
1597
|
if (existing.length) {
|
|
@@ -1482,13 +1604,13 @@ function slotsFor(props) {
|
|
|
1482
1604
|
const evaluate = () => {
|
|
1483
1605
|
const v = props[prop];
|
|
1484
1606
|
if (typeof v === "function" && ctx && ctx.invoked) {
|
|
1485
|
-
return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotProps);
|
|
1607
|
+
return v(ctx.onUpdate ? liveSlotProps(slotProps, ctx) : slotArgsProxy(() => slotProps));
|
|
1486
1608
|
}
|
|
1487
1609
|
return v;
|
|
1488
1610
|
};
|
|
1489
1611
|
const adopted = !!(ctx && ctx.frame && ctx.adopted && ctx.existing && ctx.existing.length);
|
|
1490
1612
|
const prefix = ctx && ctx.frame ? `sc-${ctx.frame}-${ctx.key}-` : "";
|
|
1491
|
-
const value = adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
|
|
1613
|
+
const value = fillOwner ? solidJs.runWithOwner(fillOwner, () => adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate()) : adopted ? claimRender(prefix, ctx.existing, evaluate) : evaluate();
|
|
1492
1614
|
if (!isReactiveContent(value)) {
|
|
1493
1615
|
return settle(normalizeSlotContent(value));
|
|
1494
1616
|
}
|
|
@@ -1501,7 +1623,7 @@ function slotsFor(props) {
|
|
|
1501
1623
|
owner.dispose();
|
|
1502
1624
|
});
|
|
1503
1625
|
const end = ctx.range.end;
|
|
1504
|
-
const bind = () => web
|
|
1626
|
+
const bind = () => web.insert(end.parentNode, () => typeof source === "function" ? source() : source, end, [...ctx.existing]);
|
|
1505
1627
|
solidJs.runWithOwner(owner, () => adopted ? claimRender(prefix, ctx.existing, bind) : bind());
|
|
1506
1628
|
return undefined;
|
|
1507
1629
|
}
|
|
@@ -1511,34 +1633,84 @@ function slotsFor(props) {
|
|
|
1511
1633
|
});
|
|
1512
1634
|
}
|
|
1513
1635
|
function revealSeam(owner) {
|
|
1514
|
-
return seam => solidJs.runWithOwner(owner, () => web
|
|
1636
|
+
return seam => solidJs.runWithOwner(owner, () => web.insert(seam.before.parentNode, solidJs.createLoadingBoundary(() => seam.content(), () => seam.fallback), seam.before));
|
|
1515
1637
|
}
|
|
1638
|
+
let streamInvoke = false;
|
|
1516
1639
|
function boundaryScope(owner) {
|
|
1517
|
-
return fn =>
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1640
|
+
return fn => {
|
|
1641
|
+
if (solidJs.getOwner()) return fn();
|
|
1642
|
+
streamInvoke = true;
|
|
1643
|
+
try {
|
|
1644
|
+
return solidJs.runWithOwner(owner, fn);
|
|
1645
|
+
} finally {
|
|
1646
|
+
streamInvoke = false;
|
|
1647
|
+
}
|
|
1648
|
+
};
|
|
1521
1649
|
}
|
|
1522
1650
|
function boundaryComponent(host, fnId) {
|
|
1523
1651
|
return (props, binding) => {
|
|
1524
1652
|
const owner = solidJs.getOwner();
|
|
1653
|
+
const id = binding ? binding() : fnId;
|
|
1654
|
+
let applied = !tables.has(id);
|
|
1655
|
+
let release;
|
|
1656
|
+
const arm = () => new Promise(r => release = r);
|
|
1657
|
+
const mountGate = applied ? undefined : arm();
|
|
1658
|
+
let setGate;
|
|
1525
1659
|
const {
|
|
1526
1660
|
element,
|
|
1527
1661
|
frame,
|
|
1528
1662
|
dispose
|
|
1529
1663
|
} = createFrameElement({
|
|
1530
1664
|
host,
|
|
1531
|
-
id
|
|
1665
|
+
id,
|
|
1532
1666
|
slots: slotsFor(props),
|
|
1533
1667
|
ownerScope: boundaryScope(owner),
|
|
1534
|
-
reveal: revealSeam(owner)
|
|
1668
|
+
reveal: revealSeam(owner),
|
|
1669
|
+
onApply: () => {
|
|
1670
|
+
applied = true;
|
|
1671
|
+
if (release) {
|
|
1672
|
+
release();
|
|
1673
|
+
release = undefined;
|
|
1674
|
+
}
|
|
1675
|
+
setGate && setGate(undefined);
|
|
1676
|
+
}
|
|
1535
1677
|
});
|
|
1536
|
-
|
|
1678
|
+
const [gatePromise, setGatePromise] = solidJs.createSignal(applied ? undefined : mountGate);
|
|
1679
|
+
setGate = setGatePromise;
|
|
1680
|
+
if (binding) {
|
|
1681
|
+
solidJs.createRenderEffect(binding, (address, prev) => {
|
|
1682
|
+
if (prev !== undefined && address !== prev && tables.has(address)) {
|
|
1683
|
+
applied = false;
|
|
1684
|
+
setGatePromise(arm());
|
|
1685
|
+
}
|
|
1686
|
+
frame.rebind(address);
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1537
1689
|
solidJs.onCleanup(dispose);
|
|
1538
|
-
return element;
|
|
1690
|
+
if (applied && !binding) return element;
|
|
1691
|
+
const gate = solidJs.createMemo(() => gatePromise());
|
|
1692
|
+
return solidJs.createMemo(() => (gate(), element));
|
|
1539
1693
|
};
|
|
1540
1694
|
}
|
|
1541
1695
|
const claimedBoundaries = new Set();
|
|
1696
|
+
const liveOps = new Map();
|
|
1697
|
+
const liveAppliers = new Set();
|
|
1698
|
+
let livePumped = null;
|
|
1699
|
+
function pumpLiveChannel() {
|
|
1700
|
+
const stream = globalThis._$HY?.r?.["sc:live"];
|
|
1701
|
+
if (!stream || stream === livePumped || typeof stream.getReader !== "function") return;
|
|
1702
|
+
livePumped = stream;
|
|
1703
|
+
const reader = stream.getReader();
|
|
1704
|
+
const pump = () => reader.read().then(r => {
|
|
1705
|
+
if (r.done) return;
|
|
1706
|
+
const op = r.value;
|
|
1707
|
+
liveOps.set(`${op.type}:${op.fid || ""}:${op.key || ""}`, op);
|
|
1708
|
+
for (const apply of liveAppliers) apply(op);
|
|
1709
|
+
return pump();
|
|
1710
|
+
});
|
|
1711
|
+
pump().catch(() => {
|
|
1712
|
+
});
|
|
1713
|
+
}
|
|
1542
1714
|
let boundaryIndex = null;
|
|
1543
1715
|
const isBoundaryId = id => !id.includes(".");
|
|
1544
1716
|
function indexBoundaries(root) {
|
|
@@ -1603,9 +1775,21 @@ function adoptBoundary(host, id, el, props, binding) {
|
|
|
1603
1775
|
claimedBoundaries.add(id);
|
|
1604
1776
|
const address = binding ? binding() : documentAddress(id);
|
|
1605
1777
|
const appliedRecords = new Set();
|
|
1778
|
+
const claimedFragments = new Set();
|
|
1779
|
+
const claimRegionFragments = root => {
|
|
1780
|
+
const fr = globalThis._$HY?.fr;
|
|
1781
|
+
if (!fr || !fr.claim) return;
|
|
1782
|
+
root.querySelectorAll('template[id^="pl-"]').forEach(tpl => {
|
|
1783
|
+
const fragId = tpl.id.slice(3);
|
|
1784
|
+
if (claimedFragments.has(fragId)) return;
|
|
1785
|
+
claimedFragments.add(fragId);
|
|
1786
|
+
fr.claim(fragId);
|
|
1787
|
+
});
|
|
1788
|
+
};
|
|
1606
1789
|
const drainRecords = () => {
|
|
1607
1790
|
const hy = globalThis._$HY;
|
|
1608
1791
|
if (!hy || !hy.r) return;
|
|
1792
|
+
pumpLiveChannel();
|
|
1609
1793
|
const slotPrefix = `sc:slot:${id}:`;
|
|
1610
1794
|
for (const key of Object.keys(hy.r)) {
|
|
1611
1795
|
if (appliedRecords.has(key)) continue;
|
|
@@ -1634,8 +1818,31 @@ function adoptBoundary(host, id, el, props, binding) {
|
|
|
1634
1818
|
}
|
|
1635
1819
|
}
|
|
1636
1820
|
};
|
|
1821
|
+
claimRegionFragments(el);
|
|
1822
|
+
const fr = globalThis._$HY?.fr;
|
|
1823
|
+
const unsubscribe = fr ? fr.subscribe((_fragId, parent) => {
|
|
1824
|
+
if (fr.claim && parent && el.contains(parent)) claimRegionFragments(parent);
|
|
1825
|
+
drainRecords();
|
|
1826
|
+
}) : undefined;
|
|
1827
|
+
const applyLiveOp = op => {
|
|
1828
|
+
if (op.type === "slot" && op.fid !== id) return;
|
|
1829
|
+
host.apply({
|
|
1830
|
+
...op,
|
|
1831
|
+
id: address,
|
|
1832
|
+
version: 0
|
|
1833
|
+
});
|
|
1834
|
+
};
|
|
1835
|
+
liveAppliers.add(applyLiveOp);
|
|
1836
|
+
solidJs.onCleanup(() => {
|
|
1837
|
+
liveAppliers.delete(applyLiveOp);
|
|
1838
|
+
unsubscribe && unsubscribe();
|
|
1839
|
+
if (fr && fr.release) for (const fragId of claimedFragments) fr.release(fragId);
|
|
1840
|
+
});
|
|
1637
1841
|
drainRecords();
|
|
1842
|
+
for (const op of liveOps.values()) applyLiveOp(op);
|
|
1638
1843
|
const owner = solidJs.getOwner();
|
|
1844
|
+
let release;
|
|
1845
|
+
let setGate;
|
|
1639
1846
|
const frame = createFrame(el, {
|
|
1640
1847
|
adopt: true,
|
|
1641
1848
|
host,
|
|
@@ -1643,6 +1850,13 @@ function adoptBoundary(host, id, el, props, binding) {
|
|
|
1643
1850
|
slots: slotsFor(props),
|
|
1644
1851
|
ownerScope: boundaryScope(owner),
|
|
1645
1852
|
reveal: revealSeam(owner),
|
|
1853
|
+
onApply: () => {
|
|
1854
|
+
if (release) {
|
|
1855
|
+
release();
|
|
1856
|
+
release = undefined;
|
|
1857
|
+
}
|
|
1858
|
+
setGate && setGate(undefined);
|
|
1859
|
+
},
|
|
1646
1860
|
...{
|
|
1647
1861
|
recordsPending: () => {
|
|
1648
1862
|
if (document.readyState === "loading") return true;
|
|
@@ -1653,7 +1867,19 @@ function adoptBoundary(host, id, el, props, binding) {
|
|
|
1653
1867
|
claimScope: id
|
|
1654
1868
|
}
|
|
1655
1869
|
});
|
|
1656
|
-
if (binding)
|
|
1870
|
+
if (binding) {
|
|
1871
|
+
const arm = () => new Promise(r => release = r);
|
|
1872
|
+
const [gatePromise, setGatePromise] = solidJs.createSignal(undefined);
|
|
1873
|
+
setGate = setGatePromise;
|
|
1874
|
+
const gate = solidJs.createMemo(() => gatePromise());
|
|
1875
|
+
solidJs.createRenderEffect(binding, (address, prev) => {
|
|
1876
|
+
if (prev !== undefined && address !== prev && tables.has(address)) {
|
|
1877
|
+
setGatePromise(arm());
|
|
1878
|
+
}
|
|
1879
|
+
frame.rebind(address);
|
|
1880
|
+
});
|
|
1881
|
+
solidJs.createRenderEffect(() => (gate(), undefined), () => {});
|
|
1882
|
+
}
|
|
1657
1883
|
solidJs.onCleanup(() => frame.dispose());
|
|
1658
1884
|
return el;
|
|
1659
1885
|
}
|
|
@@ -1697,10 +1923,10 @@ function installServerComponents(host = getFrameHost()) {
|
|
|
1697
1923
|
exports.FRAME_APPLIED_EVENT = FRAME_APPLIED_EVENT;
|
|
1698
1924
|
exports.FRAME_STREAM_HEADER = FRAME_STREAM_HEADER;
|
|
1699
1925
|
exports.applyFrameResponse = applyFrameResponse;
|
|
1926
|
+
exports.asyncArg = asyncArg;
|
|
1700
1927
|
exports.createFrame = createFrame;
|
|
1701
1928
|
exports.createFrameElement = createFrameElement;
|
|
1702
1929
|
exports.createFrameHost = createFrameHost;
|
|
1703
|
-
exports.createJSONDataTable = createJSONDataTable;
|
|
1704
1930
|
exports.createServerComponentHandler = createServerComponentHandler;
|
|
1705
1931
|
exports.getFrameHost = getFrameHost;
|
|
1706
1932
|
exports.installServerComponents = installServerComponents;
|