sibujs 1.4.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -119
- package/dist/browser.cjs +288 -80
- package/dist/browser.d.cts +19 -9
- package/dist/browser.d.ts +19 -9
- package/dist/browser.js +6 -6
- package/dist/build.cjs +1019 -313
- package/dist/build.d.cts +1 -1
- package/dist/build.d.ts +1 -1
- package/dist/build.js +15 -13
- package/dist/cdn.global.js +17 -16
- package/dist/chunk-2RA7SHDA.js +65 -0
- package/dist/chunk-2UPRY23K.js +80 -0
- package/dist/chunk-3JHCYHWN.js +125 -0
- package/dist/{chunk-ZWKZCBO6.js → chunk-3LR7GLWQ.js} +154 -33
- package/dist/{chunk-3AIRKM3B.js → chunk-3NSGB5JN.js} +115 -34
- package/dist/{chunk-3ARAQO7B.js → chunk-52YJLLRO.js} +29 -6
- package/dist/chunk-54EDRCEF.js +93 -0
- package/dist/chunk-7JDB7I65.js +1327 -0
- package/dist/{chunk-WZSPOOER.js → chunk-CC65Y57T.js} +8 -5
- package/dist/{chunk-23VV7YD3.js → chunk-DFPFITST.js} +25 -30
- package/dist/{chunk-WR5D4EGH.js → chunk-GTBNNBJ6.js} +14 -2
- package/dist/chunk-HB24TBAF.js +121 -0
- package/dist/{chunk-CZUGLNJS.js → chunk-ITX6OO3F.js} +3 -3
- package/dist/{chunk-JAKHTMQU.js → chunk-JA6667UN.js} +206 -46
- package/dist/{chunk-77L6NL3X.js → chunk-JXMMDLBY.js} +306 -183
- package/dist/{chunk-3X2YG6YM.js → chunk-JYD2PWXH.js} +59 -28
- package/dist/{chunk-F3FA4F32.js → chunk-KLRMB5ZS.js} +135 -79
- package/dist/{chunk-5X6PP2UK.js → chunk-LMLD24FC.js} +2 -2
- package/dist/{chunk-M4NLBH4I.js → chunk-LYTCUZ7H.js} +3 -2
- package/dist/{chunk-TSOKIX5Z.js → chunk-MIUAXB7K.js} +126 -74
- package/dist/{chunk-QWZG56ET.js → chunk-ND2664SF.js} +558 -190
- package/dist/{chunk-JCI5M6U6.js → chunk-O2MNQFLP.js} +261 -79
- package/dist/{chunk-EWFVA3TJ.js → chunk-R73P76YZ.js} +1 -1
- package/dist/{chunk-2BYQDGN3.js → chunk-SAHNHTFC.js} +234 -63
- package/dist/chunk-UCS6AMJ7.js +79 -0
- package/dist/{chunk-ZD6OAMTH.js → chunk-VLPPXTYG.js} +90 -35
- package/dist/{chunk-OUZZEE4S.js → chunk-WOMYAHHI.js} +17 -11
- package/dist/{contracts-xo5ckdRP.d.cts → contracts-ey_Qh8ef.d.cts} +7 -8
- package/dist/{contracts-xo5ckdRP.d.ts → contracts-ey_Qh8ef.d.ts} +7 -8
- package/dist/{customElement-D2DJp_xn.d.cts → customElement-CPfIrbvg.d.cts} +18 -9
- package/dist/{customElement-D2DJp_xn.d.ts → customElement-CPfIrbvg.d.ts} +18 -9
- package/dist/data.cjs +452 -100
- package/dist/data.d.cts +20 -2
- package/dist/data.d.ts +20 -2
- package/dist/data.js +11 -9
- package/dist/devtools.cjs +535 -247
- package/dist/devtools.d.cts +1 -1
- package/dist/devtools.d.ts +1 -1
- package/dist/devtools.js +34 -30
- package/dist/ecosystem.cjs +499 -143
- package/dist/ecosystem.d.cts +13 -11
- package/dist/ecosystem.d.ts +13 -11
- package/dist/ecosystem.js +12 -11
- package/dist/extras.cjs +3639 -1629
- package/dist/extras.d.cts +11 -11
- package/dist/extras.d.ts +11 -11
- package/dist/extras.js +58 -45
- package/dist/index.cjs +1023 -313
- package/dist/index.d.cts +128 -55
- package/dist/index.d.ts +128 -55
- package/dist/index.js +28 -16
- package/dist/{introspect-BumjnBKr.d.cts → introspect-BWNjNw64.d.cts} +22 -2
- package/dist/{introspect-CZrlcaYy.d.ts → introspect-cY2pg9pW.d.ts} +22 -2
- package/dist/motion.cjs +90 -36
- package/dist/motion.d.cts +1 -1
- package/dist/motion.d.ts +1 -1
- package/dist/motion.js +4 -4
- package/dist/patterns.cjs +414 -81
- package/dist/patterns.d.cts +53 -20
- package/dist/patterns.d.ts +53 -20
- package/dist/patterns.js +7 -7
- package/dist/performance.cjs +364 -108
- package/dist/performance.d.cts +29 -17
- package/dist/performance.d.ts +29 -17
- package/dist/performance.js +13 -6
- package/dist/plugin-D30wlGW5.d.cts +71 -0
- package/dist/plugin-D30wlGW5.d.ts +71 -0
- package/dist/plugins.cjs +652 -271
- package/dist/plugins.d.cts +13 -6
- package/dist/plugins.d.ts +13 -6
- package/dist/plugins.js +116 -50
- package/dist/{ssr-Do_SiVoL.d.cts → ssr-CrVNy6Pa.d.cts} +9 -15
- package/dist/{ssr-Do_SiVoL.d.ts → ssr-CrVNy6Pa.d.ts} +9 -15
- package/dist/{ssr-4PBXAOO3.js → ssr-FXD2PPMC.js} +4 -3
- package/dist/ssr.cjs +648 -219
- package/dist/ssr.d.cts +27 -7
- package/dist/ssr.d.ts +27 -7
- package/dist/ssr.js +12 -11
- package/dist/{tagFactory-DaJ0YWX6.d.ts → tagFactory-S17H2qxu.d.cts} +9 -1
- package/dist/{tagFactory-DaJ0YWX6.d.cts → tagFactory-S17H2qxu.d.ts} +9 -1
- package/dist/testing.cjs +252 -63
- package/dist/testing.d.cts +17 -4
- package/dist/testing.d.ts +17 -4
- package/dist/testing.js +100 -44
- package/dist/ui.cjs +576 -168
- package/dist/ui.d.cts +13 -16
- package/dist/ui.d.ts +13 -16
- package/dist/ui.js +20 -17
- package/dist/widgets.cjs +1001 -93
- package/dist/widgets.d.cts +104 -2
- package/dist/widgets.d.ts +104 -2
- package/dist/widgets.js +9 -7
- package/package.json +8 -2
- package/dist/chunk-32DY64NT.js +0 -282
- package/dist/chunk-3CRQALYP.js +0 -877
- package/dist/chunk-4EI4AG32.js +0 -482
- package/dist/chunk-4MYMUBRS.js +0 -21
- package/dist/chunk-6HLLIF3K.js +0 -398
- package/dist/chunk-6LSNVCS2.js +0 -937
- package/dist/chunk-6SA3QQES.js +0 -61
- package/dist/chunk-7BF6TK55.js +0 -1097
- package/dist/chunk-7TQKR4PP.js +0 -294
- package/dist/chunk-7V26P53V.js +0 -712
- package/dist/chunk-AZ3ISID5.js +0 -298
- package/dist/chunk-B7SWRFUT.js +0 -332
- package/dist/chunk-BGN5ZMP4.js +0 -26
- package/dist/chunk-BTU3TJDS.js +0 -365
- package/dist/chunk-BW3WT46K.js +0 -937
- package/dist/chunk-C6KFWOFV.js +0 -616
- package/dist/chunk-CHF5OHIA.js +0 -61
- package/dist/chunk-CHJ27IGK.js +0 -26
- package/dist/chunk-CMBFNA7L.js +0 -27
- package/dist/chunk-DAHRH4ON.js +0 -331
- package/dist/chunk-DKOHBI74.js +0 -924
- package/dist/chunk-DTCOOBMX.js +0 -725
- package/dist/chunk-EBGIRKQY.js +0 -616
- package/dist/chunk-EUZND3CB.js +0 -27
- package/dist/chunk-EVCZO745.js +0 -365
- package/dist/chunk-FGOEVHY3.js +0 -60
- package/dist/chunk-G3BOQPVO.js +0 -365
- package/dist/chunk-GCOK2LC3.js +0 -282
- package/dist/chunk-HGMJFBC7.js +0 -654
- package/dist/chunk-K5ZUMYVS.js +0 -89
- package/dist/chunk-KQPDEVVS.js +0 -398
- package/dist/chunk-L6JRBDNS.js +0 -60
- package/dist/chunk-LA6KQEDU.js +0 -712
- package/dist/chunk-MDVXJWFN.js +0 -304
- package/dist/chunk-MEZVEBPN.js +0 -2008
- package/dist/chunk-MK4ERFYL.js +0 -2249
- package/dist/chunk-MLKGABMK.js +0 -9
- package/dist/chunk-MQ5GOYPH.js +0 -2249
- package/dist/chunk-N6IZB6KJ.js +0 -567
- package/dist/chunk-NEKUBFPT.js +0 -60
- package/dist/chunk-NHUC2QWH.js +0 -282
- package/dist/chunk-NMRUZALC.js +0 -1097
- package/dist/chunk-NYVAC6P5.js +0 -37
- package/dist/chunk-OF7UZIVB.js +0 -725
- package/dist/chunk-P6W3STU4.js +0 -2249
- package/dist/chunk-PBHF5WKN.js +0 -616
- package/dist/chunk-PTQJDMRT.js +0 -146
- package/dist/chunk-PZEGYCF5.js +0 -61
- package/dist/chunk-QBMDLBU2.js +0 -975
- package/dist/chunk-RQGQSLQK.js +0 -725
- package/dist/chunk-SDLZDHKP.js +0 -107
- package/dist/chunk-TNQWPPE6.js +0 -37
- package/dist/chunk-UHNL42EF.js +0 -2730
- package/dist/chunk-UNXCEF6S.js +0 -21
- package/dist/chunk-V2XTI523.js +0 -347
- package/dist/chunk-VAU366PN.js +0 -2241
- package/dist/chunk-VMVDTCXB.js +0 -712
- package/dist/chunk-VRW3FULF.js +0 -725
- package/dist/chunk-WADYRCO2.js +0 -304
- package/dist/chunk-WILQZRO4.js +0 -282
- package/dist/chunk-WUHJISPP.js +0 -298
- package/dist/chunk-XYU6TZOW.js +0 -182
- package/dist/chunk-Y6GP4QGG.js +0 -276
- package/dist/chunk-YECR7UIA.js +0 -347
- package/dist/chunk-YUTWTI4B.js +0 -654
- package/dist/chunk-Z65KYU7I.js +0 -26
- package/dist/chunk-Z6POF5YC.js +0 -975
- package/dist/chunk-ZBJP6WFL.js +0 -482
- package/dist/contracts-DDrwxvJ-.d.cts +0 -245
- package/dist/contracts-DDrwxvJ-.d.ts +0 -245
- package/dist/contracts-DOrhwbke.d.cts +0 -245
- package/dist/contracts-DOrhwbke.d.ts +0 -245
- package/dist/customElement-BKQfbSZQ.d.cts +0 -262
- package/dist/customElement-BKQfbSZQ.d.ts +0 -262
- package/dist/customElement-yz8uyk-0.d.cts +0 -308
- package/dist/customElement-yz8uyk-0.d.ts +0 -308
- package/dist/introspect-Cb0zgpi2.d.cts +0 -477
- package/dist/introspect-Y2xNXGSf.d.ts +0 -477
- package/dist/plugin-Bek4RhJY.d.cts +0 -43
- package/dist/plugin-Bek4RhJY.d.ts +0 -43
- package/dist/ssr-3RXHP5ES.js +0 -38
- package/dist/ssr-6GIMY5MX.js +0 -38
- package/dist/ssr-BA6sxxUd.d.cts +0 -135
- package/dist/ssr-BA6sxxUd.d.ts +0 -135
- package/dist/ssr-WKUPVSSK.js +0 -36
- package/dist/tagFactory-Dl8QCLga.d.cts +0 -23
- package/dist/tagFactory-Dl8QCLga.d.ts +0 -23
package/dist/ssr.cjs
CHANGED
|
@@ -70,33 +70,105 @@ function isDev() {
|
|
|
70
70
|
var _isDev = isDev();
|
|
71
71
|
function devAssert(condition, message) {
|
|
72
72
|
if (_isDev && !condition) {
|
|
73
|
-
throw new Error(`[
|
|
73
|
+
throw new Error(`[SibuJS] ${message}`);
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
function devWarn(message) {
|
|
77
77
|
if (_isDev) {
|
|
78
|
-
console.warn(`[
|
|
78
|
+
console.warn(`[SibuJS] ${message}`);
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
// src/core/ssr-context.ts
|
|
83
|
+
var als = null;
|
|
84
|
+
try {
|
|
85
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
86
|
+
const req = Function("return typeof require==='function'?require:null")();
|
|
87
|
+
if (req) {
|
|
88
|
+
const mod = req("node:async_hooks");
|
|
89
|
+
als = new mod.AsyncLocalStorage();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} catch {
|
|
93
|
+
als = null;
|
|
94
|
+
}
|
|
95
|
+
var fallbackStore = { ssr: false, suspenseIdCounter: 0 };
|
|
96
|
+
function getSSRStore() {
|
|
97
|
+
if (als) {
|
|
98
|
+
const s2 = als.getStore();
|
|
99
|
+
if (s2) return s2;
|
|
100
|
+
}
|
|
101
|
+
return fallbackStore;
|
|
102
|
+
}
|
|
103
|
+
function isSSR() {
|
|
104
|
+
return getSSRStore().ssr;
|
|
105
|
+
}
|
|
106
|
+
|
|
82
107
|
// src/utils/sanitize.ts
|
|
108
|
+
var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
|
|
83
109
|
function sanitizeUrl(url) {
|
|
84
110
|
const trimmed = url.replace(/[\x00-\x20\x7f-\x9f]+/g, "").trim();
|
|
85
111
|
if (!trimmed) return "";
|
|
86
112
|
const lower = trimmed.toLowerCase();
|
|
87
|
-
|
|
88
|
-
|
|
113
|
+
let schemeEnd = -1;
|
|
114
|
+
for (let i2 = 0; i2 < lower.length; i2++) {
|
|
115
|
+
const ch = lower.charCodeAt(i2);
|
|
116
|
+
if (ch === 58) {
|
|
117
|
+
schemeEnd = i2;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
if (ch === 47 || ch === 63 || ch === 35) break;
|
|
89
121
|
}
|
|
122
|
+
if (schemeEnd === -1) return trimmed;
|
|
123
|
+
const scheme = lower.slice(0, schemeEnd + 1);
|
|
124
|
+
if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return trimmed;
|
|
125
|
+
if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
|
|
90
126
|
return trimmed;
|
|
91
127
|
}
|
|
128
|
+
function sanitizeSrcset(value) {
|
|
129
|
+
const parts = value.split(",");
|
|
130
|
+
const out = [];
|
|
131
|
+
for (let i2 = 0; i2 < parts.length; i2++) {
|
|
132
|
+
const part = parts[i2].trim();
|
|
133
|
+
if (!part) continue;
|
|
134
|
+
const m = part.match(/^(\S+)(\s+.+)?$/);
|
|
135
|
+
if (!m) continue;
|
|
136
|
+
const safe = sanitizeUrl(m[1]);
|
|
137
|
+
if (!safe) continue;
|
|
138
|
+
out.push(m[2] ? `${safe}${m[2]}` : safe);
|
|
139
|
+
}
|
|
140
|
+
return out.join(", ");
|
|
141
|
+
}
|
|
92
142
|
function sanitizeCSSValue(value) {
|
|
93
|
-
const
|
|
94
|
-
|
|
143
|
+
const decoded = value.replace(/\\([0-9a-fA-F]{1,6})\s?/g, (_m, hex) => {
|
|
144
|
+
const code2 = Number.parseInt(hex, 16);
|
|
145
|
+
if (!Number.isFinite(code2) || code2 < 0 || code2 > 1114111) return "";
|
|
146
|
+
try {
|
|
147
|
+
return String.fromCodePoint(code2);
|
|
148
|
+
} catch {
|
|
149
|
+
return "";
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
const lower = decoded.toLowerCase().replace(/\s+/g, "");
|
|
153
|
+
if (lower.includes("url(") || lower.includes("expression(") || lower.includes("javascript:") || lower.includes("vbscript:") || lower.includes("-moz-binding") || lower.includes("behavior:") || lower.includes("@import") || lower.includes("image-set(") || lower.includes("filter:progid")) {
|
|
95
154
|
return "";
|
|
96
155
|
}
|
|
97
156
|
return value;
|
|
98
157
|
}
|
|
99
|
-
var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
158
|
+
var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
159
|
+
"href",
|
|
160
|
+
"xlink:href",
|
|
161
|
+
"src",
|
|
162
|
+
"action",
|
|
163
|
+
"formaction",
|
|
164
|
+
"formtarget",
|
|
165
|
+
"cite",
|
|
166
|
+
"poster",
|
|
167
|
+
"background",
|
|
168
|
+
"srcset",
|
|
169
|
+
"ping",
|
|
170
|
+
"data"
|
|
171
|
+
]);
|
|
100
172
|
function isUrlAttribute(attr) {
|
|
101
173
|
return URL_ATTRIBUTES.has(attr);
|
|
102
174
|
}
|
|
@@ -219,7 +291,7 @@ function hydrate(component, container, options = {}) {
|
|
|
219
291
|
options.onMismatch(first);
|
|
220
292
|
} else if (_isDev2) {
|
|
221
293
|
console.warn(
|
|
222
|
-
`[
|
|
294
|
+
`[SibuJS hydration] ${first.message}
|
|
223
295
|
at ${first.path}
|
|
224
296
|
server: ${first.serverValue}
|
|
225
297
|
client: ${first.clientValue}`
|
|
@@ -227,17 +299,9 @@ function hydrate(component, container, options = {}) {
|
|
|
227
299
|
}
|
|
228
300
|
}
|
|
229
301
|
}
|
|
230
|
-
|
|
302
|
+
container.replaceChildren(clientTree);
|
|
231
303
|
container.setAttribute("data-sibu-hydrated", "true");
|
|
232
304
|
}
|
|
233
|
-
function hydrateNode(serverNode, clientNode) {
|
|
234
|
-
if (!serverNode) return;
|
|
235
|
-
const serverChildren = Array.from(serverNode.children);
|
|
236
|
-
const clientChildren = Array.from(clientNode.children);
|
|
237
|
-
for (let i2 = 0; i2 < Math.min(serverChildren.length, clientChildren.length); i2++) {
|
|
238
|
-
hydrateNode(serverChildren[i2], clientChildren[i2]);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
305
|
function collectMismatches(serverNode, clientNode, path2, out, max = 5) {
|
|
242
306
|
if (out.length >= max) return;
|
|
243
307
|
const nodePath = path2 || clientNode?.tagName?.toLowerCase() || "(root)";
|
|
@@ -467,12 +531,16 @@ function renderToReadableStream(element) {
|
|
|
467
531
|
controller.enqueue(value);
|
|
468
532
|
}
|
|
469
533
|
},
|
|
470
|
-
cancel() {
|
|
471
|
-
generator.return(void 0);
|
|
534
|
+
async cancel() {
|
|
535
|
+
await generator.return(void 0);
|
|
472
536
|
}
|
|
473
537
|
});
|
|
474
538
|
}
|
|
539
|
+
var SAFE_ID = /^[A-Za-z0-9_-]+$/;
|
|
475
540
|
function island(id, component) {
|
|
541
|
+
if (!SAFE_ID.test(id)) {
|
|
542
|
+
throw new Error(`[SibuJS SSR] island: id must match [A-Za-z0-9_-]+ (got: ${JSON.stringify(id.slice(0, 32))})`);
|
|
543
|
+
}
|
|
476
544
|
const el = component();
|
|
477
545
|
el.setAttribute("data-sibu-island", id);
|
|
478
546
|
return el;
|
|
@@ -485,8 +553,9 @@ function hydrateIslands(container, islands) {
|
|
|
485
553
|
const factory = islands[id];
|
|
486
554
|
if (typeof factory !== "function") continue;
|
|
487
555
|
const clientTree = factory();
|
|
488
|
-
|
|
489
|
-
|
|
556
|
+
clientTree.setAttribute("data-sibu-island", id);
|
|
557
|
+
clientTree.setAttribute("data-sibu-hydrated", "true");
|
|
558
|
+
marker2.replaceWith(clientTree);
|
|
490
559
|
}
|
|
491
560
|
container.setAttribute("data-sibu-hydrated", "partial");
|
|
492
561
|
}
|
|
@@ -503,8 +572,9 @@ function hydrateProgressively(container, islands, options) {
|
|
|
503
572
|
for (const entry of entries) {
|
|
504
573
|
if (entry.isIntersecting) {
|
|
505
574
|
const clientTree = factory();
|
|
506
|
-
|
|
507
|
-
|
|
575
|
+
clientTree.setAttribute("data-sibu-island", id);
|
|
576
|
+
clientTree.setAttribute("data-sibu-hydrated", "true");
|
|
577
|
+
marker2.replaceWith(clientTree);
|
|
508
578
|
observer.disconnect();
|
|
509
579
|
break;
|
|
510
580
|
}
|
|
@@ -520,20 +590,37 @@ function hydrateProgressively(container, islands, options) {
|
|
|
520
590
|
for (const cleanup2 of cleanups) cleanup2();
|
|
521
591
|
};
|
|
522
592
|
}
|
|
523
|
-
var suspenseIdCounter = 0;
|
|
524
593
|
function resetSSRState() {
|
|
525
|
-
suspenseIdCounter = 0;
|
|
594
|
+
getSSRStore().suspenseIdCounter = 0;
|
|
595
|
+
}
|
|
596
|
+
function noop() {
|
|
526
597
|
}
|
|
527
598
|
function ssrSuspense(props) {
|
|
528
|
-
const
|
|
599
|
+
const store = getSSRStore();
|
|
600
|
+
const id = `sibu-sus-${store.suspenseIdCounter++}`;
|
|
601
|
+
const timeoutMs = props.timeoutMs ?? 3e4;
|
|
529
602
|
const fallbackEl = props.fallback();
|
|
530
603
|
const wrapper = document.createElement("div");
|
|
531
604
|
wrapper.setAttribute("data-sibu-suspense-id", id);
|
|
532
605
|
wrapper.appendChild(fallbackEl);
|
|
533
|
-
const
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
606
|
+
const fallbackHtml = renderToString(fallbackEl);
|
|
607
|
+
let timer;
|
|
608
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
609
|
+
timer = setTimeout(() => reject(new Error(`[SibuJS SSR] ssrSuspense timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
610
|
+
});
|
|
611
|
+
const raced = Promise.race([props.content(), timeoutPromise]);
|
|
612
|
+
const promise = raced.then(
|
|
613
|
+
(resolvedEl) => {
|
|
614
|
+
if (timer) clearTimeout(timer);
|
|
615
|
+
return { id, html: renderToString(resolvedEl) };
|
|
616
|
+
},
|
|
617
|
+
(err) => {
|
|
618
|
+
if (timer) clearTimeout(timer);
|
|
619
|
+
if (_isDev2) console.warn("[SibuJS SSR] ssrSuspense rejected:", err);
|
|
620
|
+
return { id, html: fallbackHtml };
|
|
621
|
+
}
|
|
622
|
+
);
|
|
623
|
+
promise.catch(noop);
|
|
537
624
|
return { element: wrapper, promise };
|
|
538
625
|
}
|
|
539
626
|
var SAFE_SUSPENSE_ID = /^[A-Za-z0-9_-]+$/;
|
|
@@ -561,14 +648,27 @@ var SSR_DATA_ATTR = "__SIBU_SSR_DATA__";
|
|
|
561
648
|
function escapeScriptJson(json) {
|
|
562
649
|
return json.replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
563
650
|
}
|
|
564
|
-
|
|
565
|
-
|
|
651
|
+
var DEFAULT_MAX_SSR_BYTES = 1024 * 1024;
|
|
652
|
+
function serializeState(state, nonce, options) {
|
|
653
|
+
const rawJson = JSON.stringify(state);
|
|
654
|
+
const maxBytes = options?.maxBytes ?? DEFAULT_MAX_SSR_BYTES;
|
|
655
|
+
const byteLen = typeof TextEncoder !== "undefined" ? new TextEncoder().encode(rawJson).byteLength : Buffer.byteLength(rawJson, "utf8");
|
|
656
|
+
if (byteLen > maxBytes) {
|
|
657
|
+
throw new Error(`[SibuJS SSR] serializeState: payload (${byteLen} bytes) exceeds maxBytes (${maxBytes})`);
|
|
658
|
+
}
|
|
659
|
+
const json = escapeScriptJson(rawJson);
|
|
566
660
|
const nonceAttr = nonce ? ` nonce="${escapeAttr(nonce)}"` : "";
|
|
567
661
|
return `<script${nonceAttr}>window.${SSR_DATA_ATTR}=${json}</script>`;
|
|
568
662
|
}
|
|
569
663
|
function deserializeState(validate) {
|
|
570
664
|
if (typeof window === "undefined") return void 0;
|
|
571
|
-
|
|
665
|
+
if (_isDev2 && !validate) {
|
|
666
|
+
console.warn(
|
|
667
|
+
"[SibuJS SSR] deserializeState() called without a validate guard \u2014 tampered SSR payloads will not be detected."
|
|
668
|
+
);
|
|
669
|
+
}
|
|
670
|
+
const w = window;
|
|
671
|
+
const raw = w[SSR_DATA_ATTR];
|
|
572
672
|
if (raw === void 0) return void 0;
|
|
573
673
|
if (validate && !validate(raw)) return void 0;
|
|
574
674
|
return raw;
|
|
@@ -586,11 +686,11 @@ var subscriberStack = new Array(32);
|
|
|
586
686
|
var stackCapacity = 32;
|
|
587
687
|
var stackTop = -1;
|
|
588
688
|
var currentSubscriber = null;
|
|
589
|
-
var signalSubscribers = /* @__PURE__ */ new WeakMap();
|
|
590
689
|
var SUBS = "__s";
|
|
591
690
|
var notifyDepth = 0;
|
|
592
691
|
var pendingQueue = [];
|
|
593
692
|
var pendingSet = /* @__PURE__ */ new Set();
|
|
693
|
+
var propagateStack = [];
|
|
594
694
|
function safeInvoke(sub2) {
|
|
595
695
|
try {
|
|
596
696
|
sub2();
|
|
@@ -636,7 +736,6 @@ function recordDependency(signal2) {
|
|
|
636
736
|
let subs = signal2[SUBS];
|
|
637
737
|
if (!subs) {
|
|
638
738
|
subs = /* @__PURE__ */ new Set();
|
|
639
|
-
signalSubscribers.set(signal2, subs);
|
|
640
739
|
signal2[SUBS] = subs;
|
|
641
740
|
}
|
|
642
741
|
subs.add(currentSubscriber);
|
|
@@ -658,57 +757,71 @@ function queueSignalNotification(signal2) {
|
|
|
658
757
|
}
|
|
659
758
|
}
|
|
660
759
|
}
|
|
760
|
+
var maxDrainIterations = 1e5;
|
|
661
761
|
function drainNotificationQueue() {
|
|
662
762
|
if (notifyDepth > 0) return;
|
|
663
763
|
notifyDepth++;
|
|
664
764
|
try {
|
|
665
765
|
let i2 = 0;
|
|
666
766
|
while (i2 < pendingQueue.length) {
|
|
767
|
+
if (i2 >= maxDrainIterations) {
|
|
768
|
+
if (typeof console !== "undefined") {
|
|
769
|
+
console.error(
|
|
770
|
+
`[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
break;
|
|
774
|
+
}
|
|
667
775
|
safeInvoke(pendingQueue[i2]);
|
|
668
776
|
i2++;
|
|
669
777
|
}
|
|
670
778
|
} finally {
|
|
671
|
-
pendingQueue.length = 0;
|
|
672
|
-
pendingSet.clear();
|
|
673
779
|
notifyDepth--;
|
|
780
|
+
if (notifyDepth === 0) {
|
|
781
|
+
pendingQueue.length = 0;
|
|
782
|
+
pendingSet.clear();
|
|
783
|
+
}
|
|
674
784
|
}
|
|
675
785
|
}
|
|
676
786
|
function propagateDirty(sub2) {
|
|
677
787
|
sub2();
|
|
678
|
-
|
|
679
|
-
|
|
788
|
+
const rootSig = sub2._sig;
|
|
789
|
+
if (!rootSig) return;
|
|
790
|
+
const stack = propagateStack;
|
|
791
|
+
const baseLen = stack.length;
|
|
792
|
+
stack.push(rootSig);
|
|
793
|
+
while (stack.length > baseLen) {
|
|
794
|
+
const sig = stack.pop();
|
|
680
795
|
const first = sig.__f;
|
|
681
796
|
if (first) {
|
|
682
797
|
if (first._c) {
|
|
683
798
|
const nSig = first._sig;
|
|
684
|
-
nSig._d
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if (!pendingSet.has(first)) {
|
|
799
|
+
if (!nSig._d) {
|
|
800
|
+
nSig._d = true;
|
|
801
|
+
stack.push(nSig);
|
|
802
|
+
}
|
|
803
|
+
} else if (!pendingSet.has(first)) {
|
|
689
804
|
pendingSet.add(first);
|
|
690
805
|
pendingQueue.push(first);
|
|
691
806
|
}
|
|
692
|
-
|
|
807
|
+
continue;
|
|
693
808
|
}
|
|
694
809
|
const subs = sig[SUBS];
|
|
695
|
-
if (!subs)
|
|
696
|
-
let nextSig;
|
|
810
|
+
if (!subs) continue;
|
|
697
811
|
for (const s2 of subs) {
|
|
698
812
|
if (s2._c) {
|
|
699
|
-
s2();
|
|
700
813
|
const nSig = s2._sig;
|
|
701
|
-
if (nSig && !
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
814
|
+
if (nSig && !nSig._d) {
|
|
815
|
+
nSig._d = true;
|
|
816
|
+
stack.push(nSig);
|
|
817
|
+
} else if (!nSig) {
|
|
818
|
+
s2();
|
|
705
819
|
}
|
|
706
820
|
} else if (!pendingSet.has(s2)) {
|
|
707
821
|
pendingSet.add(s2);
|
|
708
822
|
pendingQueue.push(s2);
|
|
709
823
|
}
|
|
710
824
|
}
|
|
711
|
-
sig = nextSig;
|
|
712
825
|
}
|
|
713
826
|
}
|
|
714
827
|
function notifySubscribers(signal2) {
|
|
@@ -732,13 +845,23 @@ function notifySubscribers(signal2) {
|
|
|
732
845
|
}
|
|
733
846
|
let i2 = 0;
|
|
734
847
|
while (i2 < pendingQueue.length) {
|
|
848
|
+
if (i2 >= maxDrainIterations) {
|
|
849
|
+
if (typeof console !== "undefined") {
|
|
850
|
+
console.error(
|
|
851
|
+
`[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
break;
|
|
855
|
+
}
|
|
735
856
|
safeInvoke(pendingQueue[i2]);
|
|
736
857
|
i2++;
|
|
737
858
|
}
|
|
738
859
|
} finally {
|
|
739
|
-
pendingQueue.length = 0;
|
|
740
|
-
pendingSet.clear();
|
|
741
860
|
notifyDepth--;
|
|
861
|
+
if (notifyDepth === 0) {
|
|
862
|
+
pendingQueue.length = 0;
|
|
863
|
+
pendingSet.clear();
|
|
864
|
+
}
|
|
742
865
|
}
|
|
743
866
|
return;
|
|
744
867
|
}
|
|
@@ -758,30 +881,48 @@ function notifySubscribers(signal2) {
|
|
|
758
881
|
notifyDepth++;
|
|
759
882
|
try {
|
|
760
883
|
let directCount = 0;
|
|
884
|
+
let hasComputedSub = false;
|
|
761
885
|
for (const sub2 of subs) {
|
|
886
|
+
if (sub2._c) hasComputedSub = true;
|
|
762
887
|
pendingQueue[directCount++] = sub2;
|
|
763
888
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
889
|
+
if (!hasComputedSub) {
|
|
890
|
+
for (let i3 = 0; i3 < directCount; i3++) {
|
|
891
|
+
safeInvoke(pendingQueue[i3]);
|
|
767
892
|
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
893
|
+
} else {
|
|
894
|
+
for (let i3 = 0; i3 < directCount; i3++) {
|
|
895
|
+
if (pendingQueue[i3]._c) {
|
|
896
|
+
propagateDirty(pendingQueue[i3]);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
for (let i3 = 0; i3 < directCount; i3++) {
|
|
900
|
+
const sub2 = pendingQueue[i3];
|
|
901
|
+
if (!sub2._c && !pendingSet.has(sub2)) {
|
|
902
|
+
pendingSet.add(sub2);
|
|
903
|
+
safeInvoke(sub2);
|
|
773
904
|
}
|
|
774
905
|
}
|
|
775
906
|
}
|
|
776
907
|
let i2 = directCount;
|
|
777
908
|
while (i2 < pendingQueue.length) {
|
|
909
|
+
if (i2 - directCount >= maxDrainIterations) {
|
|
910
|
+
if (typeof console !== "undefined") {
|
|
911
|
+
console.error(
|
|
912
|
+
`[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
778
917
|
safeInvoke(pendingQueue[i2]);
|
|
779
918
|
i2++;
|
|
780
919
|
}
|
|
781
920
|
} finally {
|
|
782
|
-
pendingQueue.length = 0;
|
|
783
|
-
pendingSet.clear();
|
|
784
921
|
notifyDepth--;
|
|
922
|
+
if (notifyDepth === 0) {
|
|
923
|
+
pendingQueue.length = 0;
|
|
924
|
+
pendingSet.clear();
|
|
925
|
+
}
|
|
785
926
|
}
|
|
786
927
|
}
|
|
787
928
|
function cleanup(subscriber) {
|
|
@@ -792,7 +933,9 @@ function cleanup(subscriber) {
|
|
|
792
933
|
if (subs) {
|
|
793
934
|
subs.delete(subscriber);
|
|
794
935
|
if (singleDep.__f === subscriber) {
|
|
795
|
-
singleDep.__f = void 0;
|
|
936
|
+
singleDep.__f = subs.size === 1 ? subs.values().next().value : void 0;
|
|
937
|
+
} else if (subs.size === 1 && singleDep.__f === void 0) {
|
|
938
|
+
singleDep.__f = subs.values().next().value;
|
|
796
939
|
}
|
|
797
940
|
}
|
|
798
941
|
sub2._dep = void 0;
|
|
@@ -805,19 +948,15 @@ function cleanup(subscriber) {
|
|
|
805
948
|
if (subs) {
|
|
806
949
|
subs.delete(subscriber);
|
|
807
950
|
if (signal2.__f === subscriber) {
|
|
808
|
-
signal2.__f = void 0;
|
|
951
|
+
signal2.__f = subs.size === 1 ? subs.values().next().value : void 0;
|
|
952
|
+
} else if (subs.size === 1 && signal2.__f === void 0) {
|
|
953
|
+
signal2.__f = subs.values().next().value;
|
|
809
954
|
}
|
|
810
955
|
}
|
|
811
956
|
}
|
|
812
957
|
deps.clear();
|
|
813
958
|
}
|
|
814
959
|
|
|
815
|
-
// src/core/ssr-context.ts
|
|
816
|
-
var ssrMode = false;
|
|
817
|
-
function isSSR() {
|
|
818
|
-
return ssrMode;
|
|
819
|
-
}
|
|
820
|
-
|
|
821
960
|
// src/core/signals/effect.ts
|
|
822
961
|
var _g = globalThis;
|
|
823
962
|
function effect(effectFn, options) {
|
|
@@ -825,26 +964,86 @@ function effect(effectFn, options) {
|
|
|
825
964
|
if (isSSR()) return () => {
|
|
826
965
|
};
|
|
827
966
|
const onError = options?.onError;
|
|
967
|
+
let userCleanups = [];
|
|
968
|
+
const onCleanup = (fn) => {
|
|
969
|
+
userCleanups.push(fn);
|
|
970
|
+
};
|
|
971
|
+
const runUserCleanups = () => {
|
|
972
|
+
if (userCleanups.length === 0) return;
|
|
973
|
+
const list = userCleanups;
|
|
974
|
+
userCleanups = [];
|
|
975
|
+
for (let i2 = list.length - 1; i2 >= 0; i2--) {
|
|
976
|
+
try {
|
|
977
|
+
list[i2]();
|
|
978
|
+
} catch (err) {
|
|
979
|
+
if (typeof console !== "undefined") {
|
|
980
|
+
console.warn("[SibuJS effect] onCleanup threw:", err);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
};
|
|
985
|
+
const invokeBody = () => effectFn(onCleanup);
|
|
828
986
|
const wrappedFn = onError ? () => {
|
|
829
987
|
try {
|
|
830
|
-
|
|
988
|
+
invokeBody();
|
|
831
989
|
} catch (err) {
|
|
832
990
|
onError(err);
|
|
833
991
|
}
|
|
834
|
-
} :
|
|
992
|
+
} : invokeBody;
|
|
835
993
|
let cleanupHandle = () => {
|
|
836
994
|
};
|
|
995
|
+
let running = false;
|
|
837
996
|
const subscriber = () => {
|
|
838
|
-
|
|
839
|
-
|
|
997
|
+
if (running) {
|
|
998
|
+
if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
|
|
999
|
+
console.warn(
|
|
1000
|
+
"[SibuJS] effect re-entered itself while running \u2014 the triggering update will be ignored. Wrap mutual writes in `batch()` or split the effect to avoid this."
|
|
1001
|
+
);
|
|
1002
|
+
}
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
running = true;
|
|
1006
|
+
try {
|
|
1007
|
+
runUserCleanups();
|
|
1008
|
+
cleanupHandle();
|
|
1009
|
+
cleanupHandle = track(wrappedFn, subscriber);
|
|
1010
|
+
} finally {
|
|
1011
|
+
running = false;
|
|
1012
|
+
}
|
|
840
1013
|
};
|
|
841
|
-
|
|
1014
|
+
running = true;
|
|
1015
|
+
try {
|
|
1016
|
+
cleanupHandle = track(wrappedFn, subscriber);
|
|
1017
|
+
} finally {
|
|
1018
|
+
running = false;
|
|
1019
|
+
}
|
|
842
1020
|
const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
843
1021
|
if (hook) hook.emit("effect:create", { effectFn });
|
|
1022
|
+
let disposed = false;
|
|
844
1023
|
return () => {
|
|
1024
|
+
if (disposed) return;
|
|
1025
|
+
disposed = true;
|
|
845
1026
|
const h = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
846
|
-
if (h)
|
|
847
|
-
|
|
1027
|
+
if (h) {
|
|
1028
|
+
try {
|
|
1029
|
+
h.emit("effect:destroy", { effectFn });
|
|
1030
|
+
} catch {
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
try {
|
|
1034
|
+
runUserCleanups();
|
|
1035
|
+
} catch (err) {
|
|
1036
|
+
if (typeof console !== "undefined") {
|
|
1037
|
+
console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
try {
|
|
1041
|
+
cleanupHandle();
|
|
1042
|
+
} catch (err) {
|
|
1043
|
+
if (typeof console !== "undefined") {
|
|
1044
|
+
console.warn("[SibuJS effect] dispose threw:", err);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
848
1047
|
};
|
|
849
1048
|
}
|
|
850
1049
|
|
|
@@ -1016,10 +1215,13 @@ function enqueueBatchedSignal(signal2) {
|
|
|
1016
1215
|
return true;
|
|
1017
1216
|
}
|
|
1018
1217
|
function flushBatch() {
|
|
1019
|
-
|
|
1020
|
-
|
|
1218
|
+
try {
|
|
1219
|
+
for (const signal2 of pendingSignals) {
|
|
1220
|
+
queueSignalNotification(signal2);
|
|
1221
|
+
}
|
|
1222
|
+
} finally {
|
|
1223
|
+
pendingSignals.clear();
|
|
1021
1224
|
}
|
|
1022
|
-
pendingSignals.clear();
|
|
1023
1225
|
drainNotificationQueue();
|
|
1024
1226
|
}
|
|
1025
1227
|
|
|
@@ -1066,24 +1268,42 @@ function createISR(options) {
|
|
|
1066
1268
|
const { revalidateAfter, fetcher, initialData } = options;
|
|
1067
1269
|
const [data2, setData] = signal(initialData);
|
|
1068
1270
|
const [timestamp, setTimestamp] = signal(initialData !== void 0 ? Date.now() : 0);
|
|
1271
|
+
const controller = new AbortController();
|
|
1272
|
+
let inFlight = false;
|
|
1273
|
+
let disposed = false;
|
|
1069
1274
|
const isStale = () => {
|
|
1070
1275
|
const ts = timestamp();
|
|
1071
1276
|
if (ts === 0) return true;
|
|
1072
1277
|
return Date.now() - ts >= revalidateAfter;
|
|
1073
1278
|
};
|
|
1074
1279
|
const revalidate = async () => {
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1280
|
+
if (disposed || inFlight) return;
|
|
1281
|
+
if (controller.signal.aborted) return;
|
|
1282
|
+
inFlight = true;
|
|
1283
|
+
try {
|
|
1284
|
+
const result = await fetcher({ signal: controller.signal });
|
|
1285
|
+
if (disposed || controller.signal.aborted) return;
|
|
1286
|
+
setData(result);
|
|
1287
|
+
setTimestamp(Date.now());
|
|
1288
|
+
} finally {
|
|
1289
|
+
inFlight = false;
|
|
1290
|
+
}
|
|
1078
1291
|
};
|
|
1079
1292
|
if (initialData === void 0) {
|
|
1080
|
-
revalidate()
|
|
1293
|
+
revalidate().catch((err) => {
|
|
1294
|
+
if (typeof console !== "undefined") console.warn("[SibuJS ISR] initial fetch failed", err);
|
|
1295
|
+
});
|
|
1081
1296
|
}
|
|
1082
1297
|
const intervalId = setInterval(() => {
|
|
1083
|
-
revalidate()
|
|
1298
|
+
revalidate().catch((err) => {
|
|
1299
|
+
if (typeof console !== "undefined") console.warn("[SibuJS ISR] revalidate failed", err);
|
|
1300
|
+
});
|
|
1084
1301
|
}, revalidateAfter);
|
|
1085
1302
|
const dispose = () => {
|
|
1303
|
+
if (disposed) return;
|
|
1304
|
+
disposed = true;
|
|
1086
1305
|
clearInterval(intervalId);
|
|
1306
|
+
controller.abort();
|
|
1087
1307
|
};
|
|
1088
1308
|
return { data: data2, isStale, revalidate, dispose };
|
|
1089
1309
|
}
|
|
@@ -1191,6 +1411,9 @@ function createMiddlewareChain() {
|
|
|
1191
1411
|
|
|
1192
1412
|
// src/reactivity/bindAttribute.ts
|
|
1193
1413
|
var _isDev5 = isDev();
|
|
1414
|
+
function setProp(el, key, val) {
|
|
1415
|
+
el[key] = val;
|
|
1416
|
+
}
|
|
1194
1417
|
function isEventHandlerAttr3(name) {
|
|
1195
1418
|
if (name.length < 3) return false;
|
|
1196
1419
|
const lower = name.toLowerCase();
|
|
@@ -1216,7 +1439,7 @@ function bindAttribute(el, attr, getter) {
|
|
|
1216
1439
|
}
|
|
1217
1440
|
if (typeof value === "boolean") {
|
|
1218
1441
|
if (attr in el && (attr === "checked" || attr === "disabled" || attr === "selected")) {
|
|
1219
|
-
el
|
|
1442
|
+
setProp(el, attr, value);
|
|
1220
1443
|
} else if (value) {
|
|
1221
1444
|
el.setAttribute(attr, "");
|
|
1222
1445
|
} else {
|
|
@@ -1226,7 +1449,7 @@ function bindAttribute(el, attr, getter) {
|
|
|
1226
1449
|
}
|
|
1227
1450
|
const str = String(value);
|
|
1228
1451
|
if ((attr === "value" || attr === "checked") && attr in el) {
|
|
1229
|
-
el
|
|
1452
|
+
setProp(el, attr, attr === "checked" ? Boolean(value) : str);
|
|
1230
1453
|
} else {
|
|
1231
1454
|
el.setAttribute(attr, isUrlAttribute(attr) ? sanitizeUrl(str) : str);
|
|
1232
1455
|
}
|
|
@@ -1263,24 +1486,29 @@ function bindChildNode(placeholder, getter) {
|
|
|
1263
1486
|
let newNodes;
|
|
1264
1487
|
if (Array.isArray(result)) {
|
|
1265
1488
|
newNodes = [];
|
|
1489
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1266
1490
|
for (let i2 = 0; i2 < result.length; i2++) {
|
|
1267
1491
|
const item = result[i2];
|
|
1268
1492
|
if (item == null || typeof item === "boolean") continue;
|
|
1269
|
-
|
|
1493
|
+
const node = item instanceof Node ? item : document.createTextNode(String(item));
|
|
1494
|
+
if (seen.has(node)) {
|
|
1495
|
+
if (_isDev6)
|
|
1496
|
+
devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
|
|
1497
|
+
continue;
|
|
1498
|
+
}
|
|
1499
|
+
seen.add(node);
|
|
1500
|
+
newNodes.push(node);
|
|
1270
1501
|
}
|
|
1271
1502
|
} else {
|
|
1272
1503
|
const node = result instanceof Node ? result : document.createTextNode(String(result));
|
|
1273
1504
|
newNodes = [node];
|
|
1274
1505
|
}
|
|
1275
|
-
|
|
1276
|
-
if (
|
|
1506
|
+
let reused;
|
|
1507
|
+
if (lastNodes.length > 0 && newNodes.length > 0) {
|
|
1508
|
+
const lastSet = new Set(lastNodes);
|
|
1509
|
+
reused = /* @__PURE__ */ new Set();
|
|
1277
1510
|
for (let i2 = 0; i2 < newNodes.length; i2++) {
|
|
1278
|
-
|
|
1279
|
-
if (newNodes[i2] === lastNodes[j]) {
|
|
1280
|
-
reused.add(newNodes[i2]);
|
|
1281
|
-
break;
|
|
1282
|
-
}
|
|
1283
|
-
}
|
|
1511
|
+
if (lastSet.has(newNodes[i2])) reused.add(newNodes[i2]);
|
|
1284
1512
|
}
|
|
1285
1513
|
}
|
|
1286
1514
|
for (let i2 = 0; i2 < lastNodes.length; i2++) {
|
|
@@ -1320,6 +1548,30 @@ function registerDisposer(node, teardown) {
|
|
|
1320
1548
|
|
|
1321
1549
|
// src/core/rendering/tagFactory.ts
|
|
1322
1550
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1551
|
+
var _isDev8 = isDev();
|
|
1552
|
+
var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
1553
|
+
function validateTagName(tag) {
|
|
1554
|
+
const lower = tag.toLowerCase();
|
|
1555
|
+
if (BLOCKED_TAGS.has(lower)) {
|
|
1556
|
+
throw new Error(`tagFactory: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
|
|
1560
|
+
"config",
|
|
1561
|
+
"location",
|
|
1562
|
+
"history",
|
|
1563
|
+
"document",
|
|
1564
|
+
"window",
|
|
1565
|
+
"navigator",
|
|
1566
|
+
"name",
|
|
1567
|
+
"top",
|
|
1568
|
+
"parent",
|
|
1569
|
+
"self",
|
|
1570
|
+
"frames"
|
|
1571
|
+
]);
|
|
1572
|
+
function setProp2(el, key, val) {
|
|
1573
|
+
el[key] = val;
|
|
1574
|
+
}
|
|
1323
1575
|
var kebabCache = /* @__PURE__ */ new Map();
|
|
1324
1576
|
function toKebab(prop) {
|
|
1325
1577
|
let cached = kebabCache.get(prop);
|
|
@@ -1444,79 +1696,103 @@ function appendChildren(el, nodes) {
|
|
|
1444
1696
|
}
|
|
1445
1697
|
}
|
|
1446
1698
|
}
|
|
1447
|
-
var tagFactory = (tag, ns) =>
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
if (
|
|
1452
|
-
|
|
1453
|
-
|
|
1699
|
+
var tagFactory = (tag, ns) => {
|
|
1700
|
+
return (first, second) => {
|
|
1701
|
+
validateTagName(tag);
|
|
1702
|
+
const el = ns ? document.createElementNS(ns, tag) : document.createElement(tag);
|
|
1703
|
+
if (first === void 0) return el;
|
|
1704
|
+
if (typeof first === "string") {
|
|
1705
|
+
if (second !== void 0) {
|
|
1706
|
+
el.setAttribute("class", first);
|
|
1707
|
+
appendChildren(el, second);
|
|
1708
|
+
return el;
|
|
1709
|
+
}
|
|
1710
|
+
el.textContent = first;
|
|
1454
1711
|
return el;
|
|
1455
1712
|
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1713
|
+
if (typeof first === "number") {
|
|
1714
|
+
el.textContent = String(first);
|
|
1715
|
+
return el;
|
|
1716
|
+
}
|
|
1717
|
+
if (Array.isArray(first) || first instanceof Node || typeof first === "function") {
|
|
1718
|
+
appendChildren(el, first);
|
|
1719
|
+
return el;
|
|
1720
|
+
}
|
|
1721
|
+
const props = first;
|
|
1722
|
+
const pClass = props.class;
|
|
1723
|
+
if (pClass != null) applyClass(el, pClass);
|
|
1724
|
+
const pId = props.id;
|
|
1725
|
+
if (pId != null) {
|
|
1726
|
+
if (_isDev8 && typeof pId === "string" && CLOBBER_RISKY_IDS.has(pId.toLowerCase())) {
|
|
1727
|
+
devWarn(
|
|
1728
|
+
`tagFactory: element id="${pId}" matches a common global and may cause DOM clobbering. Avoid setting ids from untrusted input.`
|
|
1729
|
+
);
|
|
1730
|
+
}
|
|
1731
|
+
el.id = pId;
|
|
1732
|
+
}
|
|
1733
|
+
const pNodes = second !== void 0 ? second : props.nodes;
|
|
1734
|
+
if (pNodes != null) appendChildren(el, pNodes);
|
|
1735
|
+
const pOn = props.on;
|
|
1736
|
+
if (pOn) {
|
|
1737
|
+
for (const ev in pOn) {
|
|
1738
|
+
const handler = pOn[ev];
|
|
1739
|
+
if (typeof handler === "function") {
|
|
1740
|
+
el.addEventListener(ev, handler);
|
|
1741
|
+
} else if (_isDev8) {
|
|
1742
|
+
devWarn(
|
|
1743
|
+
`tagFactory: on.${ev} handler is not a function (got ${typeof handler}). Event listener was not attached.`
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
const pStyle = props.style;
|
|
1749
|
+
if (pStyle != null) applyStyle(el, pStyle);
|
|
1750
|
+
const pRef = props.ref;
|
|
1751
|
+
if (pRef) pRef.current = el;
|
|
1752
|
+
for (const key in props) {
|
|
1753
|
+
switch (key) {
|
|
1754
|
+
case "class":
|
|
1755
|
+
case "id":
|
|
1756
|
+
case "nodes":
|
|
1757
|
+
case "on":
|
|
1758
|
+
case "style":
|
|
1759
|
+
case "ref":
|
|
1760
|
+
case "onElement":
|
|
1761
|
+
continue;
|
|
1762
|
+
// already handled above / below
|
|
1763
|
+
default: {
|
|
1764
|
+
const value = props[key];
|
|
1765
|
+
if (value == null) continue;
|
|
1766
|
+
const lkey = key.toLowerCase();
|
|
1767
|
+
if (lkey[0] === "o" && lkey[1] === "n") continue;
|
|
1768
|
+
if (typeof value === "function") {
|
|
1769
|
+
registerDisposer(el, bindAttribute(el, key, value));
|
|
1770
|
+
} else if (typeof value === "boolean") {
|
|
1771
|
+
if (key in el && (key === "checked" || key === "disabled" || key === "selected")) {
|
|
1772
|
+
setProp2(el, key, value);
|
|
1773
|
+
} else if (value) {
|
|
1774
|
+
el.setAttribute(key, "");
|
|
1775
|
+
} else {
|
|
1776
|
+
el.removeAttribute(key);
|
|
1777
|
+
}
|
|
1506
1778
|
} else {
|
|
1507
|
-
|
|
1779
|
+
const str = String(value);
|
|
1780
|
+
if (lkey === "srcset") {
|
|
1781
|
+
el.setAttribute(key, sanitizeSrcset(str));
|
|
1782
|
+
} else if (isUrlAttribute(lkey)) {
|
|
1783
|
+
el.setAttribute(key, sanitizeUrl(str));
|
|
1784
|
+
} else {
|
|
1785
|
+
el.setAttribute(key, str);
|
|
1786
|
+
}
|
|
1508
1787
|
}
|
|
1509
|
-
} else {
|
|
1510
|
-
const str = String(value);
|
|
1511
|
-
el.setAttribute(key, isUrlAttribute(key) ? sanitizeUrl(str) : str);
|
|
1512
1788
|
}
|
|
1513
1789
|
}
|
|
1514
1790
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1791
|
+
if (props.onElement && typeof props.onElement === "function") {
|
|
1792
|
+
props.onElement(el);
|
|
1793
|
+
}
|
|
1794
|
+
return el;
|
|
1795
|
+
};
|
|
1520
1796
|
};
|
|
1521
1797
|
|
|
1522
1798
|
// src/core/rendering/html.ts
|
|
@@ -1670,31 +1946,38 @@ function createMicroApp(config) {
|
|
|
1670
1946
|
}
|
|
1671
1947
|
let mounted = false;
|
|
1672
1948
|
function mount(component) {
|
|
1673
|
-
|
|
1674
|
-
root.innerHTML = "";
|
|
1675
|
-
} else {
|
|
1676
|
-
while (root.firstChild) {
|
|
1677
|
-
root.removeChild(root.firstChild);
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1949
|
+
root.replaceChildren();
|
|
1680
1950
|
const el = component();
|
|
1681
1951
|
root.appendChild(el);
|
|
1682
1952
|
mounted = true;
|
|
1683
1953
|
}
|
|
1684
1954
|
function unmount() {
|
|
1685
1955
|
if (!mounted) return;
|
|
1686
|
-
|
|
1687
|
-
root.innerHTML = "";
|
|
1688
|
-
} else {
|
|
1689
|
-
while (root.firstChild) {
|
|
1690
|
-
root.removeChild(root.firstChild);
|
|
1691
|
-
}
|
|
1692
|
-
}
|
|
1956
|
+
root.replaceChildren();
|
|
1693
1957
|
mounted = false;
|
|
1694
1958
|
}
|
|
1695
1959
|
return { mount, unmount, element: host };
|
|
1696
1960
|
}
|
|
1697
|
-
function loadRemoteModule(url) {
|
|
1961
|
+
function loadRemoteModule(url, optionsOrAllowedOrigins = []) {
|
|
1962
|
+
const opts = Array.isArray(optionsOrAllowedOrigins) ? { allowedOrigins: optionsOrAllowedOrigins } : optionsOrAllowedOrigins;
|
|
1963
|
+
const allowedOrigins = opts.allowedOrigins ?? [];
|
|
1964
|
+
if (allowedOrigins.length > 0) {
|
|
1965
|
+
let parsed;
|
|
1966
|
+
try {
|
|
1967
|
+
parsed = new URL(url, typeof location !== "undefined" ? location.href : void 0);
|
|
1968
|
+
} catch {
|
|
1969
|
+
return Promise.reject(new Error(`loadRemoteModule: invalid URL "${url}"`));
|
|
1970
|
+
}
|
|
1971
|
+
if (!allowedOrigins.includes(parsed.origin)) {
|
|
1972
|
+
return Promise.reject(new Error(`loadRemoteModule: origin "${parsed.origin}" is not in the allowlist`));
|
|
1973
|
+
}
|
|
1974
|
+
} else if (!opts.unsafelyAllowAnyOrigin) {
|
|
1975
|
+
return Promise.reject(
|
|
1976
|
+
new Error(
|
|
1977
|
+
`loadRemoteModule: refused to import "${url}" with no allowedOrigins. Pass { allowedOrigins: [...] } to restrict the origin, or { unsafelyAllowAnyOrigin: true } to opt in to unrestricted imports (CWE-829).`
|
|
1978
|
+
)
|
|
1979
|
+
);
|
|
1980
|
+
}
|
|
1698
1981
|
const cached = moduleCache.get(url);
|
|
1699
1982
|
if (cached) return cached;
|
|
1700
1983
|
const promise = import(
|
|
@@ -1784,21 +2067,49 @@ function serviceWorker(scriptUrl, options) {
|
|
|
1784
2067
|
const [isReady, setIsReady] = signal(false);
|
|
1785
2068
|
const [isUpdateAvailable, setIsUpdateAvailable] = signal(false);
|
|
1786
2069
|
const [error, setError] = signal(null);
|
|
2070
|
+
let disposed = false;
|
|
2071
|
+
let updateFoundHandler = null;
|
|
2072
|
+
let stateChangeHandler = null;
|
|
2073
|
+
let trackedWorker = null;
|
|
2074
|
+
let trackedReg = null;
|
|
2075
|
+
function detachListeners() {
|
|
2076
|
+
if (trackedReg && updateFoundHandler) {
|
|
2077
|
+
trackedReg.removeEventListener("updatefound", updateFoundHandler);
|
|
2078
|
+
}
|
|
2079
|
+
if (trackedWorker && stateChangeHandler) {
|
|
2080
|
+
trackedWorker.removeEventListener("statechange", stateChangeHandler);
|
|
2081
|
+
}
|
|
2082
|
+
updateFoundHandler = null;
|
|
2083
|
+
stateChangeHandler = null;
|
|
2084
|
+
trackedWorker = null;
|
|
2085
|
+
trackedReg = null;
|
|
2086
|
+
}
|
|
1787
2087
|
if ("serviceWorker" in navigator) {
|
|
1788
2088
|
navigator.serviceWorker.register(scriptUrl, options).then((reg) => {
|
|
2089
|
+
if (disposed) return;
|
|
1789
2090
|
setRegistration(reg);
|
|
1790
2091
|
setIsReady(true);
|
|
1791
|
-
|
|
2092
|
+
trackedReg = reg;
|
|
2093
|
+
updateFoundHandler = () => {
|
|
2094
|
+
if (disposed) return;
|
|
1792
2095
|
const newWorker = reg.installing;
|
|
1793
2096
|
if (newWorker) {
|
|
1794
|
-
|
|
2097
|
+
if (trackedWorker && stateChangeHandler) {
|
|
2098
|
+
trackedWorker.removeEventListener("statechange", stateChangeHandler);
|
|
2099
|
+
}
|
|
2100
|
+
trackedWorker = newWorker;
|
|
2101
|
+
stateChangeHandler = () => {
|
|
2102
|
+
if (disposed) return;
|
|
1795
2103
|
if (newWorker.state === "installed" && navigator.serviceWorker.controller) {
|
|
1796
2104
|
setIsUpdateAvailable(true);
|
|
1797
2105
|
}
|
|
1798
|
-
}
|
|
2106
|
+
};
|
|
2107
|
+
newWorker.addEventListener("statechange", stateChangeHandler);
|
|
1799
2108
|
}
|
|
1800
|
-
}
|
|
2109
|
+
};
|
|
2110
|
+
reg.addEventListener("updatefound", updateFoundHandler);
|
|
1801
2111
|
}).catch((err) => {
|
|
2112
|
+
if (disposed) return;
|
|
1802
2113
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1803
2114
|
});
|
|
1804
2115
|
}
|
|
@@ -1809,6 +2120,8 @@ function serviceWorker(scriptUrl, options) {
|
|
|
1809
2120
|
}
|
|
1810
2121
|
}
|
|
1811
2122
|
async function unregister() {
|
|
2123
|
+
disposed = true;
|
|
2124
|
+
detachListeners();
|
|
1812
2125
|
const reg = registration();
|
|
1813
2126
|
if (reg) {
|
|
1814
2127
|
const result = await reg.unregister();
|
|
@@ -1829,24 +2142,37 @@ function worker(workerFn2) {
|
|
|
1829
2142
|
const [error, setError] = signal(null);
|
|
1830
2143
|
const [loading, setLoading] = signal(false);
|
|
1831
2144
|
let worker2 = null;
|
|
2145
|
+
let blobUrl = null;
|
|
2146
|
+
const revokeBlobUrl = () => {
|
|
2147
|
+
if (blobUrl) {
|
|
2148
|
+
URL.revokeObjectURL(blobUrl);
|
|
2149
|
+
blobUrl = null;
|
|
2150
|
+
}
|
|
2151
|
+
};
|
|
1832
2152
|
try {
|
|
1833
2153
|
if (typeof Worker === "undefined") {
|
|
1834
2154
|
throw new Error("Web Workers are not supported in this environment");
|
|
1835
2155
|
}
|
|
1836
2156
|
const fnBody = workerFn2.toString();
|
|
1837
2157
|
const blob = new Blob([`self.onmessage = ${fnBody};`], { type: "application/javascript" });
|
|
1838
|
-
|
|
1839
|
-
worker2 = new Worker(
|
|
1840
|
-
|
|
1841
|
-
|
|
2158
|
+
blobUrl = URL.createObjectURL(blob);
|
|
2159
|
+
worker2 = new Worker(blobUrl);
|
|
2160
|
+
worker2.addEventListener("message", (e) => {
|
|
2161
|
+
revokeBlobUrl();
|
|
1842
2162
|
setResult(e.data);
|
|
1843
2163
|
setLoading(false);
|
|
1844
|
-
};
|
|
1845
|
-
worker2.
|
|
2164
|
+
});
|
|
2165
|
+
worker2.addEventListener("error", (e) => {
|
|
2166
|
+
revokeBlobUrl();
|
|
1846
2167
|
setError(new Error(e.message || "Worker error"));
|
|
1847
2168
|
setLoading(false);
|
|
1848
|
-
|
|
2169
|
+
if (worker2) {
|
|
2170
|
+
worker2.terminate();
|
|
2171
|
+
worker2 = null;
|
|
2172
|
+
}
|
|
2173
|
+
});
|
|
1849
2174
|
} catch (err) {
|
|
2175
|
+
revokeBlobUrl();
|
|
1850
2176
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1851
2177
|
}
|
|
1852
2178
|
function post(data2) {
|
|
@@ -1860,6 +2186,7 @@ function worker(workerFn2) {
|
|
|
1860
2186
|
if (!worker2) return;
|
|
1861
2187
|
worker2.terminate();
|
|
1862
2188
|
worker2 = null;
|
|
2189
|
+
revokeBlobUrl();
|
|
1863
2190
|
setLoading(false);
|
|
1864
2191
|
}
|
|
1865
2192
|
return { post, result, error, loading, terminate };
|
|
@@ -1867,6 +2194,14 @@ function worker(workerFn2) {
|
|
|
1867
2194
|
function workerFn(fn) {
|
|
1868
2195
|
const [loading, setLoading] = signal(false);
|
|
1869
2196
|
let worker2 = null;
|
|
2197
|
+
let blobUrl = null;
|
|
2198
|
+
const revokeBlobUrl = () => {
|
|
2199
|
+
if (blobUrl) {
|
|
2200
|
+
URL.revokeObjectURL(blobUrl);
|
|
2201
|
+
blobUrl = null;
|
|
2202
|
+
}
|
|
2203
|
+
};
|
|
2204
|
+
const queue = [];
|
|
1870
2205
|
try {
|
|
1871
2206
|
if (typeof Worker === "undefined") {
|
|
1872
2207
|
throw new Error("Web Workers are not supported in this environment");
|
|
@@ -1882,10 +2217,26 @@ function workerFn(fn) {
|
|
|
1882
2217
|
],
|
|
1883
2218
|
{ type: "application/javascript" }
|
|
1884
2219
|
);
|
|
1885
|
-
|
|
1886
|
-
worker2 = new Worker(
|
|
1887
|
-
|
|
2220
|
+
blobUrl = URL.createObjectURL(blob);
|
|
2221
|
+
worker2 = new Worker(blobUrl);
|
|
2222
|
+
worker2.addEventListener("message", (e) => {
|
|
2223
|
+
revokeBlobUrl();
|
|
2224
|
+
const head2 = queue.shift();
|
|
2225
|
+
if (queue.length === 0) setLoading(false);
|
|
2226
|
+
if (head2) head2.resolve(e.data);
|
|
2227
|
+
});
|
|
2228
|
+
worker2.addEventListener("error", (e) => {
|
|
2229
|
+
revokeBlobUrl();
|
|
2230
|
+
const err = new Error(e.message || "Worker error");
|
|
2231
|
+
while (queue.length > 0) queue.shift().reject(err);
|
|
2232
|
+
setLoading(false);
|
|
2233
|
+
if (worker2) {
|
|
2234
|
+
worker2.terminate();
|
|
2235
|
+
worker2 = null;
|
|
2236
|
+
}
|
|
2237
|
+
});
|
|
1888
2238
|
} catch {
|
|
2239
|
+
revokeBlobUrl();
|
|
1889
2240
|
}
|
|
1890
2241
|
function run(...args) {
|
|
1891
2242
|
return new Promise((resolve, reject) => {
|
|
@@ -1894,14 +2245,7 @@ function workerFn(fn) {
|
|
|
1894
2245
|
return;
|
|
1895
2246
|
}
|
|
1896
2247
|
setLoading(true);
|
|
1897
|
-
|
|
1898
|
-
setLoading(false);
|
|
1899
|
-
resolve(e.data);
|
|
1900
|
-
};
|
|
1901
|
-
worker2.onerror = (e) => {
|
|
1902
|
-
setLoading(false);
|
|
1903
|
-
reject(new Error(e.message || "Worker error"));
|
|
1904
|
-
};
|
|
2248
|
+
queue.push({ resolve, reject });
|
|
1905
2249
|
worker2.postMessage(args);
|
|
1906
2250
|
});
|
|
1907
2251
|
}
|
|
@@ -1909,6 +2253,9 @@ function workerFn(fn) {
|
|
|
1909
2253
|
if (!worker2) return;
|
|
1910
2254
|
worker2.terminate();
|
|
1911
2255
|
worker2 = null;
|
|
2256
|
+
const err = new Error("Worker terminated");
|
|
2257
|
+
while (queue.length > 0) queue.shift().reject(err);
|
|
2258
|
+
revokeBlobUrl();
|
|
1912
2259
|
setLoading(false);
|
|
1913
2260
|
}
|
|
1914
2261
|
return { run, loading, terminate };
|
|
@@ -1916,20 +2263,63 @@ function workerFn(fn) {
|
|
|
1916
2263
|
function createWorkerPool(workerFn2, poolSize) {
|
|
1917
2264
|
const size = poolSize || typeof navigator !== "undefined" && navigator.hardwareConcurrency || 4;
|
|
1918
2265
|
const workers = [];
|
|
2266
|
+
const queues = [];
|
|
2267
|
+
const inflight = [];
|
|
1919
2268
|
let currentIndex = 0;
|
|
1920
2269
|
let alive = true;
|
|
2270
|
+
let blobUrl = null;
|
|
2271
|
+
let firedOnce = false;
|
|
2272
|
+
const revokeBlobUrl = () => {
|
|
2273
|
+
if (blobUrl) {
|
|
2274
|
+
URL.revokeObjectURL(blobUrl);
|
|
2275
|
+
blobUrl = null;
|
|
2276
|
+
}
|
|
2277
|
+
};
|
|
2278
|
+
function dispatchNext(idx) {
|
|
2279
|
+
if (!alive || inflight[idx] || queues[idx].length === 0) return;
|
|
2280
|
+
const w = workers[idx];
|
|
2281
|
+
const slot2 = queues[idx].shift();
|
|
2282
|
+
const onMsg = (e) => {
|
|
2283
|
+
if (!firedOnce) {
|
|
2284
|
+
firedOnce = true;
|
|
2285
|
+
revokeBlobUrl();
|
|
2286
|
+
}
|
|
2287
|
+
w.removeEventListener("message", onMsg);
|
|
2288
|
+
w.removeEventListener("error", onErr);
|
|
2289
|
+
inflight[idx] = null;
|
|
2290
|
+
slot2.resolve(e.data);
|
|
2291
|
+
dispatchNext(idx);
|
|
2292
|
+
};
|
|
2293
|
+
const onErr = (e) => {
|
|
2294
|
+
if (!firedOnce) {
|
|
2295
|
+
firedOnce = true;
|
|
2296
|
+
revokeBlobUrl();
|
|
2297
|
+
}
|
|
2298
|
+
w.removeEventListener("message", onMsg);
|
|
2299
|
+
w.removeEventListener("error", onErr);
|
|
2300
|
+
inflight[idx] = null;
|
|
2301
|
+
slot2.reject(new Error(e.message || "Worker error"));
|
|
2302
|
+
dispatchNext(idx);
|
|
2303
|
+
};
|
|
2304
|
+
inflight[idx] = { ...slot2, onMsg, onErr };
|
|
2305
|
+
w.addEventListener("message", onMsg);
|
|
2306
|
+
w.addEventListener("error", onErr);
|
|
2307
|
+
w.postMessage(slot2.data);
|
|
2308
|
+
}
|
|
1921
2309
|
try {
|
|
1922
2310
|
if (typeof Worker === "undefined") {
|
|
1923
2311
|
throw new Error("Web Workers are not supported in this environment");
|
|
1924
2312
|
}
|
|
1925
2313
|
const fnBody = workerFn2.toString();
|
|
1926
2314
|
const blob = new Blob([`self.onmessage = ${fnBody};`], { type: "application/javascript" });
|
|
1927
|
-
|
|
2315
|
+
blobUrl = URL.createObjectURL(blob);
|
|
1928
2316
|
for (let i2 = 0; i2 < size; i2++) {
|
|
1929
|
-
workers.push(new Worker(
|
|
2317
|
+
workers.push(new Worker(blobUrl));
|
|
2318
|
+
queues.push([]);
|
|
2319
|
+
inflight.push(null);
|
|
1930
2320
|
}
|
|
1931
|
-
URL.revokeObjectURL(url);
|
|
1932
2321
|
} catch {
|
|
2322
|
+
revokeBlobUrl();
|
|
1933
2323
|
}
|
|
1934
2324
|
function execute(data2) {
|
|
1935
2325
|
return new Promise((resolve, reject) => {
|
|
@@ -1937,23 +2327,25 @@ function createWorkerPool(workerFn2, poolSize) {
|
|
|
1937
2327
|
reject(new Error("Worker pool is not available"));
|
|
1938
2328
|
return;
|
|
1939
2329
|
}
|
|
1940
|
-
const
|
|
2330
|
+
const idx = currentIndex % workers.length;
|
|
1941
2331
|
currentIndex++;
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
};
|
|
1945
|
-
worker2.onerror = (e) => {
|
|
1946
|
-
reject(new Error(e.message || "Worker error"));
|
|
1947
|
-
};
|
|
1948
|
-
worker2.postMessage(data2);
|
|
2332
|
+
queues[idx].push({ data: data2, resolve, reject });
|
|
2333
|
+
dispatchNext(idx);
|
|
1949
2334
|
});
|
|
1950
2335
|
}
|
|
1951
2336
|
function terminate() {
|
|
1952
2337
|
alive = false;
|
|
1953
|
-
for (const w of workers)
|
|
1954
|
-
|
|
2338
|
+
for (const w of workers) w.terminate();
|
|
2339
|
+
const err = new Error("Worker pool terminated");
|
|
2340
|
+
for (let i2 = 0; i2 < queues.length; i2++) {
|
|
2341
|
+
const inf = inflight[i2];
|
|
2342
|
+
if (inf) inf.reject(err);
|
|
2343
|
+
for (const s2 of queues[i2]) s2.reject(err);
|
|
2344
|
+
queues[i2] = [];
|
|
2345
|
+
inflight[i2] = null;
|
|
1955
2346
|
}
|
|
1956
2347
|
workers.length = 0;
|
|
2348
|
+
revokeBlobUrl();
|
|
1957
2349
|
}
|
|
1958
2350
|
return { execute, terminate };
|
|
1959
2351
|
}
|
|
@@ -1989,7 +2381,28 @@ function wasm(source2, config = {}) {
|
|
|
1989
2381
|
};
|
|
1990
2382
|
}
|
|
1991
2383
|
async function loadWasmModule(source2, imports, cacheKey) {
|
|
1992
|
-
const
|
|
2384
|
+
const isOptionsBag = !!(imports && ("allowedOrigins" in imports || "unsafelyAllowAnyOrigin" in imports));
|
|
2385
|
+
const opts = isOptionsBag ? imports : { imports, cacheKey };
|
|
2386
|
+
const wasmImports = opts.imports;
|
|
2387
|
+
const key = opts.cacheKey || (typeof source2 === "string" ? source2 : void 0);
|
|
2388
|
+
if (typeof source2 === "string") {
|
|
2389
|
+
const allowed = opts.allowedOrigins ?? [];
|
|
2390
|
+
if (allowed.length > 0) {
|
|
2391
|
+
let parsed;
|
|
2392
|
+
try {
|
|
2393
|
+
parsed = new URL(source2, typeof location !== "undefined" ? location.href : void 0);
|
|
2394
|
+
} catch {
|
|
2395
|
+
throw new Error(`loadWasmModule: invalid URL "${source2}"`);
|
|
2396
|
+
}
|
|
2397
|
+
if (!allowed.includes(parsed.origin)) {
|
|
2398
|
+
throw new Error(`loadWasmModule: origin "${parsed.origin}" is not in the allowlist`);
|
|
2399
|
+
}
|
|
2400
|
+
} else if (!opts.unsafelyAllowAnyOrigin) {
|
|
2401
|
+
throw new Error(
|
|
2402
|
+
`loadWasmModule: refused to fetch "${source2}" with no allowedOrigins. Pass { allowedOrigins: [...] } to restrict the origin, or { unsafelyAllowAnyOrigin: true } to opt in (CWE-829).`
|
|
2403
|
+
);
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
1993
2406
|
if (key) {
|
|
1994
2407
|
const cachedInstance = instanceCache.get(key);
|
|
1995
2408
|
if (cachedInstance) {
|
|
@@ -2005,7 +2418,7 @@ async function loadWasmModule(source2, imports, cacheKey) {
|
|
|
2005
2418
|
if (typeof source2 === "string") {
|
|
2006
2419
|
if (typeof WebAssembly.instantiateStreaming === "function") {
|
|
2007
2420
|
const response2 = fetch(source2);
|
|
2008
|
-
const result = await WebAssembly.instantiateStreaming(response2,
|
|
2421
|
+
const result = await WebAssembly.instantiateStreaming(response2, wasmImports || {});
|
|
2009
2422
|
if (key) {
|
|
2010
2423
|
moduleCache2.set(key, result.module);
|
|
2011
2424
|
instanceCache.set(key, result.instance);
|
|
@@ -2022,12 +2435,28 @@ async function loadWasmModule(source2, imports, cacheKey) {
|
|
|
2022
2435
|
module2 = await WebAssembly.compile(bytes);
|
|
2023
2436
|
if (key) moduleCache2.set(key, module2);
|
|
2024
2437
|
}
|
|
2025
|
-
const instance = await WebAssembly.instantiate(module2,
|
|
2438
|
+
const instance = await WebAssembly.instantiate(module2, wasmImports || {});
|
|
2026
2439
|
if (key) instanceCache.set(key, instance);
|
|
2027
2440
|
return instance;
|
|
2028
2441
|
}
|
|
2029
|
-
async function preloadWasm(url) {
|
|
2442
|
+
async function preloadWasm(url, options = {}) {
|
|
2030
2443
|
if (moduleCache2.has(url)) return;
|
|
2444
|
+
const allowed = options.allowedOrigins ?? [];
|
|
2445
|
+
if (allowed.length > 0) {
|
|
2446
|
+
let parsed;
|
|
2447
|
+
try {
|
|
2448
|
+
parsed = new URL(url, typeof location !== "undefined" ? location.href : void 0);
|
|
2449
|
+
} catch {
|
|
2450
|
+
throw new Error(`preloadWasm: invalid URL "${url}"`);
|
|
2451
|
+
}
|
|
2452
|
+
if (!allowed.includes(parsed.origin)) {
|
|
2453
|
+
throw new Error(`preloadWasm: origin "${parsed.origin}" is not in the allowlist`);
|
|
2454
|
+
}
|
|
2455
|
+
} else if (!options.unsafelyAllowAnyOrigin) {
|
|
2456
|
+
throw new Error(
|
|
2457
|
+
`preloadWasm: refused to fetch "${url}" with no allowedOrigins. Pass { allowedOrigins: [...] } or { unsafelyAllowAnyOrigin: true } (CWE-829).`
|
|
2458
|
+
);
|
|
2459
|
+
}
|
|
2031
2460
|
let module2;
|
|
2032
2461
|
if (typeof WebAssembly.compileStreaming === "function") {
|
|
2033
2462
|
module2 = await WebAssembly.compileStreaming(fetch(url));
|