@solidjs/web 2.0.0-beta.32 → 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/dist/dev.cjs +51 -15
- package/dist/dev.js +47 -16
- package/dist/server.cjs +710 -71
- package/dist/server.js +707 -74
- package/dist/web.cjs +51 -15
- package/dist/web.js +47 -16
- package/frames/dist/client.cjs +181 -64
- package/frames/dist/client.dev.cjs +185 -64
- package/frames/dist/client.dev.js +183 -62
- package/frames/dist/client.js +179 -62
- package/frames/dist/server.cjs +969 -133
- package/frames/dist/server.js +971 -135
- package/package.json +17 -6
- 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 +98 -43
- package/serialization/dist/serialization.js +99 -44
- package/serialization/types/index.d.ts +18 -160
- package/serialization/types/serializer-decode.d.ts +182 -0
- package/serialization/types-cjs/index.d.cts +18 -160
- package/serialization/types-cjs/serializer-decode.d.cts +182 -0
- package/server-functions/dist/client.cjs +101 -105
- package/server-functions/dist/client.js +101 -105
- package/server-functions/dist/server.cjs +131 -107
- package/server-functions/dist/server.dev.cjs +131 -107
- package/server-functions/dist/server.dev.js +132 -108
- package/server-functions/dist/server.js +132 -108
- package/types/client.d.ts +23 -1
- package/types/cookies.d.ts +93 -0
- package/types/core.d.ts +1 -1
- package/types/frames/frame-client.d.ts +26 -0
- package/types/frames/frame-transport.d.ts +1 -1
- package/types/frames/serializer.d.ts +18 -160
- package/types/serializer-decode.d.ts +182 -0
- package/types/serializer.d.ts +18 -160
- package/types/server-functions/client.d.ts +1 -1
- package/types/server-functions/server.d.ts +1 -1
- package/types/server-functions/shared.d.ts +57 -1
- package/types/server.d.ts +21 -1
- package/types-cjs/client.d.cts +23 -1
- package/types-cjs/cookies.d.cts +93 -0
- package/types-cjs/core.d.cts +1 -1
- package/types-cjs/frames/frame-client.d.cts +26 -0
- package/types-cjs/frames/frame-transport.d.cts +1 -1
- package/types-cjs/frames/serializer.d.cts +18 -160
- package/types-cjs/serializer-decode.d.cts +182 -0
- package/types-cjs/serializer.d.cts +18 -160
- package/types-cjs/server-functions/client.d.cts +1 -1
- package/types-cjs/server-functions/server.d.cts +1 -1
- package/types-cjs/server-functions/shared.d.cts +57 -1
- package/types-cjs/server.d.cts +21 -1
package/frames/dist/server.js
CHANGED
|
@@ -1,7 +1,99 @@
|
|
|
1
|
-
import { createMemo, runWithOwner, createOwner, sharedConfig, createRoot, ssrHandleError, getOwner, NoHydration, runInServerComponentScope, Hydration } from 'solid-js';
|
|
2
|
-
import {
|
|
1
|
+
import { createMemo, runWithOwner, createOwner, sharedConfig, createRoot, ssrHandleError, getOwner, inServerComponentScope, creationStamp, NoHydration, runInServerComponentScope, Hydration, getProjectionTrace } from 'solid-js';
|
|
2
|
+
import { Feature, toCrossJSONStream, Serializer, getCrossReferenceHeader } from 'seroval';
|
|
3
3
|
import { AbortSignalPlugin, CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin } from 'seroval-plugins/web';
|
|
4
4
|
|
|
5
|
+
const STATE = Symbol.for("dom-expressions.container-trace-state");
|
|
6
|
+
const state = globalThis[STATE] || (globalThis[STATE] = {
|
|
7
|
+
materialized: new WeakMap(),
|
|
8
|
+
materializedValues: new WeakSet()
|
|
9
|
+
});
|
|
10
|
+
function setContainerTraceResolver(fn) {
|
|
11
|
+
state.resolveTrace = fn;
|
|
12
|
+
}
|
|
13
|
+
function isContainerTraced(value) {
|
|
14
|
+
const resolve = state.resolveTrace;
|
|
15
|
+
return !!(resolve && value && typeof value === "object" && resolve(value));
|
|
16
|
+
}
|
|
17
|
+
const TRACE = Symbol.for("dom-expressions.container-trace");
|
|
18
|
+
function envelopeContainerTraces(value) {
|
|
19
|
+
if (!state.resolveTrace || value == null || typeof value !== "object") return value;
|
|
20
|
+
const trace = state.resolveTrace(value);
|
|
21
|
+
if (trace) return {
|
|
22
|
+
[TRACE]: trace
|
|
23
|
+
};
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
let out = value;
|
|
26
|
+
for (let i = 0; i < value.length; i++) {
|
|
27
|
+
const next = envelopeContainerTraces(value[i]);
|
|
28
|
+
if (next !== value[i]) {
|
|
29
|
+
if (out === value) out = value.slice();
|
|
30
|
+
out[i] = next;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
if (Object.getPrototypeOf(value) === Object.prototype) {
|
|
36
|
+
let out = value;
|
|
37
|
+
for (const key of Object.keys(value)) {
|
|
38
|
+
const next = envelopeContainerTraces(value[key]);
|
|
39
|
+
if (next !== value[key]) {
|
|
40
|
+
if (out === value) out = {
|
|
41
|
+
...value
|
|
42
|
+
};
|
|
43
|
+
out[key] = next;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
function materialize(marker) {
|
|
51
|
+
let value = state.materialized.get(marker.$tr);
|
|
52
|
+
if (value === undefined) {
|
|
53
|
+
value = state.materializeTrace(marker);
|
|
54
|
+
state.materialized.set(marker.$tr, value);
|
|
55
|
+
if (value !== null && typeof value === "object") state.materializedValues.add(value);
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
function parseTrace(value, ctx) {
|
|
60
|
+
const trace = value[TRACE];
|
|
61
|
+
return {
|
|
62
|
+
a: trace.array ? 1 : 0,
|
|
63
|
+
i: ctx.parse(trace.subscribe())
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const ContainerTracePlugin = {
|
|
67
|
+
tag: "dom-expressions/container-trace",
|
|
68
|
+
test(value) {
|
|
69
|
+
return value != null && typeof value === "object" && TRACE in value;
|
|
70
|
+
},
|
|
71
|
+
parse: {
|
|
72
|
+
sync() {
|
|
73
|
+
throw new Error("A reactive container can only be serialized by a streaming serializer.");
|
|
74
|
+
},
|
|
75
|
+
async async(value, ctx) {
|
|
76
|
+
const trace = value[TRACE];
|
|
77
|
+
return {
|
|
78
|
+
a: trace.array ? 1 : 0,
|
|
79
|
+
i: await ctx.parse(trace.subscribe())
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
stream: parseTrace
|
|
83
|
+
},
|
|
84
|
+
serialize(node, ctx) {
|
|
85
|
+
return "{$tr:" + ctx.serialize(node.i) + ",$ta:" + node.a + "}";
|
|
86
|
+
},
|
|
87
|
+
deserialize(node, ctx) {
|
|
88
|
+
const iterable = ctx.deserialize(node.i);
|
|
89
|
+
const marker = {
|
|
90
|
+
$tr: iterable,
|
|
91
|
+
$ta: node.a
|
|
92
|
+
};
|
|
93
|
+
return state.materializeTrace ? materialize(marker) : marker;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
5
97
|
const runWithHydrationScope = (id, fn) => runWithOwner(createOwner({
|
|
6
98
|
id
|
|
7
99
|
}), fn);
|
|
@@ -9,15 +101,30 @@ const ssrAsyncValue = value => createMemo(() => value, {
|
|
|
9
101
|
serialize: false
|
|
10
102
|
});
|
|
11
103
|
|
|
12
|
-
const DEFAULT_DISABLED_FEATURES = Feature.AggregateError | Feature.BigIntTypedArray;
|
|
13
|
-
const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : Feature.ErrorPrototypeStack;
|
|
14
|
-
const HYDRATION_GLOBAL = "_$HY.r";
|
|
15
104
|
const DEFAULT_WEB_PLUGINS = Object.freeze([AbortSignalPlugin,
|
|
16
105
|
CustomEventPlugin, DOMExceptionPlugin, EventPlugin,
|
|
17
|
-
FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin
|
|
106
|
+
FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin,
|
|
107
|
+
ContainerTracePlugin]);
|
|
18
108
|
function resolveSerializerPlugins(customPlugins) {
|
|
19
109
|
return customPlugins ? [...customPlugins, ...DEFAULT_WEB_PLUGINS] : [...DEFAULT_WEB_PLUGINS];
|
|
20
110
|
}
|
|
111
|
+
const JSON_CODEC_DISABLED_FEATURES = Feature.RegExp;
|
|
112
|
+
const JSON_CODEC_DEPTH_LIMIT = 64;
|
|
113
|
+
function resolveCodecOptions({
|
|
114
|
+
plugins,
|
|
115
|
+
disabledFeatures,
|
|
116
|
+
depthLimit
|
|
117
|
+
} = {}) {
|
|
118
|
+
return {
|
|
119
|
+
plugins: resolveSerializerPlugins(plugins),
|
|
120
|
+
disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
|
|
121
|
+
depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const DEFAULT_DISABLED_FEATURES = Feature.AggregateError | Feature.BigIntTypedArray;
|
|
126
|
+
const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : Feature.ErrorPrototypeStack;
|
|
127
|
+
const HYDRATION_GLOBAL = "_$HY.r";
|
|
21
128
|
function createSerializer(options) {
|
|
22
129
|
return new Serializer({
|
|
23
130
|
...options,
|
|
@@ -44,34 +151,6 @@ function createHydrationSerializer({
|
|
|
44
151
|
function getLocalHeaderScript(id) {
|
|
45
152
|
return getCrossReferenceHeader(id) + ";";
|
|
46
153
|
}
|
|
47
|
-
const JSON_CODEC_DISABLED_FEATURES = Feature.RegExp;
|
|
48
|
-
const JSON_CODEC_DEPTH_LIMIT = 64;
|
|
49
|
-
function resolveCodecOptions({
|
|
50
|
-
plugins,
|
|
51
|
-
disabledFeatures,
|
|
52
|
-
depthLimit
|
|
53
|
-
} = {}) {
|
|
54
|
-
return {
|
|
55
|
-
plugins: resolveSerializerPlugins(plugins),
|
|
56
|
-
disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
|
|
57
|
-
depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
function serializeJSON(value, {
|
|
61
|
-
onParse,
|
|
62
|
-
onDone,
|
|
63
|
-
onError,
|
|
64
|
-
...codecOptions
|
|
65
|
-
}) {
|
|
66
|
-
const resolved = resolveCodecOptions(codecOptions);
|
|
67
|
-
return toCrossJSONStream(value, {
|
|
68
|
-
onParse,
|
|
69
|
-
onDone,
|
|
70
|
-
onError,
|
|
71
|
-
...resolved,
|
|
72
|
-
disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures()
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
154
|
function createJSONSerializer({
|
|
76
155
|
onData,
|
|
77
156
|
onDone,
|
|
@@ -258,7 +337,10 @@ class ChunkReader {
|
|
|
258
337
|
}
|
|
259
338
|
function serializeStream(value, codecOptions) {
|
|
260
339
|
return new ReadableStream({
|
|
261
|
-
start(controller) {
|
|
340
|
+
async start(controller) {
|
|
341
|
+
const {
|
|
342
|
+
serializeJSON
|
|
343
|
+
} = await import('@solidjs/web/serialization');
|
|
262
344
|
serializeJSON(value, {
|
|
263
345
|
...codecOptions,
|
|
264
346
|
onParse(node) {
|
|
@@ -345,7 +427,6 @@ function resolveHead(groups) {
|
|
|
345
427
|
}
|
|
346
428
|
for (const [identity, tags] of byIdentity) {
|
|
347
429
|
if (identity === "title") {
|
|
348
|
-
if (tags.length > 1) console.warn("Multiple <title> tags in one head group; the last one wins.");
|
|
349
430
|
winners.set(identity, {
|
|
350
431
|
seq: group.seq,
|
|
351
432
|
tags: [tags[tags.length - 1]]
|
|
@@ -535,7 +616,6 @@ function registerHeadTags(registry, context, tracking, emitResource, nonce, tags
|
|
|
535
616
|
for (let i = 0; i < tags.length; i++) {
|
|
536
617
|
const desc = tags[i];
|
|
537
618
|
if (!desc || !HEAD_ELIGIBLE_TAGS.has(desc.tag)) {
|
|
538
|
-
console.warn(`useHead: ignoring non-head tag`, desc);
|
|
539
619
|
continue;
|
|
540
620
|
}
|
|
541
621
|
const cls = classifyHeadTag(desc);
|
|
@@ -587,7 +667,6 @@ function headShellReady(registry, block) {
|
|
|
587
667
|
} : undefined);
|
|
588
668
|
} catch (err) {
|
|
589
669
|
if (pends(err)) continue;
|
|
590
|
-
console.warn(`useHead: error evaluating resource tag props`, err);
|
|
591
670
|
parked.splice(i, 1);
|
|
592
671
|
continue;
|
|
593
672
|
}
|
|
@@ -628,7 +707,6 @@ function emitHeadResource(registry, context, tracking, emitResource, nonce, desc
|
|
|
628
707
|
});
|
|
629
708
|
return;
|
|
630
709
|
}
|
|
631
|
-
console.warn(`useHead: error evaluating resource tag props`, err);
|
|
632
710
|
return;
|
|
633
711
|
}
|
|
634
712
|
const identity = resourceIdentity(desc.tag, props);
|
|
@@ -690,7 +768,6 @@ function commitHeadBoundary(registry, boundary, isPendingFragment) {
|
|
|
690
768
|
try {
|
|
691
769
|
resolved = reg.list();
|
|
692
770
|
} catch (err) {
|
|
693
|
-
console.warn(`useHead: error evaluating head group membership`, err);
|
|
694
771
|
continue;
|
|
695
772
|
}
|
|
696
773
|
if (!Array.isArray(resolved)) resolved = [resolved];
|
|
@@ -698,7 +775,6 @@ function commitHeadBoundary(registry, boundary, isPendingFragment) {
|
|
|
698
775
|
for (let j = 0; j < resolved.length; j++) {
|
|
699
776
|
const desc = resolved[j];
|
|
700
777
|
if (!desc || !HEAD_ELIGIBLE_TAGS.has(desc.tag)) {
|
|
701
|
-
console.warn(`useHead: ignoring non-head tag`, desc);
|
|
702
778
|
continue;
|
|
703
779
|
}
|
|
704
780
|
const cls = classifyHeadTag(desc);
|
|
@@ -724,12 +800,10 @@ function commitHeadBoundary(registry, boundary, isPendingFragment) {
|
|
|
724
800
|
} : undefined);
|
|
725
801
|
key = evalHeadValue(desc.key);
|
|
726
802
|
} catch (err) {
|
|
727
|
-
console.warn(`useHead: error evaluating tag props`, err);
|
|
728
803
|
continue;
|
|
729
804
|
}
|
|
730
805
|
const identity = replaceableIdentity(desc.tag, props, key, "u:" + registry.uniq++);
|
|
731
806
|
if ((identity === "base" || identity === "charset") && registry.shellFlushed) {
|
|
732
|
-
console.warn(`useHead: <${desc.tag}> (${identity}) registered after shell flush is ignored`);
|
|
733
807
|
continue;
|
|
734
808
|
}
|
|
735
809
|
tags.push({
|
|
@@ -811,7 +885,6 @@ function flushHeadFragment(registry, boundary) {
|
|
|
811
885
|
for (const name in t.props) {
|
|
812
886
|
if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
|
|
813
887
|
if (!HEAD_ATTR_NAME.test(name)) {
|
|
814
|
-
console.warn(`useHead: ignoring invalid attribute name "${name}"`);
|
|
815
888
|
continue;
|
|
816
889
|
}
|
|
817
890
|
const v = t.props[name];
|
|
@@ -829,7 +902,6 @@ function renderHeadAttrHtml(props) {
|
|
|
829
902
|
for (const name in props) {
|
|
830
903
|
if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
|
|
831
904
|
if (!HEAD_ATTR_NAME.test(name)) {
|
|
832
|
-
console.warn(`useHead: ignoring invalid attribute name "${name}"`);
|
|
833
905
|
continue;
|
|
834
906
|
}
|
|
835
907
|
const v = props[name];
|
|
@@ -889,6 +961,12 @@ function renderToStream(code, options = {}) {
|
|
|
889
961
|
d();
|
|
890
962
|
}
|
|
891
963
|
};
|
|
964
|
+
const failRender = err => {
|
|
965
|
+
try {
|
|
966
|
+
options.onError ? options.onError(err) : console.error(err);
|
|
967
|
+
} catch (_) {}
|
|
968
|
+
abandon();
|
|
969
|
+
};
|
|
892
970
|
const guardSink = w => ({
|
|
893
971
|
write(payload) {
|
|
894
972
|
if (dead) return;
|
|
@@ -987,10 +1065,18 @@ function renderToStream(code, options = {}) {
|
|
|
987
1065
|
rootAssetsSerialized = true;
|
|
988
1066
|
serializeFragmentAssets("", tracking.boundaryModules, context);
|
|
989
1067
|
};
|
|
1068
|
+
let holds = 0;
|
|
990
1069
|
const flushEnd = () => {
|
|
991
|
-
if (!registry.size) {
|
|
1070
|
+
if (!registry.size && !holds) {
|
|
992
1071
|
serializeRootAssets();
|
|
993
|
-
queue(() => queue(() =>
|
|
1072
|
+
queue(() => queue(() => {
|
|
1073
|
+
if (context.live.end) {
|
|
1074
|
+
const end = context.live.end;
|
|
1075
|
+
context.live.end = null;
|
|
1076
|
+
end();
|
|
1077
|
+
}
|
|
1078
|
+
serializer.flush();
|
|
1079
|
+
}));
|
|
994
1080
|
}
|
|
995
1081
|
};
|
|
996
1082
|
const registry = new Map();
|
|
@@ -1051,6 +1137,7 @@ function renderToStream(code, options = {}) {
|
|
|
1051
1137
|
sharedConfig.context = context = {
|
|
1052
1138
|
async: true,
|
|
1053
1139
|
nonce,
|
|
1140
|
+
live: {},
|
|
1054
1141
|
registerHeadTags(tags) {
|
|
1055
1142
|
registerHeadTags(headRegistry, context, tracking,
|
|
1056
1143
|
(markup, gateEntry) => {
|
|
@@ -1087,6 +1174,16 @@ function renderToStream(code, options = {}) {
|
|
|
1087
1174
|
block(p) {
|
|
1088
1175
|
if (!firstFlushed) blockingPromises.add(p);
|
|
1089
1176
|
},
|
|
1177
|
+
hold() {
|
|
1178
|
+
holds++;
|
|
1179
|
+
let released = false;
|
|
1180
|
+
return () => {
|
|
1181
|
+
if (released) return;
|
|
1182
|
+
released = true;
|
|
1183
|
+
holds--;
|
|
1184
|
+
if (!holds) queue(flushEnd);
|
|
1185
|
+
};
|
|
1186
|
+
},
|
|
1090
1187
|
replace(id, payloadFn) {
|
|
1091
1188
|
if (firstFlushed) return;
|
|
1092
1189
|
const placeholder = `<!--!$${id}-->`;
|
|
@@ -1195,6 +1292,7 @@ function renderToStream(code, options = {}) {
|
|
|
1195
1292
|
}
|
|
1196
1293
|
};
|
|
1197
1294
|
applyAssetTracking(context, tracking, manifest, noScripts);
|
|
1295
|
+
context.failRender = failRender;
|
|
1198
1296
|
registerEntryAssets(manifest);
|
|
1199
1297
|
let html = createRoot(d => {
|
|
1200
1298
|
dispose = d;
|
|
@@ -1307,7 +1405,12 @@ function renderToStream(code, options = {}) {
|
|
|
1307
1405
|
allSettled(blockingPromises).then(() => {
|
|
1308
1406
|
scheduleFlush(() => {
|
|
1309
1407
|
if (dead) return resolve();
|
|
1310
|
-
|
|
1408
|
+
try {
|
|
1409
|
+
doShell();
|
|
1410
|
+
} catch (err) {
|
|
1411
|
+
failRender(err);
|
|
1412
|
+
return resolve();
|
|
1413
|
+
}
|
|
1311
1414
|
if (!shellCompleted) return flush();
|
|
1312
1415
|
const encoder = new TextEncoder();
|
|
1313
1416
|
const writer = w.getWriter();
|
|
@@ -1364,7 +1467,12 @@ function renderToStream(code, options = {}) {
|
|
|
1364
1467
|
function flush() {
|
|
1365
1468
|
allSettled(blockingPromises).then(() => {
|
|
1366
1469
|
scheduleFlush(() => {
|
|
1367
|
-
|
|
1470
|
+
try {
|
|
1471
|
+
if (!resolveRootHoles() || !headShellReady(headRegistry, p => blockingPromises.add(p))) return flush();
|
|
1472
|
+
} catch (err) {
|
|
1473
|
+
failRender(err);
|
|
1474
|
+
return resolve(tmp);
|
|
1475
|
+
}
|
|
1368
1476
|
queue(flushEnd);
|
|
1369
1477
|
});
|
|
1370
1478
|
});
|
|
@@ -1379,7 +1487,15 @@ function renderToStream(code, options = {}) {
|
|
|
1379
1487
|
allSettled(blockingPromises).then(() => {
|
|
1380
1488
|
scheduleFlush(() => {
|
|
1381
1489
|
if (dead) return;
|
|
1382
|
-
|
|
1490
|
+
try {
|
|
1491
|
+
doShell();
|
|
1492
|
+
} catch (err) {
|
|
1493
|
+
failRender(err);
|
|
1494
|
+
try {
|
|
1495
|
+
w.end();
|
|
1496
|
+
} catch (_) {}
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1383
1499
|
if (!shellCompleted) return flush();
|
|
1384
1500
|
buffer = writable = guardSink(w);
|
|
1385
1501
|
buffer.write(tmp);
|
|
@@ -1411,9 +1527,27 @@ function renderToStream(code, options = {}) {
|
|
|
1411
1527
|
function buildAsyncWrap(err, node) {
|
|
1412
1528
|
const p = ssrHandleError(err);
|
|
1413
1529
|
if (!p) return null;
|
|
1530
|
+
if (node.$rw) return {
|
|
1531
|
+
fn: node,
|
|
1532
|
+
p
|
|
1533
|
+
};
|
|
1414
1534
|
const owner = getOwner();
|
|
1535
|
+
const live = sharedConfig.context && sharedConfig.context.liveHoles;
|
|
1536
|
+
const suppress = node.$lhSuppress || live && (live.suppressed || live.sweeping);
|
|
1537
|
+
if (!owner) {
|
|
1538
|
+
if (suppress) node.$lhSuppress = true;
|
|
1539
|
+
return {
|
|
1540
|
+
fn: node,
|
|
1541
|
+
p
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
const fn = () => runWithOwner(owner, node);
|
|
1545
|
+
fn.$rw = true;
|
|
1546
|
+
if (suppress) fn.$lhSuppress = true;
|
|
1547
|
+
if (node.$lhSkip) fn.$lhSkip = true;
|
|
1548
|
+
if (node.$lhBinding) fn.$lhBinding = node.$lhBinding;
|
|
1415
1549
|
return {
|
|
1416
|
-
fn
|
|
1550
|
+
fn,
|
|
1417
1551
|
p
|
|
1418
1552
|
};
|
|
1419
1553
|
}
|
|
@@ -1473,6 +1607,326 @@ function ssrGroupSlot(fn, idx) {
|
|
|
1473
1607
|
}
|
|
1474
1608
|
};
|
|
1475
1609
|
}
|
|
1610
|
+
const holePositionCache = new WeakMap();
|
|
1611
|
+
function holeContentPositions(t) {
|
|
1612
|
+
let cached = holePositionCache.get(t);
|
|
1613
|
+
if (cached) return cached;
|
|
1614
|
+
const pos = [];
|
|
1615
|
+
const openOff = [];
|
|
1616
|
+
const closeOff = [];
|
|
1617
|
+
let inTag = false;
|
|
1618
|
+
let quote = "";
|
|
1619
|
+
let curOpen = null;
|
|
1620
|
+
let scanningName = false;
|
|
1621
|
+
for (let i = 0; i < t.length; i++) {
|
|
1622
|
+
const seg = t[i];
|
|
1623
|
+
let close = -1;
|
|
1624
|
+
const openAtStart = inTag;
|
|
1625
|
+
let reopened = false;
|
|
1626
|
+
for (let j = 0; j < seg.length; j++) {
|
|
1627
|
+
const ch = seg[j];
|
|
1628
|
+
if (quote) {
|
|
1629
|
+
if (ch === quote) quote = "";
|
|
1630
|
+
} else if (inTag) {
|
|
1631
|
+
if (scanningName && (ch === " " || ch === "\t" || ch === "\n" || ch === ">" || ch === "/")) {
|
|
1632
|
+
scanningName = false;
|
|
1633
|
+
curOpen = {
|
|
1634
|
+
seg: i,
|
|
1635
|
+
off: j
|
|
1636
|
+
};
|
|
1637
|
+
}
|
|
1638
|
+
if (ch === '"' || ch === "'") quote = ch;else if (ch === ">") {
|
|
1639
|
+
inTag = false;
|
|
1640
|
+
if (openAtStart && !reopened && close === -1) close = j;
|
|
1641
|
+
curOpen = null;
|
|
1642
|
+
}
|
|
1643
|
+
} else if (ch === "<") {
|
|
1644
|
+
inTag = true;
|
|
1645
|
+
scanningName = true;
|
|
1646
|
+
reopened = true;
|
|
1647
|
+
curOpen = null;
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
if (inTag && scanningName) {
|
|
1651
|
+
scanningName = false;
|
|
1652
|
+
curOpen = {
|
|
1653
|
+
seg: i,
|
|
1654
|
+
off: seg.length
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
closeOff.push(close);
|
|
1658
|
+
openOff.push(inTag && curOpen && curOpen.seg === i ? curOpen.off : -1);
|
|
1659
|
+
if (i < t.length - 1) pos.push(!inTag);
|
|
1660
|
+
}
|
|
1661
|
+
cached = {
|
|
1662
|
+
pos,
|
|
1663
|
+
openOff,
|
|
1664
|
+
closeOff
|
|
1665
|
+
};
|
|
1666
|
+
holePositionCache.set(t, cached);
|
|
1667
|
+
return cached;
|
|
1668
|
+
}
|
|
1669
|
+
function createLiveHoles(sink, scoped) {
|
|
1670
|
+
let nextId = 0;
|
|
1671
|
+
const stamp = typeof creationStamp === "function" ? creationStamp : () => 0;
|
|
1672
|
+
const inScope = scoped && typeof inServerComponentScope === "function" ? inServerComponentScope : null;
|
|
1673
|
+
const stripMarkers = html => html.replace(/<!--lh:\/?\d+-->/g, "");
|
|
1674
|
+
function resolveHoleValue(hole) {
|
|
1675
|
+
const result = {
|
|
1676
|
+
t: [""],
|
|
1677
|
+
h: [],
|
|
1678
|
+
p: []
|
|
1679
|
+
};
|
|
1680
|
+
try {
|
|
1681
|
+
resolveSSRNode(hole(), result);
|
|
1682
|
+
} catch (err) {
|
|
1683
|
+
const wrap = buildAsyncWrap(err, hole);
|
|
1684
|
+
if (!wrap) throw err;
|
|
1685
|
+
result.h.push(wrap.fn);
|
|
1686
|
+
result.p.push(wrap.p);
|
|
1687
|
+
result.t.push("");
|
|
1688
|
+
}
|
|
1689
|
+
return result;
|
|
1690
|
+
}
|
|
1691
|
+
function closeChildren(b) {
|
|
1692
|
+
for (const c of b.children) {
|
|
1693
|
+
c.closed = true;
|
|
1694
|
+
if (c.key) sink.closeBinding(c.key);
|
|
1695
|
+
closeChildren(c);
|
|
1696
|
+
}
|
|
1697
|
+
b.children.length = 0;
|
|
1698
|
+
}
|
|
1699
|
+
const engine = {
|
|
1700
|
+
suppressed: 0,
|
|
1701
|
+
sweeping: false,
|
|
1702
|
+
parent: null,
|
|
1703
|
+
recordStamp: 0,
|
|
1704
|
+
gateHit: false,
|
|
1705
|
+
content(hole) {
|
|
1706
|
+
if (hole.$lhSuppress) {
|
|
1707
|
+
const r = {
|
|
1708
|
+
t: [""],
|
|
1709
|
+
h: [],
|
|
1710
|
+
p: []
|
|
1711
|
+
};
|
|
1712
|
+
engine.suppressed++;
|
|
1713
|
+
try {
|
|
1714
|
+
try {
|
|
1715
|
+
resolveSSRNode(hole(), r);
|
|
1716
|
+
} catch (err) {
|
|
1717
|
+
const wrap = buildAsyncWrap(err, hole);
|
|
1718
|
+
if (wrap) {
|
|
1719
|
+
r.h.push(wrap.fn);
|
|
1720
|
+
r.p.push(wrap.p);
|
|
1721
|
+
r.t.push("");
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
} finally {
|
|
1725
|
+
engine.suppressed--;
|
|
1726
|
+
}
|
|
1727
|
+
const b = hole.$lhBinding;
|
|
1728
|
+
if (b && !b.closed && !r.h.length && !engine.sweeping) {
|
|
1729
|
+
b.last = stripMarkers(r.t[0]);
|
|
1730
|
+
}
|
|
1731
|
+
return r.h.length ? r : r.t[0];
|
|
1732
|
+
}
|
|
1733
|
+
if (engine.suppressed || engine.sweeping) return null;
|
|
1734
|
+
if (hole.$lhSkip) return null;
|
|
1735
|
+
if (inScope && !inScope()) return null;
|
|
1736
|
+
const recordsBefore = engine.recordStamp;
|
|
1737
|
+
const ownersBefore = stamp();
|
|
1738
|
+
const owner = getOwner();
|
|
1739
|
+
const b = {
|
|
1740
|
+
key: null,
|
|
1741
|
+
children: [],
|
|
1742
|
+
last: null,
|
|
1743
|
+
closed: false,
|
|
1744
|
+
sweep() {
|
|
1745
|
+
if (b.closed) return;
|
|
1746
|
+
const prevSweeping = engine.sweeping;
|
|
1747
|
+
engine.sweeping = true;
|
|
1748
|
+
engine.gateHit = false;
|
|
1749
|
+
const sweepOwnersBefore = stamp();
|
|
1750
|
+
let res;
|
|
1751
|
+
try {
|
|
1752
|
+
res = owner ? runWithOwner(owner, () => resolveHoleValue(hole)) : resolveHoleValue(hole);
|
|
1753
|
+
} catch (err) {
|
|
1754
|
+
b.closed = true;
|
|
1755
|
+
sink.closeBinding(b.key);
|
|
1756
|
+
sink.error(b.key, String(err && err.message || err));
|
|
1757
|
+
return;
|
|
1758
|
+
} finally {
|
|
1759
|
+
engine.sweeping = prevSweeping;
|
|
1760
|
+
}
|
|
1761
|
+
if (engine.gateHit || stamp() !== sweepOwnersBefore) {
|
|
1762
|
+
b.closed = true;
|
|
1763
|
+
sink.closeBinding(b.key);
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
if (res.h.length) return;
|
|
1767
|
+
const html = res.t[0];
|
|
1768
|
+
if (b.last === null || html === b.last) return;
|
|
1769
|
+
b.last = html;
|
|
1770
|
+
closeChildren(b);
|
|
1771
|
+
sink.hole(b.key, html);
|
|
1772
|
+
}
|
|
1773
|
+
};
|
|
1774
|
+
if (engine.parent) engine.parent.children.push(b);
|
|
1775
|
+
const prevParent = engine.parent;
|
|
1776
|
+
engine.parent = b;
|
|
1777
|
+
let value;
|
|
1778
|
+
let escalated = null;
|
|
1779
|
+
try {
|
|
1780
|
+
value = hole();
|
|
1781
|
+
} catch (err) {
|
|
1782
|
+
const wrap = buildAsyncWrap(err, hole);
|
|
1783
|
+
if (!wrap) {
|
|
1784
|
+
engine.parent = prevParent;
|
|
1785
|
+
closeChildren(b);
|
|
1786
|
+
return "";
|
|
1787
|
+
}
|
|
1788
|
+
escalated = wrap;
|
|
1789
|
+
}
|
|
1790
|
+
if (!escalated && (typeof value === "function" && value.$lhSkip || value !== null && typeof value === "object" && value.$slot)) {
|
|
1791
|
+
engine.parent = prevParent;
|
|
1792
|
+
const r = {
|
|
1793
|
+
t: [""],
|
|
1794
|
+
h: [],
|
|
1795
|
+
p: []
|
|
1796
|
+
};
|
|
1797
|
+
engine.suppressed++;
|
|
1798
|
+
try {
|
|
1799
|
+
resolveSSRNode(value, r);
|
|
1800
|
+
} finally {
|
|
1801
|
+
engine.suppressed--;
|
|
1802
|
+
}
|
|
1803
|
+
return r.h.length ? r : r.t[0];
|
|
1804
|
+
}
|
|
1805
|
+
let res;
|
|
1806
|
+
if (escalated) {
|
|
1807
|
+
closeChildren(b);
|
|
1808
|
+
escalated.fn.$lhSuppress = true;
|
|
1809
|
+
escalated.fn.$lhBinding = b;
|
|
1810
|
+
res = {
|
|
1811
|
+
t: ["", ""],
|
|
1812
|
+
h: [escalated.fn],
|
|
1813
|
+
p: [escalated.p]
|
|
1814
|
+
};
|
|
1815
|
+
} else {
|
|
1816
|
+
res = {
|
|
1817
|
+
t: [""],
|
|
1818
|
+
h: [],
|
|
1819
|
+
p: []
|
|
1820
|
+
};
|
|
1821
|
+
try {
|
|
1822
|
+
resolveSSRNode(value, res);
|
|
1823
|
+
} catch (_) {
|
|
1824
|
+
engine.parent = prevParent;
|
|
1825
|
+
closeChildren(b);
|
|
1826
|
+
return "";
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
engine.parent = prevParent;
|
|
1830
|
+
if (engine.recordStamp !== recordsBefore || stamp() !== ownersBefore) {
|
|
1831
|
+
return res.h.length ? res : res.t[0];
|
|
1832
|
+
}
|
|
1833
|
+
const id = nextId++;
|
|
1834
|
+
const key = b.key = "lh:" + id;
|
|
1835
|
+
const open = `<!--lh:${id}-->`;
|
|
1836
|
+
const close = `<!--lh:/${id}-->`;
|
|
1837
|
+
if (!res.h.length) {
|
|
1838
|
+
b.last = stripMarkers(res.t[0]);
|
|
1839
|
+
sink.openBinding(key, b);
|
|
1840
|
+
return open + res.t[0] + close;
|
|
1841
|
+
}
|
|
1842
|
+
const t = res.t.slice();
|
|
1843
|
+
t[0] = open + t[0];
|
|
1844
|
+
t[t.length - 1] += close;
|
|
1845
|
+
sink.openBinding(key, b);
|
|
1846
|
+
return {
|
|
1847
|
+
t,
|
|
1848
|
+
h: res.h,
|
|
1849
|
+
p: res.p
|
|
1850
|
+
};
|
|
1851
|
+
},
|
|
1852
|
+
mint() {
|
|
1853
|
+
return nextId++;
|
|
1854
|
+
},
|
|
1855
|
+
active() {
|
|
1856
|
+
return !inScope || inScope();
|
|
1857
|
+
},
|
|
1858
|
+
attr(cap) {
|
|
1859
|
+
const owner = getOwner();
|
|
1860
|
+
const b = {
|
|
1861
|
+
key: "lha:" + cap.id,
|
|
1862
|
+
children: [],
|
|
1863
|
+
last: cap.base,
|
|
1864
|
+
closed: false,
|
|
1865
|
+
sweep() {
|
|
1866
|
+
if (b.closed) return;
|
|
1867
|
+
const prevSweeping = engine.sweeping;
|
|
1868
|
+
engine.sweeping = true;
|
|
1869
|
+
engine.gateHit = false;
|
|
1870
|
+
const sweepOwnersBefore = stamp();
|
|
1871
|
+
let html = "";
|
|
1872
|
+
try {
|
|
1873
|
+
let group = null;
|
|
1874
|
+
let groupVal = null;
|
|
1875
|
+
const run = () => {
|
|
1876
|
+
for (const part of cap.parts) {
|
|
1877
|
+
if (typeof part === "string") {
|
|
1878
|
+
html += part;
|
|
1879
|
+
continue;
|
|
1880
|
+
}
|
|
1881
|
+
let v;
|
|
1882
|
+
if (part.g) {
|
|
1883
|
+
if (group !== part.g) {
|
|
1884
|
+
group = part.g;
|
|
1885
|
+
groupVal = part.g();
|
|
1886
|
+
}
|
|
1887
|
+
v = groupVal[part.i];
|
|
1888
|
+
} else {
|
|
1889
|
+
v = part.f();
|
|
1890
|
+
}
|
|
1891
|
+
const vt = typeof v;
|
|
1892
|
+
if (vt === "string" || vt === "number") html += v;
|
|
1893
|
+
}
|
|
1894
|
+
};
|
|
1895
|
+
owner ? runWithOwner(owner, run) : run();
|
|
1896
|
+
} catch (err) {
|
|
1897
|
+
if (ssrHandleError(err, true)) return;
|
|
1898
|
+
b.closed = true;
|
|
1899
|
+
sink.closeBinding(b.key);
|
|
1900
|
+
sink.error("lha:" + cap.id, String(err && err.message || err));
|
|
1901
|
+
return;
|
|
1902
|
+
} finally {
|
|
1903
|
+
engine.sweeping = prevSweeping;
|
|
1904
|
+
}
|
|
1905
|
+
if (engine.gateHit || stamp() !== sweepOwnersBefore) {
|
|
1906
|
+
b.closed = true;
|
|
1907
|
+
sink.closeBinding(b.key);
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1910
|
+
if (html === b.last) return;
|
|
1911
|
+
const before = attrNames(b.last);
|
|
1912
|
+
const after = attrNames(html);
|
|
1913
|
+
const removed = before.filter(n => !after.includes(n));
|
|
1914
|
+
b.last = html;
|
|
1915
|
+
sink.attr(String(cap.id), html, removed);
|
|
1916
|
+
}
|
|
1917
|
+
};
|
|
1918
|
+
sink.openBinding(b.key, b);
|
|
1919
|
+
}
|
|
1920
|
+
};
|
|
1921
|
+
return engine;
|
|
1922
|
+
}
|
|
1923
|
+
function attrNames(text) {
|
|
1924
|
+
const names = [];
|
|
1925
|
+
const re = /(?:^|\s)([^\s=/>"']+)(?:="[^"]*")?/g;
|
|
1926
|
+
let m;
|
|
1927
|
+
while (m = re.exec(text)) names.push(m[1]);
|
|
1928
|
+
return names;
|
|
1929
|
+
}
|
|
1476
1930
|
function ssr(t) {
|
|
1477
1931
|
const len = arguments.length;
|
|
1478
1932
|
if (len === 1) return {
|
|
@@ -1483,13 +1937,54 @@ function ssr(t) {
|
|
|
1483
1937
|
let lastGroup = null;
|
|
1484
1938
|
let lastGroupVal = null;
|
|
1485
1939
|
let lastGroupIdx = 0;
|
|
1940
|
+
const live = sharedConfig.context && sharedConfig.context.liveHoles;
|
|
1941
|
+
const hp = live ? holeContentPositions(t) : null;
|
|
1942
|
+
let lastOpen = null;
|
|
1943
|
+
let cap = null;
|
|
1944
|
+
if (live && hp.openOff[0] >= 0) lastOpen = {
|
|
1945
|
+
r: null,
|
|
1946
|
+
seg: -1,
|
|
1947
|
+
off: hp.openOff[0]
|
|
1948
|
+
};
|
|
1949
|
+
const captureStart = () => {
|
|
1950
|
+
if (cap) return true;
|
|
1951
|
+
if (!lastOpen || live.suppressed || live.sweeping || !live.active()) return false;
|
|
1952
|
+
if (lastOpen.r !== result || result !== null && lastOpen.seg !== result.t.length - 1) {
|
|
1953
|
+
return false;
|
|
1954
|
+
}
|
|
1955
|
+
const id = live.mint();
|
|
1956
|
+
const inject = ` data-lha="${id}"`;
|
|
1957
|
+
let prefix;
|
|
1958
|
+
if (result === null) {
|
|
1959
|
+
s = s.slice(0, lastOpen.off) + inject + s.slice(lastOpen.off);
|
|
1960
|
+
prefix = s.slice(lastOpen.off + inject.length);
|
|
1961
|
+
} else {
|
|
1962
|
+
const seg = result.t[lastOpen.seg];
|
|
1963
|
+
result.t[lastOpen.seg] = seg.slice(0, lastOpen.off) + inject + seg.slice(lastOpen.off);
|
|
1964
|
+
prefix = result.t[lastOpen.seg].slice(lastOpen.off + inject.length);
|
|
1965
|
+
}
|
|
1966
|
+
cap = {
|
|
1967
|
+
id,
|
|
1968
|
+
parts: [prefix],
|
|
1969
|
+
base: prefix
|
|
1970
|
+
};
|
|
1971
|
+
return true;
|
|
1972
|
+
};
|
|
1486
1973
|
for (let i = 1; i < len; i++) {
|
|
1487
1974
|
const hole = arguments[i];
|
|
1488
1975
|
const ht = typeof hole;
|
|
1489
1976
|
if (ht === "string") {
|
|
1490
1977
|
if (result === null) s += hole;else result.t[result.t.length - 1] += hole;
|
|
1978
|
+
if (cap) {
|
|
1979
|
+
cap.parts.push(hole);
|
|
1980
|
+
cap.base += hole;
|
|
1981
|
+
}
|
|
1491
1982
|
} else if (ht === "number") {
|
|
1492
1983
|
if (result === null) s += hole;else result.t[result.t.length - 1] += hole;
|
|
1984
|
+
if (cap) {
|
|
1985
|
+
cap.parts.push("" + hole);
|
|
1986
|
+
cap.base += hole;
|
|
1987
|
+
}
|
|
1493
1988
|
} else if (hole == null || ht === "boolean") ; else if (ht === "function" && hole.$g) {
|
|
1494
1989
|
let value;
|
|
1495
1990
|
let hasValue = false;
|
|
@@ -1513,7 +2008,14 @@ function ssr(t) {
|
|
|
1513
2008
|
if (Array.isArray(lastGroupVal)) {
|
|
1514
2009
|
value = lastGroupVal[lastGroupIdx++];
|
|
1515
2010
|
hasValue = true;
|
|
2011
|
+
if (live && !hp.pos[i - 1] && captureStart()) {
|
|
2012
|
+
cap.parts.push({
|
|
2013
|
+
g: hole,
|
|
2014
|
+
i: lastGroupIdx - 1
|
|
2015
|
+
});
|
|
2016
|
+
}
|
|
1516
2017
|
} else {
|
|
2018
|
+
cap = null;
|
|
1517
2019
|
result.h.push(ssrGroupSlot(lastGroupVal.fn, lastGroupIdx++));
|
|
1518
2020
|
result.p.push(lastGroupVal.p);
|
|
1519
2021
|
result.t.push("");
|
|
@@ -1523,6 +2025,7 @@ function ssr(t) {
|
|
|
1523
2025
|
const vt = typeof value;
|
|
1524
2026
|
if (vt === "string" || vt === "number") {
|
|
1525
2027
|
if (result === null) s += value;else result.t[result.t.length - 1] += value;
|
|
2028
|
+
if (cap && !hp.pos[i - 1]) cap.base += value;
|
|
1526
2029
|
} else if (value == null || vt === "boolean") ; else if (result !== null) {
|
|
1527
2030
|
resolveSSRNode(value, result);
|
|
1528
2031
|
} else {
|
|
@@ -1540,19 +2043,67 @@ function ssr(t) {
|
|
|
1540
2043
|
}
|
|
1541
2044
|
}
|
|
1542
2045
|
}
|
|
1543
|
-
} else if (result !== null) {
|
|
1544
|
-
resolveSSRNode(hole, result);
|
|
1545
2046
|
} else if (ht === "function") {
|
|
1546
|
-
|
|
1547
|
-
if (
|
|
1548
|
-
|
|
1549
|
-
t
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
2047
|
+
let liveNode = null;
|
|
2048
|
+
if (live && hp.pos[i - 1] && (liveNode = live.content(hole)) !== null) {
|
|
2049
|
+
if (typeof liveNode === "string") {
|
|
2050
|
+
if (result === null) s += liveNode;else result.t[result.t.length - 1] += liveNode;
|
|
2051
|
+
} else {
|
|
2052
|
+
if (result === null) {
|
|
2053
|
+
result = {
|
|
2054
|
+
t: [s],
|
|
2055
|
+
h: [],
|
|
2056
|
+
p: []
|
|
2057
|
+
};
|
|
2058
|
+
s = "";
|
|
2059
|
+
}
|
|
2060
|
+
resolveSSRNode(liveNode, result);
|
|
2061
|
+
}
|
|
2062
|
+
} else if (result !== null) {
|
|
2063
|
+
const inTag = live && !hp.pos[i - 1];
|
|
2064
|
+
const capturing = inTag && captureStart();
|
|
2065
|
+
const li = capturing ? result.t.length - 1 : 0;
|
|
2066
|
+
const before = capturing ? result.t[li].length : 0;
|
|
2067
|
+
if (live) live.suppressed++;
|
|
2068
|
+
try {
|
|
2069
|
+
resolveSSRNode(hole, result);
|
|
2070
|
+
} finally {
|
|
2071
|
+
if (live) live.suppressed--;
|
|
2072
|
+
}
|
|
2073
|
+
if (capturing) {
|
|
2074
|
+
if (result.t.length - 1 === li) {
|
|
2075
|
+
cap.base += result.t[li].slice(before);
|
|
2076
|
+
cap.parts.push({
|
|
2077
|
+
f: hole
|
|
2078
|
+
});
|
|
2079
|
+
} else {
|
|
2080
|
+
cap = null;
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
} else {
|
|
2084
|
+
const capturing = live && !hp.pos[i - 1] && captureStart();
|
|
2085
|
+
const r = tryResolveFunctionHole(hole);
|
|
2086
|
+
if (typeof r === "string") {
|
|
2087
|
+
s += r;
|
|
2088
|
+
if (capturing) {
|
|
2089
|
+
cap.base += r;
|
|
2090
|
+
cap.parts.push({
|
|
2091
|
+
f: hole
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
} else {
|
|
2095
|
+
if (capturing) cap = null;
|
|
2096
|
+
result = {
|
|
2097
|
+
t: [s],
|
|
2098
|
+
h: [],
|
|
2099
|
+
p: []
|
|
2100
|
+
};
|
|
2101
|
+
s = "";
|
|
2102
|
+
appendResolvedNode(result, r);
|
|
2103
|
+
}
|
|
1555
2104
|
}
|
|
2105
|
+
} else if (result !== null) {
|
|
2106
|
+
resolveSSRNode(hole, result);
|
|
1556
2107
|
} else {
|
|
1557
2108
|
const r = tryResolveString(hole);
|
|
1558
2109
|
if (typeof r === "string") {
|
|
@@ -1568,6 +2119,32 @@ function ssr(t) {
|
|
|
1568
2119
|
}
|
|
1569
2120
|
}
|
|
1570
2121
|
const next = t[i];
|
|
2122
|
+
if (live) {
|
|
2123
|
+
if (cap) {
|
|
2124
|
+
const co = hp.closeOff[i];
|
|
2125
|
+
if (co >= 0) {
|
|
2126
|
+
const tail = next.slice(0, co);
|
|
2127
|
+
cap.parts.push(tail);
|
|
2128
|
+
cap.base += tail;
|
|
2129
|
+
live.attr(cap);
|
|
2130
|
+
cap = null;
|
|
2131
|
+
} else {
|
|
2132
|
+
cap.parts.push(next);
|
|
2133
|
+
cap.base += next;
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
if (hp.openOff[i] >= 0) {
|
|
2137
|
+
lastOpen = result === null ? {
|
|
2138
|
+
r: null,
|
|
2139
|
+
seg: -1,
|
|
2140
|
+
off: s.length + hp.openOff[i]
|
|
2141
|
+
} : {
|
|
2142
|
+
r: result,
|
|
2143
|
+
seg: result.t.length - 1,
|
|
2144
|
+
off: result.t[result.t.length - 1].length + hp.openOff[i]
|
|
2145
|
+
};
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
1571
2148
|
if (result === null) s += next;else result.t[result.t.length - 1] += next;
|
|
1572
2149
|
}
|
|
1573
2150
|
if (result === null) return {
|
|
@@ -1800,7 +2377,6 @@ function tryResolveString(node) {
|
|
|
1800
2377
|
merge: node
|
|
1801
2378
|
};
|
|
1802
2379
|
if (node.t === undefined) {
|
|
1803
|
-
console.warn(`Unrecognized value. Skipped inserting`, node);
|
|
1804
2380
|
return "";
|
|
1805
2381
|
}
|
|
1806
2382
|
return Array.isArray(node.t) ? node.t[0] : node.t;
|
|
@@ -1825,13 +2401,19 @@ function resolveSSRNode(node, result = {
|
|
|
1825
2401
|
if (t === "string" || t === "number") {
|
|
1826
2402
|
result.t[result.t.length - 1] += node;
|
|
1827
2403
|
} else if (node == null || t === "boolean") ; else if (Array.isArray(node)) {
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
2404
|
+
const slotLive = node.$slot && sharedConfig.context && sharedConfig.context.liveHoles;
|
|
2405
|
+
if (slotLive) slotLive.suppressed++;
|
|
2406
|
+
try {
|
|
2407
|
+
let prevNonObj = false;
|
|
2408
|
+
for (let i = 0, len = node.length; i < len; i++) {
|
|
2409
|
+
const item = node[i];
|
|
2410
|
+
const itemNonObj = item !== null && typeof item !== "object";
|
|
2411
|
+
if (!top && prevNonObj && itemNonObj) result.t[result.t.length - 1] += `<!--!$-->`;
|
|
2412
|
+
prevNonObj = itemNonObj;
|
|
2413
|
+
resolveSSRNode(item, result);
|
|
2414
|
+
}
|
|
2415
|
+
} finally {
|
|
2416
|
+
if (slotLive) slotLive.suppressed--;
|
|
1835
2417
|
}
|
|
1836
2418
|
} else if (t === "object") {
|
|
1837
2419
|
if (node.h) {
|
|
@@ -1843,16 +2425,22 @@ function resolveSSRNode(node, result = {
|
|
|
1843
2425
|
}
|
|
1844
2426
|
} else if (node.t !== undefined) {
|
|
1845
2427
|
result.t[result.t.length - 1] += node.t;
|
|
1846
|
-
} else
|
|
2428
|
+
} else ;
|
|
1847
2429
|
} else if (t === "function") {
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
2430
|
+
const live = sharedConfig.context && sharedConfig.context.liveHoles;
|
|
2431
|
+
let liveNode = null;
|
|
2432
|
+
if (live && (liveNode = live.content(node)) !== null) {
|
|
2433
|
+
if (typeof liveNode === "string") result.t[result.t.length - 1] += liveNode;else resolveSSRNode(liveNode, result);
|
|
2434
|
+
} else {
|
|
2435
|
+
try {
|
|
2436
|
+
resolveSSRNode(node(), result);
|
|
2437
|
+
} catch (err) {
|
|
2438
|
+
const wrap = buildAsyncWrap(err, node);
|
|
2439
|
+
if (wrap) {
|
|
2440
|
+
result.h.push(wrap.fn);
|
|
2441
|
+
result.p.push(wrap.p);
|
|
2442
|
+
result.t.push("");
|
|
2443
|
+
}
|
|
1856
2444
|
}
|
|
1857
2445
|
}
|
|
1858
2446
|
}
|
|
@@ -1887,7 +2475,7 @@ function parseServerComponent(value, ctx) {
|
|
|
1887
2475
|
address: ctx.parse(value[SERVER_COMPONENT_ADDRESS])
|
|
1888
2476
|
};
|
|
1889
2477
|
}
|
|
1890
|
-
const ServerComponentPlugin =
|
|
2478
|
+
const ServerComponentPlugin = {
|
|
1891
2479
|
tag: "dom-expressions/server-component",
|
|
1892
2480
|
test(value) {
|
|
1893
2481
|
return typeof value === "function" && SERVER_COMPONENT in value;
|
|
@@ -1911,18 +2499,17 @@ const ServerComponentPlugin = /*#__PURE__*/createPlugin({
|
|
|
1911
2499
|
ctx.deserialize(node.address);
|
|
1912
2500
|
return globalThis._$SC.r(id);
|
|
1913
2501
|
}
|
|
1914
|
-
}
|
|
2502
|
+
};
|
|
1915
2503
|
function flightCodec(codec) {
|
|
1916
2504
|
const plugins = codec && codec.plugins || [];
|
|
1917
|
-
|
|
1918
|
-
if (plugin && plugin.tag === "dom-expressions/server-component") return codec;
|
|
1919
|
-
}
|
|
2505
|
+
if (plugins.some(plugin => plugin && plugin.tag === ServerComponentPlugin.tag)) return codec;
|
|
1920
2506
|
return {
|
|
1921
2507
|
...codec,
|
|
1922
2508
|
plugins: [...plugins, ServerComponentPlugin]
|
|
1923
2509
|
};
|
|
1924
2510
|
}
|
|
1925
2511
|
|
|
2512
|
+
const scopeStamp = typeof creationStamp === "function" ? creationStamp : () => 0;
|
|
1926
2513
|
function serverOwned(render) {
|
|
1927
2514
|
return NoHydration ? NoHydration({
|
|
1928
2515
|
get children() {
|
|
@@ -2147,6 +2734,26 @@ function createFrameSink(emit, frame) {
|
|
|
2147
2734
|
html
|
|
2148
2735
|
});
|
|
2149
2736
|
},
|
|
2737
|
+
hole(key, html) {
|
|
2738
|
+
emit({
|
|
2739
|
+
type: "hole",
|
|
2740
|
+
id,
|
|
2741
|
+
version,
|
|
2742
|
+
key,
|
|
2743
|
+
html
|
|
2744
|
+
});
|
|
2745
|
+
},
|
|
2746
|
+
attr(key, attrs, removed) {
|
|
2747
|
+
const chunk = {
|
|
2748
|
+
type: "attr",
|
|
2749
|
+
id,
|
|
2750
|
+
version,
|
|
2751
|
+
key,
|
|
2752
|
+
attrs
|
|
2753
|
+
};
|
|
2754
|
+
if (removed && removed.length) chunk.removed = removed;
|
|
2755
|
+
emit(chunk);
|
|
2756
|
+
},
|
|
2150
2757
|
openBinding(key, b) {
|
|
2151
2758
|
bindings.set(key, b);
|
|
2152
2759
|
},
|
|
@@ -2178,6 +2785,7 @@ function renderServerComponent(component, options = {}) {
|
|
|
2178
2785
|
if (ctx) {
|
|
2179
2786
|
ctx.commit = sink.commit;
|
|
2180
2787
|
ctx.commitEpoch = () => sink.epoch;
|
|
2788
|
+
ctx.liveHoles = createLiveHoles(sink);
|
|
2181
2789
|
}
|
|
2182
2790
|
return serverComponentScope(() => component(props));
|
|
2183
2791
|
};
|
|
@@ -2238,7 +2846,8 @@ function frameStream(makeCode, options) {
|
|
|
2238
2846
|
}
|
|
2239
2847
|
function slotRange(occurrence) {
|
|
2240
2848
|
return {
|
|
2241
|
-
t: `<!--slot:${occurrence}:start--><!--slot:${occurrence}:end
|
|
2849
|
+
t: `<!--slot:${occurrence}:start--><!--slot:${occurrence}:end-->`,
|
|
2850
|
+
$slot: true
|
|
2242
2851
|
};
|
|
2243
2852
|
}
|
|
2244
2853
|
const OCCURRENCE_UNSAFE = /[^A-Za-z0-9_.-]/g;
|
|
@@ -2286,14 +2895,28 @@ function tapFirstYield(iterable) {
|
|
|
2286
2895
|
}
|
|
2287
2896
|
};
|
|
2288
2897
|
}
|
|
2898
|
+
function suppressedFill(render) {
|
|
2899
|
+
const live = sharedConfig.context && sharedConfig.context.liveHoles;
|
|
2900
|
+
if (!live) return render();
|
|
2901
|
+
live.suppressed++;
|
|
2902
|
+
try {
|
|
2903
|
+
return render();
|
|
2904
|
+
} finally {
|
|
2905
|
+
live.suppressed--;
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2289
2908
|
function createDocumentSlotProps(clientProps, frameId) {
|
|
2290
2909
|
const counts = Object.create(null);
|
|
2291
2910
|
const getters = new Map();
|
|
2292
|
-
const range = (occurrence, content) =>
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2911
|
+
const range = (occurrence, content) => {
|
|
2912
|
+
const r = [{
|
|
2913
|
+
t: `<!--slot:${occurrence}:start-->`
|
|
2914
|
+
}, content, {
|
|
2915
|
+
t: `<!--slot:${occurrence}:end-->`
|
|
2916
|
+
}];
|
|
2917
|
+
r.$slot = true;
|
|
2918
|
+
return r;
|
|
2919
|
+
};
|
|
2297
2920
|
const zoneOwner = getOwner ? getOwner() : null;
|
|
2298
2921
|
const scoped = (occurrence, render) => {
|
|
2299
2922
|
const id = `sc-${frameId}-${occurrence}-`;
|
|
@@ -2316,27 +2939,68 @@ function createDocumentSlotProps(clientProps, frameId) {
|
|
|
2316
2939
|
if (!fn) {
|
|
2317
2940
|
fn = (...callArgs) => {
|
|
2318
2941
|
if (callArgs.length === 0 || callArgs[0] === undefined) {
|
|
2319
|
-
return scoped(prop, () => {
|
|
2942
|
+
return suppressedFill(() => scoped(prop, () => {
|
|
2320
2943
|
const value = clientProps[prop];
|
|
2321
2944
|
return range(prop, typeof value === "function" ? value() : value);
|
|
2322
|
-
});
|
|
2945
|
+
}));
|
|
2323
2946
|
}
|
|
2324
2947
|
const raw = callArgs[0];
|
|
2325
2948
|
const occurrence = occurrenceId(prop, raw, counts);
|
|
2326
2949
|
const slot = clientProps[prop];
|
|
2327
2950
|
if (typeof slot !== "function") return range(occurrence, undefined);
|
|
2328
2951
|
const resolved = {};
|
|
2952
|
+
const liveArgs = sharedConfig.context && sharedConfig.context.live && sharedConfig.context.live.args;
|
|
2329
2953
|
const vals = {};
|
|
2954
|
+
const evals = {};
|
|
2955
|
+
const states = {};
|
|
2956
|
+
const minted = {};
|
|
2330
2957
|
for (const key of Object.keys(raw)) {
|
|
2331
2958
|
if (key === "$key") continue;
|
|
2332
|
-
|
|
2333
|
-
|
|
2959
|
+
const desc = Object.getOwnPropertyDescriptor(raw, key);
|
|
2960
|
+
let evaluate = null;
|
|
2961
|
+
let value;
|
|
2962
|
+
if (desc.get) {
|
|
2963
|
+
const get = desc.get;
|
|
2964
|
+
evaluate = () => unwrapThunks(get.call(raw));
|
|
2965
|
+
} else {
|
|
2966
|
+
value = desc.value;
|
|
2967
|
+
if (typeof value === "function") {
|
|
2968
|
+
const fn = value;
|
|
2969
|
+
evaluate = () => unwrapThunks(fn);
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
if (evaluate) {
|
|
2973
|
+
evals[key] = evaluate;
|
|
2974
|
+
const stampBefore = scopeStamp();
|
|
2975
|
+
try {
|
|
2976
|
+
value = evaluate();
|
|
2977
|
+
states[key] = {
|
|
2978
|
+
settled: true,
|
|
2979
|
+
last: value
|
|
2980
|
+
};
|
|
2981
|
+
} catch (err) {
|
|
2982
|
+
const blocked = ssrHandleError && ssrHandleError(err);
|
|
2983
|
+
if (!blocked) throw err;
|
|
2984
|
+
const state = states[key] = {
|
|
2985
|
+
settled: false,
|
|
2986
|
+
last: undefined
|
|
2987
|
+
};
|
|
2988
|
+
value = retryArgUntilSettled(evaluate, blocked, key, occurrence, v => {
|
|
2989
|
+
state.settled = true;
|
|
2990
|
+
state.last = v;
|
|
2991
|
+
if (liveArgs) liveArgs.commit();
|
|
2992
|
+
});
|
|
2993
|
+
}
|
|
2994
|
+
if (scopeStamp() !== stampBefore) minted[key] = true;
|
|
2995
|
+
}
|
|
2334
2996
|
vals[key] = value;
|
|
2335
2997
|
}
|
|
2336
2998
|
const regions = [];
|
|
2337
2999
|
for (const key of Object.keys(vals)) {
|
|
2338
3000
|
const value = vals[key];
|
|
2339
|
-
if (
|
|
3001
|
+
if (isContainerTraced(value)) {
|
|
3002
|
+
resolved[key] = value;
|
|
3003
|
+
} else if (isServerContent(value)) {
|
|
2340
3004
|
const childId = `${frameId}.${occurrence}.${key}`;
|
|
2341
3005
|
const region = {
|
|
2342
3006
|
key,
|
|
@@ -2375,7 +3039,7 @@ function createDocumentSlotProps(clientProps, frameId) {
|
|
|
2375
3039
|
resolved[key] = value;
|
|
2376
3040
|
}
|
|
2377
3041
|
}
|
|
2378
|
-
const out = scoped(occurrence, () => range(occurrence, slot(resolved)));
|
|
3042
|
+
const out = suppressedFill(() => scoped(occurrence, () => range(occurrence, slot(resolved))));
|
|
2379
3043
|
const unused = regions.filter(r => !r.used);
|
|
2380
3044
|
if (sharedConfig.context) {
|
|
2381
3045
|
const args = {};
|
|
@@ -2388,17 +3052,33 @@ function createDocumentSlotProps(clientProps, frameId) {
|
|
|
2388
3052
|
};
|
|
2389
3053
|
continue;
|
|
2390
3054
|
}
|
|
2391
|
-
if (isServerContent(value)) continue;
|
|
2392
|
-
args[key] = value;
|
|
3055
|
+
if (!isContainerTraced(value) && isServerContent(value)) continue;
|
|
3056
|
+
args[key] = envelopeContainerTraces(value);
|
|
2393
3057
|
}
|
|
2394
|
-
sharedConfig.context.serialize(`sc:slot:${frameId}:${occurrence}`,
|
|
3058
|
+
sharedConfig.context.serialize(`sc:slot:${frameId}:${occurrence}`, {
|
|
3059
|
+
...args
|
|
3060
|
+
});
|
|
2395
3061
|
for (const region of unused) {
|
|
2396
3062
|
region.locked = true;
|
|
2397
3063
|
sharedConfig.context.serialize(`sc:region:${region.childId}`, resolveRegionHtml(sharedConfig.context, region.value));
|
|
2398
3064
|
}
|
|
3065
|
+
if (liveArgs) {
|
|
3066
|
+
for (const key of Object.keys(evals)) {
|
|
3067
|
+
if (regions.some(r => r.key === key)) continue;
|
|
3068
|
+
if (minted[key]) continue;
|
|
3069
|
+
const ledgerKey = `${frameId}:${occurrence}:${key}`;
|
|
3070
|
+
openArgBinding(liveArgs, ledgerKey, occurrence, key, evals[key], states[key], value => {
|
|
3071
|
+
args[key] = envelopeContainerTraces(value);
|
|
3072
|
+
liveArgs.slot(frameId, occurrence, {
|
|
3073
|
+
...args
|
|
3074
|
+
});
|
|
3075
|
+
});
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
2399
3078
|
}
|
|
2400
3079
|
return out;
|
|
2401
3080
|
};
|
|
3081
|
+
fn.$lhSkip = true;
|
|
2402
3082
|
getters.set(prop, fn);
|
|
2403
3083
|
}
|
|
2404
3084
|
return fn;
|
|
@@ -2412,6 +3092,113 @@ function frameElementOpen(id) {
|
|
|
2412
3092
|
return `<${FRAME_TAG} ${FRAME_ID_ATTR}="${escaped}" style="display:contents">`;
|
|
2413
3093
|
}
|
|
2414
3094
|
const FRAME_ELEMENT_CLOSE = `</${FRAME_TAG}>`;
|
|
3095
|
+
function armDocumentLiveHoles(ctx) {
|
|
3096
|
+
if (!ctx || ctx.liveHoles !== undefined) return;
|
|
3097
|
+
const live = ctx.live;
|
|
3098
|
+
if (live && live.holes !== undefined) {
|
|
3099
|
+
ctx.liveHoles = live.holes;
|
|
3100
|
+
if (live.holes) {
|
|
3101
|
+
ctx.commit = live.commit;
|
|
3102
|
+
ctx.commitEpoch = live.commitEpoch;
|
|
3103
|
+
}
|
|
3104
|
+
return;
|
|
3105
|
+
}
|
|
3106
|
+
if (!live || !ctx.async || ctx.noHydrate || !ctx.serialize || typeof ReadableStream !== "function") {
|
|
3107
|
+
ctx.liveHoles = null;
|
|
3108
|
+
if (live) live.holes = null;
|
|
3109
|
+
return;
|
|
3110
|
+
}
|
|
3111
|
+
const bindings = new Map();
|
|
3112
|
+
let epoch = 0;
|
|
3113
|
+
let sweepScheduled = false;
|
|
3114
|
+
let closed = false;
|
|
3115
|
+
const sweep = () => {
|
|
3116
|
+
epoch++;
|
|
3117
|
+
for (const b of [...bindings.values()]) {
|
|
3118
|
+
try {
|
|
3119
|
+
b.sweep();
|
|
3120
|
+
} catch (_) {
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
};
|
|
3124
|
+
const scheduleSweep = () => {
|
|
3125
|
+
if (closed || sweepScheduled || !bindings.size) return;
|
|
3126
|
+
sweepScheduled = true;
|
|
3127
|
+
queueMicrotask(() => {
|
|
3128
|
+
sweepScheduled = false;
|
|
3129
|
+
if (!closed) sweep();
|
|
3130
|
+
});
|
|
3131
|
+
};
|
|
3132
|
+
let channel;
|
|
3133
|
+
ctx.serialize("sc:live", new ReadableStream({
|
|
3134
|
+
start(c) {
|
|
3135
|
+
channel = c;
|
|
3136
|
+
}
|
|
3137
|
+
}));
|
|
3138
|
+
const push = op => {
|
|
3139
|
+
if (!closed) channel.enqueue(op);
|
|
3140
|
+
};
|
|
3141
|
+
ctx.liveHoles = live.holes = createLiveHoles({
|
|
3142
|
+
openBinding(key, b) {
|
|
3143
|
+
bindings.set(key, b);
|
|
3144
|
+
},
|
|
3145
|
+
closeBinding(key) {
|
|
3146
|
+
bindings.delete(key);
|
|
3147
|
+
},
|
|
3148
|
+
hole(key, html) {
|
|
3149
|
+
push({
|
|
3150
|
+
type: "hole",
|
|
3151
|
+
key,
|
|
3152
|
+
html
|
|
3153
|
+
});
|
|
3154
|
+
},
|
|
3155
|
+
attr(key, attrs, removed) {
|
|
3156
|
+
const op = {
|
|
3157
|
+
type: "attr",
|
|
3158
|
+
key,
|
|
3159
|
+
attrs
|
|
3160
|
+
};
|
|
3161
|
+
if (removed && removed.length) op.removed = removed;
|
|
3162
|
+
push(op);
|
|
3163
|
+
},
|
|
3164
|
+
error(key, error) {
|
|
3165
|
+
push({
|
|
3166
|
+
type: "error",
|
|
3167
|
+
key,
|
|
3168
|
+
error
|
|
3169
|
+
});
|
|
3170
|
+
},
|
|
3171
|
+
commit: scheduleSweep,
|
|
3172
|
+
get epoch() {
|
|
3173
|
+
return epoch;
|
|
3174
|
+
}
|
|
3175
|
+
}, true);
|
|
3176
|
+
ctx.commit = live.commit = scheduleSweep;
|
|
3177
|
+
ctx.commitEpoch = live.commitEpoch = () => epoch;
|
|
3178
|
+
live.args = {
|
|
3179
|
+
openBinding(key, b) {
|
|
3180
|
+
bindings.set(key, b);
|
|
3181
|
+
},
|
|
3182
|
+
closeBinding(key) {
|
|
3183
|
+
bindings.delete(key);
|
|
3184
|
+
},
|
|
3185
|
+
slot(fid, occurrence, args) {
|
|
3186
|
+
push({
|
|
3187
|
+
type: "slot",
|
|
3188
|
+
fid,
|
|
3189
|
+
key: occurrence,
|
|
3190
|
+
args
|
|
3191
|
+
});
|
|
3192
|
+
},
|
|
3193
|
+
commit: scheduleSweep
|
|
3194
|
+
};
|
|
3195
|
+
live.end = () => {
|
|
3196
|
+
if (closed) return;
|
|
3197
|
+
if (bindings.size) sweep();
|
|
3198
|
+
closed = true;
|
|
3199
|
+
channel.close();
|
|
3200
|
+
};
|
|
3201
|
+
}
|
|
2415
3202
|
function frameTransformDirectResult(value, {
|
|
2416
3203
|
id,
|
|
2417
3204
|
args
|
|
@@ -2422,6 +3209,7 @@ function frameTransformDirectResult(value, {
|
|
|
2422
3209
|
t: frameElementOpen(id)
|
|
2423
3210
|
},
|
|
2424
3211
|
serverOwned(() => {
|
|
3212
|
+
armDocumentLiveHoles(sharedConfig.context);
|
|
2425
3213
|
const slotProps = createDocumentSlotProps(props, id);
|
|
2426
3214
|
return serverComponentScope(() => component(slotProps));
|
|
2427
3215
|
}), {
|
|
@@ -2485,60 +3273,48 @@ function retryArgUntilSettled(evaluate, blocked, key, occurrence, onSettle) {
|
|
|
2485
3273
|
blocked.then(retry, retry);
|
|
2486
3274
|
});
|
|
2487
3275
|
}
|
|
2488
|
-
function openArgBinding(sink,
|
|
3276
|
+
function openArgBinding(sink, ledgerKey, occurrence, key, evaluate, state, emit) {
|
|
2489
3277
|
const owner = getOwner();
|
|
2490
|
-
|
|
2491
|
-
const reEmit = value => {
|
|
2492
|
-
const ref = `arg:${occurrence}:${key}@${sink.nextArgRef(ledgerKey)}`;
|
|
2493
|
-
sink.mintRef(ref);
|
|
2494
|
-
ctx.serialize(ref, value);
|
|
2495
|
-
args[key] = {
|
|
2496
|
-
$ref: ref
|
|
2497
|
-
};
|
|
2498
|
-
sink.slot(occurrence, {
|
|
2499
|
-
...args
|
|
2500
|
-
});
|
|
2501
|
-
};
|
|
2502
|
-
const binding = {
|
|
3278
|
+
sink.openBinding(ledgerKey, {
|
|
2503
3279
|
sweep() {
|
|
2504
3280
|
if (!state.settled) return;
|
|
2505
3281
|
let value;
|
|
3282
|
+
const stampBefore = scopeStamp();
|
|
2506
3283
|
try {
|
|
2507
3284
|
value = owner ? runWithOwner(owner, evaluate) : evaluate();
|
|
2508
3285
|
} catch (err) {
|
|
2509
3286
|
const blocked = ssrHandleError && ssrHandleError(err);
|
|
2510
3287
|
if (!blocked) {
|
|
2511
3288
|
sink.closeBinding(ledgerKey);
|
|
2512
|
-
|
|
3289
|
+
emit(Promise.reject(err instanceof Error ? err : new Error(String(err))));
|
|
3290
|
+
return;
|
|
3291
|
+
}
|
|
3292
|
+
if (scopeStamp() !== stampBefore) {
|
|
3293
|
+
sink.closeBinding(ledgerKey);
|
|
2513
3294
|
return;
|
|
2514
3295
|
}
|
|
2515
3296
|
state.settled = false;
|
|
2516
|
-
|
|
3297
|
+
emit(retryArgUntilSettled(evaluate, blocked, key, occurrence, v => {
|
|
2517
3298
|
state.settled = true;
|
|
2518
3299
|
state.last = v;
|
|
2519
3300
|
sink.commit();
|
|
2520
3301
|
}));
|
|
2521
3302
|
return;
|
|
2522
3303
|
}
|
|
3304
|
+
if (scopeStamp() !== stampBefore) {
|
|
3305
|
+
sink.closeBinding(ledgerKey);
|
|
3306
|
+
return;
|
|
3307
|
+
}
|
|
2523
3308
|
if (value === state.last) return;
|
|
2524
3309
|
state.last = value;
|
|
2525
3310
|
if (isServerContent(value)) {
|
|
2526
3311
|
sink.closeBinding(ledgerKey);
|
|
2527
|
-
|
|
3312
|
+
emit(Promise.reject(contentArgError(key, occurrence)));
|
|
2528
3313
|
return;
|
|
2529
3314
|
}
|
|
2530
|
-
|
|
2531
|
-
if (value == null || t === "string" || t === "number" || t === "boolean") {
|
|
2532
|
-
args[key] = value;
|
|
2533
|
-
sink.slot(occurrence, {
|
|
2534
|
-
...args
|
|
2535
|
-
});
|
|
2536
|
-
} else {
|
|
2537
|
-
reEmit(value);
|
|
2538
|
-
}
|
|
3315
|
+
emit(value);
|
|
2539
3316
|
}
|
|
2540
|
-
};
|
|
2541
|
-
sink.openBinding(ledgerKey, binding);
|
|
3317
|
+
});
|
|
2542
3318
|
}
|
|
2543
3319
|
function createSlotProps(sink, frame) {
|
|
2544
3320
|
const counts = Object.create(null);
|
|
@@ -2556,6 +3332,17 @@ function createSlotProps(sink, frame) {
|
|
|
2556
3332
|
if (callArgs.length === 0 || callArgs[0] === undefined) {
|
|
2557
3333
|
return slotRange(prop);
|
|
2558
3334
|
}
|
|
3335
|
+
const live = sharedConfig.context && sharedConfig.context.liveHoles;
|
|
3336
|
+
if (live) {
|
|
3337
|
+
if (live.sweeping) {
|
|
3338
|
+
live.gateHit = true;
|
|
3339
|
+
return {
|
|
3340
|
+
t: "",
|
|
3341
|
+
$slot: true
|
|
3342
|
+
};
|
|
3343
|
+
}
|
|
3344
|
+
live.recordStamp++;
|
|
3345
|
+
}
|
|
2559
3346
|
const raw = callArgs[0];
|
|
2560
3347
|
const occurrence = occurrenceId(prop, raw, counts);
|
|
2561
3348
|
const args = {};
|
|
@@ -2574,6 +3361,7 @@ function createSlotProps(sink, frame) {
|
|
|
2574
3361
|
let evaluate = null;
|
|
2575
3362
|
let value;
|
|
2576
3363
|
let state = null;
|
|
3364
|
+
const stampBefore = scopeStamp();
|
|
2577
3365
|
try {
|
|
2578
3366
|
if (desc.get) {
|
|
2579
3367
|
const get = desc.get;
|
|
@@ -2601,6 +3389,7 @@ function createSlotProps(sink, frame) {
|
|
|
2601
3389
|
sink.commit();
|
|
2602
3390
|
});
|
|
2603
3391
|
}
|
|
3392
|
+
const mintedEval = scopeStamp() !== stampBefore;
|
|
2604
3393
|
const t = typeof value;
|
|
2605
3394
|
if (value == null || t === "string" || t === "number" || t === "boolean") {
|
|
2606
3395
|
args[key] = value;
|
|
@@ -2608,7 +3397,7 @@ function createSlotProps(sink, frame) {
|
|
|
2608
3397
|
settled: true,
|
|
2609
3398
|
last: value
|
|
2610
3399
|
};
|
|
2611
|
-
} else if (isServerContent(value)) {
|
|
3400
|
+
} else if (!isContainerTraced(value) && isServerContent(value)) {
|
|
2612
3401
|
const resolved = ctx.resolve(value);
|
|
2613
3402
|
if (resolved.h.length) {
|
|
2614
3403
|
throw new Error("Async server content in a slot arg needs a boundary (arg '" + key + "' of " + occurrence + "). Wrap the async read in a <Suspense>, or move it above the slot.");
|
|
@@ -2619,7 +3408,7 @@ function createSlotProps(sink, frame) {
|
|
|
2619
3408
|
};
|
|
2620
3409
|
} else {
|
|
2621
3410
|
const ref = `arg:${occurrence}:${key}`;
|
|
2622
|
-
ctx.serialize(ref, value);
|
|
3411
|
+
ctx.serialize(ref, envelopeContainerTraces(value));
|
|
2623
3412
|
args[key] = {
|
|
2624
3413
|
$ref: ref
|
|
2625
3414
|
};
|
|
@@ -2628,7 +3417,7 @@ function createSlotProps(sink, frame) {
|
|
|
2628
3417
|
last: value
|
|
2629
3418
|
};
|
|
2630
3419
|
}
|
|
2631
|
-
if (evaluate && state) opened.push({
|
|
3420
|
+
if (evaluate && state && !mintedEval) opened.push({
|
|
2632
3421
|
key,
|
|
2633
3422
|
evaluate,
|
|
2634
3423
|
state
|
|
@@ -2642,10 +3431,28 @@ function createSlotProps(sink, frame) {
|
|
|
2642
3431
|
});
|
|
2643
3432
|
const ctx = sharedConfig.context;
|
|
2644
3433
|
for (const b of opened) {
|
|
2645
|
-
|
|
3434
|
+
const key = b.key;
|
|
3435
|
+
const ledgerKey = `${occurrence}:${key}`;
|
|
3436
|
+
openArgBinding(sink, ledgerKey, occurrence, key, b.evaluate, b.state, value => {
|
|
3437
|
+
const t = typeof value;
|
|
3438
|
+
if (value == null || t === "string" || t === "number" || t === "boolean") {
|
|
3439
|
+
args[key] = value;
|
|
3440
|
+
} else {
|
|
3441
|
+
const ref = `arg:${occurrence}:${key}@${sink.nextArgRef(ledgerKey)}`;
|
|
3442
|
+
sink.mintRef(ref);
|
|
3443
|
+
ctx.serialize(ref, envelopeContainerTraces(value));
|
|
3444
|
+
args[key] = {
|
|
3445
|
+
$ref: ref
|
|
3446
|
+
};
|
|
3447
|
+
}
|
|
3448
|
+
sink.slot(occurrence, {
|
|
3449
|
+
...args
|
|
3450
|
+
});
|
|
3451
|
+
});
|
|
2646
3452
|
}
|
|
2647
3453
|
return slotRange(occurrence);
|
|
2648
3454
|
};
|
|
3455
|
+
fn.$lhSkip = true;
|
|
2649
3456
|
getters.set(prop, fn);
|
|
2650
3457
|
}
|
|
2651
3458
|
return fn;
|
|
@@ -2677,16 +3484,27 @@ function serverComponentResponse(component, options = {}, init = {}) {
|
|
|
2677
3484
|
version
|
|
2678
3485
|
}
|
|
2679
3486
|
});
|
|
3487
|
+
let closed = false;
|
|
2680
3488
|
const body = new ReadableStream({
|
|
2681
3489
|
start(controller) {
|
|
2682
3490
|
stream.pipe({
|
|
2683
3491
|
write(chunk) {
|
|
2684
|
-
|
|
3492
|
+
if (closed) return;
|
|
3493
|
+
try {
|
|
3494
|
+
controller.enqueue(createChunk(JSON.stringify(chunk)));
|
|
3495
|
+
} catch (_) {
|
|
3496
|
+
closed = true;
|
|
3497
|
+
}
|
|
2685
3498
|
},
|
|
2686
3499
|
end() {
|
|
3500
|
+
if (closed) return;
|
|
3501
|
+
closed = true;
|
|
2687
3502
|
controller.close();
|
|
2688
3503
|
}
|
|
2689
3504
|
});
|
|
3505
|
+
},
|
|
3506
|
+
cancel() {
|
|
3507
|
+
closed = true;
|
|
2690
3508
|
}
|
|
2691
3509
|
});
|
|
2692
3510
|
return new Response(body, {
|
|
@@ -2770,9 +3588,17 @@ function frameFlightResponse({
|
|
|
2770
3588
|
headers.set(FRAME_STREAM_HEADER, primary ? primary.id : "");
|
|
2771
3589
|
headers.set("X-Content-Raw", "1");
|
|
2772
3590
|
headers.set(SINGLE_FLIGHT_HEADER, "true");
|
|
3591
|
+
let closed = false;
|
|
2773
3592
|
const body = new ReadableStream({
|
|
2774
3593
|
async start(controller) {
|
|
2775
|
-
const write = chunk =>
|
|
3594
|
+
const write = chunk => {
|
|
3595
|
+
if (closed) return;
|
|
3596
|
+
try {
|
|
3597
|
+
controller.enqueue(createChunk(JSON.stringify(chunk)));
|
|
3598
|
+
} catch (_) {
|
|
3599
|
+
closed = true;
|
|
3600
|
+
}
|
|
3601
|
+
};
|
|
2776
3602
|
try {
|
|
2777
3603
|
for (const {
|
|
2778
3604
|
id,
|
|
@@ -2799,10 +3625,19 @@ function frameFlightResponse({
|
|
|
2799
3625
|
});
|
|
2800
3626
|
}
|
|
2801
3627
|
}
|
|
2802
|
-
|
|
3628
|
+
if (!closed) {
|
|
3629
|
+
closed = true;
|
|
3630
|
+
controller.close();
|
|
3631
|
+
}
|
|
2803
3632
|
} catch (err) {
|
|
2804
|
-
|
|
3633
|
+
if (!closed) {
|
|
3634
|
+
closed = true;
|
|
3635
|
+
controller.error(err);
|
|
3636
|
+
}
|
|
2805
3637
|
}
|
|
3638
|
+
},
|
|
3639
|
+
cancel() {
|
|
3640
|
+
closed = true;
|
|
2806
3641
|
}
|
|
2807
3642
|
});
|
|
2808
3643
|
return new Response(body, {
|
|
@@ -2811,6 +3646,7 @@ function frameFlightResponse({
|
|
|
2811
3646
|
});
|
|
2812
3647
|
}
|
|
2813
3648
|
|
|
3649
|
+
setContainerTraceResolver(getProjectionTrace);
|
|
2814
3650
|
function asyncArg(value) {
|
|
2815
3651
|
return value;
|
|
2816
3652
|
}
|