sibujs 1.5.0 → 2.1.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/dist/browser.cjs +332 -121
- package/dist/browser.d.cts +5 -0
- package/dist/browser.d.ts +5 -0
- package/dist/browser.js +6 -6
- package/dist/build.cjs +1049 -344
- 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-BMPL52BF.js → chunk-3DZP6OIT.js} +118 -66
- package/dist/chunk-3JHCYHWN.js +125 -0
- package/dist/{chunk-CZUGLNJS.js → chunk-45YP72ZQ.js} +3 -3
- package/dist/{chunk-JCDUJN2F.js → chunk-AMK2TYNW.js} +490 -153
- package/dist/{chunk-NHUC2QWH.js → chunk-CWBVQML6.js} +1 -1
- package/dist/{chunk-XHK6BDAJ.js → chunk-DRUZZAK4.js} +25 -8
- package/dist/{chunk-RJ46C3CS.js → chunk-GWWURC5M.js} +71 -20
- package/dist/{chunk-3X2YG6YM.js → chunk-JYD2PWXH.js} +59 -28
- package/dist/{chunk-2BYQDGN3.js → chunk-KGYT6UO6.js} +234 -63
- package/dist/{chunk-5X6PP2UK.js → chunk-LMLD24FC.js} +2 -2
- package/dist/{chunk-M4NLBH4I.js → chunk-LYTCUZ7H.js} +3 -2
- package/dist/{chunk-XUEEGU5O.js → chunk-NASX6ST2.js} +16 -4
- package/dist/{chunk-VQDZK23A.js → chunk-O6EFQ3KT.js} +181 -66
- package/dist/{chunk-BGN5ZMP4.js → chunk-OJ3P4ECI.js} +14 -2
- package/dist/chunk-ON5MMR2J.js +1327 -0
- package/dist/{chunk-SFKNRVCU.js → chunk-P2HSJDDN.js} +135 -79
- package/dist/chunk-QO3WC6FS.js +384 -0
- package/dist/{chunk-WZSPOOER.js → chunk-RDTDJCAB.js} +8 -5
- package/dist/{chunk-7GRNSCFT.js → chunk-TH2ILCYW.js} +312 -185
- package/dist/chunk-UCS6AMJ7.js +79 -0
- package/dist/{chunk-VAPYJN4X.js → chunk-V6C4FADE.js} +93 -23
- package/dist/{chunk-OUZZEE4S.js → chunk-WANSMF2L.js} +17 -11
- package/dist/{chunk-23VV7YD3.js → chunk-WIPZPFBQ.js} +25 -30
- package/dist/chunk-WZA53FXU.js +149 -0
- package/dist/{chunk-BGTHZHJ5.js → chunk-ZAQSMOED.js} +188 -44
- package/dist/{customElement-BL3Uo8dL.d.cts → customElement-CPfIrbvg.d.cts} +14 -10
- package/dist/{customElement-BL3Uo8dL.d.ts → customElement-CPfIrbvg.d.ts} +14 -10
- package/dist/data.cjs +536 -151
- package/dist/data.d.cts +20 -2
- package/dist/data.d.ts +20 -2
- package/dist/data.js +11 -9
- package/dist/devtools.cjs +613 -266
- package/dist/devtools.d.cts +1 -1
- package/dist/devtools.d.ts +1 -1
- package/dist/devtools.js +12 -6
- package/dist/ecosystem.cjs +602 -197
- package/dist/ecosystem.d.cts +9 -7
- package/dist/ecosystem.d.ts +9 -7
- package/dist/ecosystem.js +12 -11
- package/dist/extras.cjs +3500 -1608
- package/dist/extras.d.cts +9 -9
- package/dist/extras.d.ts +9 -9
- package/dist/extras.js +58 -45
- package/dist/index.cjs +1055 -344
- package/dist/index.d.cts +85 -8
- package/dist/index.d.ts +85 -8
- package/dist/index.js +32 -16
- package/dist/{introspect-BumjnBKr.d.cts → introspect-2TOlQ7oa.d.cts} +25 -3
- package/dist/{introspect-CZrlcaYy.d.ts → introspect-DnIpHQQz.d.ts} +25 -3
- package/dist/motion.cjs +122 -63
- package/dist/motion.js +4 -4
- package/dist/patterns.cjs +450 -110
- package/dist/patterns.d.cts +11 -12
- package/dist/patterns.d.ts +11 -12
- package/dist/patterns.js +7 -7
- package/dist/performance.cjs +373 -149
- package/dist/performance.d.cts +23 -16
- package/dist/performance.d.ts +23 -16
- package/dist/performance.js +13 -8
- package/dist/plugin-D30wlGW5.d.cts +71 -0
- package/dist/plugin-D30wlGW5.d.ts +71 -0
- package/dist/plugins.cjs +729 -301
- package/dist/plugins.d.cts +10 -3
- package/dist/plugins.d.ts +10 -3
- package/dist/plugins.js +106 -38
- 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 +736 -274
- package/dist/ssr.d.cts +26 -6
- package/dist/ssr.d.ts +26 -6
- package/dist/ssr.js +12 -11
- package/dist/{tagFactory-DaJ0YWX6.d.cts → tagFactory-S17H2qxu.d.cts} +9 -1
- package/dist/{tagFactory-DaJ0YWX6.d.ts → tagFactory-S17H2qxu.d.ts} +9 -1
- package/dist/testing.cjs +303 -76
- package/dist/testing.d.cts +17 -4
- package/dist/testing.d.ts +17 -4
- package/dist/testing.js +100 -44
- package/dist/ui.cjs +589 -178
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +20 -17
- package/dist/widgets.cjs +1103 -146
- 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-3AIRKM3B.js +0 -1263
- package/dist/chunk-3ARAQO7B.js +0 -398
- package/dist/chunk-3CRQALYP.js +0 -877
- package/dist/chunk-4EI4AG32.js +0 -482
- package/dist/chunk-4MYMUBRS.js +0 -21
- package/dist/chunk-5ZYQ6KDD.js +0 -154
- package/dist/chunk-6BMPXPUW.js +0 -26
- package/dist/chunk-6HLLIF3K.js +0 -398
- package/dist/chunk-6LSNVCS2.js +0 -937
- package/dist/chunk-6SA3QQES.js +0 -61
- package/dist/chunk-77L6NL3X.js +0 -1097
- 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-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-EWFVA3TJ.js +0 -282
- package/dist/chunk-F3FA4F32.js +0 -292
- package/dist/chunk-FGOEVHY3.js +0 -60
- package/dist/chunk-G3BOQPVO.js +0 -365
- package/dist/chunk-GCOK2LC3.js +0 -282
- package/dist/chunk-GJPXRJ45.js +0 -37
- package/dist/chunk-HGMJFBC7.js +0 -654
- package/dist/chunk-JAKHTMQU.js +0 -1000
- package/dist/chunk-JCI5M6U6.js +0 -956
- package/dist/chunk-K4G4ZQNR.js +0 -286
- 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-MB6QFH3I.js +0 -2776
- 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-MYRV7VDM.js +0 -742
- package/dist/chunk-N6IZB6KJ.js +0 -567
- package/dist/chunk-NEKUBFPT.js +0 -60
- package/dist/chunk-NMRUZALC.js +0 -1097
- package/dist/chunk-NYVAC6P5.js +0 -37
- package/dist/chunk-NZIIMDWI.js +0 -84
- package/dist/chunk-OF7UZIVB.js +0 -725
- package/dist/chunk-P3XWXJZU.js +0 -282
- package/dist/chunk-P6W3STU4.js +0 -2249
- package/dist/chunk-PBHF5WKN.js +0 -616
- package/dist/chunk-PDZQY43A.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-QWZG56ET.js +0 -2744
- package/dist/chunk-RQGQSLQK.js +0 -725
- package/dist/chunk-SDLZDHKP.js +0 -107
- package/dist/chunk-TDGZL5CU.js +0 -365
- package/dist/chunk-TNQWPPE6.js +0 -37
- package/dist/chunk-TSOKIX5Z.js +0 -654
- 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-VQNQZCWJ.js +0 -61
- package/dist/chunk-VRW3FULF.js +0 -725
- package/dist/chunk-WADYRCO2.js +0 -304
- package/dist/chunk-WILQZRO4.js +0 -282
- package/dist/chunk-WR5D4EGH.js +0 -26
- 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/chunk-ZD6OAMTH.js +0 -277
- package/dist/chunk-ZWKZCBO6.js +0 -317
- 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/contracts-xo5ckdRP.d.cts +0 -240
- package/dist/contracts-xo5ckdRP.d.ts +0 -240
- package/dist/customElement-BKQfbSZQ.d.cts +0 -262
- package/dist/customElement-BKQfbSZQ.d.ts +0 -262
- package/dist/customElement-D2DJp_xn.d.cts +0 -313
- package/dist/customElement-D2DJp_xn.d.ts +0 -313
- 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;
|
|
@@ -582,15 +682,28 @@ function escapeAttr(str) {
|
|
|
582
682
|
|
|
583
683
|
// src/reactivity/track.ts
|
|
584
684
|
var _isDev3 = isDev();
|
|
585
|
-
var
|
|
586
|
-
var
|
|
685
|
+
var STACK_INITIAL = 32;
|
|
686
|
+
var STACK_SHRINK_THRESHOLD = 128;
|
|
687
|
+
var subscriberStack = new Array(STACK_INITIAL);
|
|
688
|
+
var stackCapacity = STACK_INITIAL;
|
|
587
689
|
var stackTop = -1;
|
|
588
690
|
var currentSubscriber = null;
|
|
589
|
-
var signalSubscribers = /* @__PURE__ */ new WeakMap();
|
|
590
691
|
var SUBS = "__s";
|
|
692
|
+
function syncFastPath(signal2, subs) {
|
|
693
|
+
const size = subs.size;
|
|
694
|
+
if (size === 0) {
|
|
695
|
+
signal2.__f = void 0;
|
|
696
|
+
delete signal2[SUBS];
|
|
697
|
+
} else if (size === 1) {
|
|
698
|
+
signal2.__f = subs.values().next().value;
|
|
699
|
+
} else {
|
|
700
|
+
signal2.__f = void 0;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
591
703
|
var notifyDepth = 0;
|
|
592
704
|
var pendingQueue = [];
|
|
593
705
|
var pendingSet = /* @__PURE__ */ new Set();
|
|
706
|
+
var propagateStack = [];
|
|
594
707
|
function safeInvoke(sub2) {
|
|
595
708
|
try {
|
|
596
709
|
sub2();
|
|
@@ -613,37 +726,49 @@ function track(effectFn, subscriber) {
|
|
|
613
726
|
} finally {
|
|
614
727
|
stackTop--;
|
|
615
728
|
currentSubscriber = stackTop >= 0 ? subscriberStack[stackTop] : null;
|
|
729
|
+
if (stackTop < 0 && stackCapacity > STACK_SHRINK_THRESHOLD) {
|
|
730
|
+
stackCapacity = Math.max(STACK_INITIAL, stackCapacity >>> 1);
|
|
731
|
+
subscriberStack.length = stackCapacity;
|
|
732
|
+
}
|
|
616
733
|
}
|
|
617
734
|
return () => cleanup(subscriber);
|
|
618
735
|
}
|
|
619
736
|
function recordDependency(signal2) {
|
|
620
737
|
if (!currentSubscriber) return;
|
|
621
738
|
const sub2 = currentSubscriber;
|
|
622
|
-
|
|
739
|
+
const epoch = sub2._epoch;
|
|
740
|
+
if (sub2._dep === signal2) {
|
|
741
|
+
sub2._depEpoch = epoch;
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
623
744
|
const deps = sub2._deps;
|
|
624
745
|
if (deps) {
|
|
625
|
-
|
|
626
|
-
deps.add(signal2);
|
|
746
|
+
deps.set(signal2, epoch);
|
|
627
747
|
} else if (sub2._dep !== void 0) {
|
|
628
|
-
const
|
|
629
|
-
set
|
|
630
|
-
set
|
|
631
|
-
sub2._deps =
|
|
748
|
+
const map2 = /* @__PURE__ */ new Map();
|
|
749
|
+
map2.set(sub2._dep, sub2._depEpoch);
|
|
750
|
+
map2.set(signal2, epoch);
|
|
751
|
+
sub2._deps = map2;
|
|
632
752
|
sub2._dep = void 0;
|
|
753
|
+
sub2._depEpoch = void 0;
|
|
633
754
|
} else {
|
|
634
755
|
sub2._dep = signal2;
|
|
756
|
+
sub2._depEpoch = epoch;
|
|
635
757
|
}
|
|
636
|
-
|
|
758
|
+
const sig = signal2;
|
|
759
|
+
let subs = sig[SUBS];
|
|
637
760
|
if (!subs) {
|
|
638
761
|
subs = /* @__PURE__ */ new Set();
|
|
639
|
-
|
|
640
|
-
signal2[SUBS] = subs;
|
|
762
|
+
sig[SUBS] = subs;
|
|
641
763
|
}
|
|
764
|
+
const prevSize = subs.size;
|
|
642
765
|
subs.add(currentSubscriber);
|
|
643
|
-
if (subs.size
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
766
|
+
if (subs.size !== prevSize) {
|
|
767
|
+
if (subs.size === 1) {
|
|
768
|
+
sig.__f = currentSubscriber;
|
|
769
|
+
} else if (sig.__f !== void 0) {
|
|
770
|
+
sig.__f = void 0;
|
|
771
|
+
}
|
|
647
772
|
}
|
|
648
773
|
}
|
|
649
774
|
function queueSignalNotification(signal2) {
|
|
@@ -658,66 +783,102 @@ function queueSignalNotification(signal2) {
|
|
|
658
783
|
}
|
|
659
784
|
}
|
|
660
785
|
}
|
|
661
|
-
var
|
|
786
|
+
var maxSubscriberRepeats = 50;
|
|
787
|
+
var maxDrainIterations = 1e6;
|
|
788
|
+
var drainEpoch = 0;
|
|
789
|
+
function tickRepeat(sub2) {
|
|
790
|
+
const s2 = sub2;
|
|
791
|
+
if (s2._runEpoch !== drainEpoch) {
|
|
792
|
+
s2._runEpoch = drainEpoch;
|
|
793
|
+
s2._runs = 1;
|
|
794
|
+
return false;
|
|
795
|
+
}
|
|
796
|
+
return ++s2._runs > maxSubscriberRepeats;
|
|
797
|
+
}
|
|
798
|
+
function cycleError(sub2) {
|
|
799
|
+
if (typeof console !== "undefined") {
|
|
800
|
+
const name = sub2.__name ?? "<unnamed>";
|
|
801
|
+
console.error(
|
|
802
|
+
`[SibuJS] subscriber "${name}" fired more than ${maxSubscriberRepeats} times \u2014 likely a write-reads-self cycle between effects/signals. Breaking to prevent infinite loop.`
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
function absoluteDrainError() {
|
|
807
|
+
if (typeof console !== "undefined") {
|
|
808
|
+
console.error(
|
|
809
|
+
`[SibuJS] Notification drain exceeded ${maxDrainIterations} iterations \u2014 absolute safety net tripped. Breaking to prevent infinite loop.`
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
function drainQueue() {
|
|
814
|
+
let i2 = 0;
|
|
815
|
+
while (i2 < pendingQueue.length) {
|
|
816
|
+
if (i2 >= maxDrainIterations) {
|
|
817
|
+
absoluteDrainError();
|
|
818
|
+
break;
|
|
819
|
+
}
|
|
820
|
+
const sub2 = pendingQueue[i2++];
|
|
821
|
+
if (tickRepeat(sub2)) {
|
|
822
|
+
cycleError(sub2);
|
|
823
|
+
break;
|
|
824
|
+
}
|
|
825
|
+
pendingSet.delete(sub2);
|
|
826
|
+
safeInvoke(sub2);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
662
829
|
function drainNotificationQueue() {
|
|
663
830
|
if (notifyDepth > 0) return;
|
|
664
831
|
notifyDepth++;
|
|
832
|
+
drainEpoch++;
|
|
665
833
|
try {
|
|
666
|
-
|
|
667
|
-
while (i2 < pendingQueue.length) {
|
|
668
|
-
if (i2 >= MAX_DRAIN_ITERATIONS) {
|
|
669
|
-
if (typeof console !== "undefined") {
|
|
670
|
-
console.error(
|
|
671
|
-
`[SibuJS] Notification queue exceeded ${MAX_DRAIN_ITERATIONS} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
672
|
-
);
|
|
673
|
-
}
|
|
674
|
-
break;
|
|
675
|
-
}
|
|
676
|
-
safeInvoke(pendingQueue[i2]);
|
|
677
|
-
i2++;
|
|
678
|
-
}
|
|
834
|
+
drainQueue();
|
|
679
835
|
} finally {
|
|
680
|
-
pendingQueue.length = 0;
|
|
681
|
-
pendingSet.clear();
|
|
682
836
|
notifyDepth--;
|
|
837
|
+
if (notifyDepth === 0) {
|
|
838
|
+
pendingQueue.length = 0;
|
|
839
|
+
pendingSet.clear();
|
|
840
|
+
}
|
|
683
841
|
}
|
|
684
842
|
}
|
|
685
843
|
function propagateDirty(sub2) {
|
|
686
844
|
sub2();
|
|
687
|
-
|
|
688
|
-
|
|
845
|
+
const rootSig = sub2._sig;
|
|
846
|
+
if (!rootSig) return;
|
|
847
|
+
const stack = propagateStack;
|
|
848
|
+
const baseLen = stack.length;
|
|
849
|
+
stack.push(rootSig);
|
|
850
|
+
while (stack.length > baseLen) {
|
|
851
|
+
const sig = stack.pop();
|
|
689
852
|
const first = sig.__f;
|
|
690
853
|
if (first) {
|
|
691
854
|
if (first._c) {
|
|
692
855
|
const nSig = first._sig;
|
|
693
|
-
nSig._d
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
if (!pendingSet.has(first)) {
|
|
856
|
+
if (!nSig._d) {
|
|
857
|
+
nSig._d = true;
|
|
858
|
+
stack.push(nSig);
|
|
859
|
+
}
|
|
860
|
+
} else if (!pendingSet.has(first)) {
|
|
698
861
|
pendingSet.add(first);
|
|
699
862
|
pendingQueue.push(first);
|
|
700
863
|
}
|
|
701
|
-
|
|
864
|
+
continue;
|
|
702
865
|
}
|
|
703
866
|
const subs = sig[SUBS];
|
|
704
|
-
if (!subs)
|
|
705
|
-
let nextSig;
|
|
867
|
+
if (!subs) continue;
|
|
706
868
|
for (const s2 of subs) {
|
|
707
869
|
if (s2._c) {
|
|
708
|
-
s2();
|
|
709
870
|
const nSig = s2._sig;
|
|
710
|
-
if (nSig && !
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
871
|
+
if (nSig && !nSig._d) {
|
|
872
|
+
nSig._d = true;
|
|
873
|
+
stack.push(nSig);
|
|
874
|
+
} else if (!nSig) {
|
|
875
|
+
s2();
|
|
714
876
|
}
|
|
715
877
|
} else if (!pendingSet.has(s2)) {
|
|
716
878
|
pendingSet.add(s2);
|
|
717
879
|
pendingQueue.push(s2);
|
|
718
880
|
}
|
|
719
881
|
}
|
|
720
|
-
sig = nextSig;
|
|
721
882
|
}
|
|
722
883
|
}
|
|
723
884
|
function notifySubscribers(signal2) {
|
|
@@ -733,21 +894,22 @@ function notifySubscribers(signal2) {
|
|
|
733
894
|
return;
|
|
734
895
|
}
|
|
735
896
|
notifyDepth++;
|
|
897
|
+
drainEpoch++;
|
|
736
898
|
try {
|
|
737
899
|
if (first._c) {
|
|
738
900
|
propagateDirty(first);
|
|
901
|
+
} else if (tickRepeat(first)) {
|
|
902
|
+
cycleError(first);
|
|
739
903
|
} else {
|
|
740
904
|
safeInvoke(first);
|
|
741
905
|
}
|
|
742
|
-
|
|
743
|
-
while (i2 < pendingQueue.length) {
|
|
744
|
-
safeInvoke(pendingQueue[i2]);
|
|
745
|
-
i2++;
|
|
746
|
-
}
|
|
906
|
+
drainQueue();
|
|
747
907
|
} finally {
|
|
748
|
-
pendingQueue.length = 0;
|
|
749
|
-
pendingSet.clear();
|
|
750
908
|
notifyDepth--;
|
|
909
|
+
if (notifyDepth === 0) {
|
|
910
|
+
pendingQueue.length = 0;
|
|
911
|
+
pendingSet.clear();
|
|
912
|
+
}
|
|
751
913
|
}
|
|
752
914
|
return;
|
|
753
915
|
}
|
|
@@ -765,68 +927,50 @@ function notifySubscribers(signal2) {
|
|
|
765
927
|
return;
|
|
766
928
|
}
|
|
767
929
|
notifyDepth++;
|
|
930
|
+
drainEpoch++;
|
|
768
931
|
try {
|
|
769
|
-
let directCount = 0;
|
|
770
932
|
for (const sub2 of subs) {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
for (let i3 = 0; i3 < directCount; i3++) {
|
|
779
|
-
if (!pendingQueue[i3]._c) {
|
|
780
|
-
if (!pendingSet.has(pendingQueue[i3])) {
|
|
781
|
-
safeInvoke(pendingQueue[i3]);
|
|
782
|
-
}
|
|
933
|
+
if (sub2._c) {
|
|
934
|
+
propagateDirty(sub2);
|
|
935
|
+
} else if (!pendingSet.has(sub2)) {
|
|
936
|
+
pendingSet.add(sub2);
|
|
937
|
+
pendingQueue.push(sub2);
|
|
783
938
|
}
|
|
784
939
|
}
|
|
785
|
-
|
|
786
|
-
while (i2 < pendingQueue.length) {
|
|
787
|
-
safeInvoke(pendingQueue[i2]);
|
|
788
|
-
i2++;
|
|
789
|
-
}
|
|
940
|
+
drainQueue();
|
|
790
941
|
} finally {
|
|
791
|
-
pendingQueue.length = 0;
|
|
792
|
-
pendingSet.clear();
|
|
793
942
|
notifyDepth--;
|
|
943
|
+
if (notifyDepth === 0) {
|
|
944
|
+
pendingQueue.length = 0;
|
|
945
|
+
pendingSet.clear();
|
|
946
|
+
}
|
|
794
947
|
}
|
|
795
948
|
}
|
|
796
949
|
function cleanup(subscriber) {
|
|
797
950
|
const sub2 = subscriber;
|
|
798
951
|
const singleDep = sub2._dep;
|
|
799
952
|
if (singleDep !== void 0) {
|
|
800
|
-
const
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
singleDep.__f = void 0;
|
|
805
|
-
}
|
|
953
|
+
const sig = singleDep;
|
|
954
|
+
const subs = sig[SUBS];
|
|
955
|
+
if (subs?.delete(subscriber)) {
|
|
956
|
+
syncFastPath(sig, subs);
|
|
806
957
|
}
|
|
807
958
|
sub2._dep = void 0;
|
|
959
|
+
sub2._depEpoch = void 0;
|
|
808
960
|
return;
|
|
809
961
|
}
|
|
810
962
|
const deps = sub2._deps;
|
|
811
963
|
if (!deps || deps.size === 0) return;
|
|
812
|
-
for (const signal2 of deps) {
|
|
813
|
-
const
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
signal2.__f = void 0;
|
|
818
|
-
}
|
|
964
|
+
for (const signal2 of deps.keys()) {
|
|
965
|
+
const sig = signal2;
|
|
966
|
+
const subs = sig[SUBS];
|
|
967
|
+
if (subs?.delete(subscriber)) {
|
|
968
|
+
syncFastPath(sig, subs);
|
|
819
969
|
}
|
|
820
970
|
}
|
|
821
971
|
deps.clear();
|
|
822
972
|
}
|
|
823
973
|
|
|
824
|
-
// src/core/ssr-context.ts
|
|
825
|
-
var ssrMode = false;
|
|
826
|
-
function isSSR() {
|
|
827
|
-
return ssrMode;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
974
|
// src/core/signals/effect.ts
|
|
831
975
|
var _g = globalThis;
|
|
832
976
|
function effect(effectFn, options) {
|
|
@@ -834,26 +978,114 @@ function effect(effectFn, options) {
|
|
|
834
978
|
if (isSSR()) return () => {
|
|
835
979
|
};
|
|
836
980
|
const onError = options?.onError;
|
|
981
|
+
let userCleanups = [];
|
|
982
|
+
const onCleanup = (fn) => {
|
|
983
|
+
userCleanups.push(fn);
|
|
984
|
+
};
|
|
985
|
+
const runUserCleanups = () => {
|
|
986
|
+
if (userCleanups.length === 0) return;
|
|
987
|
+
const list = userCleanups;
|
|
988
|
+
userCleanups = [];
|
|
989
|
+
for (let i2 = list.length - 1; i2 >= 0; i2--) {
|
|
990
|
+
try {
|
|
991
|
+
list[i2]();
|
|
992
|
+
} catch (err) {
|
|
993
|
+
if (typeof console !== "undefined") {
|
|
994
|
+
console.warn("[SibuJS effect] onCleanup threw:", err);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
const invokeBody = () => effectFn(onCleanup);
|
|
837
1000
|
const wrappedFn = onError ? () => {
|
|
838
1001
|
try {
|
|
839
|
-
|
|
1002
|
+
invokeBody();
|
|
840
1003
|
} catch (err) {
|
|
841
1004
|
onError(err);
|
|
842
1005
|
}
|
|
843
|
-
} :
|
|
1006
|
+
} : invokeBody;
|
|
844
1007
|
let cleanupHandle = () => {
|
|
845
1008
|
};
|
|
1009
|
+
let running = false;
|
|
1010
|
+
let rerunPending = false;
|
|
1011
|
+
const MAX_RERUNS = 100;
|
|
846
1012
|
const subscriber = () => {
|
|
847
|
-
|
|
848
|
-
|
|
1013
|
+
if (running) {
|
|
1014
|
+
rerunPending = true;
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
running = true;
|
|
1018
|
+
try {
|
|
1019
|
+
let reruns = 0;
|
|
1020
|
+
do {
|
|
1021
|
+
rerunPending = false;
|
|
1022
|
+
runUserCleanups();
|
|
1023
|
+
cleanupHandle();
|
|
1024
|
+
cleanupHandle = track(wrappedFn, subscriber);
|
|
1025
|
+
if (++reruns > MAX_RERUNS) {
|
|
1026
|
+
if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
|
|
1027
|
+
console.error(
|
|
1028
|
+
`[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
rerunPending = false;
|
|
1032
|
+
break;
|
|
1033
|
+
}
|
|
1034
|
+
} while (rerunPending);
|
|
1035
|
+
} finally {
|
|
1036
|
+
running = false;
|
|
1037
|
+
rerunPending = false;
|
|
1038
|
+
}
|
|
849
1039
|
};
|
|
850
|
-
|
|
1040
|
+
running = true;
|
|
1041
|
+
try {
|
|
1042
|
+
let reruns = 0;
|
|
1043
|
+
do {
|
|
1044
|
+
rerunPending = false;
|
|
1045
|
+
runUserCleanups();
|
|
1046
|
+
cleanupHandle();
|
|
1047
|
+
cleanupHandle = track(wrappedFn, subscriber);
|
|
1048
|
+
if (++reruns > MAX_RERUNS) {
|
|
1049
|
+
if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
|
|
1050
|
+
console.error(
|
|
1051
|
+
`[SibuJS] effect re-requested itself ${MAX_RERUNS}+ times on initial run \u2014 likely a write-reads-self cycle. Breaking to prevent infinite loop.`
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
rerunPending = false;
|
|
1055
|
+
break;
|
|
1056
|
+
}
|
|
1057
|
+
} while (rerunPending);
|
|
1058
|
+
} finally {
|
|
1059
|
+
running = false;
|
|
1060
|
+
rerunPending = false;
|
|
1061
|
+
}
|
|
851
1062
|
const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
852
1063
|
if (hook) hook.emit("effect:create", { effectFn });
|
|
1064
|
+
let disposed = false;
|
|
853
1065
|
return () => {
|
|
1066
|
+
if (disposed) return;
|
|
1067
|
+
disposed = true;
|
|
854
1068
|
const h = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
855
|
-
if (h)
|
|
856
|
-
|
|
1069
|
+
if (h) {
|
|
1070
|
+
try {
|
|
1071
|
+
h.emit("effect:destroy", { effectFn });
|
|
1072
|
+
} catch {
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
try {
|
|
1076
|
+
runUserCleanups();
|
|
1077
|
+
} catch (err) {
|
|
1078
|
+
if (typeof console !== "undefined") {
|
|
1079
|
+
console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
try {
|
|
1083
|
+
cleanupHandle();
|
|
1084
|
+
} catch (err) {
|
|
1085
|
+
if (typeof console !== "undefined") {
|
|
1086
|
+
console.warn("[SibuJS effect] dispose threw:", err);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
857
1089
|
};
|
|
858
1090
|
}
|
|
859
1091
|
|
|
@@ -1025,10 +1257,13 @@ function enqueueBatchedSignal(signal2) {
|
|
|
1025
1257
|
return true;
|
|
1026
1258
|
}
|
|
1027
1259
|
function flushBatch() {
|
|
1028
|
-
|
|
1029
|
-
|
|
1260
|
+
try {
|
|
1261
|
+
for (const signal2 of pendingSignals) {
|
|
1262
|
+
queueSignalNotification(signal2);
|
|
1263
|
+
}
|
|
1264
|
+
} finally {
|
|
1265
|
+
pendingSignals.clear();
|
|
1030
1266
|
}
|
|
1031
|
-
pendingSignals.clear();
|
|
1032
1267
|
drainNotificationQueue();
|
|
1033
1268
|
}
|
|
1034
1269
|
|
|
@@ -1075,24 +1310,42 @@ function createISR(options) {
|
|
|
1075
1310
|
const { revalidateAfter, fetcher, initialData } = options;
|
|
1076
1311
|
const [data2, setData] = signal(initialData);
|
|
1077
1312
|
const [timestamp, setTimestamp] = signal(initialData !== void 0 ? Date.now() : 0);
|
|
1313
|
+
const controller = new AbortController();
|
|
1314
|
+
let inFlight = false;
|
|
1315
|
+
let disposed = false;
|
|
1078
1316
|
const isStale = () => {
|
|
1079
1317
|
const ts = timestamp();
|
|
1080
1318
|
if (ts === 0) return true;
|
|
1081
1319
|
return Date.now() - ts >= revalidateAfter;
|
|
1082
1320
|
};
|
|
1083
1321
|
const revalidate = async () => {
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1322
|
+
if (disposed || inFlight) return;
|
|
1323
|
+
if (controller.signal.aborted) return;
|
|
1324
|
+
inFlight = true;
|
|
1325
|
+
try {
|
|
1326
|
+
const result = await fetcher({ signal: controller.signal });
|
|
1327
|
+
if (disposed || controller.signal.aborted) return;
|
|
1328
|
+
setData(result);
|
|
1329
|
+
setTimestamp(Date.now());
|
|
1330
|
+
} finally {
|
|
1331
|
+
inFlight = false;
|
|
1332
|
+
}
|
|
1087
1333
|
};
|
|
1088
1334
|
if (initialData === void 0) {
|
|
1089
|
-
revalidate()
|
|
1335
|
+
revalidate().catch((err) => {
|
|
1336
|
+
if (typeof console !== "undefined") console.warn("[SibuJS ISR] initial fetch failed", err);
|
|
1337
|
+
});
|
|
1090
1338
|
}
|
|
1091
1339
|
const intervalId = setInterval(() => {
|
|
1092
|
-
revalidate()
|
|
1340
|
+
revalidate().catch((err) => {
|
|
1341
|
+
if (typeof console !== "undefined") console.warn("[SibuJS ISR] revalidate failed", err);
|
|
1342
|
+
});
|
|
1093
1343
|
}, revalidateAfter);
|
|
1094
1344
|
const dispose = () => {
|
|
1345
|
+
if (disposed) return;
|
|
1346
|
+
disposed = true;
|
|
1095
1347
|
clearInterval(intervalId);
|
|
1348
|
+
controller.abort();
|
|
1096
1349
|
};
|
|
1097
1350
|
return { data: data2, isStale, revalidate, dispose };
|
|
1098
1351
|
}
|
|
@@ -1200,6 +1453,9 @@ function createMiddlewareChain() {
|
|
|
1200
1453
|
|
|
1201
1454
|
// src/reactivity/bindAttribute.ts
|
|
1202
1455
|
var _isDev5 = isDev();
|
|
1456
|
+
function setProp(el, key, val) {
|
|
1457
|
+
el[key] = val;
|
|
1458
|
+
}
|
|
1203
1459
|
function isEventHandlerAttr3(name) {
|
|
1204
1460
|
if (name.length < 3) return false;
|
|
1205
1461
|
const lower = name.toLowerCase();
|
|
@@ -1225,7 +1481,7 @@ function bindAttribute(el, attr, getter) {
|
|
|
1225
1481
|
}
|
|
1226
1482
|
if (typeof value === "boolean") {
|
|
1227
1483
|
if (attr in el && (attr === "checked" || attr === "disabled" || attr === "selected")) {
|
|
1228
|
-
el
|
|
1484
|
+
setProp(el, attr, value);
|
|
1229
1485
|
} else if (value) {
|
|
1230
1486
|
el.setAttribute(attr, "");
|
|
1231
1487
|
} else {
|
|
@@ -1235,7 +1491,7 @@ function bindAttribute(el, attr, getter) {
|
|
|
1235
1491
|
}
|
|
1236
1492
|
const str = String(value);
|
|
1237
1493
|
if ((attr === "value" || attr === "checked") && attr in el) {
|
|
1238
|
-
el
|
|
1494
|
+
setProp(el, attr, attr === "checked" ? Boolean(value) : str);
|
|
1239
1495
|
} else {
|
|
1240
1496
|
el.setAttribute(attr, isUrlAttribute(attr) ? sanitizeUrl(str) : str);
|
|
1241
1497
|
}
|
|
@@ -1272,24 +1528,29 @@ function bindChildNode(placeholder, getter) {
|
|
|
1272
1528
|
let newNodes;
|
|
1273
1529
|
if (Array.isArray(result)) {
|
|
1274
1530
|
newNodes = [];
|
|
1531
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1275
1532
|
for (let i2 = 0; i2 < result.length; i2++) {
|
|
1276
1533
|
const item = result[i2];
|
|
1277
1534
|
if (item == null || typeof item === "boolean") continue;
|
|
1278
|
-
|
|
1535
|
+
const node = item instanceof Node ? item : document.createTextNode(String(item));
|
|
1536
|
+
if (seen.has(node)) {
|
|
1537
|
+
if (_isDev6)
|
|
1538
|
+
devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
|
|
1539
|
+
continue;
|
|
1540
|
+
}
|
|
1541
|
+
seen.add(node);
|
|
1542
|
+
newNodes.push(node);
|
|
1279
1543
|
}
|
|
1280
1544
|
} else {
|
|
1281
1545
|
const node = result instanceof Node ? result : document.createTextNode(String(result));
|
|
1282
1546
|
newNodes = [node];
|
|
1283
1547
|
}
|
|
1284
|
-
|
|
1285
|
-
if (
|
|
1548
|
+
let reused;
|
|
1549
|
+
if (lastNodes.length > 0 && newNodes.length > 0) {
|
|
1550
|
+
const lastSet = new Set(lastNodes);
|
|
1551
|
+
reused = /* @__PURE__ */ new Set();
|
|
1286
1552
|
for (let i2 = 0; i2 < newNodes.length; i2++) {
|
|
1287
|
-
|
|
1288
|
-
if (newNodes[i2] === lastNodes[j]) {
|
|
1289
|
-
reused.add(newNodes[i2]);
|
|
1290
|
-
break;
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1553
|
+
if (lastSet.has(newNodes[i2])) reused.add(newNodes[i2]);
|
|
1293
1554
|
}
|
|
1294
1555
|
}
|
|
1295
1556
|
for (let i2 = 0; i2 < lastNodes.length; i2++) {
|
|
@@ -1329,6 +1590,30 @@ function registerDisposer(node, teardown) {
|
|
|
1329
1590
|
|
|
1330
1591
|
// src/core/rendering/tagFactory.ts
|
|
1331
1592
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1593
|
+
var _isDev8 = isDev();
|
|
1594
|
+
var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
1595
|
+
function validateTagName(tag) {
|
|
1596
|
+
const lower = tag.toLowerCase();
|
|
1597
|
+
if (BLOCKED_TAGS.has(lower)) {
|
|
1598
|
+
throw new Error(`tagFactory: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
|
|
1602
|
+
"config",
|
|
1603
|
+
"location",
|
|
1604
|
+
"history",
|
|
1605
|
+
"document",
|
|
1606
|
+
"window",
|
|
1607
|
+
"navigator",
|
|
1608
|
+
"name",
|
|
1609
|
+
"top",
|
|
1610
|
+
"parent",
|
|
1611
|
+
"self",
|
|
1612
|
+
"frames"
|
|
1613
|
+
]);
|
|
1614
|
+
function setProp2(el, key, val) {
|
|
1615
|
+
el[key] = val;
|
|
1616
|
+
}
|
|
1332
1617
|
var kebabCache = /* @__PURE__ */ new Map();
|
|
1333
1618
|
function toKebab(prop) {
|
|
1334
1619
|
let cached = kebabCache.get(prop);
|
|
@@ -1453,79 +1738,103 @@ function appendChildren(el, nodes) {
|
|
|
1453
1738
|
}
|
|
1454
1739
|
}
|
|
1455
1740
|
}
|
|
1456
|
-
var tagFactory = (tag, ns) =>
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
if (
|
|
1461
|
-
|
|
1462
|
-
|
|
1741
|
+
var tagFactory = (tag, ns) => {
|
|
1742
|
+
return (first, second) => {
|
|
1743
|
+
validateTagName(tag);
|
|
1744
|
+
const el = ns ? document.createElementNS(ns, tag) : document.createElement(tag);
|
|
1745
|
+
if (first === void 0) return el;
|
|
1746
|
+
if (typeof first === "string") {
|
|
1747
|
+
if (second !== void 0) {
|
|
1748
|
+
el.setAttribute("class", first);
|
|
1749
|
+
appendChildren(el, second);
|
|
1750
|
+
return el;
|
|
1751
|
+
}
|
|
1752
|
+
el.textContent = first;
|
|
1463
1753
|
return el;
|
|
1464
1754
|
}
|
|
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
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1755
|
+
if (typeof first === "number") {
|
|
1756
|
+
el.textContent = String(first);
|
|
1757
|
+
return el;
|
|
1758
|
+
}
|
|
1759
|
+
if (Array.isArray(first) || first instanceof Node || typeof first === "function") {
|
|
1760
|
+
appendChildren(el, first);
|
|
1761
|
+
return el;
|
|
1762
|
+
}
|
|
1763
|
+
const props = first;
|
|
1764
|
+
const pClass = props.class;
|
|
1765
|
+
if (pClass != null) applyClass(el, pClass);
|
|
1766
|
+
const pId = props.id;
|
|
1767
|
+
if (pId != null) {
|
|
1768
|
+
if (_isDev8 && typeof pId === "string" && CLOBBER_RISKY_IDS.has(pId.toLowerCase())) {
|
|
1769
|
+
devWarn(
|
|
1770
|
+
`tagFactory: element id="${pId}" matches a common global and may cause DOM clobbering. Avoid setting ids from untrusted input.`
|
|
1771
|
+
);
|
|
1772
|
+
}
|
|
1773
|
+
el.id = pId;
|
|
1774
|
+
}
|
|
1775
|
+
const pNodes = second !== void 0 ? second : props.nodes;
|
|
1776
|
+
if (pNodes != null) appendChildren(el, pNodes);
|
|
1777
|
+
const pOn = props.on;
|
|
1778
|
+
if (pOn) {
|
|
1779
|
+
for (const ev in pOn) {
|
|
1780
|
+
const handler = pOn[ev];
|
|
1781
|
+
if (typeof handler === "function") {
|
|
1782
|
+
el.addEventListener(ev, handler);
|
|
1783
|
+
} else if (_isDev8) {
|
|
1784
|
+
devWarn(
|
|
1785
|
+
`tagFactory: on.${ev} handler is not a function (got ${typeof handler}). Event listener was not attached.`
|
|
1786
|
+
);
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
const pStyle = props.style;
|
|
1791
|
+
if (pStyle != null) applyStyle(el, pStyle);
|
|
1792
|
+
const pRef = props.ref;
|
|
1793
|
+
if (pRef) pRef.current = el;
|
|
1794
|
+
for (const key in props) {
|
|
1795
|
+
switch (key) {
|
|
1796
|
+
case "class":
|
|
1797
|
+
case "id":
|
|
1798
|
+
case "nodes":
|
|
1799
|
+
case "on":
|
|
1800
|
+
case "style":
|
|
1801
|
+
case "ref":
|
|
1802
|
+
case "onElement":
|
|
1803
|
+
continue;
|
|
1804
|
+
// already handled above / below
|
|
1805
|
+
default: {
|
|
1806
|
+
const value = props[key];
|
|
1807
|
+
if (value == null) continue;
|
|
1808
|
+
const lkey = key.toLowerCase();
|
|
1809
|
+
if (lkey[0] === "o" && lkey[1] === "n") continue;
|
|
1810
|
+
if (typeof value === "function") {
|
|
1811
|
+
registerDisposer(el, bindAttribute(el, key, value));
|
|
1812
|
+
} else if (typeof value === "boolean") {
|
|
1813
|
+
if (key in el && (key === "checked" || key === "disabled" || key === "selected")) {
|
|
1814
|
+
setProp2(el, key, value);
|
|
1815
|
+
} else if (value) {
|
|
1816
|
+
el.setAttribute(key, "");
|
|
1817
|
+
} else {
|
|
1818
|
+
el.removeAttribute(key);
|
|
1819
|
+
}
|
|
1515
1820
|
} else {
|
|
1516
|
-
|
|
1821
|
+
const str = String(value);
|
|
1822
|
+
if (lkey === "srcset") {
|
|
1823
|
+
el.setAttribute(key, sanitizeSrcset(str));
|
|
1824
|
+
} else if (isUrlAttribute(lkey)) {
|
|
1825
|
+
el.setAttribute(key, sanitizeUrl(str));
|
|
1826
|
+
} else {
|
|
1827
|
+
el.setAttribute(key, str);
|
|
1828
|
+
}
|
|
1517
1829
|
}
|
|
1518
|
-
} else {
|
|
1519
|
-
const str = String(value);
|
|
1520
|
-
el.setAttribute(key, isUrlAttribute(key) ? sanitizeUrl(str) : str);
|
|
1521
1830
|
}
|
|
1522
1831
|
}
|
|
1523
1832
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1833
|
+
if (props.onElement && typeof props.onElement === "function") {
|
|
1834
|
+
props.onElement(el);
|
|
1835
|
+
}
|
|
1836
|
+
return el;
|
|
1837
|
+
};
|
|
1529
1838
|
};
|
|
1530
1839
|
|
|
1531
1840
|
// src/core/rendering/html.ts
|
|
@@ -1679,31 +1988,38 @@ function createMicroApp(config) {
|
|
|
1679
1988
|
}
|
|
1680
1989
|
let mounted = false;
|
|
1681
1990
|
function mount(component) {
|
|
1682
|
-
|
|
1683
|
-
root.innerHTML = "";
|
|
1684
|
-
} else {
|
|
1685
|
-
while (root.firstChild) {
|
|
1686
|
-
root.removeChild(root.firstChild);
|
|
1687
|
-
}
|
|
1688
|
-
}
|
|
1991
|
+
root.replaceChildren();
|
|
1689
1992
|
const el = component();
|
|
1690
1993
|
root.appendChild(el);
|
|
1691
1994
|
mounted = true;
|
|
1692
1995
|
}
|
|
1693
1996
|
function unmount() {
|
|
1694
1997
|
if (!mounted) return;
|
|
1695
|
-
|
|
1696
|
-
root.innerHTML = "";
|
|
1697
|
-
} else {
|
|
1698
|
-
while (root.firstChild) {
|
|
1699
|
-
root.removeChild(root.firstChild);
|
|
1700
|
-
}
|
|
1701
|
-
}
|
|
1998
|
+
root.replaceChildren();
|
|
1702
1999
|
mounted = false;
|
|
1703
2000
|
}
|
|
1704
2001
|
return { mount, unmount, element: host };
|
|
1705
2002
|
}
|
|
1706
|
-
function loadRemoteModule(url) {
|
|
2003
|
+
function loadRemoteModule(url, optionsOrAllowedOrigins = []) {
|
|
2004
|
+
const opts = Array.isArray(optionsOrAllowedOrigins) ? { allowedOrigins: optionsOrAllowedOrigins } : optionsOrAllowedOrigins;
|
|
2005
|
+
const allowedOrigins = opts.allowedOrigins ?? [];
|
|
2006
|
+
if (allowedOrigins.length > 0) {
|
|
2007
|
+
let parsed;
|
|
2008
|
+
try {
|
|
2009
|
+
parsed = new URL(url, typeof location !== "undefined" ? location.href : void 0);
|
|
2010
|
+
} catch {
|
|
2011
|
+
return Promise.reject(new Error(`loadRemoteModule: invalid URL "${url}"`));
|
|
2012
|
+
}
|
|
2013
|
+
if (!allowedOrigins.includes(parsed.origin)) {
|
|
2014
|
+
return Promise.reject(new Error(`loadRemoteModule: origin "${parsed.origin}" is not in the allowlist`));
|
|
2015
|
+
}
|
|
2016
|
+
} else if (!opts.unsafelyAllowAnyOrigin) {
|
|
2017
|
+
return Promise.reject(
|
|
2018
|
+
new Error(
|
|
2019
|
+
`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).`
|
|
2020
|
+
)
|
|
2021
|
+
);
|
|
2022
|
+
}
|
|
1707
2023
|
const cached = moduleCache.get(url);
|
|
1708
2024
|
if (cached) return cached;
|
|
1709
2025
|
const promise = import(
|
|
@@ -1793,21 +2109,49 @@ function serviceWorker(scriptUrl, options) {
|
|
|
1793
2109
|
const [isReady, setIsReady] = signal(false);
|
|
1794
2110
|
const [isUpdateAvailable, setIsUpdateAvailable] = signal(false);
|
|
1795
2111
|
const [error, setError] = signal(null);
|
|
2112
|
+
let disposed = false;
|
|
2113
|
+
let updateFoundHandler = null;
|
|
2114
|
+
let stateChangeHandler = null;
|
|
2115
|
+
let trackedWorker = null;
|
|
2116
|
+
let trackedReg = null;
|
|
2117
|
+
function detachListeners() {
|
|
2118
|
+
if (trackedReg && updateFoundHandler) {
|
|
2119
|
+
trackedReg.removeEventListener("updatefound", updateFoundHandler);
|
|
2120
|
+
}
|
|
2121
|
+
if (trackedWorker && stateChangeHandler) {
|
|
2122
|
+
trackedWorker.removeEventListener("statechange", stateChangeHandler);
|
|
2123
|
+
}
|
|
2124
|
+
updateFoundHandler = null;
|
|
2125
|
+
stateChangeHandler = null;
|
|
2126
|
+
trackedWorker = null;
|
|
2127
|
+
trackedReg = null;
|
|
2128
|
+
}
|
|
1796
2129
|
if ("serviceWorker" in navigator) {
|
|
1797
2130
|
navigator.serviceWorker.register(scriptUrl, options).then((reg) => {
|
|
2131
|
+
if (disposed) return;
|
|
1798
2132
|
setRegistration(reg);
|
|
1799
2133
|
setIsReady(true);
|
|
1800
|
-
|
|
2134
|
+
trackedReg = reg;
|
|
2135
|
+
updateFoundHandler = () => {
|
|
2136
|
+
if (disposed) return;
|
|
1801
2137
|
const newWorker = reg.installing;
|
|
1802
2138
|
if (newWorker) {
|
|
1803
|
-
|
|
2139
|
+
if (trackedWorker && stateChangeHandler) {
|
|
2140
|
+
trackedWorker.removeEventListener("statechange", stateChangeHandler);
|
|
2141
|
+
}
|
|
2142
|
+
trackedWorker = newWorker;
|
|
2143
|
+
stateChangeHandler = () => {
|
|
2144
|
+
if (disposed) return;
|
|
1804
2145
|
if (newWorker.state === "installed" && navigator.serviceWorker.controller) {
|
|
1805
2146
|
setIsUpdateAvailable(true);
|
|
1806
2147
|
}
|
|
1807
|
-
}
|
|
2148
|
+
};
|
|
2149
|
+
newWorker.addEventListener("statechange", stateChangeHandler);
|
|
1808
2150
|
}
|
|
1809
|
-
}
|
|
2151
|
+
};
|
|
2152
|
+
reg.addEventListener("updatefound", updateFoundHandler);
|
|
1810
2153
|
}).catch((err) => {
|
|
2154
|
+
if (disposed) return;
|
|
1811
2155
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1812
2156
|
});
|
|
1813
2157
|
}
|
|
@@ -1818,6 +2162,8 @@ function serviceWorker(scriptUrl, options) {
|
|
|
1818
2162
|
}
|
|
1819
2163
|
}
|
|
1820
2164
|
async function unregister() {
|
|
2165
|
+
disposed = true;
|
|
2166
|
+
detachListeners();
|
|
1821
2167
|
const reg = registration();
|
|
1822
2168
|
if (reg) {
|
|
1823
2169
|
const result = await reg.unregister();
|
|
@@ -1838,24 +2184,37 @@ function worker(workerFn2) {
|
|
|
1838
2184
|
const [error, setError] = signal(null);
|
|
1839
2185
|
const [loading, setLoading] = signal(false);
|
|
1840
2186
|
let worker2 = null;
|
|
2187
|
+
let blobUrl = null;
|
|
2188
|
+
const revokeBlobUrl = () => {
|
|
2189
|
+
if (blobUrl) {
|
|
2190
|
+
URL.revokeObjectURL(blobUrl);
|
|
2191
|
+
blobUrl = null;
|
|
2192
|
+
}
|
|
2193
|
+
};
|
|
1841
2194
|
try {
|
|
1842
2195
|
if (typeof Worker === "undefined") {
|
|
1843
2196
|
throw new Error("Web Workers are not supported in this environment");
|
|
1844
2197
|
}
|
|
1845
2198
|
const fnBody = workerFn2.toString();
|
|
1846
2199
|
const blob = new Blob([`self.onmessage = ${fnBody};`], { type: "application/javascript" });
|
|
1847
|
-
|
|
1848
|
-
worker2 = new Worker(
|
|
1849
|
-
|
|
1850
|
-
|
|
2200
|
+
blobUrl = URL.createObjectURL(blob);
|
|
2201
|
+
worker2 = new Worker(blobUrl);
|
|
2202
|
+
worker2.addEventListener("message", (e) => {
|
|
2203
|
+
revokeBlobUrl();
|
|
1851
2204
|
setResult(e.data);
|
|
1852
2205
|
setLoading(false);
|
|
1853
|
-
};
|
|
1854
|
-
worker2.
|
|
2206
|
+
});
|
|
2207
|
+
worker2.addEventListener("error", (e) => {
|
|
2208
|
+
revokeBlobUrl();
|
|
1855
2209
|
setError(new Error(e.message || "Worker error"));
|
|
1856
2210
|
setLoading(false);
|
|
1857
|
-
|
|
2211
|
+
if (worker2) {
|
|
2212
|
+
worker2.terminate();
|
|
2213
|
+
worker2 = null;
|
|
2214
|
+
}
|
|
2215
|
+
});
|
|
1858
2216
|
} catch (err) {
|
|
2217
|
+
revokeBlobUrl();
|
|
1859
2218
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
1860
2219
|
}
|
|
1861
2220
|
function post(data2) {
|
|
@@ -1869,6 +2228,7 @@ function worker(workerFn2) {
|
|
|
1869
2228
|
if (!worker2) return;
|
|
1870
2229
|
worker2.terminate();
|
|
1871
2230
|
worker2 = null;
|
|
2231
|
+
revokeBlobUrl();
|
|
1872
2232
|
setLoading(false);
|
|
1873
2233
|
}
|
|
1874
2234
|
return { post, result, error, loading, terminate };
|
|
@@ -1876,6 +2236,14 @@ function worker(workerFn2) {
|
|
|
1876
2236
|
function workerFn(fn) {
|
|
1877
2237
|
const [loading, setLoading] = signal(false);
|
|
1878
2238
|
let worker2 = null;
|
|
2239
|
+
let blobUrl = null;
|
|
2240
|
+
const revokeBlobUrl = () => {
|
|
2241
|
+
if (blobUrl) {
|
|
2242
|
+
URL.revokeObjectURL(blobUrl);
|
|
2243
|
+
blobUrl = null;
|
|
2244
|
+
}
|
|
2245
|
+
};
|
|
2246
|
+
const queue = [];
|
|
1879
2247
|
try {
|
|
1880
2248
|
if (typeof Worker === "undefined") {
|
|
1881
2249
|
throw new Error("Web Workers are not supported in this environment");
|
|
@@ -1891,10 +2259,26 @@ function workerFn(fn) {
|
|
|
1891
2259
|
],
|
|
1892
2260
|
{ type: "application/javascript" }
|
|
1893
2261
|
);
|
|
1894
|
-
|
|
1895
|
-
worker2 = new Worker(
|
|
1896
|
-
|
|
2262
|
+
blobUrl = URL.createObjectURL(blob);
|
|
2263
|
+
worker2 = new Worker(blobUrl);
|
|
2264
|
+
worker2.addEventListener("message", (e) => {
|
|
2265
|
+
revokeBlobUrl();
|
|
2266
|
+
const head2 = queue.shift();
|
|
2267
|
+
if (queue.length === 0) setLoading(false);
|
|
2268
|
+
if (head2) head2.resolve(e.data);
|
|
2269
|
+
});
|
|
2270
|
+
worker2.addEventListener("error", (e) => {
|
|
2271
|
+
revokeBlobUrl();
|
|
2272
|
+
const err = new Error(e.message || "Worker error");
|
|
2273
|
+
while (queue.length > 0) queue.shift().reject(err);
|
|
2274
|
+
setLoading(false);
|
|
2275
|
+
if (worker2) {
|
|
2276
|
+
worker2.terminate();
|
|
2277
|
+
worker2 = null;
|
|
2278
|
+
}
|
|
2279
|
+
});
|
|
1897
2280
|
} catch {
|
|
2281
|
+
revokeBlobUrl();
|
|
1898
2282
|
}
|
|
1899
2283
|
function run(...args) {
|
|
1900
2284
|
return new Promise((resolve, reject) => {
|
|
@@ -1903,14 +2287,7 @@ function workerFn(fn) {
|
|
|
1903
2287
|
return;
|
|
1904
2288
|
}
|
|
1905
2289
|
setLoading(true);
|
|
1906
|
-
|
|
1907
|
-
setLoading(false);
|
|
1908
|
-
resolve(e.data);
|
|
1909
|
-
};
|
|
1910
|
-
worker2.onerror = (e) => {
|
|
1911
|
-
setLoading(false);
|
|
1912
|
-
reject(new Error(e.message || "Worker error"));
|
|
1913
|
-
};
|
|
2290
|
+
queue.push({ resolve, reject });
|
|
1914
2291
|
worker2.postMessage(args);
|
|
1915
2292
|
});
|
|
1916
2293
|
}
|
|
@@ -1918,6 +2295,9 @@ function workerFn(fn) {
|
|
|
1918
2295
|
if (!worker2) return;
|
|
1919
2296
|
worker2.terminate();
|
|
1920
2297
|
worker2 = null;
|
|
2298
|
+
const err = new Error("Worker terminated");
|
|
2299
|
+
while (queue.length > 0) queue.shift().reject(err);
|
|
2300
|
+
revokeBlobUrl();
|
|
1921
2301
|
setLoading(false);
|
|
1922
2302
|
}
|
|
1923
2303
|
return { run, loading, terminate };
|
|
@@ -1925,20 +2305,63 @@ function workerFn(fn) {
|
|
|
1925
2305
|
function createWorkerPool(workerFn2, poolSize) {
|
|
1926
2306
|
const size = poolSize || typeof navigator !== "undefined" && navigator.hardwareConcurrency || 4;
|
|
1927
2307
|
const workers = [];
|
|
2308
|
+
const queues = [];
|
|
2309
|
+
const inflight = [];
|
|
1928
2310
|
let currentIndex = 0;
|
|
1929
2311
|
let alive = true;
|
|
2312
|
+
let blobUrl = null;
|
|
2313
|
+
let firedOnce = false;
|
|
2314
|
+
const revokeBlobUrl = () => {
|
|
2315
|
+
if (blobUrl) {
|
|
2316
|
+
URL.revokeObjectURL(blobUrl);
|
|
2317
|
+
blobUrl = null;
|
|
2318
|
+
}
|
|
2319
|
+
};
|
|
2320
|
+
function dispatchNext(idx) {
|
|
2321
|
+
if (!alive || inflight[idx] || queues[idx].length === 0) return;
|
|
2322
|
+
const w = workers[idx];
|
|
2323
|
+
const slot2 = queues[idx].shift();
|
|
2324
|
+
const onMsg = (e) => {
|
|
2325
|
+
if (!firedOnce) {
|
|
2326
|
+
firedOnce = true;
|
|
2327
|
+
revokeBlobUrl();
|
|
2328
|
+
}
|
|
2329
|
+
w.removeEventListener("message", onMsg);
|
|
2330
|
+
w.removeEventListener("error", onErr);
|
|
2331
|
+
inflight[idx] = null;
|
|
2332
|
+
slot2.resolve(e.data);
|
|
2333
|
+
dispatchNext(idx);
|
|
2334
|
+
};
|
|
2335
|
+
const onErr = (e) => {
|
|
2336
|
+
if (!firedOnce) {
|
|
2337
|
+
firedOnce = true;
|
|
2338
|
+
revokeBlobUrl();
|
|
2339
|
+
}
|
|
2340
|
+
w.removeEventListener("message", onMsg);
|
|
2341
|
+
w.removeEventListener("error", onErr);
|
|
2342
|
+
inflight[idx] = null;
|
|
2343
|
+
slot2.reject(new Error(e.message || "Worker error"));
|
|
2344
|
+
dispatchNext(idx);
|
|
2345
|
+
};
|
|
2346
|
+
inflight[idx] = { ...slot2, onMsg, onErr };
|
|
2347
|
+
w.addEventListener("message", onMsg);
|
|
2348
|
+
w.addEventListener("error", onErr);
|
|
2349
|
+
w.postMessage(slot2.data);
|
|
2350
|
+
}
|
|
1930
2351
|
try {
|
|
1931
2352
|
if (typeof Worker === "undefined") {
|
|
1932
2353
|
throw new Error("Web Workers are not supported in this environment");
|
|
1933
2354
|
}
|
|
1934
2355
|
const fnBody = workerFn2.toString();
|
|
1935
2356
|
const blob = new Blob([`self.onmessage = ${fnBody};`], { type: "application/javascript" });
|
|
1936
|
-
|
|
2357
|
+
blobUrl = URL.createObjectURL(blob);
|
|
1937
2358
|
for (let i2 = 0; i2 < size; i2++) {
|
|
1938
|
-
workers.push(new Worker(
|
|
2359
|
+
workers.push(new Worker(blobUrl));
|
|
2360
|
+
queues.push([]);
|
|
2361
|
+
inflight.push(null);
|
|
1939
2362
|
}
|
|
1940
|
-
URL.revokeObjectURL(url);
|
|
1941
2363
|
} catch {
|
|
2364
|
+
revokeBlobUrl();
|
|
1942
2365
|
}
|
|
1943
2366
|
function execute(data2) {
|
|
1944
2367
|
return new Promise((resolve, reject) => {
|
|
@@ -1946,23 +2369,25 @@ function createWorkerPool(workerFn2, poolSize) {
|
|
|
1946
2369
|
reject(new Error("Worker pool is not available"));
|
|
1947
2370
|
return;
|
|
1948
2371
|
}
|
|
1949
|
-
const
|
|
2372
|
+
const idx = currentIndex % workers.length;
|
|
1950
2373
|
currentIndex++;
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
};
|
|
1954
|
-
worker2.onerror = (e) => {
|
|
1955
|
-
reject(new Error(e.message || "Worker error"));
|
|
1956
|
-
};
|
|
1957
|
-
worker2.postMessage(data2);
|
|
2374
|
+
queues[idx].push({ data: data2, resolve, reject });
|
|
2375
|
+
dispatchNext(idx);
|
|
1958
2376
|
});
|
|
1959
2377
|
}
|
|
1960
2378
|
function terminate() {
|
|
1961
2379
|
alive = false;
|
|
1962
|
-
for (const w of workers)
|
|
1963
|
-
|
|
2380
|
+
for (const w of workers) w.terminate();
|
|
2381
|
+
const err = new Error("Worker pool terminated");
|
|
2382
|
+
for (let i2 = 0; i2 < queues.length; i2++) {
|
|
2383
|
+
const inf = inflight[i2];
|
|
2384
|
+
if (inf) inf.reject(err);
|
|
2385
|
+
for (const s2 of queues[i2]) s2.reject(err);
|
|
2386
|
+
queues[i2] = [];
|
|
2387
|
+
inflight[i2] = null;
|
|
1964
2388
|
}
|
|
1965
2389
|
workers.length = 0;
|
|
2390
|
+
revokeBlobUrl();
|
|
1966
2391
|
}
|
|
1967
2392
|
return { execute, terminate };
|
|
1968
2393
|
}
|
|
@@ -1998,7 +2423,28 @@ function wasm(source2, config = {}) {
|
|
|
1998
2423
|
};
|
|
1999
2424
|
}
|
|
2000
2425
|
async function loadWasmModule(source2, imports, cacheKey) {
|
|
2001
|
-
const
|
|
2426
|
+
const isOptionsBag = !!(imports && ("allowedOrigins" in imports || "unsafelyAllowAnyOrigin" in imports));
|
|
2427
|
+
const opts = isOptionsBag ? imports : { imports, cacheKey };
|
|
2428
|
+
const wasmImports = opts.imports;
|
|
2429
|
+
const key = opts.cacheKey || (typeof source2 === "string" ? source2 : void 0);
|
|
2430
|
+
if (typeof source2 === "string") {
|
|
2431
|
+
const allowed = opts.allowedOrigins ?? [];
|
|
2432
|
+
if (allowed.length > 0) {
|
|
2433
|
+
let parsed;
|
|
2434
|
+
try {
|
|
2435
|
+
parsed = new URL(source2, typeof location !== "undefined" ? location.href : void 0);
|
|
2436
|
+
} catch {
|
|
2437
|
+
throw new Error(`loadWasmModule: invalid URL "${source2}"`);
|
|
2438
|
+
}
|
|
2439
|
+
if (!allowed.includes(parsed.origin)) {
|
|
2440
|
+
throw new Error(`loadWasmModule: origin "${parsed.origin}" is not in the allowlist`);
|
|
2441
|
+
}
|
|
2442
|
+
} else if (!opts.unsafelyAllowAnyOrigin) {
|
|
2443
|
+
throw new Error(
|
|
2444
|
+
`loadWasmModule: refused to fetch "${source2}" with no allowedOrigins. Pass { allowedOrigins: [...] } to restrict the origin, or { unsafelyAllowAnyOrigin: true } to opt in (CWE-829).`
|
|
2445
|
+
);
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2002
2448
|
if (key) {
|
|
2003
2449
|
const cachedInstance = instanceCache.get(key);
|
|
2004
2450
|
if (cachedInstance) {
|
|
@@ -2014,7 +2460,7 @@ async function loadWasmModule(source2, imports, cacheKey) {
|
|
|
2014
2460
|
if (typeof source2 === "string") {
|
|
2015
2461
|
if (typeof WebAssembly.instantiateStreaming === "function") {
|
|
2016
2462
|
const response2 = fetch(source2);
|
|
2017
|
-
const result = await WebAssembly.instantiateStreaming(response2,
|
|
2463
|
+
const result = await WebAssembly.instantiateStreaming(response2, wasmImports || {});
|
|
2018
2464
|
if (key) {
|
|
2019
2465
|
moduleCache2.set(key, result.module);
|
|
2020
2466
|
instanceCache.set(key, result.instance);
|
|
@@ -2031,12 +2477,28 @@ async function loadWasmModule(source2, imports, cacheKey) {
|
|
|
2031
2477
|
module2 = await WebAssembly.compile(bytes);
|
|
2032
2478
|
if (key) moduleCache2.set(key, module2);
|
|
2033
2479
|
}
|
|
2034
|
-
const instance = await WebAssembly.instantiate(module2,
|
|
2480
|
+
const instance = await WebAssembly.instantiate(module2, wasmImports || {});
|
|
2035
2481
|
if (key) instanceCache.set(key, instance);
|
|
2036
2482
|
return instance;
|
|
2037
2483
|
}
|
|
2038
|
-
async function preloadWasm(url) {
|
|
2484
|
+
async function preloadWasm(url, options = {}) {
|
|
2039
2485
|
if (moduleCache2.has(url)) return;
|
|
2486
|
+
const allowed = options.allowedOrigins ?? [];
|
|
2487
|
+
if (allowed.length > 0) {
|
|
2488
|
+
let parsed;
|
|
2489
|
+
try {
|
|
2490
|
+
parsed = new URL(url, typeof location !== "undefined" ? location.href : void 0);
|
|
2491
|
+
} catch {
|
|
2492
|
+
throw new Error(`preloadWasm: invalid URL "${url}"`);
|
|
2493
|
+
}
|
|
2494
|
+
if (!allowed.includes(parsed.origin)) {
|
|
2495
|
+
throw new Error(`preloadWasm: origin "${parsed.origin}" is not in the allowlist`);
|
|
2496
|
+
}
|
|
2497
|
+
} else if (!options.unsafelyAllowAnyOrigin) {
|
|
2498
|
+
throw new Error(
|
|
2499
|
+
`preloadWasm: refused to fetch "${url}" with no allowedOrigins. Pass { allowedOrigins: [...] } or { unsafelyAllowAnyOrigin: true } (CWE-829).`
|
|
2500
|
+
);
|
|
2501
|
+
}
|
|
2040
2502
|
let module2;
|
|
2041
2503
|
if (typeof WebAssembly.compileStreaming === "function") {
|
|
2042
2504
|
module2 = await WebAssembly.compileStreaming(fetch(url));
|