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/plugins.cjs
CHANGED
|
@@ -26,12 +26,12 @@ function isDev() {
|
|
|
26
26
|
}
|
|
27
27
|
function devAssert(condition, message) {
|
|
28
28
|
if (_isDev && !condition) {
|
|
29
|
-
throw new Error(`[
|
|
29
|
+
throw new Error(`[SibuJS] ${message}`);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
function devWarn(message) {
|
|
33
33
|
if (_isDev) {
|
|
34
|
-
console.warn(`[
|
|
34
|
+
console.warn(`[SibuJS] ${message}`);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
var _isDev;
|
|
@@ -47,14 +47,47 @@ function sanitizeUrl(url) {
|
|
|
47
47
|
const trimmed = url.replace(/[\x00-\x20\x7f-\x9f]+/g, "").trim();
|
|
48
48
|
if (!trimmed) return "";
|
|
49
49
|
const lower = trimmed.toLowerCase();
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
let schemeEnd = -1;
|
|
51
|
+
for (let i2 = 0; i2 < lower.length; i2++) {
|
|
52
|
+
const ch = lower.charCodeAt(i2);
|
|
53
|
+
if (ch === 58) {
|
|
54
|
+
schemeEnd = i2;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
if (ch === 47 || ch === 63 || ch === 35) break;
|
|
52
58
|
}
|
|
59
|
+
if (schemeEnd === -1) return trimmed;
|
|
60
|
+
const scheme = lower.slice(0, schemeEnd + 1);
|
|
61
|
+
if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return trimmed;
|
|
62
|
+
if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
|
|
53
63
|
return trimmed;
|
|
54
64
|
}
|
|
65
|
+
function sanitizeSrcset(value) {
|
|
66
|
+
const parts = value.split(",");
|
|
67
|
+
const out = [];
|
|
68
|
+
for (let i2 = 0; i2 < parts.length; i2++) {
|
|
69
|
+
const part = parts[i2].trim();
|
|
70
|
+
if (!part) continue;
|
|
71
|
+
const m = part.match(/^(\S+)(\s+.+)?$/);
|
|
72
|
+
if (!m) continue;
|
|
73
|
+
const safe = sanitizeUrl(m[1]);
|
|
74
|
+
if (!safe) continue;
|
|
75
|
+
out.push(m[2] ? `${safe}${m[2]}` : safe);
|
|
76
|
+
}
|
|
77
|
+
return out.join(", ");
|
|
78
|
+
}
|
|
55
79
|
function sanitizeCSSValue(value) {
|
|
56
|
-
const
|
|
57
|
-
|
|
80
|
+
const decoded = value.replace(/\\([0-9a-fA-F]{1,6})\s?/g, (_m, hex) => {
|
|
81
|
+
const code2 = Number.parseInt(hex, 16);
|
|
82
|
+
if (!Number.isFinite(code2) || code2 < 0 || code2 > 1114111) return "";
|
|
83
|
+
try {
|
|
84
|
+
return String.fromCodePoint(code2);
|
|
85
|
+
} catch {
|
|
86
|
+
return "";
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
const lower = decoded.toLowerCase().replace(/\s+/g, "");
|
|
90
|
+
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")) {
|
|
58
91
|
return "";
|
|
59
92
|
}
|
|
60
93
|
return value;
|
|
@@ -62,11 +95,56 @@ function sanitizeCSSValue(value) {
|
|
|
62
95
|
function isUrlAttribute(attr) {
|
|
63
96
|
return URL_ATTRIBUTES.has(attr);
|
|
64
97
|
}
|
|
65
|
-
var URL_ATTRIBUTES;
|
|
98
|
+
var SAFE_URL_PROTOCOLS, URL_ATTRIBUTES;
|
|
66
99
|
var init_sanitize = __esm({
|
|
67
100
|
"src/utils/sanitize.ts"() {
|
|
68
101
|
"use strict";
|
|
69
|
-
|
|
102
|
+
SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
|
|
103
|
+
URL_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
104
|
+
"href",
|
|
105
|
+
"xlink:href",
|
|
106
|
+
"src",
|
|
107
|
+
"action",
|
|
108
|
+
"formaction",
|
|
109
|
+
"formtarget",
|
|
110
|
+
"cite",
|
|
111
|
+
"poster",
|
|
112
|
+
"background",
|
|
113
|
+
"srcset",
|
|
114
|
+
"ping",
|
|
115
|
+
"data"
|
|
116
|
+
]);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// src/core/ssr-context.ts
|
|
121
|
+
function getSSRStore() {
|
|
122
|
+
if (als) {
|
|
123
|
+
const s2 = als.getStore();
|
|
124
|
+
if (s2) return s2;
|
|
125
|
+
}
|
|
126
|
+
return fallbackStore;
|
|
127
|
+
}
|
|
128
|
+
function isSSR() {
|
|
129
|
+
return getSSRStore().ssr;
|
|
130
|
+
}
|
|
131
|
+
var als, fallbackStore;
|
|
132
|
+
var init_ssr_context = __esm({
|
|
133
|
+
"src/core/ssr-context.ts"() {
|
|
134
|
+
"use strict";
|
|
135
|
+
als = null;
|
|
136
|
+
try {
|
|
137
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
138
|
+
const req = Function("return typeof require==='function'?require:null")();
|
|
139
|
+
if (req) {
|
|
140
|
+
const mod = req("node:async_hooks");
|
|
141
|
+
als = new mod.AsyncLocalStorage();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} catch {
|
|
145
|
+
als = null;
|
|
146
|
+
}
|
|
147
|
+
fallbackStore = { ssr: false, suspenseIdCounter: 0 };
|
|
70
148
|
}
|
|
71
149
|
});
|
|
72
150
|
|
|
@@ -100,7 +178,7 @@ function isEventHandlerAttr2(name) {
|
|
|
100
178
|
return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
|
|
101
179
|
}
|
|
102
180
|
function ssrErrorComment(err) {
|
|
103
|
-
if (
|
|
181
|
+
if (_isDev8) {
|
|
104
182
|
const msg = escapeHtml(err instanceof Error ? err.message : String(err));
|
|
105
183
|
return `<!--SSR error: ${safeCommentText(msg)}-->`;
|
|
106
184
|
}
|
|
@@ -130,10 +208,10 @@ function renderToString(element) {
|
|
|
130
208
|
}
|
|
131
209
|
const tag = element.tagName.toLowerCase();
|
|
132
210
|
if (tag === "script" || tag === "style") {
|
|
133
|
-
return
|
|
211
|
+
return _isDev8 ? `<!--ssr:${tag}-stripped-->` : "";
|
|
134
212
|
}
|
|
135
213
|
if (!/^[a-z][a-z0-9-]*$/i.test(tag)) {
|
|
136
|
-
return
|
|
214
|
+
return _isDev8 ? "<!--ssr:invalid-tag-->" : "";
|
|
137
215
|
}
|
|
138
216
|
let html2 = `<${tag}`;
|
|
139
217
|
for (const attr of Array.from(element.attributes)) {
|
|
@@ -174,9 +252,9 @@ function hydrate(component, container, options = {}) {
|
|
|
174
252
|
const first = mismatches[0];
|
|
175
253
|
if (options.onMismatch) {
|
|
176
254
|
options.onMismatch(first);
|
|
177
|
-
} else if (
|
|
255
|
+
} else if (_isDev8) {
|
|
178
256
|
console.warn(
|
|
179
|
-
`[
|
|
257
|
+
`[SibuJS hydration] ${first.message}
|
|
180
258
|
at ${first.path}
|
|
181
259
|
server: ${first.serverValue}
|
|
182
260
|
client: ${first.clientValue}`
|
|
@@ -184,17 +262,9 @@ function hydrate(component, container, options = {}) {
|
|
|
184
262
|
}
|
|
185
263
|
}
|
|
186
264
|
}
|
|
187
|
-
|
|
265
|
+
container.replaceChildren(clientTree);
|
|
188
266
|
container.setAttribute("data-sibu-hydrated", "true");
|
|
189
267
|
}
|
|
190
|
-
function hydrateNode(serverNode, clientNode) {
|
|
191
|
-
if (!serverNode) return;
|
|
192
|
-
const serverChildren = Array.from(serverNode.children);
|
|
193
|
-
const clientChildren = Array.from(clientNode.children);
|
|
194
|
-
for (let i2 = 0; i2 < Math.min(serverChildren.length, clientChildren.length); i2++) {
|
|
195
|
-
hydrateNode(serverChildren[i2], clientChildren[i2]);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
268
|
function collectMismatches(serverNode, clientNode, path2, out, max = 5) {
|
|
199
269
|
if (out.length >= max) return;
|
|
200
270
|
const nodePath = path2 || clientNode?.tagName?.toLowerCase() || "(root)";
|
|
@@ -372,11 +442,11 @@ async function* renderToStream(element) {
|
|
|
372
442
|
}
|
|
373
443
|
const tag = element.tagName.toLowerCase();
|
|
374
444
|
if (tag === "script" || tag === "style") {
|
|
375
|
-
if (
|
|
445
|
+
if (_isDev8) yield `<!--ssr:${tag}-stripped-->`;
|
|
376
446
|
return;
|
|
377
447
|
}
|
|
378
448
|
if (!/^[a-z][a-z0-9-]*$/i.test(tag)) {
|
|
379
|
-
if (
|
|
449
|
+
if (_isDev8) yield "<!--ssr:invalid-tag-->";
|
|
380
450
|
return;
|
|
381
451
|
}
|
|
382
452
|
let openTag = `<${tag}`;
|
|
@@ -424,12 +494,15 @@ function renderToReadableStream(element) {
|
|
|
424
494
|
controller.enqueue(value);
|
|
425
495
|
}
|
|
426
496
|
},
|
|
427
|
-
cancel() {
|
|
428
|
-
generator.return(void 0);
|
|
497
|
+
async cancel() {
|
|
498
|
+
await generator.return(void 0);
|
|
429
499
|
}
|
|
430
500
|
});
|
|
431
501
|
}
|
|
432
502
|
function island(id, component) {
|
|
503
|
+
if (!SAFE_ID.test(id)) {
|
|
504
|
+
throw new Error(`[SibuJS SSR] island: id must match [A-Za-z0-9_-]+ (got: ${JSON.stringify(id.slice(0, 32))})`);
|
|
505
|
+
}
|
|
433
506
|
const el = component();
|
|
434
507
|
el.setAttribute("data-sibu-island", id);
|
|
435
508
|
return el;
|
|
@@ -442,8 +515,9 @@ function hydrateIslands(container, islands) {
|
|
|
442
515
|
const factory = islands[id];
|
|
443
516
|
if (typeof factory !== "function") continue;
|
|
444
517
|
const clientTree = factory();
|
|
445
|
-
|
|
446
|
-
|
|
518
|
+
clientTree.setAttribute("data-sibu-island", id);
|
|
519
|
+
clientTree.setAttribute("data-sibu-hydrated", "true");
|
|
520
|
+
marker2.replaceWith(clientTree);
|
|
447
521
|
}
|
|
448
522
|
container.setAttribute("data-sibu-hydrated", "partial");
|
|
449
523
|
}
|
|
@@ -460,8 +534,9 @@ function hydrateProgressively(container, islands, options) {
|
|
|
460
534
|
for (const entry of entries) {
|
|
461
535
|
if (entry.isIntersecting) {
|
|
462
536
|
const clientTree = factory();
|
|
463
|
-
|
|
464
|
-
|
|
537
|
+
clientTree.setAttribute("data-sibu-island", id);
|
|
538
|
+
clientTree.setAttribute("data-sibu-hydrated", "true");
|
|
539
|
+
marker2.replaceWith(clientTree);
|
|
465
540
|
observer.disconnect();
|
|
466
541
|
break;
|
|
467
542
|
}
|
|
@@ -478,18 +553,36 @@ function hydrateProgressively(container, islands, options) {
|
|
|
478
553
|
};
|
|
479
554
|
}
|
|
480
555
|
function resetSSRState() {
|
|
481
|
-
suspenseIdCounter = 0;
|
|
556
|
+
getSSRStore().suspenseIdCounter = 0;
|
|
557
|
+
}
|
|
558
|
+
function noop() {
|
|
482
559
|
}
|
|
483
560
|
function ssrSuspense(props) {
|
|
484
|
-
const
|
|
561
|
+
const store = getSSRStore();
|
|
562
|
+
const id = `sibu-sus-${store.suspenseIdCounter++}`;
|
|
563
|
+
const timeoutMs = props.timeoutMs ?? 3e4;
|
|
485
564
|
const fallbackEl = props.fallback();
|
|
486
565
|
const wrapper = document.createElement("div");
|
|
487
566
|
wrapper.setAttribute("data-sibu-suspense-id", id);
|
|
488
567
|
wrapper.appendChild(fallbackEl);
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
568
|
+
const fallbackHtml = renderToString(fallbackEl);
|
|
569
|
+
let timer;
|
|
570
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
571
|
+
timer = setTimeout(() => reject(new Error(`[SibuJS SSR] ssrSuspense timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
572
|
+
});
|
|
573
|
+
const raced = Promise.race([props.content(), timeoutPromise]);
|
|
574
|
+
const promise = raced.then(
|
|
575
|
+
(resolvedEl) => {
|
|
576
|
+
if (timer) clearTimeout(timer);
|
|
577
|
+
return { id, html: renderToString(resolvedEl) };
|
|
578
|
+
},
|
|
579
|
+
(err) => {
|
|
580
|
+
if (timer) clearTimeout(timer);
|
|
581
|
+
if (_isDev8) console.warn("[SibuJS SSR] ssrSuspense rejected:", err);
|
|
582
|
+
return { id, html: fallbackHtml };
|
|
583
|
+
}
|
|
584
|
+
);
|
|
585
|
+
promise.catch(noop);
|
|
493
586
|
return { element: wrapper, promise };
|
|
494
587
|
}
|
|
495
588
|
function suspenseSwapScript(id, nonce) {
|
|
@@ -515,14 +608,26 @@ async function* renderToSuspenseStream(element, pendingBoundaries = [], options)
|
|
|
515
608
|
function escapeScriptJson(json) {
|
|
516
609
|
return json.replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
517
610
|
}
|
|
518
|
-
function serializeState(state, nonce) {
|
|
519
|
-
const
|
|
611
|
+
function serializeState(state, nonce, options) {
|
|
612
|
+
const rawJson = JSON.stringify(state);
|
|
613
|
+
const maxBytes = options?.maxBytes ?? DEFAULT_MAX_SSR_BYTES;
|
|
614
|
+
const byteLen = typeof TextEncoder !== "undefined" ? new TextEncoder().encode(rawJson).byteLength : Buffer.byteLength(rawJson, "utf8");
|
|
615
|
+
if (byteLen > maxBytes) {
|
|
616
|
+
throw new Error(`[SibuJS SSR] serializeState: payload (${byteLen} bytes) exceeds maxBytes (${maxBytes})`);
|
|
617
|
+
}
|
|
618
|
+
const json = escapeScriptJson(rawJson);
|
|
520
619
|
const nonceAttr = nonce ? ` nonce="${escapeAttr(nonce)}"` : "";
|
|
521
620
|
return `<script${nonceAttr}>window.${SSR_DATA_ATTR}=${json}</script>`;
|
|
522
621
|
}
|
|
523
622
|
function deserializeState(validate) {
|
|
524
623
|
if (typeof window === "undefined") return void 0;
|
|
525
|
-
|
|
624
|
+
if (_isDev8 && !validate) {
|
|
625
|
+
console.warn(
|
|
626
|
+
"[SibuJS SSR] deserializeState() called without a validate guard \u2014 tampered SSR payloads will not be detected."
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
const w = window;
|
|
630
|
+
const raw = w[SSR_DATA_ATTR];
|
|
526
631
|
if (raw === void 0) return void 0;
|
|
527
632
|
if (validate && !validate(raw)) return void 0;
|
|
528
633
|
return raw;
|
|
@@ -533,13 +638,14 @@ function escapeHtml(str) {
|
|
|
533
638
|
function escapeAttr(str) {
|
|
534
639
|
return str.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
535
640
|
}
|
|
536
|
-
var
|
|
641
|
+
var _isDev8, SAFE_ATTR_NAME, URL_ATTRS, VOID_ELEMENTS, SAFE_ID, SAFE_SUSPENSE_ID, SSR_DATA_ATTR, DEFAULT_MAX_SSR_BYTES;
|
|
537
642
|
var init_ssr = __esm({
|
|
538
643
|
"src/platform/ssr.ts"() {
|
|
539
644
|
"use strict";
|
|
540
645
|
init_dev();
|
|
646
|
+
init_ssr_context();
|
|
541
647
|
init_sanitize();
|
|
542
|
-
|
|
648
|
+
_isDev8 = isDev();
|
|
543
649
|
SAFE_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
|
|
544
650
|
URL_ATTRS = /* @__PURE__ */ new Set([
|
|
545
651
|
"href",
|
|
@@ -571,9 +677,10 @@ var init_ssr = __esm({
|
|
|
571
677
|
"track",
|
|
572
678
|
"wbr"
|
|
573
679
|
]);
|
|
574
|
-
|
|
680
|
+
SAFE_ID = /^[A-Za-z0-9_-]+$/;
|
|
575
681
|
SAFE_SUSPENSE_ID = /^[A-Za-z0-9_-]+$/;
|
|
576
682
|
SSR_DATA_ATTR = "__SIBU_SSR_DATA__";
|
|
683
|
+
DEFAULT_MAX_SSR_BYTES = 1024 * 1024;
|
|
577
684
|
}
|
|
578
685
|
});
|
|
579
686
|
|
|
@@ -588,6 +695,7 @@ __export(plugins_exports, {
|
|
|
588
695
|
Suspense: () => Suspense,
|
|
589
696
|
Trans: () => Trans,
|
|
590
697
|
VERSION: () => VERSION,
|
|
698
|
+
__removeRouterPagehideHandler: () => __removeRouterPagehideHandler,
|
|
591
699
|
addRoute: () => addRoute,
|
|
592
700
|
afterEach: () => afterEach,
|
|
593
701
|
back: () => back,
|
|
@@ -603,6 +711,7 @@ __export(plugins_exports, {
|
|
|
603
711
|
createMigrationRunner: () => createMigrationRunner,
|
|
604
712
|
createModuleRegistry: () => createModuleRegistry,
|
|
605
713
|
createPlugin: () => createPlugin,
|
|
714
|
+
createPluginRegistry: () => createPluginRegistry,
|
|
606
715
|
createRouter: () => createRouter,
|
|
607
716
|
createSSRCache: () => createSSRCache,
|
|
608
717
|
createSSRRouter: () => createSSRRouter,
|
|
@@ -645,6 +754,7 @@ __export(plugins_exports, {
|
|
|
645
754
|
routerState: () => routerState,
|
|
646
755
|
satisfies: () => satisfies,
|
|
647
756
|
serializeRouteState: () => serializeRouteState,
|
|
757
|
+
setDefaultPluginRegistry: () => setDefaultPluginRegistry,
|
|
648
758
|
setLocale: () => setLocale,
|
|
649
759
|
setRouteTransition: () => setRouteTransition,
|
|
650
760
|
setRoutes: () => setRoutes,
|
|
@@ -655,6 +765,9 @@ __export(plugins_exports, {
|
|
|
655
765
|
});
|
|
656
766
|
module.exports = __toCommonJS(plugins_exports);
|
|
657
767
|
|
|
768
|
+
// src/core/rendering/tagFactory.ts
|
|
769
|
+
init_dev();
|
|
770
|
+
|
|
658
771
|
// src/reactivity/bindAttribute.ts
|
|
659
772
|
init_dev();
|
|
660
773
|
init_sanitize();
|
|
@@ -666,11 +779,11 @@ var subscriberStack = new Array(32);
|
|
|
666
779
|
var stackCapacity = 32;
|
|
667
780
|
var stackTop = -1;
|
|
668
781
|
var currentSubscriber = null;
|
|
669
|
-
var signalSubscribers = /* @__PURE__ */ new WeakMap();
|
|
670
782
|
var SUBS = "__s";
|
|
671
783
|
var notifyDepth = 0;
|
|
672
784
|
var pendingQueue = [];
|
|
673
785
|
var pendingSet = /* @__PURE__ */ new Set();
|
|
786
|
+
var propagateStack = [];
|
|
674
787
|
function safeInvoke(sub2) {
|
|
675
788
|
try {
|
|
676
789
|
sub2();
|
|
@@ -716,7 +829,6 @@ function recordDependency(signal2) {
|
|
|
716
829
|
let subs = signal2[SUBS];
|
|
717
830
|
if (!subs) {
|
|
718
831
|
subs = /* @__PURE__ */ new Set();
|
|
719
|
-
signalSubscribers.set(signal2, subs);
|
|
720
832
|
signal2[SUBS] = subs;
|
|
721
833
|
}
|
|
722
834
|
subs.add(currentSubscriber);
|
|
@@ -726,42 +838,46 @@ function recordDependency(signal2) {
|
|
|
726
838
|
signal2.__f = void 0;
|
|
727
839
|
}
|
|
728
840
|
}
|
|
841
|
+
var maxDrainIterations = 1e5;
|
|
729
842
|
function propagateDirty(sub2) {
|
|
730
843
|
sub2();
|
|
731
|
-
|
|
732
|
-
|
|
844
|
+
const rootSig = sub2._sig;
|
|
845
|
+
if (!rootSig) return;
|
|
846
|
+
const stack = propagateStack;
|
|
847
|
+
const baseLen = stack.length;
|
|
848
|
+
stack.push(rootSig);
|
|
849
|
+
while (stack.length > baseLen) {
|
|
850
|
+
const sig = stack.pop();
|
|
733
851
|
const first = sig.__f;
|
|
734
852
|
if (first) {
|
|
735
853
|
if (first._c) {
|
|
736
854
|
const nSig = first._sig;
|
|
737
|
-
nSig._d
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
if (!pendingSet.has(first)) {
|
|
855
|
+
if (!nSig._d) {
|
|
856
|
+
nSig._d = true;
|
|
857
|
+
stack.push(nSig);
|
|
858
|
+
}
|
|
859
|
+
} else if (!pendingSet.has(first)) {
|
|
742
860
|
pendingSet.add(first);
|
|
743
861
|
pendingQueue.push(first);
|
|
744
862
|
}
|
|
745
|
-
|
|
863
|
+
continue;
|
|
746
864
|
}
|
|
747
865
|
const subs = sig[SUBS];
|
|
748
|
-
if (!subs)
|
|
749
|
-
let nextSig;
|
|
866
|
+
if (!subs) continue;
|
|
750
867
|
for (const s2 of subs) {
|
|
751
868
|
if (s2._c) {
|
|
752
|
-
s2();
|
|
753
869
|
const nSig = s2._sig;
|
|
754
|
-
if (nSig && !
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
870
|
+
if (nSig && !nSig._d) {
|
|
871
|
+
nSig._d = true;
|
|
872
|
+
stack.push(nSig);
|
|
873
|
+
} else if (!nSig) {
|
|
874
|
+
s2();
|
|
758
875
|
}
|
|
759
876
|
} else if (!pendingSet.has(s2)) {
|
|
760
877
|
pendingSet.add(s2);
|
|
761
878
|
pendingQueue.push(s2);
|
|
762
879
|
}
|
|
763
880
|
}
|
|
764
|
-
sig = nextSig;
|
|
765
881
|
}
|
|
766
882
|
}
|
|
767
883
|
function notifySubscribers(signal2) {
|
|
@@ -785,13 +901,23 @@ function notifySubscribers(signal2) {
|
|
|
785
901
|
}
|
|
786
902
|
let i2 = 0;
|
|
787
903
|
while (i2 < pendingQueue.length) {
|
|
904
|
+
if (i2 >= maxDrainIterations) {
|
|
905
|
+
if (typeof console !== "undefined") {
|
|
906
|
+
console.error(
|
|
907
|
+
`[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
break;
|
|
911
|
+
}
|
|
788
912
|
safeInvoke(pendingQueue[i2]);
|
|
789
913
|
i2++;
|
|
790
914
|
}
|
|
791
915
|
} finally {
|
|
792
|
-
pendingQueue.length = 0;
|
|
793
|
-
pendingSet.clear();
|
|
794
916
|
notifyDepth--;
|
|
917
|
+
if (notifyDepth === 0) {
|
|
918
|
+
pendingQueue.length = 0;
|
|
919
|
+
pendingSet.clear();
|
|
920
|
+
}
|
|
795
921
|
}
|
|
796
922
|
return;
|
|
797
923
|
}
|
|
@@ -811,30 +937,48 @@ function notifySubscribers(signal2) {
|
|
|
811
937
|
notifyDepth++;
|
|
812
938
|
try {
|
|
813
939
|
let directCount = 0;
|
|
940
|
+
let hasComputedSub = false;
|
|
814
941
|
for (const sub2 of subs) {
|
|
942
|
+
if (sub2._c) hasComputedSub = true;
|
|
815
943
|
pendingQueue[directCount++] = sub2;
|
|
816
944
|
}
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
945
|
+
if (!hasComputedSub) {
|
|
946
|
+
for (let i3 = 0; i3 < directCount; i3++) {
|
|
947
|
+
safeInvoke(pendingQueue[i3]);
|
|
820
948
|
}
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
949
|
+
} else {
|
|
950
|
+
for (let i3 = 0; i3 < directCount; i3++) {
|
|
951
|
+
if (pendingQueue[i3]._c) {
|
|
952
|
+
propagateDirty(pendingQueue[i3]);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
for (let i3 = 0; i3 < directCount; i3++) {
|
|
956
|
+
const sub2 = pendingQueue[i3];
|
|
957
|
+
if (!sub2._c && !pendingSet.has(sub2)) {
|
|
958
|
+
pendingSet.add(sub2);
|
|
959
|
+
safeInvoke(sub2);
|
|
826
960
|
}
|
|
827
961
|
}
|
|
828
962
|
}
|
|
829
963
|
let i2 = directCount;
|
|
830
964
|
while (i2 < pendingQueue.length) {
|
|
965
|
+
if (i2 - directCount >= maxDrainIterations) {
|
|
966
|
+
if (typeof console !== "undefined") {
|
|
967
|
+
console.error(
|
|
968
|
+
`[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
|
|
969
|
+
);
|
|
970
|
+
}
|
|
971
|
+
break;
|
|
972
|
+
}
|
|
831
973
|
safeInvoke(pendingQueue[i2]);
|
|
832
974
|
i2++;
|
|
833
975
|
}
|
|
834
976
|
} finally {
|
|
835
|
-
pendingQueue.length = 0;
|
|
836
|
-
pendingSet.clear();
|
|
837
977
|
notifyDepth--;
|
|
978
|
+
if (notifyDepth === 0) {
|
|
979
|
+
pendingQueue.length = 0;
|
|
980
|
+
pendingSet.clear();
|
|
981
|
+
}
|
|
838
982
|
}
|
|
839
983
|
}
|
|
840
984
|
function cleanup(subscriber) {
|
|
@@ -845,7 +989,9 @@ function cleanup(subscriber) {
|
|
|
845
989
|
if (subs) {
|
|
846
990
|
subs.delete(subscriber);
|
|
847
991
|
if (singleDep.__f === subscriber) {
|
|
848
|
-
singleDep.__f = void 0;
|
|
992
|
+
singleDep.__f = subs.size === 1 ? subs.values().next().value : void 0;
|
|
993
|
+
} else if (subs.size === 1 && singleDep.__f === void 0) {
|
|
994
|
+
singleDep.__f = subs.values().next().value;
|
|
849
995
|
}
|
|
850
996
|
}
|
|
851
997
|
sub2._dep = void 0;
|
|
@@ -858,7 +1004,9 @@ function cleanup(subscriber) {
|
|
|
858
1004
|
if (subs) {
|
|
859
1005
|
subs.delete(subscriber);
|
|
860
1006
|
if (signal2.__f === subscriber) {
|
|
861
|
-
signal2.__f = void 0;
|
|
1007
|
+
signal2.__f = subs.size === 1 ? subs.values().next().value : void 0;
|
|
1008
|
+
} else if (subs.size === 1 && signal2.__f === void 0) {
|
|
1009
|
+
signal2.__f = subs.values().next().value;
|
|
862
1010
|
}
|
|
863
1011
|
}
|
|
864
1012
|
}
|
|
@@ -867,6 +1015,9 @@ function cleanup(subscriber) {
|
|
|
867
1015
|
|
|
868
1016
|
// src/reactivity/bindAttribute.ts
|
|
869
1017
|
var _isDev3 = isDev();
|
|
1018
|
+
function setProp(el, key, val) {
|
|
1019
|
+
el[key] = val;
|
|
1020
|
+
}
|
|
870
1021
|
function isEventHandlerAttr(name) {
|
|
871
1022
|
if (name.length < 3) return false;
|
|
872
1023
|
const lower = name.toLowerCase();
|
|
@@ -892,7 +1043,7 @@ function bindAttribute(el, attr, getter) {
|
|
|
892
1043
|
}
|
|
893
1044
|
if (typeof value === "boolean") {
|
|
894
1045
|
if (attr in el && (attr === "checked" || attr === "disabled" || attr === "selected")) {
|
|
895
|
-
el
|
|
1046
|
+
setProp(el, attr, value);
|
|
896
1047
|
} else if (value) {
|
|
897
1048
|
el.setAttribute(attr, "");
|
|
898
1049
|
} else {
|
|
@@ -902,7 +1053,7 @@ function bindAttribute(el, attr, getter) {
|
|
|
902
1053
|
}
|
|
903
1054
|
const str = String(value);
|
|
904
1055
|
if ((attr === "value" || attr === "checked") && attr in el) {
|
|
905
|
-
el
|
|
1056
|
+
setProp(el, attr, attr === "checked" ? Boolean(value) : str);
|
|
906
1057
|
} else {
|
|
907
1058
|
el.setAttribute(attr, isUrlAttribute(attr) ? sanitizeUrl(str) : str);
|
|
908
1059
|
}
|
|
@@ -940,24 +1091,29 @@ function bindChildNode(placeholder, getter) {
|
|
|
940
1091
|
let newNodes;
|
|
941
1092
|
if (Array.isArray(result)) {
|
|
942
1093
|
newNodes = [];
|
|
1094
|
+
const seen = /* @__PURE__ */ new Set();
|
|
943
1095
|
for (let i2 = 0; i2 < result.length; i2++) {
|
|
944
1096
|
const item = result[i2];
|
|
945
1097
|
if (item == null || typeof item === "boolean") continue;
|
|
946
|
-
|
|
1098
|
+
const node = item instanceof Node ? item : document.createTextNode(String(item));
|
|
1099
|
+
if (seen.has(node)) {
|
|
1100
|
+
if (_isDev4)
|
|
1101
|
+
devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
|
|
1102
|
+
continue;
|
|
1103
|
+
}
|
|
1104
|
+
seen.add(node);
|
|
1105
|
+
newNodes.push(node);
|
|
947
1106
|
}
|
|
948
1107
|
} else {
|
|
949
1108
|
const node = result instanceof Node ? result : document.createTextNode(String(result));
|
|
950
1109
|
newNodes = [node];
|
|
951
1110
|
}
|
|
952
|
-
|
|
953
|
-
if (
|
|
1111
|
+
let reused;
|
|
1112
|
+
if (lastNodes.length > 0 && newNodes.length > 0) {
|
|
1113
|
+
const lastSet = new Set(lastNodes);
|
|
1114
|
+
reused = /* @__PURE__ */ new Set();
|
|
954
1115
|
for (let i2 = 0; i2 < newNodes.length; i2++) {
|
|
955
|
-
|
|
956
|
-
if (newNodes[i2] === lastNodes[j]) {
|
|
957
|
-
reused.add(newNodes[i2]);
|
|
958
|
-
break;
|
|
959
|
-
}
|
|
960
|
-
}
|
|
1116
|
+
if (lastSet.has(newNodes[i2])) reused.add(newNodes[i2]);
|
|
961
1117
|
}
|
|
962
1118
|
}
|
|
963
1119
|
for (let i2 = 0; i2 < lastNodes.length; i2++) {
|
|
@@ -1004,7 +1160,7 @@ function dispose(node) {
|
|
|
1004
1160
|
while (stack.length > 0) {
|
|
1005
1161
|
const current = stack.pop();
|
|
1006
1162
|
order.push(current);
|
|
1007
|
-
const children = current.childNodes;
|
|
1163
|
+
const children = Array.from(current.childNodes);
|
|
1008
1164
|
for (let i2 = 0; i2 < children.length; i2++) {
|
|
1009
1165
|
stack.push(children[i2]);
|
|
1010
1166
|
}
|
|
@@ -1013,15 +1169,65 @@ function dispose(node) {
|
|
|
1013
1169
|
const current = order[i2];
|
|
1014
1170
|
const disposers = elementDisposers.get(current);
|
|
1015
1171
|
if (disposers) {
|
|
1016
|
-
|
|
1017
|
-
for (const d of disposers) d();
|
|
1172
|
+
const snapshot = disposers.slice();
|
|
1018
1173
|
elementDisposers.delete(current);
|
|
1174
|
+
if (_isDev5) activeBindingCount -= snapshot.length;
|
|
1175
|
+
for (const d of snapshot) {
|
|
1176
|
+
try {
|
|
1177
|
+
d();
|
|
1178
|
+
} catch (err) {
|
|
1179
|
+
if (_isDev5 && typeof console !== "undefined") {
|
|
1180
|
+
console.warn("[SibuJS] Disposer threw during cleanup:", err);
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
let extraPasses = 0;
|
|
1185
|
+
while (extraPasses++ < 8) {
|
|
1186
|
+
const added = elementDisposers.get(current);
|
|
1187
|
+
if (!added || added.length === 0) break;
|
|
1188
|
+
const moreSnapshot = added.slice();
|
|
1189
|
+
elementDisposers.delete(current);
|
|
1190
|
+
if (_isDev5) activeBindingCount -= moreSnapshot.length;
|
|
1191
|
+
for (const d of moreSnapshot) {
|
|
1192
|
+
try {
|
|
1193
|
+
d();
|
|
1194
|
+
} catch (err) {
|
|
1195
|
+
if (_isDev5 && typeof console !== "undefined") {
|
|
1196
|
+
console.warn("[SibuJS] Disposer threw during cleanup:", err);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1019
1201
|
}
|
|
1020
1202
|
}
|
|
1021
1203
|
}
|
|
1022
1204
|
|
|
1023
1205
|
// src/core/rendering/tagFactory.ts
|
|
1024
1206
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1207
|
+
var _isDev6 = isDev();
|
|
1208
|
+
var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
1209
|
+
function validateTagName(tag) {
|
|
1210
|
+
const lower = tag.toLowerCase();
|
|
1211
|
+
if (BLOCKED_TAGS.has(lower)) {
|
|
1212
|
+
throw new Error(`tagFactory: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
|
|
1216
|
+
"config",
|
|
1217
|
+
"location",
|
|
1218
|
+
"history",
|
|
1219
|
+
"document",
|
|
1220
|
+
"window",
|
|
1221
|
+
"navigator",
|
|
1222
|
+
"name",
|
|
1223
|
+
"top",
|
|
1224
|
+
"parent",
|
|
1225
|
+
"self",
|
|
1226
|
+
"frames"
|
|
1227
|
+
]);
|
|
1228
|
+
function setProp2(el, key, val) {
|
|
1229
|
+
el[key] = val;
|
|
1230
|
+
}
|
|
1025
1231
|
var kebabCache = /* @__PURE__ */ new Map();
|
|
1026
1232
|
function toKebab(prop) {
|
|
1027
1233
|
let cached = kebabCache.get(prop);
|
|
@@ -1146,79 +1352,103 @@ function appendChildren(el, nodes) {
|
|
|
1146
1352
|
}
|
|
1147
1353
|
}
|
|
1148
1354
|
}
|
|
1149
|
-
var tagFactory = (tag, ns) =>
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
if (
|
|
1154
|
-
|
|
1155
|
-
|
|
1355
|
+
var tagFactory = (tag, ns) => {
|
|
1356
|
+
return (first, second) => {
|
|
1357
|
+
validateTagName(tag);
|
|
1358
|
+
const el = ns ? document.createElementNS(ns, tag) : document.createElement(tag);
|
|
1359
|
+
if (first === void 0) return el;
|
|
1360
|
+
if (typeof first === "string") {
|
|
1361
|
+
if (second !== void 0) {
|
|
1362
|
+
el.setAttribute("class", first);
|
|
1363
|
+
appendChildren(el, second);
|
|
1364
|
+
return el;
|
|
1365
|
+
}
|
|
1366
|
+
el.textContent = first;
|
|
1156
1367
|
return el;
|
|
1157
1368
|
}
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1369
|
+
if (typeof first === "number") {
|
|
1370
|
+
el.textContent = String(first);
|
|
1371
|
+
return el;
|
|
1372
|
+
}
|
|
1373
|
+
if (Array.isArray(first) || first instanceof Node || typeof first === "function") {
|
|
1374
|
+
appendChildren(el, first);
|
|
1375
|
+
return el;
|
|
1376
|
+
}
|
|
1377
|
+
const props = first;
|
|
1378
|
+
const pClass = props.class;
|
|
1379
|
+
if (pClass != null) applyClass(el, pClass);
|
|
1380
|
+
const pId = props.id;
|
|
1381
|
+
if (pId != null) {
|
|
1382
|
+
if (_isDev6 && typeof pId === "string" && CLOBBER_RISKY_IDS.has(pId.toLowerCase())) {
|
|
1383
|
+
devWarn(
|
|
1384
|
+
`tagFactory: element id="${pId}" matches a common global and may cause DOM clobbering. Avoid setting ids from untrusted input.`
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
el.id = pId;
|
|
1388
|
+
}
|
|
1389
|
+
const pNodes = second !== void 0 ? second : props.nodes;
|
|
1390
|
+
if (pNodes != null) appendChildren(el, pNodes);
|
|
1391
|
+
const pOn = props.on;
|
|
1392
|
+
if (pOn) {
|
|
1393
|
+
for (const ev in pOn) {
|
|
1394
|
+
const handler = pOn[ev];
|
|
1395
|
+
if (typeof handler === "function") {
|
|
1396
|
+
el.addEventListener(ev, handler);
|
|
1397
|
+
} else if (_isDev6) {
|
|
1398
|
+
devWarn(
|
|
1399
|
+
`tagFactory: on.${ev} handler is not a function (got ${typeof handler}). Event listener was not attached.`
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
const pStyle = props.style;
|
|
1405
|
+
if (pStyle != null) applyStyle(el, pStyle);
|
|
1406
|
+
const pRef = props.ref;
|
|
1407
|
+
if (pRef) pRef.current = el;
|
|
1408
|
+
for (const key in props) {
|
|
1409
|
+
switch (key) {
|
|
1410
|
+
case "class":
|
|
1411
|
+
case "id":
|
|
1412
|
+
case "nodes":
|
|
1413
|
+
case "on":
|
|
1414
|
+
case "style":
|
|
1415
|
+
case "ref":
|
|
1416
|
+
case "onElement":
|
|
1417
|
+
continue;
|
|
1418
|
+
// already handled above / below
|
|
1419
|
+
default: {
|
|
1420
|
+
const value = props[key];
|
|
1421
|
+
if (value == null) continue;
|
|
1422
|
+
const lkey = key.toLowerCase();
|
|
1423
|
+
if (lkey[0] === "o" && lkey[1] === "n") continue;
|
|
1424
|
+
if (typeof value === "function") {
|
|
1425
|
+
registerDisposer(el, bindAttribute(el, key, value));
|
|
1426
|
+
} else if (typeof value === "boolean") {
|
|
1427
|
+
if (key in el && (key === "checked" || key === "disabled" || key === "selected")) {
|
|
1428
|
+
setProp2(el, key, value);
|
|
1429
|
+
} else if (value) {
|
|
1430
|
+
el.setAttribute(key, "");
|
|
1431
|
+
} else {
|
|
1432
|
+
el.removeAttribute(key);
|
|
1433
|
+
}
|
|
1208
1434
|
} else {
|
|
1209
|
-
|
|
1435
|
+
const str = String(value);
|
|
1436
|
+
if (lkey === "srcset") {
|
|
1437
|
+
el.setAttribute(key, sanitizeSrcset(str));
|
|
1438
|
+
} else if (isUrlAttribute(lkey)) {
|
|
1439
|
+
el.setAttribute(key, sanitizeUrl(str));
|
|
1440
|
+
} else {
|
|
1441
|
+
el.setAttribute(key, str);
|
|
1442
|
+
}
|
|
1210
1443
|
}
|
|
1211
|
-
} else {
|
|
1212
|
-
const str = String(value);
|
|
1213
|
-
el.setAttribute(key, isUrlAttribute(key) ? sanitizeUrl(str) : str);
|
|
1214
1444
|
}
|
|
1215
1445
|
}
|
|
1216
1446
|
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1447
|
+
if (props.onElement && typeof props.onElement === "function") {
|
|
1448
|
+
props.onElement(el);
|
|
1449
|
+
}
|
|
1450
|
+
return el;
|
|
1451
|
+
};
|
|
1222
1452
|
};
|
|
1223
1453
|
|
|
1224
1454
|
// src/core/rendering/html.ts
|
|
@@ -1371,10 +1601,10 @@ function enqueueBatchedSignal(signal2) {
|
|
|
1371
1601
|
// src/core/signals/signal.ts
|
|
1372
1602
|
init_dev();
|
|
1373
1603
|
var _g = globalThis;
|
|
1374
|
-
var
|
|
1604
|
+
var _isDev7 = isDev();
|
|
1375
1605
|
function signal(initial, options) {
|
|
1376
1606
|
const state = { value: initial };
|
|
1377
|
-
const debugName =
|
|
1607
|
+
const debugName = _isDev7 ? options?.name : void 0;
|
|
1378
1608
|
const equalsFn = options?.equals;
|
|
1379
1609
|
if (debugName) {
|
|
1380
1610
|
state.__name = debugName;
|
|
@@ -1388,7 +1618,7 @@ function signal(initial, options) {
|
|
|
1388
1618
|
function set(next) {
|
|
1389
1619
|
const newValue = typeof next === "function" ? next(state.value) : next;
|
|
1390
1620
|
if (equalsFn ? equalsFn(state.value, newValue) : Object.is(newValue, state.value)) return;
|
|
1391
|
-
if (
|
|
1621
|
+
if (_isDev7) {
|
|
1392
1622
|
const oldValue = state.value;
|
|
1393
1623
|
state.value = newValue;
|
|
1394
1624
|
const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
@@ -1400,7 +1630,7 @@ function signal(initial, options) {
|
|
|
1400
1630
|
notifySubscribers(state);
|
|
1401
1631
|
}
|
|
1402
1632
|
}
|
|
1403
|
-
if (
|
|
1633
|
+
if (_isDev7) {
|
|
1404
1634
|
const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
1405
1635
|
if (hook) hook.emit("signal:create", { signal: state, name: debugName, getter: get, initial });
|
|
1406
1636
|
}
|
|
@@ -1425,9 +1655,7 @@ function t(key, params) {
|
|
|
1425
1655
|
return params ? message.replace(/\{(\w+)\}/g, (_, p2) => String(params[p2] ?? "")) : message;
|
|
1426
1656
|
}
|
|
1427
1657
|
function Trans(key, params) {
|
|
1428
|
-
return span(
|
|
1429
|
-
nodes: () => t(key, params)
|
|
1430
|
-
});
|
|
1658
|
+
return span(() => t(key, params));
|
|
1431
1659
|
}
|
|
1432
1660
|
function hasTranslation(key) {
|
|
1433
1661
|
const locale = currentLocale();
|
|
@@ -1439,40 +1667,93 @@ function getAvailableLocales() {
|
|
|
1439
1667
|
|
|
1440
1668
|
// src/core/signals/effect.ts
|
|
1441
1669
|
init_dev();
|
|
1442
|
-
|
|
1443
|
-
// src/core/ssr-context.ts
|
|
1444
|
-
var ssrMode = false;
|
|
1445
|
-
function isSSR() {
|
|
1446
|
-
return ssrMode;
|
|
1447
|
-
}
|
|
1448
|
-
|
|
1449
|
-
// src/core/signals/effect.ts
|
|
1670
|
+
init_ssr_context();
|
|
1450
1671
|
var _g2 = globalThis;
|
|
1451
1672
|
function effect(effectFn, options) {
|
|
1452
1673
|
devAssert(typeof effectFn === "function", "effect: argument must be a function.");
|
|
1453
1674
|
if (isSSR()) return () => {
|
|
1454
1675
|
};
|
|
1455
1676
|
const onError = options?.onError;
|
|
1677
|
+
let userCleanups = [];
|
|
1678
|
+
const onCleanup = (fn) => {
|
|
1679
|
+
userCleanups.push(fn);
|
|
1680
|
+
};
|
|
1681
|
+
const runUserCleanups = () => {
|
|
1682
|
+
if (userCleanups.length === 0) return;
|
|
1683
|
+
const list = userCleanups;
|
|
1684
|
+
userCleanups = [];
|
|
1685
|
+
for (let i2 = list.length - 1; i2 >= 0; i2--) {
|
|
1686
|
+
try {
|
|
1687
|
+
list[i2]();
|
|
1688
|
+
} catch (err) {
|
|
1689
|
+
if (typeof console !== "undefined") {
|
|
1690
|
+
console.warn("[SibuJS effect] onCleanup threw:", err);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
};
|
|
1695
|
+
const invokeBody = () => effectFn(onCleanup);
|
|
1456
1696
|
const wrappedFn = onError ? () => {
|
|
1457
1697
|
try {
|
|
1458
|
-
|
|
1698
|
+
invokeBody();
|
|
1459
1699
|
} catch (err) {
|
|
1460
1700
|
onError(err);
|
|
1461
1701
|
}
|
|
1462
|
-
} :
|
|
1702
|
+
} : invokeBody;
|
|
1463
1703
|
let cleanupHandle = () => {
|
|
1464
1704
|
};
|
|
1705
|
+
let running = false;
|
|
1465
1706
|
const subscriber = () => {
|
|
1466
|
-
|
|
1467
|
-
|
|
1707
|
+
if (running) {
|
|
1708
|
+
if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
|
|
1709
|
+
console.warn(
|
|
1710
|
+
"[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."
|
|
1711
|
+
);
|
|
1712
|
+
}
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
running = true;
|
|
1716
|
+
try {
|
|
1717
|
+
runUserCleanups();
|
|
1718
|
+
cleanupHandle();
|
|
1719
|
+
cleanupHandle = track(wrappedFn, subscriber);
|
|
1720
|
+
} finally {
|
|
1721
|
+
running = false;
|
|
1722
|
+
}
|
|
1468
1723
|
};
|
|
1469
|
-
|
|
1724
|
+
running = true;
|
|
1725
|
+
try {
|
|
1726
|
+
cleanupHandle = track(wrappedFn, subscriber);
|
|
1727
|
+
} finally {
|
|
1728
|
+
running = false;
|
|
1729
|
+
}
|
|
1470
1730
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
1471
1731
|
if (hook) hook.emit("effect:create", { effectFn });
|
|
1732
|
+
let disposed = false;
|
|
1472
1733
|
return () => {
|
|
1734
|
+
if (disposed) return;
|
|
1735
|
+
disposed = true;
|
|
1473
1736
|
const h = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
1474
|
-
if (h)
|
|
1475
|
-
|
|
1737
|
+
if (h) {
|
|
1738
|
+
try {
|
|
1739
|
+
h.emit("effect:destroy", { effectFn });
|
|
1740
|
+
} catch {
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
try {
|
|
1744
|
+
runUserCleanups();
|
|
1745
|
+
} catch (err) {
|
|
1746
|
+
if (typeof console !== "undefined") {
|
|
1747
|
+
console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
try {
|
|
1751
|
+
cleanupHandle();
|
|
1752
|
+
} catch (err) {
|
|
1753
|
+
if (typeof console !== "undefined") {
|
|
1754
|
+
console.warn("[SibuJS effect] dispose threw:", err);
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1476
1757
|
};
|
|
1477
1758
|
}
|
|
1478
1759
|
|
|
@@ -1598,9 +1879,12 @@ var RouteMatcher = class {
|
|
|
1598
1879
|
return this.namedRoutes.get(name) || null;
|
|
1599
1880
|
}
|
|
1600
1881
|
matchPattern(path2, routePath) {
|
|
1601
|
-
if (routePath === "*"
|
|
1882
|
+
if (routePath === "*") {
|
|
1883
|
+
return { params: { pathMatch: path2 } };
|
|
1884
|
+
}
|
|
1885
|
+
if (routePath.endsWith("/*")) {
|
|
1602
1886
|
const basePath = routePath.slice(0, -2);
|
|
1603
|
-
if (path2.startsWith(basePath)) {
|
|
1887
|
+
if (path2 === basePath || path2.startsWith(`${basePath}/`)) {
|
|
1604
1888
|
return { params: { pathMatch: path2.slice(basePath.length) } };
|
|
1605
1889
|
}
|
|
1606
1890
|
return null;
|
|
@@ -1719,6 +2003,8 @@ var GuardManager = class {
|
|
|
1719
2003
|
const next = (result) => {
|
|
1720
2004
|
if (resolved || signal2.aborted) return;
|
|
1721
2005
|
resolved = true;
|
|
2006
|
+
clearTimeout(timeoutId);
|
|
2007
|
+
signal2.removeEventListener("abort", abortHandler);
|
|
1722
2008
|
if (result instanceof Error) {
|
|
1723
2009
|
reject(result);
|
|
1724
2010
|
} else if (result === false) {
|
|
@@ -1732,10 +2018,10 @@ var GuardManager = class {
|
|
|
1732
2018
|
const abortHandler = () => {
|
|
1733
2019
|
if (!resolved) {
|
|
1734
2020
|
resolved = true;
|
|
2021
|
+
clearTimeout(timeoutId);
|
|
1735
2022
|
reject(new Error("Navigation aborted"));
|
|
1736
2023
|
}
|
|
1737
2024
|
};
|
|
1738
|
-
signal2.addEventListener("abort", abortHandler);
|
|
1739
2025
|
const timeoutId = setTimeout(() => {
|
|
1740
2026
|
if (!resolved) {
|
|
1741
2027
|
resolved = true;
|
|
@@ -1743,6 +2029,7 @@ var GuardManager = class {
|
|
|
1743
2029
|
reject(new Error("Guard timeout"));
|
|
1744
2030
|
}
|
|
1745
2031
|
}, this.timeout);
|
|
2032
|
+
signal2.addEventListener("abort", abortHandler);
|
|
1746
2033
|
try {
|
|
1747
2034
|
guard(to, from, next);
|
|
1748
2035
|
} catch (error) {
|
|
@@ -1753,12 +2040,6 @@ var GuardManager = class {
|
|
|
1753
2040
|
reject(error instanceof Error ? error : new Error(String(error)));
|
|
1754
2041
|
}
|
|
1755
2042
|
}
|
|
1756
|
-
Promise.resolve().then(() => {
|
|
1757
|
-
if (resolved) {
|
|
1758
|
-
clearTimeout(timeoutId);
|
|
1759
|
-
signal2.removeEventListener("abort", abortHandler);
|
|
1760
|
-
}
|
|
1761
|
-
});
|
|
1762
2043
|
});
|
|
1763
2044
|
}
|
|
1764
2045
|
addBeforeEach(guard) {
|
|
@@ -1843,9 +2124,11 @@ var ComponentLoader = class {
|
|
|
1843
2124
|
}
|
|
1844
2125
|
return component;
|
|
1845
2126
|
} catch (error) {
|
|
1846
|
-
|
|
2127
|
+
const wrapped = new Error(
|
|
1847
2128
|
`Failed to load component for route "${routePath}": ${error instanceof Error ? error.message : String(error)}`
|
|
1848
2129
|
);
|
|
2130
|
+
wrapped.cause = error;
|
|
2131
|
+
throw wrapped;
|
|
1849
2132
|
}
|
|
1850
2133
|
}
|
|
1851
2134
|
isAsyncComponent(comp) {
|
|
@@ -2031,10 +2314,13 @@ var _SibuRouter = class _SibuRouter {
|
|
|
2031
2314
|
}
|
|
2032
2315
|
if ("redirect" in route2) {
|
|
2033
2316
|
const redirectPath = typeof route2.redirect === "function" ? route2.redirect(to) : route2.redirect;
|
|
2034
|
-
if (typeof redirectPath === "string" && /^https
|
|
2035
|
-
console
|
|
2036
|
-
|
|
2037
|
-
|
|
2317
|
+
if (typeof redirectPath === "string" && /^(https?:)?\/\//i.test(redirectPath)) {
|
|
2318
|
+
if (typeof console !== "undefined") {
|
|
2319
|
+
console.error(
|
|
2320
|
+
`[SibuJS Router] Refusing absolute/protocol-relative redirect "${redirectPath}" \u2014 open-redirect risk.`
|
|
2321
|
+
);
|
|
2322
|
+
}
|
|
2323
|
+
throw new NavigationFailureError("aborted", from, to);
|
|
2038
2324
|
}
|
|
2039
2325
|
if (typeof redirectPath === "string" && !isSafeNavigationTarget(redirectPath)) {
|
|
2040
2326
|
throw new NavigationFailureError("aborted", from, to);
|
|
@@ -2237,6 +2523,7 @@ function createRouter(routesOrOptions, options = {}) {
|
|
|
2237
2523
|
routes = [];
|
|
2238
2524
|
}
|
|
2239
2525
|
globalRouter = new SibuRouter(routes, options);
|
|
2526
|
+
ensureRouterPagehide();
|
|
2240
2527
|
return globalRouter;
|
|
2241
2528
|
}
|
|
2242
2529
|
function setRoutes(routes) {
|
|
@@ -2310,7 +2597,9 @@ function Route() {
|
|
|
2310
2597
|
let currentTopRoute = null;
|
|
2311
2598
|
const cleanupNodes = () => {
|
|
2312
2599
|
[currentNode, loadingNode, errorNode].forEach((node) => {
|
|
2313
|
-
if (node
|
|
2600
|
+
if (!node) return;
|
|
2601
|
+
dispose(node);
|
|
2602
|
+
if (node.parentNode) {
|
|
2314
2603
|
node.parentNode.removeChild(node);
|
|
2315
2604
|
}
|
|
2316
2605
|
});
|
|
@@ -2341,13 +2630,24 @@ function Route() {
|
|
|
2341
2630
|
loadingNode = null;
|
|
2342
2631
|
}
|
|
2343
2632
|
};
|
|
2344
|
-
const showError = (error) => {
|
|
2633
|
+
const showError = (error, routeDef) => {
|
|
2345
2634
|
if (!anchor.parentNode) return;
|
|
2346
2635
|
cleanupNodes();
|
|
2347
2636
|
errorNode = document.createElement("div");
|
|
2348
2637
|
errorNode.className = "route-error";
|
|
2349
2638
|
errorNode.setAttribute("role", "alert");
|
|
2350
2639
|
errorNode.setAttribute("aria-live", "assertive");
|
|
2640
|
+
if (routeDef && "component" in routeDef) {
|
|
2641
|
+
const src = routeDef.component.toString();
|
|
2642
|
+
const importMatch = src.match(/import\(["']([^"']+)["']\)/);
|
|
2643
|
+
if (importMatch) {
|
|
2644
|
+
errorNode.setAttribute("data-component-source", importMatch[1]);
|
|
2645
|
+
}
|
|
2646
|
+
if (routeDef.component.name) {
|
|
2647
|
+
errorNode.setAttribute("data-component-name", routeDef.component.name);
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
errorNode.__routeError = error;
|
|
2351
2651
|
const title2 = document.createElement("h3");
|
|
2352
2652
|
title2.textContent = "Route Error";
|
|
2353
2653
|
title2.className = "route-error-title";
|
|
@@ -2358,12 +2658,14 @@ function Route() {
|
|
|
2358
2658
|
retryButton.textContent = "Retry";
|
|
2359
2659
|
retryButton.className = "route-error-retry";
|
|
2360
2660
|
retryButton.type = "button";
|
|
2361
|
-
|
|
2661
|
+
const onRetryClick = () => {
|
|
2362
2662
|
if (globalRouter) {
|
|
2363
2663
|
globalRouter.clearErrorCache();
|
|
2364
2664
|
update();
|
|
2365
2665
|
}
|
|
2366
|
-
}
|
|
2666
|
+
};
|
|
2667
|
+
retryButton.addEventListener("click", onRetryClick);
|
|
2668
|
+
registerDisposer(retryButton, () => retryButton.removeEventListener("click", onRetryClick));
|
|
2367
2669
|
errorNode.appendChild(title2);
|
|
2368
2670
|
errorNode.appendChild(message);
|
|
2369
2671
|
errorNode.appendChild(retryButton);
|
|
@@ -2395,7 +2697,11 @@ function Route() {
|
|
|
2395
2697
|
currentTopRoute = routeDef;
|
|
2396
2698
|
if ("redirect" in routeDef) {
|
|
2397
2699
|
const redirectPath = typeof routeDef.redirect === "function" ? routeDef.redirect(route2) : routeDef.redirect;
|
|
2398
|
-
queueMicrotask(() =>
|
|
2700
|
+
queueMicrotask(() => {
|
|
2701
|
+
globalRouter?.navigate(redirectPath).catch((err) => {
|
|
2702
|
+
if (typeof console !== "undefined") console.error("[router] redirect failed:", err);
|
|
2703
|
+
});
|
|
2704
|
+
});
|
|
2399
2705
|
return;
|
|
2400
2706
|
}
|
|
2401
2707
|
if ("component" in routeDef) {
|
|
@@ -2414,7 +2720,7 @@ function Route() {
|
|
|
2414
2720
|
} catch (error) {
|
|
2415
2721
|
hideLoading();
|
|
2416
2722
|
console.error("[Route] Component error:", error);
|
|
2417
|
-
showError(error instanceof Error ? error : new Error(String(error)));
|
|
2723
|
+
showError(error instanceof Error ? error : new Error(String(error)), routeDef);
|
|
2418
2724
|
}
|
|
2419
2725
|
}
|
|
2420
2726
|
} catch (error) {
|
|
@@ -2434,13 +2740,16 @@ function Route() {
|
|
|
2434
2740
|
await originalUpdate();
|
|
2435
2741
|
routeInitialized = true;
|
|
2436
2742
|
};
|
|
2437
|
-
track(wrappedUpdate);
|
|
2743
|
+
const routeTeardown = track(wrappedUpdate);
|
|
2438
2744
|
if (!routeInitialized) {
|
|
2439
2745
|
queueMicrotask(() => {
|
|
2440
2746
|
if (!routeInitialized && anchor.parentNode) wrappedUpdate();
|
|
2441
2747
|
});
|
|
2442
2748
|
}
|
|
2443
|
-
routeCleanups.push(
|
|
2749
|
+
routeCleanups.push(() => {
|
|
2750
|
+
routeTeardown();
|
|
2751
|
+
cleanupNodes();
|
|
2752
|
+
});
|
|
2444
2753
|
return anchor;
|
|
2445
2754
|
}
|
|
2446
2755
|
function KeepAliveRoute(options) {
|
|
@@ -2469,7 +2778,11 @@ function KeepAliveRoute(options) {
|
|
|
2469
2778
|
const { route: routeDef } = match;
|
|
2470
2779
|
if ("redirect" in routeDef) {
|
|
2471
2780
|
const redirectPath = typeof routeDef.redirect === "function" ? routeDef.redirect(route2) : routeDef.redirect;
|
|
2472
|
-
queueMicrotask(() =>
|
|
2781
|
+
queueMicrotask(() => {
|
|
2782
|
+
globalRouter?.navigate(redirectPath).catch((err) => {
|
|
2783
|
+
if (typeof console !== "undefined") console.error("[router] redirect failed:", err);
|
|
2784
|
+
});
|
|
2785
|
+
});
|
|
2473
2786
|
return;
|
|
2474
2787
|
}
|
|
2475
2788
|
if (!("component" in routeDef)) return;
|
|
@@ -2539,13 +2852,14 @@ function KeepAliveRoute(options) {
|
|
|
2539
2852
|
await update();
|
|
2540
2853
|
initialized = true;
|
|
2541
2854
|
};
|
|
2542
|
-
track(wrappedUpdate);
|
|
2855
|
+
const kaTeardown = track(wrappedUpdate);
|
|
2543
2856
|
if (!initialized) {
|
|
2544
2857
|
queueMicrotask(() => {
|
|
2545
2858
|
if (!initialized && anchor.parentNode) wrappedUpdate();
|
|
2546
2859
|
});
|
|
2547
2860
|
}
|
|
2548
2861
|
routeCleanups.push(() => {
|
|
2862
|
+
kaTeardown();
|
|
2549
2863
|
for (const node of cache.values()) {
|
|
2550
2864
|
dispose(node);
|
|
2551
2865
|
if (node.parentNode) node.parentNode.removeChild(node);
|
|
@@ -2612,12 +2926,18 @@ function RouterLink(props) {
|
|
|
2612
2926
|
}
|
|
2613
2927
|
});
|
|
2614
2928
|
}
|
|
2615
|
-
|
|
2929
|
+
const onLinkClick = (e) => {
|
|
2616
2930
|
if (target || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) {
|
|
2617
2931
|
return;
|
|
2618
2932
|
}
|
|
2619
2933
|
e.preventDefault();
|
|
2620
|
-
globalRouter?.navigate(to, { replace: replace2 })
|
|
2934
|
+
globalRouter?.navigate(to, { replace: replace2 }).catch((err) => {
|
|
2935
|
+
if (typeof console !== "undefined") console.error("[router] link navigate failed:", err);
|
|
2936
|
+
});
|
|
2937
|
+
};
|
|
2938
|
+
link2.addEventListener("click", onLinkClick);
|
|
2939
|
+
registerDisposer(link2, () => {
|
|
2940
|
+
link2.removeEventListener("click", onLinkClick);
|
|
2621
2941
|
});
|
|
2622
2942
|
return link2;
|
|
2623
2943
|
}
|
|
@@ -2728,10 +3048,21 @@ function destroyRouter() {
|
|
|
2728
3048
|
globalRouter = null;
|
|
2729
3049
|
}
|
|
2730
3050
|
}
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
3051
|
+
var _routerPagehideHandler = null;
|
|
3052
|
+
function ensureRouterPagehide() {
|
|
3053
|
+
if (_routerPagehideHandler || typeof window === "undefined") return;
|
|
3054
|
+
_routerPagehideHandler = (event) => {
|
|
3055
|
+
if (event.persisted === false) {
|
|
3056
|
+
destroyRouter();
|
|
3057
|
+
}
|
|
3058
|
+
};
|
|
3059
|
+
window.addEventListener("pagehide", _routerPagehideHandler);
|
|
3060
|
+
}
|
|
3061
|
+
function __removeRouterPagehideHandler() {
|
|
3062
|
+
if (_routerPagehideHandler && typeof window !== "undefined") {
|
|
3063
|
+
window.removeEventListener("pagehide", _routerPagehideHandler);
|
|
3064
|
+
_routerPagehideHandler = null;
|
|
3065
|
+
}
|
|
2735
3066
|
}
|
|
2736
3067
|
function Outlet() {
|
|
2737
3068
|
const anchor = document.createComment("route-outlet-nested");
|
|
@@ -2757,12 +3088,20 @@ function Outlet() {
|
|
|
2757
3088
|
console.error("[Outlet] Failed to render child route:", error);
|
|
2758
3089
|
}
|
|
2759
3090
|
};
|
|
2760
|
-
track(update);
|
|
3091
|
+
const outletTeardown = track(update);
|
|
2761
3092
|
if (!anchor.parentNode) {
|
|
2762
3093
|
queueMicrotask(() => {
|
|
2763
3094
|
if (anchor.parentNode) update();
|
|
2764
3095
|
});
|
|
2765
3096
|
}
|
|
3097
|
+
routeCleanups.push(() => {
|
|
3098
|
+
outletTeardown();
|
|
3099
|
+
if (currentNode) {
|
|
3100
|
+
dispose(currentNode);
|
|
3101
|
+
if (currentNode.parentNode) currentNode.parentNode.removeChild(currentNode);
|
|
3102
|
+
currentNode = null;
|
|
3103
|
+
}
|
|
3104
|
+
});
|
|
2766
3105
|
return anchor;
|
|
2767
3106
|
}
|
|
2768
3107
|
function addRoute(route2, parentPath) {
|
|
@@ -3080,6 +3419,10 @@ function hydrateRouter(routes, options) {
|
|
|
3080
3419
|
if (resolved.component) {
|
|
3081
3420
|
hydrate2(resolved.component, container);
|
|
3082
3421
|
}
|
|
3422
|
+
}).catch((err) => {
|
|
3423
|
+
if (typeof console !== "undefined") {
|
|
3424
|
+
console.error("[SibuJS routerSSR] failed to load hydrate:", err);
|
|
3425
|
+
}
|
|
3083
3426
|
});
|
|
3084
3427
|
}
|
|
3085
3428
|
}
|
|
@@ -3153,83 +3496,117 @@ function escapeAttrLocal(str) {
|
|
|
3153
3496
|
}
|
|
3154
3497
|
|
|
3155
3498
|
// src/plugins/plugin.ts
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
init: [],
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3499
|
+
function createPluginRegistry() {
|
|
3500
|
+
const installedPlugins = /* @__PURE__ */ new Set();
|
|
3501
|
+
const hooks = { init: [], mount: [], unmount: [], error: [] };
|
|
3502
|
+
const provided = /* @__PURE__ */ new Map();
|
|
3503
|
+
const registry = {
|
|
3504
|
+
installedPlugins,
|
|
3505
|
+
hooks,
|
|
3506
|
+
provided,
|
|
3507
|
+
plugin(p2, options) {
|
|
3508
|
+
if (installedPlugins.has(p2.name)) {
|
|
3509
|
+
console.warn(`[Plugin] "${p2.name}" is already installed.`);
|
|
3510
|
+
return;
|
|
3511
|
+
}
|
|
3512
|
+
const ctx = {
|
|
3513
|
+
onInit: (cb) => hooks.init.push(cb),
|
|
3514
|
+
onMount: (cb) => hooks.mount.push(cb),
|
|
3515
|
+
onUnmount: (cb) => hooks.unmount.push(cb),
|
|
3516
|
+
onError: (cb) => hooks.error.push(cb),
|
|
3517
|
+
provide: (key, value) => provided.set(key, value)
|
|
3518
|
+
};
|
|
3519
|
+
const initHooksBefore = hooks.init.length;
|
|
3520
|
+
p2.install(ctx, options);
|
|
3521
|
+
installedPlugins.add(p2.name);
|
|
3522
|
+
const justAdded = hooks.init.slice(initHooksBefore);
|
|
3523
|
+
for (const cb of justAdded) {
|
|
3524
|
+
try {
|
|
3525
|
+
cb();
|
|
3526
|
+
} catch (e) {
|
|
3527
|
+
console.error(`[Plugin] "${p2.name}" init error:`, e);
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
},
|
|
3531
|
+
inject(key, defaultValue) {
|
|
3532
|
+
if (provided.has(key)) return provided.get(key);
|
|
3533
|
+
if (defaultValue !== void 0) return defaultValue;
|
|
3534
|
+
throw new Error(`[Plugin] No provider found for key "${key}"`);
|
|
3535
|
+
},
|
|
3536
|
+
triggerMount(element) {
|
|
3537
|
+
const snapshot = hooks.mount.slice();
|
|
3538
|
+
for (const hook of snapshot) {
|
|
3539
|
+
try {
|
|
3540
|
+
hook(element);
|
|
3541
|
+
} catch (e) {
|
|
3542
|
+
console.error("[Plugin] Mount hook error:", e);
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
},
|
|
3546
|
+
triggerUnmount(element) {
|
|
3547
|
+
const snapshot = hooks.unmount.slice();
|
|
3548
|
+
for (const hook of snapshot) {
|
|
3549
|
+
try {
|
|
3550
|
+
hook(element);
|
|
3551
|
+
} catch (e) {
|
|
3552
|
+
console.error("[Plugin] Unmount hook error:", e);
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3555
|
+
},
|
|
3556
|
+
triggerError(error) {
|
|
3557
|
+
const snapshot = hooks.error.slice();
|
|
3558
|
+
for (const hook of snapshot) {
|
|
3559
|
+
try {
|
|
3560
|
+
hook(error);
|
|
3561
|
+
} catch (e) {
|
|
3562
|
+
console.error("[Plugin] Error hook error:", e);
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
},
|
|
3566
|
+
reset() {
|
|
3567
|
+
installedPlugins.clear();
|
|
3568
|
+
hooks.init.length = 0;
|
|
3569
|
+
hooks.mount.length = 0;
|
|
3570
|
+
hooks.unmount.length = 0;
|
|
3571
|
+
hooks.error.length = 0;
|
|
3572
|
+
provided.clear();
|
|
3573
|
+
}
|
|
3574
|
+
};
|
|
3575
|
+
return registry;
|
|
3576
|
+
}
|
|
3577
|
+
var defaultRegistry = createPluginRegistry();
|
|
3578
|
+
var defaultRegistryTouched = false;
|
|
3164
3579
|
function createPlugin(name, install) {
|
|
3165
3580
|
return { name, install };
|
|
3166
3581
|
}
|
|
3167
3582
|
function plugin(plugin2, options) {
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
return;
|
|
3171
|
-
}
|
|
3172
|
-
const ctx = {
|
|
3173
|
-
onInit: (cb) => hooks.init.push(cb),
|
|
3174
|
-
onMount: (cb) => hooks.mount.push(cb),
|
|
3175
|
-
onUnmount: (cb) => hooks.unmount.push(cb),
|
|
3176
|
-
onError: (cb) => hooks.error.push(cb),
|
|
3177
|
-
provide: (key, value) => provided.set(key, value)
|
|
3178
|
-
};
|
|
3179
|
-
const initHooksBefore = hooks.init.length;
|
|
3180
|
-
plugin2.install(ctx, options);
|
|
3181
|
-
installedPlugins.add(plugin2.name);
|
|
3182
|
-
for (let i2 = initHooksBefore; i2 < hooks.init.length; i2++) {
|
|
3183
|
-
try {
|
|
3184
|
-
hooks.init[i2]();
|
|
3185
|
-
} catch (e) {
|
|
3186
|
-
console.error(`[Plugin] "${plugin2.name}" init error:`, e);
|
|
3187
|
-
}
|
|
3188
|
-
}
|
|
3583
|
+
defaultRegistryTouched = true;
|
|
3584
|
+
defaultRegistry.plugin(plugin2, options);
|
|
3189
3585
|
}
|
|
3190
3586
|
function inject(key, defaultValue) {
|
|
3191
|
-
|
|
3192
|
-
return provided.get(key);
|
|
3193
|
-
}
|
|
3194
|
-
if (defaultValue !== void 0) {
|
|
3195
|
-
return defaultValue;
|
|
3196
|
-
}
|
|
3197
|
-
throw new Error(`[Plugin] No provider found for key "${key}"`);
|
|
3587
|
+
return defaultRegistry.inject(key, defaultValue);
|
|
3198
3588
|
}
|
|
3199
3589
|
function triggerPluginMount(element) {
|
|
3200
|
-
|
|
3201
|
-
try {
|
|
3202
|
-
hook(element);
|
|
3203
|
-
} catch (e) {
|
|
3204
|
-
console.error("[Plugin] Mount hook error:", e);
|
|
3205
|
-
}
|
|
3206
|
-
}
|
|
3590
|
+
defaultRegistry.triggerMount(element);
|
|
3207
3591
|
}
|
|
3208
3592
|
function triggerPluginUnmount(element) {
|
|
3209
|
-
|
|
3210
|
-
try {
|
|
3211
|
-
hook(element);
|
|
3212
|
-
} catch (e) {
|
|
3213
|
-
console.error("[Plugin] Unmount hook error:", e);
|
|
3214
|
-
}
|
|
3215
|
-
}
|
|
3593
|
+
defaultRegistry.triggerUnmount(element);
|
|
3216
3594
|
}
|
|
3217
3595
|
function triggerPluginError(error) {
|
|
3218
|
-
|
|
3219
|
-
try {
|
|
3220
|
-
hook(error);
|
|
3221
|
-
} catch (e) {
|
|
3222
|
-
console.error("[Plugin] Error hook error:", e);
|
|
3223
|
-
}
|
|
3224
|
-
}
|
|
3596
|
+
defaultRegistry.triggerError(error);
|
|
3225
3597
|
}
|
|
3226
3598
|
function resetPlugins() {
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3599
|
+
defaultRegistry.reset();
|
|
3600
|
+
defaultRegistryTouched = false;
|
|
3601
|
+
}
|
|
3602
|
+
function setDefaultPluginRegistry(registry) {
|
|
3603
|
+
if (defaultRegistryTouched && defaultRegistry.installedPlugins.size > 0) {
|
|
3604
|
+
console.warn(
|
|
3605
|
+
"[Plugin] Replacing default plugin registry while plugins are already installed on the singleton. This may indicate mixed singleton/registry usage."
|
|
3606
|
+
);
|
|
3607
|
+
}
|
|
3608
|
+
defaultRegistry = registry;
|
|
3609
|
+
defaultRegistryTouched = true;
|
|
3233
3610
|
}
|
|
3234
3611
|
|
|
3235
3612
|
// src/plugins/modular.ts
|
|
@@ -3707,7 +4084,8 @@ init_ssr();
|
|
|
3707
4084
|
function preloadCritical(resources) {
|
|
3708
4085
|
if (typeof document === "undefined") return;
|
|
3709
4086
|
for (const resource of resources) {
|
|
3710
|
-
const
|
|
4087
|
+
const safeHref = typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(resource.href) : resource.href.replace(/["\\]/g, "\\$&");
|
|
4088
|
+
const existing = document.querySelector(`link[rel="preload"][href="${safeHref}"]`);
|
|
3711
4089
|
if (existing) continue;
|
|
3712
4090
|
const link2 = document.createElement("link");
|
|
3713
4091
|
link2.rel = "preload";
|
|
@@ -3942,6 +4320,7 @@ function createBootSequence() {
|
|
|
3942
4320
|
Suspense,
|
|
3943
4321
|
Trans,
|
|
3944
4322
|
VERSION,
|
|
4323
|
+
__removeRouterPagehideHandler,
|
|
3945
4324
|
addRoute,
|
|
3946
4325
|
afterEach,
|
|
3947
4326
|
back,
|
|
@@ -3957,6 +4336,7 @@ function createBootSequence() {
|
|
|
3957
4336
|
createMigrationRunner,
|
|
3958
4337
|
createModuleRegistry,
|
|
3959
4338
|
createPlugin,
|
|
4339
|
+
createPluginRegistry,
|
|
3960
4340
|
createRouter,
|
|
3961
4341
|
createSSRCache,
|
|
3962
4342
|
createSSRRouter,
|
|
@@ -3999,6 +4379,7 @@ function createBootSequence() {
|
|
|
3999
4379
|
routerState,
|
|
4000
4380
|
satisfies,
|
|
4001
4381
|
serializeRouteState,
|
|
4382
|
+
setDefaultPluginRegistry,
|
|
4002
4383
|
setLocale,
|
|
4003
4384
|
setRouteTransition,
|
|
4004
4385
|
setRoutes,
|