@solidjs/web 2.0.0-beta.16 → 2.0.0-beta.18
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 +153 -14
- package/dist/dev.js +154 -16
- package/dist/server.cjs +140 -40
- package/dist/server.js +141 -42
- package/dist/web.cjs +153 -14
- package/dist/web.js +154 -16
- package/package.json +25 -10
- package/serialization/dist/serialization.cjs +83 -0
- package/serialization/dist/serialization.js +75 -0
- package/serialization/package.json +20 -0
- package/serialization/types/index.d.ts +97 -0
- package/serialization/types-cjs/index.d.cts +97 -0
- package/serialization/types-cjs/package.json +3 -0
- package/types/client.d.ts +13 -0
- package/types/index.d.ts +7 -1
- package/types/serializer.d.ts +97 -0
- package/types/server.d.ts +54 -15
- package/types-cjs/client.d.cts +13 -0
- package/types-cjs/index.d.cts +7 -1
- package/types-cjs/serializer.d.cts +97 -0
- package/types-cjs/server.d.cts +54 -15
- package/storage/types/src/client.d.ts +0 -1
- package/storage/types/src/index.d.ts +0 -171
- package/storage/types/src/jsx.d.ts +0 -29
- package/storage/types/src/server-mock.d.ts +0 -161
- package/storage/types/storage/src/index.d.ts +0 -2
- package/storage/types-cjs/src/client.d.cts +0 -1
- package/storage/types-cjs/src/index.d.cts +0 -171
- package/storage/types-cjs/src/jsx.d.cts +0 -29
- package/storage/types-cjs/src/server-mock.d.cts +0 -161
- package/storage/types-cjs/storage/src/index.d.cts +0 -2
package/dist/web.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createRenderEffect, createMemo, sharedConfig, untrack, runWithOwner, flatten, createRoot, merge, createComponent, omit,
|
|
1
|
+
import { createRenderEffect, createMemo, sharedConfig, untrack, runWithOwner, flatten, createRoot, merge, createComponent, omit, createOwner, enableHydration, flush, getOwner, createEffect } from 'solid-js';
|
|
2
2
|
export { Errored, For, Hydration, Loading, Match, NoHydration, Repeat, Reveal, Show, Switch, createComponent, getOwner, untrack } from 'solid-js';
|
|
3
3
|
|
|
4
4
|
const DOMWithState = {
|
|
@@ -503,22 +503,117 @@ function assign(node, props, skipChildren, prevProps = {}, skipRef = false) {
|
|
|
503
503
|
prevProps[prop] = assignProp(node, prop, props[prop], prevProps[prop], skipRef, nodeName);
|
|
504
504
|
}
|
|
505
505
|
}
|
|
506
|
+
const ASSET_REMOVAL_GRACE = 100;
|
|
507
|
+
const assetRegistry = new Map();
|
|
508
|
+
function assetEntryKey(descriptor) {
|
|
509
|
+
if (descriptor.policy === "exclusive") return "x|" + descriptor.key;
|
|
510
|
+
return descriptor.type === "inline-style" ? "i|" + descriptor.id : descriptor.type + "|" + descriptor.href;
|
|
511
|
+
}
|
|
512
|
+
function findAssetElement(selector, attr, value) {
|
|
513
|
+
const nodes = document.querySelectorAll(selector);
|
|
514
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
515
|
+
if (nodes[i].getAttribute(attr) === value) return nodes[i];
|
|
516
|
+
}
|
|
517
|
+
return null;
|
|
518
|
+
}
|
|
519
|
+
function mountAssetElement(descriptor) {
|
|
520
|
+
let el;
|
|
521
|
+
if (descriptor.type === "inline-style") {
|
|
522
|
+
el = findAssetElement("style[data-asset]", "data-asset", descriptor.id);
|
|
523
|
+
if (!el) {
|
|
524
|
+
el = document.createElement("style");
|
|
525
|
+
el.setAttribute("data-asset", descriptor.id);
|
|
526
|
+
el.textContent = descriptor.content || "";
|
|
527
|
+
}
|
|
528
|
+
} else {
|
|
529
|
+
const rel = descriptor.type === "module" ? "modulepreload" : "stylesheet";
|
|
530
|
+
el = findAssetElement(`link[rel="${rel}"]`, "href", descriptor.href);
|
|
531
|
+
if (!el) {
|
|
532
|
+
el = document.createElement("link");
|
|
533
|
+
el.rel = rel;
|
|
534
|
+
el.href = descriptor.href;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (descriptor.attrs) {
|
|
538
|
+
for (const name in descriptor.attrs) el.setAttribute(name, descriptor.attrs[name]);
|
|
539
|
+
}
|
|
540
|
+
if (!el.isConnected) document.head.appendChild(el);
|
|
541
|
+
return el;
|
|
542
|
+
}
|
|
543
|
+
function acquireAsset(descriptor) {
|
|
544
|
+
const key = assetEntryKey(descriptor);
|
|
545
|
+
let entry = assetRegistry.get(key);
|
|
546
|
+
if (descriptor.policy === "exclusive") {
|
|
547
|
+
if (!entry) {
|
|
548
|
+
entry = {
|
|
549
|
+
original: descriptor.get(),
|
|
550
|
+
set: descriptor.set,
|
|
551
|
+
writers: []
|
|
552
|
+
};
|
|
553
|
+
assetRegistry.set(key, entry);
|
|
554
|
+
}
|
|
555
|
+
const writer = {
|
|
556
|
+
value: descriptor.value
|
|
557
|
+
};
|
|
558
|
+
entry.writers.push(writer);
|
|
559
|
+
entry.set(writer.value);
|
|
560
|
+
let released = false;
|
|
561
|
+
return () => {
|
|
562
|
+
if (released) return;
|
|
563
|
+
released = true;
|
|
564
|
+
const index = entry.writers.indexOf(writer);
|
|
565
|
+
const wasTop = index === entry.writers.length - 1;
|
|
566
|
+
entry.writers.splice(index, 1);
|
|
567
|
+
if (!wasTop) return;
|
|
568
|
+
if (entry.writers.length) {
|
|
569
|
+
entry.set(entry.writers[entry.writers.length - 1].value);
|
|
570
|
+
} else {
|
|
571
|
+
entry.set(entry.original);
|
|
572
|
+
assetRegistry.delete(key);
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
if (!entry) {
|
|
577
|
+
entry = {
|
|
578
|
+
count: 0,
|
|
579
|
+
element: null,
|
|
580
|
+
timer: null
|
|
581
|
+
};
|
|
582
|
+
assetRegistry.set(key, entry);
|
|
583
|
+
}
|
|
584
|
+
if (entry.timer) {
|
|
585
|
+
clearTimeout(entry.timer);
|
|
586
|
+
entry.timer = null;
|
|
587
|
+
}
|
|
588
|
+
entry.count++;
|
|
589
|
+
if (!entry.element || !entry.element.isConnected) entry.element = mountAssetElement(descriptor);
|
|
590
|
+
let released = false;
|
|
591
|
+
return () => {
|
|
592
|
+
if (released) return;
|
|
593
|
+
released = true;
|
|
594
|
+
if (--entry.count > 0) return;
|
|
595
|
+
entry.timer = setTimeout(() => {
|
|
596
|
+
assetRegistry.delete(key);
|
|
597
|
+
entry.element && entry.element.remove();
|
|
598
|
+
}, ASSET_REMOVAL_GRACE);
|
|
599
|
+
};
|
|
600
|
+
}
|
|
506
601
|
function loadModuleAssets(mapping) {
|
|
507
602
|
const hy = globalThis._$HY;
|
|
508
603
|
if (!hy) return;
|
|
509
604
|
const pending = [];
|
|
510
|
-
for (const
|
|
511
|
-
if (hy.modules[
|
|
512
|
-
const entryUrl = mapping[
|
|
513
|
-
if (!hy.loading[
|
|
514
|
-
hy.loading[
|
|
515
|
-
hy.modules[
|
|
605
|
+
for (const key in mapping) {
|
|
606
|
+
if (hy.modules[key]) continue;
|
|
607
|
+
const entryUrl = mapping[key];
|
|
608
|
+
if (!hy.loading[key]) {
|
|
609
|
+
hy.loading[key] = import(entryUrl).then(mod => {
|
|
610
|
+
hy.modules[key] = mod;
|
|
516
611
|
}, err => {
|
|
517
|
-
delete hy.loading[
|
|
612
|
+
delete hy.loading[key];
|
|
518
613
|
throw err;
|
|
519
614
|
});
|
|
520
615
|
}
|
|
521
|
-
pending.push(hy.loading[
|
|
616
|
+
pending.push(hy.loading[key]);
|
|
522
617
|
}
|
|
523
618
|
return pending.length ? Promise.all(pending).then(() => {}) : undefined;
|
|
524
619
|
}
|
|
@@ -805,7 +900,12 @@ function insertExpression(parent, value, current, marker) {
|
|
|
805
900
|
const tc = typeof current;
|
|
806
901
|
if (tc === "string" || tc === "number") {
|
|
807
902
|
parent.firstChild.data = value;
|
|
808
|
-
} else
|
|
903
|
+
} else {
|
|
904
|
+
if (ownsAllChildren(parent, current)) parent.textContent = value;else {
|
|
905
|
+
removeOwnedChildren(parent, current);
|
|
906
|
+
parent.insertBefore(document.createTextNode(value), parent.firstChild);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
809
909
|
} else if (value === undefined) {
|
|
810
910
|
cleanChildren(parent, current, marker);
|
|
811
911
|
} else if (value.nodeType) {
|
|
@@ -828,7 +928,7 @@ function insertExpression(parent, value, current, marker) {
|
|
|
828
928
|
appendNodes(parent, value, marker);
|
|
829
929
|
} else reconcileArrays(parent, current, value, marker);
|
|
830
930
|
} else {
|
|
831
|
-
current && cleanChildren(parent);
|
|
931
|
+
current && cleanChildren(parent, current);
|
|
832
932
|
appendNodes(parent, value);
|
|
833
933
|
}
|
|
834
934
|
} else ;
|
|
@@ -868,8 +968,34 @@ function appendNodes(parent, array, marker = null) {
|
|
|
868
968
|
if (marker) n[$$SLOT] = marker;
|
|
869
969
|
}
|
|
870
970
|
}
|
|
971
|
+
function ownsAllChildren(parent, current) {
|
|
972
|
+
if (current == null) return true;
|
|
973
|
+
if (Array.isArray(current)) {
|
|
974
|
+
return current.length ? parent.firstChild === current[0] && parent.lastChild === current[current.length - 1] : parent.firstChild === null;
|
|
975
|
+
}
|
|
976
|
+
if (current === "") return parent.firstChild === null;
|
|
977
|
+
if (current.nodeType) return parent.firstChild === current && parent.lastChild === current;
|
|
978
|
+
const first = parent.firstChild;
|
|
979
|
+
return first !== null && first.nodeType === 3 && parent.lastChild === first;
|
|
980
|
+
}
|
|
981
|
+
function removeOwnedChildren(parent, current) {
|
|
982
|
+
if (Array.isArray(current)) {
|
|
983
|
+
for (let i = 0; i < current.length; i++) {
|
|
984
|
+
const el = current[i];
|
|
985
|
+
if (el.parentNode === parent) el.remove();
|
|
986
|
+
}
|
|
987
|
+
} else if (current.nodeType) {
|
|
988
|
+
if (current.parentNode === parent) current.remove();
|
|
989
|
+
} else {
|
|
990
|
+
const first = parent.firstChild;
|
|
991
|
+
if (first && first.nodeType === 3) first.remove();
|
|
992
|
+
}
|
|
993
|
+
}
|
|
871
994
|
function cleanChildren(parent, current, marker, replacement) {
|
|
872
|
-
if (marker === undefined)
|
|
995
|
+
if (marker === undefined) {
|
|
996
|
+
if (ownsAllChildren(parent, current)) return parent.textContent = "";
|
|
997
|
+
return removeOwnedChildren(parent, current);
|
|
998
|
+
}
|
|
873
999
|
if (current.length) {
|
|
874
1000
|
let inserted = false;
|
|
875
1001
|
for (let i = current.length - 1; i >= 0; i--) {
|
|
@@ -940,11 +1066,16 @@ const hydrate = (...args) => {
|
|
|
940
1066
|
return hydrate$1(...args);
|
|
941
1067
|
};
|
|
942
1068
|
function Portal(props) {
|
|
1069
|
+
return runWithOwner(createOwner(), () => portalImpl(props));
|
|
1070
|
+
}
|
|
1071
|
+
function portalImpl(props) {
|
|
943
1072
|
const treeMarker = document.createTextNode(""),
|
|
944
1073
|
startMarker = document.createTextNode(""),
|
|
945
1074
|
endMarker = document.createTextNode(""),
|
|
946
1075
|
mount = () => props.mount || document.body,
|
|
947
|
-
content = createMemo(() => [startMarker, props.children]
|
|
1076
|
+
content = createMemo(() => [startMarker, props.children], {
|
|
1077
|
+
ssrSource: "client"
|
|
1078
|
+
});
|
|
948
1079
|
createRenderEffect(
|
|
949
1080
|
() => [mount(), content(), getOwner()], ([, c, owner]) => {
|
|
950
1081
|
const m = untrack(mount);
|
|
@@ -965,8 +1096,10 @@ function Portal(props) {
|
|
|
965
1096
|
c = n;
|
|
966
1097
|
}
|
|
967
1098
|
};
|
|
968
|
-
},
|
|
969
|
-
|
|
1099
|
+
},
|
|
1100
|
+
{
|
|
1101
|
+
schedule: true,
|
|
1102
|
+
ssrSource: "client"
|
|
970
1103
|
});
|
|
971
1104
|
createEffect(mount, () => {
|
|
972
1105
|
const m = untrack(mount);
|
|
@@ -974,6 +1107,11 @@ function Portal(props) {
|
|
|
974
1107
|
if (!ownerRoot || ownerRoot.contains(m)) return;
|
|
975
1108
|
registerDelegatedContainer(m, ownerRoot);
|
|
976
1109
|
return () => unregisterDelegatedContainer(m, ownerRoot);
|
|
1110
|
+
}, {
|
|
1111
|
+
ssrSource: "client"
|
|
1112
|
+
});
|
|
1113
|
+
if (sharedConfig.hydrating) return createMemo(() => treeMarker, {
|
|
1114
|
+
ssrSource: "client"
|
|
977
1115
|
});
|
|
978
1116
|
return treeMarker;
|
|
979
1117
|
}
|
|
@@ -1005,4 +1143,4 @@ function createElement(tagName, is = undefined) {
|
|
|
1005
1143
|
});
|
|
1006
1144
|
}
|
|
1007
1145
|
|
|
1008
|
-
export { voidFn as Assets, ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, voidFn as HydrationScript, MathMLElements, Namespaces, Portal, RawTextElements, RequestContext, SVGElements, VoidElements, addEvent, applyRef, assign, className, delegateEvents, dynamic, dynamicProperty, effect, escape, voidFn as generateHydrationScript, voidFn as getAssets, getDelegatedRoot, getFirstChild, getHydrationKey, getNextElement, getNextMarker, getNextMatch, getNextSibling, voidFn as getRequestEvent, hydrate, insert, isDev, isServer, memo, mergeProps, ref, registerDelegatedContainer, registerDelegatedRoot, render, renderToStream, renderToString, renderToStringAsync, resolveSSRNode, runHydrationEvents, scope, setAttribute, setAttributeNS, setProperty, setStyleProperty, spread, ssr, ssrAttribute, ssrClassList, ssrElement, ssrHydrationKey, ssrStyle, style, template, unregisterDelegatedContainer, unregisterDelegatedRoot, voidFn as useAssets };
|
|
1146
|
+
export { voidFn as Assets, ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, voidFn as HydrationScript, MathMLElements, Namespaces, Portal, RawTextElements, RequestContext, SVGElements, VoidElements, acquireAsset, addEvent, applyRef, assign, className, delegateEvents, dynamic, dynamicProperty, effect, escape, voidFn as generateHydrationScript, voidFn as getAssets, getDelegatedRoot, getFirstChild, getHydrationKey, getNextElement, getNextMarker, getNextMatch, getNextSibling, voidFn as getRequestEvent, hydrate, insert, isDev, isServer, memo, mergeProps, ref, registerDelegatedContainer, registerDelegatedRoot, render, renderToStream, renderToString, renderToStringAsync, resolveSSRNode, runHydrationEvents, scope, setAttribute, setAttributeNS, setProperty, setStyleProperty, spread, ssr, ssrAttribute, ssrClassList, ssrElement, ssrHydrationKey, ssrStyle, style, template, unregisterDelegatedContainer, unregisterDelegatedRoot, voidFn as useAssets };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidjs/web",
|
|
3
3
|
"description": "Solid's web runtime: client rendering, hydration, SSR, and DOM-specific control flow (Portal, Dynamic).",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.18",
|
|
5
5
|
"author": "Ryan Carniato",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://solidjs.com",
|
|
@@ -27,7 +27,11 @@
|
|
|
27
27
|
"storage/dist",
|
|
28
28
|
"storage/types",
|
|
29
29
|
"storage/types-cjs",
|
|
30
|
-
"storage/package.json"
|
|
30
|
+
"storage/package.json",
|
|
31
|
+
"serialization/dist",
|
|
32
|
+
"serialization/types",
|
|
33
|
+
"serialization/types-cjs",
|
|
34
|
+
"serialization/package.json"
|
|
31
35
|
],
|
|
32
36
|
"exports": {
|
|
33
37
|
".": {
|
|
@@ -130,30 +134,41 @@
|
|
|
130
134
|
"default": "./storage/dist/storage.cjs"
|
|
131
135
|
}
|
|
132
136
|
},
|
|
137
|
+
"./serialization": {
|
|
138
|
+
"import": {
|
|
139
|
+
"types": "./serialization/types/index.d.ts",
|
|
140
|
+
"default": "./serialization/dist/serialization.js"
|
|
141
|
+
},
|
|
142
|
+
"require": {
|
|
143
|
+
"types": "./serialization/types-cjs/index.d.cts",
|
|
144
|
+
"default": "./serialization/dist/serialization.cjs"
|
|
145
|
+
}
|
|
146
|
+
},
|
|
133
147
|
"./types/*": "./types/*"
|
|
134
148
|
},
|
|
135
149
|
"dependencies": {
|
|
136
|
-
"seroval": "
|
|
137
|
-
"seroval-plugins": "
|
|
150
|
+
"seroval": "~1.5.4",
|
|
151
|
+
"seroval-plugins": "~1.5.4"
|
|
138
152
|
},
|
|
139
153
|
"peerDependencies": {
|
|
140
|
-
"solid-js": "^2.0.0-beta.
|
|
154
|
+
"solid-js": "^2.0.0-beta.18"
|
|
141
155
|
},
|
|
142
156
|
"devDependencies": {
|
|
143
|
-
"solid-js": "2.0.0-beta.
|
|
157
|
+
"solid-js": "2.0.0-beta.18"
|
|
144
158
|
},
|
|
145
159
|
"scripts": {
|
|
146
160
|
"build": "npm-run-all -nl build:clean types:copy-jsx build:js",
|
|
147
161
|
"build:clean": "rimraf dist/",
|
|
148
162
|
"build:js": "rollup -c",
|
|
149
163
|
"link": "symlink-dir . node_modules/@solidjs/web",
|
|
150
|
-
"types": "npm-run-all -nl types:clean types:copy-jsx types:web types:copy-web types:web-storage types:cjs",
|
|
151
|
-
"types:clean": "rimraf types/ types-cjs/ storage/types-cjs/",
|
|
164
|
+
"types": "npm-run-all -nl types:clean types:copy-jsx types:web types:copy-web types:web-storage types:copy-serialization types:cjs",
|
|
165
|
+
"types:clean": "rimraf types/ types-cjs/ storage/types/ storage/types-cjs/ serialization/types/ serialization/types-cjs/",
|
|
152
166
|
"types:copy-jsx": "ncp ../../node_modules/@dom-expressions/runtime/src/jsx.d.ts ./src/jsx.d.ts && ncp ../../node_modules/@dom-expressions/runtime/src/jsx-properties.d.ts ./src/jsx-properties.d.ts && dom-expressions-jsx-types --input ./src/jsx.d.ts --element \"SolidElement | Node | ArrayElement\" --import 'import type { Element as SolidElement } from \"solid-js\";'",
|
|
153
167
|
"types:web": "tsc --project ./tsconfig.build.json",
|
|
154
|
-
"types:copy-web": "ncp ../../node_modules/@dom-expressions/runtime/src/client.d.ts ./types/client.d.ts && ncp ../../node_modules/@dom-expressions/runtime/src/server.d.ts ./types/server.d.ts && ncp ./src/jsx.d.ts ./types/jsx.d.ts && ncp ./src/jsx-properties.d.ts ./types/jsx-properties.d.ts",
|
|
168
|
+
"types:copy-web": "ncp ../../node_modules/@dom-expressions/runtime/src/client.d.ts ./types/client.d.ts && ncp ../../node_modules/@dom-expressions/runtime/src/server.d.ts ./types/server.d.ts && ncp ../../node_modules/@dom-expressions/runtime/src/serializer.d.ts ./types/serializer.d.ts && ncp ./src/jsx.d.ts ./types/jsx.d.ts && ncp ./src/jsx-properties.d.ts ./types/jsx-properties.d.ts",
|
|
155
169
|
"types:web-storage": "tsc --project ./storage/tsconfig.build.json",
|
|
156
|
-
"types:
|
|
170
|
+
"types:copy-serialization": "node -e \"fs.mkdirSync('./serialization/types', { recursive: true }); fs.copyFileSync('../../node_modules/@dom-expressions/runtime/src/serializer.d.ts', './serialization/types/index.d.ts');\"",
|
|
171
|
+
"types:cjs": "node ../../scripts/sync-dual-types.mjs ./types ./types-cjs ./storage/types ./storage/types-cjs ./serialization/types ./serialization/types-cjs",
|
|
157
172
|
"test": "vitest run && vitest run --config vite.config.server.mjs && vitest run --config vite.config.hydrate.mjs",
|
|
158
173
|
"test:server": "vitest run --config vite.config.server.mjs",
|
|
159
174
|
"coverage": "vitest run --coverage",
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var seroval = require('seroval');
|
|
4
|
+
var web = require('seroval-plugins/web');
|
|
5
|
+
|
|
6
|
+
const DEFAULT_DISABLED_FEATURES = seroval.Feature.AggregateError | seroval.Feature.BigIntTypedArray;
|
|
7
|
+
const HYDRATION_GLOBAL = "_$HY.r";
|
|
8
|
+
const DEFAULT_WEB_PLUGINS = Object.freeze([web.AbortSignalPlugin,
|
|
9
|
+
web.CustomEventPlugin, web.DOMExceptionPlugin, web.EventPlugin,
|
|
10
|
+
web.FormDataPlugin, web.HeadersPlugin, web.ReadableStreamPlugin, web.RequestPlugin, web.ResponsePlugin, web.URLSearchParamsPlugin, web.URLPlugin]);
|
|
11
|
+
function resolveSerializerPlugins(customPlugins) {
|
|
12
|
+
return customPlugins ? [...customPlugins, ...DEFAULT_WEB_PLUGINS] : [...DEFAULT_WEB_PLUGINS];
|
|
13
|
+
}
|
|
14
|
+
function createSerializer(options) {
|
|
15
|
+
return new seroval.Serializer({
|
|
16
|
+
...options,
|
|
17
|
+
plugins: resolveSerializerPlugins(options.plugins),
|
|
18
|
+
disabledFeatures: options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function createHydrationSerializer({
|
|
22
|
+
onData,
|
|
23
|
+
onDone,
|
|
24
|
+
scopeId,
|
|
25
|
+
onError,
|
|
26
|
+
plugins
|
|
27
|
+
}) {
|
|
28
|
+
return createSerializer({
|
|
29
|
+
scopeId,
|
|
30
|
+
plugins,
|
|
31
|
+
globalIdentifier: HYDRATION_GLOBAL,
|
|
32
|
+
onData,
|
|
33
|
+
onDone,
|
|
34
|
+
onError
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function getLocalHeaderScript(id) {
|
|
38
|
+
return seroval.getCrossReferenceHeader(id) + ";";
|
|
39
|
+
}
|
|
40
|
+
const JSON_CODEC_DISABLED_FEATURES = seroval.Feature.RegExp;
|
|
41
|
+
const JSON_CODEC_DEPTH_LIMIT = 64;
|
|
42
|
+
function resolveCodecOptions({
|
|
43
|
+
plugins,
|
|
44
|
+
disabledFeatures,
|
|
45
|
+
depthLimit
|
|
46
|
+
} = {}) {
|
|
47
|
+
return {
|
|
48
|
+
plugins: resolveSerializerPlugins(plugins),
|
|
49
|
+
disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
|
|
50
|
+
depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function serializeJSON(value, {
|
|
54
|
+
onParse,
|
|
55
|
+
onDone,
|
|
56
|
+
onError,
|
|
57
|
+
...codecOptions
|
|
58
|
+
}) {
|
|
59
|
+
return seroval.toCrossJSONStream(value, {
|
|
60
|
+
onParse,
|
|
61
|
+
onDone,
|
|
62
|
+
onError,
|
|
63
|
+
...resolveCodecOptions(codecOptions)
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function createJSONDeserializer(options) {
|
|
67
|
+
const refs = new Map();
|
|
68
|
+
const resolved = resolveCodecOptions(options);
|
|
69
|
+
return function deserializeJSONChunk(node) {
|
|
70
|
+
return seroval.fromCrossJSON(node, {
|
|
71
|
+
refs,
|
|
72
|
+
...resolved
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
exports.DEFAULT_WEB_PLUGINS = DEFAULT_WEB_PLUGINS;
|
|
78
|
+
exports.createHydrationSerializer = createHydrationSerializer;
|
|
79
|
+
exports.createJSONDeserializer = createJSONDeserializer;
|
|
80
|
+
exports.createSerializer = createSerializer;
|
|
81
|
+
exports.getLocalHeaderScript = getLocalHeaderScript;
|
|
82
|
+
exports.resolveSerializerPlugins = resolveSerializerPlugins;
|
|
83
|
+
exports.serializeJSON = serializeJSON;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Feature, Serializer, getCrossReferenceHeader, toCrossJSONStream, fromCrossJSON } from 'seroval';
|
|
2
|
+
import { AbortSignalPlugin, CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin } from 'seroval-plugins/web';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_DISABLED_FEATURES = Feature.AggregateError | Feature.BigIntTypedArray;
|
|
5
|
+
const HYDRATION_GLOBAL = "_$HY.r";
|
|
6
|
+
const DEFAULT_WEB_PLUGINS = Object.freeze([AbortSignalPlugin,
|
|
7
|
+
CustomEventPlugin, DOMExceptionPlugin, EventPlugin,
|
|
8
|
+
FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin]);
|
|
9
|
+
function resolveSerializerPlugins(customPlugins) {
|
|
10
|
+
return customPlugins ? [...customPlugins, ...DEFAULT_WEB_PLUGINS] : [...DEFAULT_WEB_PLUGINS];
|
|
11
|
+
}
|
|
12
|
+
function createSerializer(options) {
|
|
13
|
+
return new Serializer({
|
|
14
|
+
...options,
|
|
15
|
+
plugins: resolveSerializerPlugins(options.plugins),
|
|
16
|
+
disabledFeatures: options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function createHydrationSerializer({
|
|
20
|
+
onData,
|
|
21
|
+
onDone,
|
|
22
|
+
scopeId,
|
|
23
|
+
onError,
|
|
24
|
+
plugins
|
|
25
|
+
}) {
|
|
26
|
+
return createSerializer({
|
|
27
|
+
scopeId,
|
|
28
|
+
plugins,
|
|
29
|
+
globalIdentifier: HYDRATION_GLOBAL,
|
|
30
|
+
onData,
|
|
31
|
+
onDone,
|
|
32
|
+
onError
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function getLocalHeaderScript(id) {
|
|
36
|
+
return getCrossReferenceHeader(id) + ";";
|
|
37
|
+
}
|
|
38
|
+
const JSON_CODEC_DISABLED_FEATURES = Feature.RegExp;
|
|
39
|
+
const JSON_CODEC_DEPTH_LIMIT = 64;
|
|
40
|
+
function resolveCodecOptions({
|
|
41
|
+
plugins,
|
|
42
|
+
disabledFeatures,
|
|
43
|
+
depthLimit
|
|
44
|
+
} = {}) {
|
|
45
|
+
return {
|
|
46
|
+
plugins: resolveSerializerPlugins(plugins),
|
|
47
|
+
disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
|
|
48
|
+
depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function serializeJSON(value, {
|
|
52
|
+
onParse,
|
|
53
|
+
onDone,
|
|
54
|
+
onError,
|
|
55
|
+
...codecOptions
|
|
56
|
+
}) {
|
|
57
|
+
return toCrossJSONStream(value, {
|
|
58
|
+
onParse,
|
|
59
|
+
onDone,
|
|
60
|
+
onError,
|
|
61
|
+
...resolveCodecOptions(codecOptions)
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function createJSONDeserializer(options) {
|
|
65
|
+
const refs = new Map();
|
|
66
|
+
const resolved = resolveCodecOptions(options);
|
|
67
|
+
return function deserializeJSONChunk(node) {
|
|
68
|
+
return fromCrossJSON(node, {
|
|
69
|
+
refs,
|
|
70
|
+
...resolved
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { DEFAULT_WEB_PLUGINS, createHydrationSerializer, createJSONDeserializer, createSerializer, getLocalHeaderScript, resolveSerializerPlugins, serializeJSON };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@solidjs/web/serialization",
|
|
3
|
+
"main": "./dist/serialization.cjs",
|
|
4
|
+
"module": "./dist/serialization.js",
|
|
5
|
+
"types": "./types/index.d.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./types/index.d.ts",
|
|
12
|
+
"default": "./dist/serialization.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./types-cjs/index.d.cts",
|
|
16
|
+
"default": "./dist/serialization.cjs"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Plugin, Serializer, SerovalNode } from "seroval";
|
|
2
|
+
|
|
3
|
+
export type { SerovalNode };
|
|
4
|
+
|
|
5
|
+
/** A Seroval plugin usable with the web serializers. */
|
|
6
|
+
export type SerializerPlugin = Plugin<any, any>;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Baseline plugin set for serializing web-platform values (AbortSignal,
|
|
10
|
+
* Event, FormData, Headers, ReadableStream, Request, Response, URL, ...).
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_WEB_PLUGINS: readonly SerializerPlugin[];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Composes custom plugins with `DEFAULT_WEB_PLUGINS`. Custom plugins come
|
|
16
|
+
* first so they can shadow a default for values both would match. Returns a
|
|
17
|
+
* fresh array; the defaults are never mutated.
|
|
18
|
+
*/
|
|
19
|
+
export function resolveSerializerPlugins(customPlugins?: SerializerPlugin[]): SerializerPlugin[];
|
|
20
|
+
|
|
21
|
+
export interface WebSerializerOptions {
|
|
22
|
+
/** Name of the global object the emitted scripts write resolved values into. */
|
|
23
|
+
globalIdentifier: string;
|
|
24
|
+
scopeId?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Seroval feature bitflags to exclude from output. Defaults to disabling
|
|
27
|
+
* post-ES2017 features (AggregateError, BigInt typed arrays).
|
|
28
|
+
*/
|
|
29
|
+
disabledFeatures?: number;
|
|
30
|
+
/** Extra plugins, composed ahead of `DEFAULT_WEB_PLUGINS`. */
|
|
31
|
+
plugins?: SerializerPlugin[];
|
|
32
|
+
onData: (result: string) => void;
|
|
33
|
+
onError?: (error: unknown) => void;
|
|
34
|
+
onDone?: () => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Creates a streaming Seroval serializer preconfigured with the web plugin
|
|
39
|
+
* set and the default feature policy.
|
|
40
|
+
*/
|
|
41
|
+
export function createSerializer(options: WebSerializerOptions): Serializer;
|
|
42
|
+
|
|
43
|
+
export type HydrationSerializerOptions = Omit<
|
|
44
|
+
WebSerializerOptions,
|
|
45
|
+
"globalIdentifier" | "disabledFeatures"
|
|
46
|
+
>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Serializer for SSR hydration output. Pins the hydration global (`_$HY.r`)
|
|
50
|
+
* and feature policy — only the wiring options (callbacks, scope, extra
|
|
51
|
+
* plugins) are configurable.
|
|
52
|
+
*/
|
|
53
|
+
export function createHydrationSerializer(options: HydrationSerializerOptions): Serializer;
|
|
54
|
+
|
|
55
|
+
/** Returns the cross-reference bootstrap script for a render scope. */
|
|
56
|
+
export function getLocalHeaderScript(id?: string): string;
|
|
57
|
+
|
|
58
|
+
// ---- JSON codec (server function transports) ----
|
|
59
|
+
|
|
60
|
+
export interface JSONCodecOptions {
|
|
61
|
+
/** Extra plugins, composed ahead of `DEFAULT_WEB_PLUGINS`. Must match on both peers. */
|
|
62
|
+
plugins?: SerializerPlugin[];
|
|
63
|
+
/**
|
|
64
|
+
* Seroval feature bitflags to exclude. Defaults to disabling `RegExp`
|
|
65
|
+
* (payloads may come from an untrusted peer). Must match on both peers.
|
|
66
|
+
*/
|
|
67
|
+
disabledFeatures?: number;
|
|
68
|
+
/** Maximum parse/deserialize depth. Defaults to 64. Must match on both peers. */
|
|
69
|
+
depthLimit?: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface JSONSerializeOptions extends JSONCodecOptions {
|
|
73
|
+
/**
|
|
74
|
+
* Receives each serialized node; `initial` is true for the first chunk
|
|
75
|
+
* (the source value itself). Async values produce additional chunks as
|
|
76
|
+
* they resolve.
|
|
77
|
+
*/
|
|
78
|
+
onParse: (node: SerovalNode, initial: boolean) => void;
|
|
79
|
+
onError?: (error: unknown) => void;
|
|
80
|
+
/** Fires once all async values have settled. */
|
|
81
|
+
onDone?: () => void;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Serializes `value` as SerovalNode chunks delivered through `onParse`.
|
|
86
|
+
* Wire framing of the nodes is the transport's concern. Returns a cancel
|
|
87
|
+
* function that aborts pending async serialization.
|
|
88
|
+
*/
|
|
89
|
+
export function serializeJSON(value: unknown, options: JSONSerializeOptions): () => void;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Creates the decoding counterpart of `serializeJSON`. Cross-references
|
|
93
|
+
* between chunks resolve through state shared across calls, so all chunks
|
|
94
|
+
* from one stream must go through the same deserializer instance. The first
|
|
95
|
+
* chunk's return value is the decoded source value.
|
|
96
|
+
*/
|
|
97
|
+
export function createJSONDeserializer(options?: JSONCodecOptions): <T>(node: SerovalNode) => T;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Plugin, Serializer, SerovalNode } from "seroval";
|
|
2
|
+
|
|
3
|
+
export type { SerovalNode };
|
|
4
|
+
|
|
5
|
+
/** A Seroval plugin usable with the web serializers. */
|
|
6
|
+
export type SerializerPlugin = Plugin<any, any>;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Baseline plugin set for serializing web-platform values (AbortSignal,
|
|
10
|
+
* Event, FormData, Headers, ReadableStream, Request, Response, URL, ...).
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_WEB_PLUGINS: readonly SerializerPlugin[];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Composes custom plugins with `DEFAULT_WEB_PLUGINS`. Custom plugins come
|
|
16
|
+
* first so they can shadow a default for values both would match. Returns a
|
|
17
|
+
* fresh array; the defaults are never mutated.
|
|
18
|
+
*/
|
|
19
|
+
export function resolveSerializerPlugins(customPlugins?: SerializerPlugin[]): SerializerPlugin[];
|
|
20
|
+
|
|
21
|
+
export interface WebSerializerOptions {
|
|
22
|
+
/** Name of the global object the emitted scripts write resolved values into. */
|
|
23
|
+
globalIdentifier: string;
|
|
24
|
+
scopeId?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Seroval feature bitflags to exclude from output. Defaults to disabling
|
|
27
|
+
* post-ES2017 features (AggregateError, BigInt typed arrays).
|
|
28
|
+
*/
|
|
29
|
+
disabledFeatures?: number;
|
|
30
|
+
/** Extra plugins, composed ahead of `DEFAULT_WEB_PLUGINS`. */
|
|
31
|
+
plugins?: SerializerPlugin[];
|
|
32
|
+
onData: (result: string) => void;
|
|
33
|
+
onError?: (error: unknown) => void;
|
|
34
|
+
onDone?: () => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Creates a streaming Seroval serializer preconfigured with the web plugin
|
|
39
|
+
* set and the default feature policy.
|
|
40
|
+
*/
|
|
41
|
+
export function createSerializer(options: WebSerializerOptions): Serializer;
|
|
42
|
+
|
|
43
|
+
export type HydrationSerializerOptions = Omit<
|
|
44
|
+
WebSerializerOptions,
|
|
45
|
+
"globalIdentifier" | "disabledFeatures"
|
|
46
|
+
>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Serializer for SSR hydration output. Pins the hydration global (`_$HY.r`)
|
|
50
|
+
* and feature policy — only the wiring options (callbacks, scope, extra
|
|
51
|
+
* plugins) are configurable.
|
|
52
|
+
*/
|
|
53
|
+
export function createHydrationSerializer(options: HydrationSerializerOptions): Serializer;
|
|
54
|
+
|
|
55
|
+
/** Returns the cross-reference bootstrap script for a render scope. */
|
|
56
|
+
export function getLocalHeaderScript(id?: string): string;
|
|
57
|
+
|
|
58
|
+
// ---- JSON codec (server function transports) ----
|
|
59
|
+
|
|
60
|
+
export interface JSONCodecOptions {
|
|
61
|
+
/** Extra plugins, composed ahead of `DEFAULT_WEB_PLUGINS`. Must match on both peers. */
|
|
62
|
+
plugins?: SerializerPlugin[];
|
|
63
|
+
/**
|
|
64
|
+
* Seroval feature bitflags to exclude. Defaults to disabling `RegExp`
|
|
65
|
+
* (payloads may come from an untrusted peer). Must match on both peers.
|
|
66
|
+
*/
|
|
67
|
+
disabledFeatures?: number;
|
|
68
|
+
/** Maximum parse/deserialize depth. Defaults to 64. Must match on both peers. */
|
|
69
|
+
depthLimit?: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface JSONSerializeOptions extends JSONCodecOptions {
|
|
73
|
+
/**
|
|
74
|
+
* Receives each serialized node; `initial` is true for the first chunk
|
|
75
|
+
* (the source value itself). Async values produce additional chunks as
|
|
76
|
+
* they resolve.
|
|
77
|
+
*/
|
|
78
|
+
onParse: (node: SerovalNode, initial: boolean) => void;
|
|
79
|
+
onError?: (error: unknown) => void;
|
|
80
|
+
/** Fires once all async values have settled. */
|
|
81
|
+
onDone?: () => void;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Serializes `value` as SerovalNode chunks delivered through `onParse`.
|
|
86
|
+
* Wire framing of the nodes is the transport's concern. Returns a cancel
|
|
87
|
+
* function that aborts pending async serialization.
|
|
88
|
+
*/
|
|
89
|
+
export function serializeJSON(value: unknown, options: JSONSerializeOptions): () => void;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Creates the decoding counterpart of `serializeJSON`. Cross-references
|
|
93
|
+
* between chunks resolve through state shared across calls, so all chunks
|
|
94
|
+
* from one stream must go through the same deserializer instance. The first
|
|
95
|
+
* chunk's return value is the decoded source value.
|
|
96
|
+
*/
|
|
97
|
+
export function createJSONDeserializer(options?: JSONCodecOptions): <T>(node: SerovalNode) => T;
|