sibujs 4.12.0 → 4.13.1
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 +71 -18
- package/dist/browser.js +4 -4
- package/dist/build.cjs +6618 -6178
- package/dist/build.d.cts +554 -415
- package/dist/build.d.ts +554 -415
- package/dist/build.js +2091 -1735
- package/dist/cdn.dev.global.js +12 -12
- package/dist/cdn.full.dev.global.js +13 -13
- package/dist/cdn.full.global.js +12 -12
- package/dist/cdn.global.js +12 -12
- package/dist/{chunk-WFRQ6D7H.js → chunk-22OPSWMF.js} +1 -1
- package/dist/{chunk-ZJCHY2IB.js → chunk-2NC56RGY.js} +1 -1
- package/dist/{chunk-NB7TFSJE.js → chunk-2O6JJCUR.js} +4 -4
- package/dist/{chunk-B2Y5BJSP.js → chunk-4UTGDVSA.js} +70 -16
- package/dist/{chunk-NAVLCP4S.js → chunk-5RIBLY2N.js} +4 -4
- package/dist/{chunk-T5O2CUHV.js → chunk-5XUGJM3J.js} +1 -1
- package/dist/{chunk-HXT2RNH5.js → chunk-ADZHPN2B.js} +1 -1
- package/dist/chunk-B36ADEIR.js +21 -0
- package/dist/{chunk-DFZL3AX7.js → chunk-C73VBPEF.js} +9 -5
- package/dist/{chunk-WH4U2VUE.js → chunk-CPQKWCJ2.js} +13 -5
- package/dist/{chunk-LEUEKK4G.js → chunk-EU7T7EB3.js} +2 -2
- package/dist/{chunk-QLG5IK7F.js → chunk-G3Z2FEBR.js} +4 -4
- package/dist/{chunk-ZPY2UAKM.js → chunk-J4X7ICH4.js} +3 -3
- package/dist/{chunk-XX4BRMWF.js → chunk-K4LNUT5L.js} +1 -1
- package/dist/{chunk-CI4W6XAU.js → chunk-KC62VURU.js} +3 -3
- package/dist/chunk-N5TBYXHW.js +17 -0
- package/dist/{chunk-653KGQS2.js → chunk-OIKD7YDY.js} +2 -2
- package/dist/{chunk-LYTUTXQP.js → chunk-PBJYCE2Z.js} +46 -4
- package/dist/{chunk-EMB5PG7V.js → chunk-QC3NP47A.js} +1 -1
- package/dist/{chunk-IHA62NGJ.js → chunk-QKFVMIAV.js} +1 -1
- package/dist/{chunk-LXBMVGVB.js → chunk-QZ47OZ25.js} +3 -3
- package/dist/{chunk-ZTYCCBU3.js → chunk-VFPLWUT7.js} +44 -26
- package/dist/{chunk-RK7EPQPG.js → chunk-YFTBCCVH.js} +1 -1
- package/dist/data.cjs +71 -18
- package/dist/data.js +5 -5
- package/dist/datePicker-DxuxWpgF.d.cts +285 -0
- package/dist/datePicker-DxuxWpgF.d.ts +285 -0
- package/dist/devtools.cjs +71 -18
- package/dist/devtools.js +4 -4
- package/dist/ecosystem.cjs +82 -21
- package/dist/ecosystem.js +7 -7
- package/dist/extras.cjs +131 -23
- package/dist/extras.d.cts +2 -2
- package/dist/extras.d.ts +2 -2
- package/dist/extras.js +21 -20
- package/dist/index.cjs +115 -37
- package/dist/index.d.cts +59 -5
- package/dist/index.d.ts +59 -5
- package/dist/index.js +10 -10
- package/dist/motion.cjs +69 -16
- package/dist/motion.js +3 -3
- package/dist/patterns.cjs +71 -18
- package/dist/patterns.js +5 -5
- package/dist/performance.cjs +69 -16
- package/dist/performance.js +4 -4
- package/dist/plugins.cjs +1421 -996
- package/dist/plugins.d.cts +132 -3
- package/dist/plugins.d.ts +132 -3
- package/dist/plugins.js +262 -11
- package/dist/routeMiddleware-B1sp4P7a.d.ts +688 -0
- package/dist/routeMiddleware-CedQTsLK.d.cts +688 -0
- package/dist/ssr.cjs +3607 -3524
- package/dist/ssr.d.cts +20 -671
- package/dist/ssr.d.ts +20 -671
- package/dist/ssr.js +15 -7
- package/dist/testing.cjs +71 -18
- package/dist/testing.js +2 -2
- package/dist/ui.cjs +78 -18
- package/dist/ui.js +8 -7
- package/dist/widgets.cjs +1352 -952
- package/dist/widgets.d.cts +100 -268
- package/dist/widgets.d.ts +100 -268
- package/dist/widgets.js +316 -7
- package/package.json +9 -1
package/dist/plugins.cjs
CHANGED
|
@@ -980,6 +980,80 @@ var init_globalSingleton = __esm({
|
|
|
980
980
|
}
|
|
981
981
|
});
|
|
982
982
|
|
|
983
|
+
// src/utils/headEntry.ts
|
|
984
|
+
function isEmittableHeadAttrName(name) {
|
|
985
|
+
if (!SAFE_HEAD_ATTR_NAME.test(name)) return false;
|
|
986
|
+
const canonical = canonicalAttrName(name);
|
|
987
|
+
if (isEventHandlerAttr(canonical)) return false;
|
|
988
|
+
if (isHtmlContentAttribute(canonical)) return false;
|
|
989
|
+
return true;
|
|
990
|
+
}
|
|
991
|
+
function sanitizeHeadAttrValue(canonical, value) {
|
|
992
|
+
return resolveAttributeValue(canonical, value);
|
|
993
|
+
}
|
|
994
|
+
function findDuplicateAttributeName(names) {
|
|
995
|
+
const seen = /* @__PURE__ */ new Set();
|
|
996
|
+
for (const name of names) {
|
|
997
|
+
const canonical = canonicalAttrName(name);
|
|
998
|
+
if (seen.has(canonical)) return canonical;
|
|
999
|
+
seen.add(canonical);
|
|
1000
|
+
}
|
|
1001
|
+
return null;
|
|
1002
|
+
}
|
|
1003
|
+
function planEntry(props, resolver, applyRefreshPolicy) {
|
|
1004
|
+
const rawNames = Object.keys(props);
|
|
1005
|
+
const duplicate = findDuplicateAttributeName(rawNames);
|
|
1006
|
+
if (duplicate !== null) {
|
|
1007
|
+
return { kind: "drop", reason: `duplicate case-insensitive attribute ${JSON.stringify(duplicate)}` };
|
|
1008
|
+
}
|
|
1009
|
+
const attributes = /* @__PURE__ */ new Map();
|
|
1010
|
+
let reactive = false;
|
|
1011
|
+
for (const name of rawNames) {
|
|
1012
|
+
if (!Object.hasOwn(props, name)) continue;
|
|
1013
|
+
if (!isEmittableHeadAttrName(name)) continue;
|
|
1014
|
+
const authored = props[name];
|
|
1015
|
+
if (resolver.isReactiveValue?.(authored)) reactive = true;
|
|
1016
|
+
const canonical = canonicalAttrName(name);
|
|
1017
|
+
const sanitized = sanitizeHeadAttrValue(canonical, resolver.resolveValue(name, authored));
|
|
1018
|
+
if (sanitized === null) continue;
|
|
1019
|
+
attributes.set(canonical, sanitized);
|
|
1020
|
+
}
|
|
1021
|
+
if (attributes.size === 0) return { kind: "drop", reason: "no effective attributes remain" };
|
|
1022
|
+
const refresh = applyRefreshPolicy ? resolveMetaRefreshPolicy(attributes) : { kind: "not-refresh" };
|
|
1023
|
+
if (refresh.kind === "forbidden") return { kind: "drop", reason: refresh.reason };
|
|
1024
|
+
if (reactive && (refresh.kind === "allowed" || refresh.kind === "delay-only")) {
|
|
1025
|
+
return { kind: "drop", reason: "a reactive meta entry may not publish a native refresh directive" };
|
|
1026
|
+
}
|
|
1027
|
+
return { kind: "publish", attributes, refresh };
|
|
1028
|
+
}
|
|
1029
|
+
function planMetaEntry(props, resolver) {
|
|
1030
|
+
return planEntry(props, resolver, true);
|
|
1031
|
+
}
|
|
1032
|
+
function planHeadElementEntry(props, resolver) {
|
|
1033
|
+
return planEntry(props, resolver, false);
|
|
1034
|
+
}
|
|
1035
|
+
function escapeHeadAttrValue(value) {
|
|
1036
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
1037
|
+
}
|
|
1038
|
+
function serializeHeadEntry(tag, attrs) {
|
|
1039
|
+
const plan = tag === "meta" ? planMetaEntry(attrs, STATIC_VALUE_RESOLVER) : planHeadElementEntry(attrs, STATIC_VALUE_RESOLVER);
|
|
1040
|
+
if (plan.kind === "drop") return "";
|
|
1041
|
+
const pairs = Array.from(plan.attributes, ([name, value]) => `${name}="${escapeHeadAttrValue(value)}"`).join(" ");
|
|
1042
|
+
return `<${tag} ${pairs} />`;
|
|
1043
|
+
}
|
|
1044
|
+
var SAFE_HEAD_ATTR_NAME, STATIC_VALUE_RESOLVER;
|
|
1045
|
+
var init_headEntry = __esm({
|
|
1046
|
+
"src/utils/headEntry.ts"() {
|
|
1047
|
+
"use strict";
|
|
1048
|
+
init_metaRefresh();
|
|
1049
|
+
init_sanitize();
|
|
1050
|
+
SAFE_HEAD_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
|
|
1051
|
+
STATIC_VALUE_RESOLVER = {
|
|
1052
|
+
resolveValue: (_name, value) => String(value)
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
});
|
|
1056
|
+
|
|
983
1057
|
// src/utils/embedPolicy.ts
|
|
984
1058
|
function currentEmbedAllowlist() {
|
|
985
1059
|
const scoped = getRequestStore()?.caches?.get(REQUEST_CACHE)?.get("allowed");
|
|
@@ -1122,80 +1196,6 @@ var init_guards = __esm({
|
|
|
1122
1196
|
}
|
|
1123
1197
|
});
|
|
1124
1198
|
|
|
1125
|
-
// src/utils/headEntry.ts
|
|
1126
|
-
function isEmittableHeadAttrName(name) {
|
|
1127
|
-
if (!SAFE_HEAD_ATTR_NAME.test(name)) return false;
|
|
1128
|
-
const canonical = canonicalAttrName(name);
|
|
1129
|
-
if (isEventHandlerAttr(canonical)) return false;
|
|
1130
|
-
if (isHtmlContentAttribute(canonical)) return false;
|
|
1131
|
-
return true;
|
|
1132
|
-
}
|
|
1133
|
-
function sanitizeHeadAttrValue(canonical, value) {
|
|
1134
|
-
return resolveAttributeValue(canonical, value);
|
|
1135
|
-
}
|
|
1136
|
-
function findDuplicateAttributeName(names) {
|
|
1137
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1138
|
-
for (const name of names) {
|
|
1139
|
-
const canonical = canonicalAttrName(name);
|
|
1140
|
-
if (seen.has(canonical)) return canonical;
|
|
1141
|
-
seen.add(canonical);
|
|
1142
|
-
}
|
|
1143
|
-
return null;
|
|
1144
|
-
}
|
|
1145
|
-
function planEntry(props, resolver, applyRefreshPolicy) {
|
|
1146
|
-
const rawNames = Object.keys(props);
|
|
1147
|
-
const duplicate = findDuplicateAttributeName(rawNames);
|
|
1148
|
-
if (duplicate !== null) {
|
|
1149
|
-
return { kind: "drop", reason: `duplicate case-insensitive attribute ${JSON.stringify(duplicate)}` };
|
|
1150
|
-
}
|
|
1151
|
-
const attributes = /* @__PURE__ */ new Map();
|
|
1152
|
-
let reactive = false;
|
|
1153
|
-
for (const name of rawNames) {
|
|
1154
|
-
if (!Object.hasOwn(props, name)) continue;
|
|
1155
|
-
if (!isEmittableHeadAttrName(name)) continue;
|
|
1156
|
-
const authored = props[name];
|
|
1157
|
-
if (resolver.isReactiveValue?.(authored)) reactive = true;
|
|
1158
|
-
const canonical = canonicalAttrName(name);
|
|
1159
|
-
const sanitized = sanitizeHeadAttrValue(canonical, resolver.resolveValue(name, authored));
|
|
1160
|
-
if (sanitized === null) continue;
|
|
1161
|
-
attributes.set(canonical, sanitized);
|
|
1162
|
-
}
|
|
1163
|
-
if (attributes.size === 0) return { kind: "drop", reason: "no effective attributes remain" };
|
|
1164
|
-
const refresh = applyRefreshPolicy ? resolveMetaRefreshPolicy(attributes) : { kind: "not-refresh" };
|
|
1165
|
-
if (refresh.kind === "forbidden") return { kind: "drop", reason: refresh.reason };
|
|
1166
|
-
if (reactive && (refresh.kind === "allowed" || refresh.kind === "delay-only")) {
|
|
1167
|
-
return { kind: "drop", reason: "a reactive meta entry may not publish a native refresh directive" };
|
|
1168
|
-
}
|
|
1169
|
-
return { kind: "publish", attributes, refresh };
|
|
1170
|
-
}
|
|
1171
|
-
function planMetaEntry(props, resolver) {
|
|
1172
|
-
return planEntry(props, resolver, true);
|
|
1173
|
-
}
|
|
1174
|
-
function planHeadElementEntry(props, resolver) {
|
|
1175
|
-
return planEntry(props, resolver, false);
|
|
1176
|
-
}
|
|
1177
|
-
function escapeHeadAttrValue(value) {
|
|
1178
|
-
return value.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
1179
|
-
}
|
|
1180
|
-
function serializeHeadEntry(tag, attrs) {
|
|
1181
|
-
const plan = tag === "meta" ? planMetaEntry(attrs, STATIC_VALUE_RESOLVER) : planHeadElementEntry(attrs, STATIC_VALUE_RESOLVER);
|
|
1182
|
-
if (plan.kind === "drop") return "";
|
|
1183
|
-
const pairs = Array.from(plan.attributes, ([name, value]) => `${name}="${escapeHeadAttrValue(value)}"`).join(" ");
|
|
1184
|
-
return `<${tag} ${pairs} />`;
|
|
1185
|
-
}
|
|
1186
|
-
var SAFE_HEAD_ATTR_NAME, STATIC_VALUE_RESOLVER;
|
|
1187
|
-
var init_headEntry = __esm({
|
|
1188
|
-
"src/utils/headEntry.ts"() {
|
|
1189
|
-
"use strict";
|
|
1190
|
-
init_metaRefresh();
|
|
1191
|
-
init_sanitize();
|
|
1192
|
-
SAFE_HEAD_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
|
|
1193
|
-
STATIC_VALUE_RESOLVER = {
|
|
1194
|
-
resolveValue: (_name, value) => String(value)
|
|
1195
|
-
};
|
|
1196
|
-
}
|
|
1197
|
-
});
|
|
1198
|
-
|
|
1199
1199
|
// src/platform/ssr.ts
|
|
1200
1200
|
var ssr_exports = {};
|
|
1201
1201
|
__export(ssr_exports, {
|
|
@@ -1943,10 +1943,13 @@ __export(plugins_exports, {
|
|
|
1943
1943
|
renderRouteToString: () => renderRouteToString,
|
|
1944
1944
|
replace: () => replace,
|
|
1945
1945
|
resetPlugins: () => resetPlugins,
|
|
1946
|
+
resolveRouteHead: () => resolveRouteHead,
|
|
1946
1947
|
resolveServerRoute: () => resolveServerRoute,
|
|
1947
1948
|
route: () => route,
|
|
1949
|
+
routeHeadToHTML: () => routeHeadToHTML,
|
|
1948
1950
|
router: () => router,
|
|
1949
1951
|
routerPlugin: () => routerPlugin,
|
|
1952
|
+
routerReady: () => routerReady,
|
|
1950
1953
|
routerState: () => routerState,
|
|
1951
1954
|
satisfies: () => satisfies,
|
|
1952
1955
|
serializeRouteState: () => serializeRouteState,
|
|
@@ -1962,100 +1965,219 @@ __export(plugins_exports, {
|
|
|
1962
1965
|
});
|
|
1963
1966
|
module.exports = __toCommonJS(plugins_exports);
|
|
1964
1967
|
|
|
1965
|
-
// src/
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
var BOOLEAN_IDL_ATTRS = /* @__PURE__ */ new Set(["checked", "disabled", "selected"]);
|
|
1981
|
-
function isHtmlElement(el) {
|
|
1982
|
-
return el.namespaceURI === null || el.namespaceURI === HTML_NS2;
|
|
1983
|
-
}
|
|
1984
|
-
function warnContextualRefusal(label2, name, refusal) {
|
|
1985
|
-
devWarnLazy(() => {
|
|
1986
|
-
const reasons = [
|
|
1987
|
-
"",
|
|
1988
|
-
'the element would become a <meta http-equiv="refresh"> directive the shared refresh policy forbids (a destination outside the URL allowlist, or a directive too malformed to read unambiguously)',
|
|
1989
|
-
"a <meta> whose http-equiv or content is reactive may never carry a refresh directive: a browser schedules the navigation as soon as the directive is valid, and nothing can withdraw it when the state changes back",
|
|
1990
|
-
"a runtime value may not choose the program a <script> runs; name the script in static template source, or load it through Head({ script }) as an explicit trust decision",
|
|
1991
|
-
"an SVG animation may not target a URL, event-handler or nested-document attribute; its to / values would be written into that attribute without passing the URL policy",
|
|
1992
|
-
'a runtime-chosen href may not become an applied <link rel="stylesheet">: a well-formed URL is not a trusted stylesheet. Name the stylesheet in static template source, or load a runtime-chosen one through Head({ link }) as an explicit trust decision'
|
|
1993
|
-
];
|
|
1994
|
-
return `${label2}: refusing "${name}" in this element's context \u2014 ${reasons[refusal]}. The write was not performed.`;
|
|
1995
|
-
});
|
|
1996
|
-
}
|
|
1997
|
-
function setProp(el, key, val) {
|
|
1998
|
-
el[key] = val;
|
|
1999
|
-
}
|
|
2000
|
-
function namespaceFor(el, name) {
|
|
2001
|
-
if (el.namespaceURI !== SVG_NS2) return null;
|
|
2002
|
-
const lower = name.toLowerCase();
|
|
2003
|
-
if (lower.startsWith("xlink:")) return XLINK_NS;
|
|
2004
|
-
if (lower.startsWith("xml:")) return XML_NS;
|
|
2005
|
-
return null;
|
|
2006
|
-
}
|
|
2007
|
-
function setSafeAttribute(el, name, value, options = {}) {
|
|
2008
|
-
const written = commitSafeAttribute(el, name, value, options);
|
|
2009
|
-
if (el.localName === "link") settleAttributeProvenance(el, name, options.reactive ? "reactive" : "runtime");
|
|
2010
|
-
return written;
|
|
2011
|
-
}
|
|
2012
|
-
function commitSafeAttribute(el, name, value, options) {
|
|
2013
|
-
const ns = namespaceFor(el, name);
|
|
2014
|
-
const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
|
|
2015
|
-
if (isEventHandlerAttr(name)) {
|
|
2016
|
-
if (DEV) {
|
|
2017
|
-
devWarn(
|
|
2018
|
-
`${options.label ?? "setSafeAttribute"}: refusing to set event-handler attribute "${name}". Its value would be evaluated as JavaScript. Use on:{ ${name.slice(2)}: fn } instead.`
|
|
2019
|
-
);
|
|
2020
|
-
}
|
|
2021
|
-
if (ns) el.removeAttributeNS(ns, localName);
|
|
2022
|
-
else el.removeAttribute(name);
|
|
2023
|
-
return false;
|
|
2024
|
-
}
|
|
2025
|
-
const pending = value == null || value === false ? null : value === true ? "" : String(value);
|
|
2026
|
-
const refusal = contextualAttributeRefusal(el, name, pending, options.reactive ? "reactive" : "runtime");
|
|
2027
|
-
if (refusal !== ContextualRefusal.None) {
|
|
2028
|
-
warnContextualRefusal(options.label ?? "setSafeAttribute", name, refusal);
|
|
2029
|
-
if (ns) el.removeAttributeNS(ns, localName);
|
|
2030
|
-
else el.removeAttribute(name);
|
|
2031
|
-
return false;
|
|
2032
|
-
}
|
|
2033
|
-
if (value == null) {
|
|
2034
|
-
if (ns) el.removeAttributeNS(ns, localName);
|
|
2035
|
-
else el.removeAttribute(name);
|
|
2036
|
-
return true;
|
|
2037
|
-
}
|
|
2038
|
-
if (isHtmlContentAttribute(name)) {
|
|
2039
|
-
if (DEV) {
|
|
2040
|
-
devWarn(
|
|
2041
|
-
`${options.label ?? "setSafeAttribute"}: refusing to set "${name}". The browser parses this attribute as a nested HTML document, so a generic string value cannot be made safe \u2014 attribute escaping is undone before the parse. Build the frame's content another way.`
|
|
2042
|
-
);
|
|
2043
|
-
}
|
|
2044
|
-
if (ns) el.removeAttributeNS(ns, localName);
|
|
2045
|
-
else el.removeAttribute(name);
|
|
2046
|
-
return false;
|
|
2047
|
-
}
|
|
2048
|
-
const html2 = isHtmlElement(el);
|
|
2049
|
-
const idlName = html2 ? name.toLowerCase() : name;
|
|
2050
|
-
if (typeof value === "boolean") {
|
|
2051
|
-
if (name.length > 5 && name.slice(0, 5).toLowerCase() === "aria-") {
|
|
2052
|
-
const token = value ? "true" : "false";
|
|
2053
|
-
if ((ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name)) !== token) {
|
|
2054
|
-
if (ns) el.setAttributeNS(ns, name, token);
|
|
2055
|
-
else el.setAttribute(name, token);
|
|
1968
|
+
// src/plugins/ecosystem.ts
|
|
1969
|
+
function createTestHarness() {
|
|
1970
|
+
let container;
|
|
1971
|
+
return {
|
|
1972
|
+
/** Set up a clean DOM container before each test */
|
|
1973
|
+
setup() {
|
|
1974
|
+
container = document.createElement("div");
|
|
1975
|
+
container.setAttribute("data-sibu-test", "true");
|
|
1976
|
+
document.body.appendChild(container);
|
|
1977
|
+
return container;
|
|
1978
|
+
},
|
|
1979
|
+
/** Tear down the DOM container after each test */
|
|
1980
|
+
teardown() {
|
|
1981
|
+
if (container?.parentNode) {
|
|
1982
|
+
container.parentNode.removeChild(container);
|
|
2056
1983
|
}
|
|
2057
|
-
|
|
2058
|
-
|
|
1984
|
+
},
|
|
1985
|
+
/** Render a component into the test container */
|
|
1986
|
+
render(component) {
|
|
1987
|
+
const el = typeof component === "function" ? component() : component;
|
|
1988
|
+
container.appendChild(el);
|
|
1989
|
+
return el;
|
|
1990
|
+
},
|
|
1991
|
+
/** Get the test container */
|
|
1992
|
+
getContainer() {
|
|
1993
|
+
return container;
|
|
1994
|
+
},
|
|
1995
|
+
/** Wait for reactive updates to settle */
|
|
1996
|
+
async flush() {
|
|
1997
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
1998
|
+
await new Promise((r) => requestAnimationFrame(() => r()));
|
|
1999
|
+
},
|
|
2000
|
+
/** Query within the container */
|
|
2001
|
+
query(selector) {
|
|
2002
|
+
return container.querySelector(selector);
|
|
2003
|
+
},
|
|
2004
|
+
/** Query all matching elements within the container */
|
|
2005
|
+
queryAll(selector) {
|
|
2006
|
+
return Array.from(container.querySelectorAll(selector));
|
|
2007
|
+
},
|
|
2008
|
+
/** Simulate a click event */
|
|
2009
|
+
click(el) {
|
|
2010
|
+
el.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
|
|
2011
|
+
},
|
|
2012
|
+
/** Simulate input value change */
|
|
2013
|
+
input(el, value) {
|
|
2014
|
+
el.value = value;
|
|
2015
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
2016
|
+
}
|
|
2017
|
+
};
|
|
2018
|
+
}
|
|
2019
|
+
var bundlerMetadata = {
|
|
2020
|
+
name: "sibu",
|
|
2021
|
+
sideEffects: false,
|
|
2022
|
+
modules: {
|
|
2023
|
+
core: ["html", "mount", "each", "slots", "fragment", "catch", "portal", "directives"],
|
|
2024
|
+
hooks: ["signal", "effect", "derived", "watch", "store", "ref", "array", "deepSignal"],
|
|
2025
|
+
plugins: ["router", "i18n"],
|
|
2026
|
+
components: ["ErrorBoundary", "Loading"],
|
|
2027
|
+
ssr: ["ssr"],
|
|
2028
|
+
advanced: ["globalStore", "machine", "optimistic", "timeTravel", "scheduler", "plugin"]
|
|
2029
|
+
},
|
|
2030
|
+
/** Generate import map for module resolution */
|
|
2031
|
+
generateImportMap(base2 = "/node_modules/sibu/") {
|
|
2032
|
+
const map2 = {};
|
|
2033
|
+
for (const [category, modules] of Object.entries(this.modules)) {
|
|
2034
|
+
for (const mod of modules) {
|
|
2035
|
+
const dir = category === "hooks" ? "core" : category;
|
|
2036
|
+
map2[`sibu/${mod}`] = `${base2}src/${dir}/${mod}.js`;
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
return map2;
|
|
2040
|
+
}
|
|
2041
|
+
};
|
|
2042
|
+
function healthCheck() {
|
|
2043
|
+
const checks = [];
|
|
2044
|
+
const hasDOM = typeof document !== "undefined";
|
|
2045
|
+
checks.push({
|
|
2046
|
+
name: "DOM Environment",
|
|
2047
|
+
passed: hasDOM,
|
|
2048
|
+
message: hasDOM ? "DOM is available" : "No DOM environment (SSR mode)"
|
|
2049
|
+
});
|
|
2050
|
+
const hasRAF = typeof requestAnimationFrame !== "undefined";
|
|
2051
|
+
checks.push({
|
|
2052
|
+
name: "requestAnimationFrame",
|
|
2053
|
+
passed: hasRAF,
|
|
2054
|
+
message: hasRAF ? "Available" : "Not available (polyfill may be needed)"
|
|
2055
|
+
});
|
|
2056
|
+
const hasMO = typeof MutationObserver !== "undefined";
|
|
2057
|
+
checks.push({
|
|
2058
|
+
name: "MutationObserver",
|
|
2059
|
+
passed: hasMO,
|
|
2060
|
+
message: hasMO ? "Available" : "Not available (lifecycle hooks may not work)"
|
|
2061
|
+
});
|
|
2062
|
+
const allPassed = checks.every((c) => c.passed);
|
|
2063
|
+
return {
|
|
2064
|
+
status: allPassed ? "ok" : "warning",
|
|
2065
|
+
checks
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2068
|
+
var env = {
|
|
2069
|
+
/** True when running in a browser with a DOM */
|
|
2070
|
+
isBrowser: typeof window !== "undefined" && typeof document !== "undefined",
|
|
2071
|
+
/** True when running in Node.js */
|
|
2072
|
+
isNode: typeof process !== "undefined" && !!process.versions?.node,
|
|
2073
|
+
/** True when running inside a Web Worker */
|
|
2074
|
+
isWorker: typeof self !== "undefined" && typeof self.importScripts === "function",
|
|
2075
|
+
/** True when running inside Deno */
|
|
2076
|
+
isDeno: typeof globalThis.Deno !== "undefined",
|
|
2077
|
+
/** True when running inside Bun */
|
|
2078
|
+
isBun: typeof globalThis.Bun !== "undefined",
|
|
2079
|
+
/** True when no window object is available (server-side rendering) */
|
|
2080
|
+
isSSR: typeof window === "undefined",
|
|
2081
|
+
/** True when NODE_ENV is not "production" */
|
|
2082
|
+
isDev: typeof process !== "undefined" && process.env?.NODE_ENV !== "production",
|
|
2083
|
+
/** True when NODE_ENV is "test" or VITEST is set */
|
|
2084
|
+
isTest: typeof process !== "undefined" && (process.env?.NODE_ENV === "test" || process.env?.VITEST === "true")
|
|
2085
|
+
};
|
|
2086
|
+
|
|
2087
|
+
// src/core/rendering/tagFactory.ts
|
|
2088
|
+
init_dev();
|
|
2089
|
+
|
|
2090
|
+
// src/reactivity/bindAttribute.ts
|
|
2091
|
+
init_errors();
|
|
2092
|
+
init_sanitize();
|
|
2093
|
+
|
|
2094
|
+
// src/utils/setSafeAttribute.ts
|
|
2095
|
+
init_dev();
|
|
2096
|
+
init_elementPolicy();
|
|
2097
|
+
init_sanitize();
|
|
2098
|
+
var HTML_NS2 = "http://www.w3.org/1999/xhtml";
|
|
2099
|
+
var SVG_NS2 = "http://www.w3.org/2000/svg";
|
|
2100
|
+
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
2101
|
+
var XML_NS = "http://www.w3.org/XML/1998/namespace";
|
|
2102
|
+
var BOOLEAN_IDL_ATTRS = /* @__PURE__ */ new Set(["checked", "disabled", "selected"]);
|
|
2103
|
+
function isHtmlElement(el) {
|
|
2104
|
+
return el.namespaceURI === null || el.namespaceURI === HTML_NS2;
|
|
2105
|
+
}
|
|
2106
|
+
function warnContextualRefusal(label2, name, refusal) {
|
|
2107
|
+
devWarnLazy(() => {
|
|
2108
|
+
const reasons = [
|
|
2109
|
+
"",
|
|
2110
|
+
'the element would become a <meta http-equiv="refresh"> directive the shared refresh policy forbids (a destination outside the URL allowlist, or a directive too malformed to read unambiguously)',
|
|
2111
|
+
"a <meta> whose http-equiv or content is reactive may never carry a refresh directive: a browser schedules the navigation as soon as the directive is valid, and nothing can withdraw it when the state changes back",
|
|
2112
|
+
"a runtime value may not choose the program a <script> runs; name the script in static template source, or load it through Head({ script }) as an explicit trust decision",
|
|
2113
|
+
"an SVG animation may not target a URL, event-handler or nested-document attribute; its to / values would be written into that attribute without passing the URL policy",
|
|
2114
|
+
'a runtime-chosen href may not become an applied <link rel="stylesheet">: a well-formed URL is not a trusted stylesheet. Name the stylesheet in static template source, or load a runtime-chosen one through Head({ link }) as an explicit trust decision'
|
|
2115
|
+
];
|
|
2116
|
+
return `${label2}: refusing "${name}" in this element's context \u2014 ${reasons[refusal]}. The write was not performed.`;
|
|
2117
|
+
});
|
|
2118
|
+
}
|
|
2119
|
+
function setProp(el, key, val) {
|
|
2120
|
+
el[key] = val;
|
|
2121
|
+
}
|
|
2122
|
+
function namespaceFor(el, name) {
|
|
2123
|
+
if (el.namespaceURI !== SVG_NS2) return null;
|
|
2124
|
+
const lower = name.toLowerCase();
|
|
2125
|
+
if (lower.startsWith("xlink:")) return XLINK_NS;
|
|
2126
|
+
if (lower.startsWith("xml:")) return XML_NS;
|
|
2127
|
+
return null;
|
|
2128
|
+
}
|
|
2129
|
+
function setSafeAttribute(el, name, value, options = {}) {
|
|
2130
|
+
const written = commitSafeAttribute(el, name, value, options);
|
|
2131
|
+
if (el.localName === "link") settleAttributeProvenance(el, name, options.reactive ? "reactive" : "runtime");
|
|
2132
|
+
return written;
|
|
2133
|
+
}
|
|
2134
|
+
function commitSafeAttribute(el, name, value, options) {
|
|
2135
|
+
const ns = namespaceFor(el, name);
|
|
2136
|
+
const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
|
|
2137
|
+
if (isEventHandlerAttr(name)) {
|
|
2138
|
+
if (DEV) {
|
|
2139
|
+
devWarn(
|
|
2140
|
+
`${options.label ?? "setSafeAttribute"}: refusing to set event-handler attribute "${name}". Its value would be evaluated as JavaScript. Use on:{ ${name.slice(2)}: fn } instead.`
|
|
2141
|
+
);
|
|
2142
|
+
}
|
|
2143
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
2144
|
+
else el.removeAttribute(name);
|
|
2145
|
+
return false;
|
|
2146
|
+
}
|
|
2147
|
+
const pending = value == null || value === false ? null : value === true ? "" : String(value);
|
|
2148
|
+
const refusal = contextualAttributeRefusal(el, name, pending, options.reactive ? "reactive" : "runtime");
|
|
2149
|
+
if (refusal !== ContextualRefusal.None) {
|
|
2150
|
+
warnContextualRefusal(options.label ?? "setSafeAttribute", name, refusal);
|
|
2151
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
2152
|
+
else el.removeAttribute(name);
|
|
2153
|
+
return false;
|
|
2154
|
+
}
|
|
2155
|
+
if (value == null) {
|
|
2156
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
2157
|
+
else el.removeAttribute(name);
|
|
2158
|
+
return true;
|
|
2159
|
+
}
|
|
2160
|
+
if (isHtmlContentAttribute(name)) {
|
|
2161
|
+
if (DEV) {
|
|
2162
|
+
devWarn(
|
|
2163
|
+
`${options.label ?? "setSafeAttribute"}: refusing to set "${name}". The browser parses this attribute as a nested HTML document, so a generic string value cannot be made safe \u2014 attribute escaping is undone before the parse. Build the frame's content another way.`
|
|
2164
|
+
);
|
|
2165
|
+
}
|
|
2166
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
2167
|
+
else el.removeAttribute(name);
|
|
2168
|
+
return false;
|
|
2169
|
+
}
|
|
2170
|
+
const html2 = isHtmlElement(el);
|
|
2171
|
+
const idlName = html2 ? name.toLowerCase() : name;
|
|
2172
|
+
if (typeof value === "boolean") {
|
|
2173
|
+
if (name.length > 5 && name.slice(0, 5).toLowerCase() === "aria-") {
|
|
2174
|
+
const token = value ? "true" : "false";
|
|
2175
|
+
if ((ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name)) !== token) {
|
|
2176
|
+
if (ns) el.setAttributeNS(ns, name, token);
|
|
2177
|
+
else el.setAttribute(name, token);
|
|
2178
|
+
}
|
|
2179
|
+
return true;
|
|
2180
|
+
}
|
|
2059
2181
|
if (html2 && BOOLEAN_IDL_ATTRS.has(idlName) && idlName in el) {
|
|
2060
2182
|
setProp(el, idlName, value);
|
|
2061
2183
|
} else if (value) {
|
|
@@ -2253,6 +2375,7 @@ function bindOwnerScope(fn) {
|
|
|
2253
2375
|
if (scope === null) return fn;
|
|
2254
2376
|
return (...args) => runWithOwnerScope(scope, () => fn(...args));
|
|
2255
2377
|
}
|
|
2378
|
+
var currentStructOwner = null;
|
|
2256
2379
|
var subscriberEpochCounter = 0;
|
|
2257
2380
|
function retrack(effectFn, subscriber) {
|
|
2258
2381
|
const prev = currentSubscriber;
|
|
@@ -2272,6 +2395,9 @@ function retrack(effectFn, subscriber) {
|
|
|
2272
2395
|
if (prevScope !== null && !sub2._epoch && sub2._scope === void 0) sub2._scope = prevScope;
|
|
2273
2396
|
const scope = sub2._scope === void 0 ? null : sub2._scope;
|
|
2274
2397
|
if (scope !== prevScope) currentOwnerScope = scope;
|
|
2398
|
+
const prevStructOwner = currentStructOwner;
|
|
2399
|
+
if (prevStructOwner !== null && !sub2._epoch && !sub2._c && sub2._owner == null) sub2._owner = prevStructOwner;
|
|
2400
|
+
if (sub2._tok != null) currentStructOwner = sub2._tok;
|
|
2275
2401
|
const epoch = ++subscriberEpochCounter;
|
|
2276
2402
|
sub2._epoch = epoch;
|
|
2277
2403
|
sub2._structDirty = false;
|
|
@@ -2285,6 +2411,7 @@ function retrack(effectFn, subscriber) {
|
|
|
2285
2411
|
} finally {
|
|
2286
2412
|
currentSubscriber = prev;
|
|
2287
2413
|
currentOwnerScope = prevScope;
|
|
2414
|
+
currentStructOwner = prevStructOwner;
|
|
2288
2415
|
if (savedDepth !== 0) {
|
|
2289
2416
|
suspendDepth = savedDepth;
|
|
2290
2417
|
suspendSavedSub = savedSuspendSub;
|
|
@@ -2341,7 +2468,25 @@ function track(effectFn, subscriber) {
|
|
|
2341
2468
|
}
|
|
2342
2469
|
return sub2._dispose ?? (sub2._dispose = () => cleanup(subscriber));
|
|
2343
2470
|
}
|
|
2344
|
-
function reactiveBinding(commit, ownerNode) {
|
|
2471
|
+
function reactiveBinding(commit, ownerNode, structural) {
|
|
2472
|
+
return createBinding(commit, ownerNode, structural === true)._dispose;
|
|
2473
|
+
}
|
|
2474
|
+
function structuralBinding(commit, ownerNode) {
|
|
2475
|
+
const sub2 = createBinding(commit, ownerNode, true);
|
|
2476
|
+
return {
|
|
2477
|
+
stop: sub2._dispose,
|
|
2478
|
+
run: (fn) => {
|
|
2479
|
+
const prev = currentStructOwner;
|
|
2480
|
+
currentStructOwner = sub2._tok ?? null;
|
|
2481
|
+
try {
|
|
2482
|
+
return fn();
|
|
2483
|
+
} finally {
|
|
2484
|
+
currentStructOwner = prev;
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
};
|
|
2488
|
+
}
|
|
2489
|
+
function createBinding(commit, ownerNode, structural) {
|
|
2345
2490
|
const run = () => {
|
|
2346
2491
|
const s2 = subscriber;
|
|
2347
2492
|
if (s2._disposed || s2._reentrant) return;
|
|
@@ -2364,19 +2509,25 @@ function reactiveBinding(commit, ownerNode) {
|
|
|
2364
2509
|
subscriber._disposed = false;
|
|
2365
2510
|
subscriber._errorPhase = "binding";
|
|
2366
2511
|
subscriber._errorNode = ownerNode;
|
|
2512
|
+
subscriber._tok = null;
|
|
2513
|
+
subscriber._owner = null;
|
|
2514
|
+
if (structural) subscriber._tok = { sub: subscriber };
|
|
2367
2515
|
try {
|
|
2368
2516
|
run();
|
|
2369
2517
|
} catch (err) {
|
|
2370
2518
|
subscriber._disposed = true;
|
|
2371
2519
|
subscriber._errorNode = void 0;
|
|
2520
|
+
if (subscriber._tok != null) subscriber._tok.sub = null;
|
|
2372
2521
|
cleanup(subscriber);
|
|
2373
2522
|
throw err;
|
|
2374
2523
|
}
|
|
2375
|
-
|
|
2524
|
+
subscriber._dispose = () => {
|
|
2376
2525
|
subscriber._disposed = true;
|
|
2377
2526
|
subscriber._errorNode = void 0;
|
|
2527
|
+
if (subscriber._tok != null) subscriber._tok.sub = null;
|
|
2378
2528
|
cleanup(subscriber);
|
|
2379
|
-
}
|
|
2529
|
+
};
|
|
2530
|
+
return subscriber;
|
|
2380
2531
|
}
|
|
2381
2532
|
function recordDependency(signal2) {
|
|
2382
2533
|
if (!currentSubscriber) return;
|
|
@@ -2400,6 +2551,7 @@ function recordDependency(signal2) {
|
|
|
2400
2551
|
}
|
|
2401
2552
|
function cleanup(subscriber) {
|
|
2402
2553
|
const sub2 = subscriber;
|
|
2554
|
+
if (sub2._owner != null) sub2._owner = null;
|
|
2403
2555
|
let node = sub2.depsHead ?? null;
|
|
2404
2556
|
sub2.depsHead = null;
|
|
2405
2557
|
sub2.depsTail = null;
|
|
@@ -2459,20 +2611,41 @@ function drainQueue() {
|
|
|
2459
2611
|
break;
|
|
2460
2612
|
}
|
|
2461
2613
|
const sub2 = pendingQueue[i2++];
|
|
2462
|
-
pendingSet.delete(sub2);
|
|
2463
|
-
if (
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2614
|
+
if (!pendingSet.delete(sub2)) continue;
|
|
2615
|
+
if (sub2._owner != null && pendingSet.size > 0) {
|
|
2616
|
+
runPendingOwners(sub2);
|
|
2617
|
+
if (pendingSet.has(sub2)) continue;
|
|
2618
|
+
}
|
|
2619
|
+
runQueued(sub2);
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
function runPendingOwners(sub2) {
|
|
2623
|
+
for (; ; ) {
|
|
2624
|
+
let outer = null;
|
|
2625
|
+
for (let t2 = sub2._owner ?? null; t2 !== null; ) {
|
|
2626
|
+
const o = t2.sub;
|
|
2627
|
+
if (o === null) break;
|
|
2628
|
+
if (pendingSet.has(o)) outer = o;
|
|
2629
|
+
t2 = o._owner ?? null;
|
|
2630
|
+
}
|
|
2631
|
+
if (outer === null) return;
|
|
2632
|
+
pendingSet.delete(outer);
|
|
2633
|
+
runQueued(outer);
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
function runQueued(sub2) {
|
|
2637
|
+
if (quarantined.size > 0 && quarantined.has(sub2)) return;
|
|
2638
|
+
if (sub2._hasComputedDep === true && !depsChanged(sub2)) return;
|
|
2639
|
+
if (tickRepeat(sub2)) {
|
|
2640
|
+
cycleError(sub2);
|
|
2641
|
+
quarantined.add(sub2);
|
|
2642
|
+
return;
|
|
2643
|
+
}
|
|
2644
|
+
const pushed = beginDisposerCapture(sub2._cap ?? null);
|
|
2645
|
+
try {
|
|
2646
|
+
safeInvoke(sub2);
|
|
2647
|
+
} finally {
|
|
2648
|
+
if (pushed) endDisposerCapture();
|
|
2476
2649
|
}
|
|
2477
2650
|
}
|
|
2478
2651
|
function drainNotificationQueue() {
|
|
@@ -2608,7 +2781,7 @@ function forEachSubscriber(signal2, visit) {
|
|
|
2608
2781
|
}
|
|
2609
2782
|
|
|
2610
2783
|
// src/reactivity/track.ts
|
|
2611
|
-
var _runtimeVersion = true ? "4.
|
|
2784
|
+
var _runtimeVersion = true ? "4.13.1" : "dev";
|
|
2612
2785
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
2613
2786
|
function resolveReactiveApi() {
|
|
2614
2787
|
const g2 = globalThis;
|
|
@@ -2643,6 +2816,7 @@ function resolveReactiveApi() {
|
|
|
2643
2816
|
getOwnerScope,
|
|
2644
2817
|
runWithOwnerScope,
|
|
2645
2818
|
bindOwnerScope,
|
|
2819
|
+
structuralBinding,
|
|
2646
2820
|
version: _runtimeVersion
|
|
2647
2821
|
};
|
|
2648
2822
|
g2[REGISTRY_KEY] = local;
|
|
@@ -2669,6 +2843,7 @@ var forEachSubscriber2 = API.forEachSubscriber;
|
|
|
2669
2843
|
var getOwnerScope2 = API.getOwnerScope ?? getOwnerScope;
|
|
2670
2844
|
var runWithOwnerScope2 = API.runWithOwnerScope ?? runWithOwnerScope;
|
|
2671
2845
|
var bindOwnerScope2 = API.bindOwnerScope ?? bindOwnerScope;
|
|
2846
|
+
var structuralBinding2 = API.structuralBinding ?? ((commit, ownerNode) => ({ stop: API.reactiveBinding(commit, ownerNode), run: (fn) => fn() }));
|
|
2672
2847
|
|
|
2673
2848
|
// src/reactivity/bindAttribute.ts
|
|
2674
2849
|
function bindAttribute(el, attr, getter) {
|
|
@@ -2764,9 +2939,10 @@ function refocus(el, snapshot) {
|
|
|
2764
2939
|
field.setSelectionRange(start, end, snapshot.direction ?? "none");
|
|
2765
2940
|
}
|
|
2766
2941
|
}
|
|
2767
|
-
function restoreFocusWithin(snapshot, nodes, where) {
|
|
2942
|
+
function restoreFocusWithin(snapshot, nodes, where, policy) {
|
|
2768
2943
|
if (!snapshot) return;
|
|
2769
2944
|
if (typeof document === "undefined") return;
|
|
2945
|
+
if (policy === "discard") return;
|
|
2770
2946
|
const active = document.activeElement;
|
|
2771
2947
|
if (active === snapshot.el) return;
|
|
2772
2948
|
if (active && active !== document.body && active !== document.documentElement) return;
|
|
@@ -2783,10 +2959,17 @@ function restoreFocusWithin(snapshot, nodes, where) {
|
|
|
2783
2959
|
}
|
|
2784
2960
|
ambiguous = count > 1;
|
|
2785
2961
|
}
|
|
2962
|
+
if (policy !== void 0 && typeof policy === "object") {
|
|
2963
|
+
const target = typeof policy.restoreTo === "function" ? policy.restoreTo() : policy.restoreTo;
|
|
2964
|
+
if (target?.isConnected) {
|
|
2965
|
+
target.focus();
|
|
2966
|
+
if (document.activeElement === target) return;
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2786
2969
|
devWarnLazy(() => {
|
|
2787
2970
|
const id = snapshot.attr ? ` (${snapshot.attr}="${snapshot.value}")` : "";
|
|
2788
2971
|
const why = ambiguous ? `several elements in the rebuilt subtree share ${snapshot.attr}="${snapshot.value}", so there is no way to tell which one the user was in \u2014 a shared name (a radio group) identifies a GROUP, not a control. Add a unique id or data-focus-key to each` : "no element in the rebuilt subtree carries the same identity. Give it a stable id, name, or data-focus-key that the rebuild reproduces";
|
|
2789
|
-
return `${where}: a reactive rebuild discarded the focused element <${snapshot.tag.toLowerCase()}>${id} and could not re-establish it, so focus fell back to <body>. An in-progress edit ends here, and an in-progress IME composition is lost outright \u2014 a composition belongs to the DOM node, so it cannot survive the node being destroyed. ${why}, or stop the rebuild from happening: key the subtree with match(() => shapeKey(), { \u2026 }) so it is re-created only when the shape actually changes, and drive the rest with reactive attributes and text children, which mutate nodes in place instead of replacing them
|
|
2972
|
+
return `${where}: a reactive rebuild discarded the focused element <${snapshot.tag.toLowerCase()}>${id} and could not re-establish it, so focus fell back to <body>. An in-progress edit ends here, and an in-progress IME composition is lost outright \u2014 a composition belongs to the DOM node, so it cannot survive the node being destroyed. ${why}, or stop the rebuild from happening: key the subtree with match(() => shapeKey(), { \u2026 }) so it is re-created only when the shape actually changes, and drive the rest with reactive attributes and text children, which mutate nodes in place instead of replacing them. If dropping focus is INTENDED here (closing a panel, say), pass { focus: "discard" } to when()/match() to silence this, or { focus: { restoreTo: element } } to send focus somewhere other than <body>.`;
|
|
2790
2973
|
});
|
|
2791
2974
|
}
|
|
2792
2975
|
|
|
@@ -2861,7 +3044,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
2861
3044
|
lastNodes = newNodes;
|
|
2862
3045
|
restoreFocusWithin(focused, newNodes, "bindChildNode");
|
|
2863
3046
|
}
|
|
2864
|
-
return reactiveBinding2(commit, placeholder);
|
|
3047
|
+
return reactiveBinding2(commit, placeholder, true);
|
|
2865
3048
|
}
|
|
2866
3049
|
|
|
2867
3050
|
// src/core/rendering/tagFactory.ts
|
|
@@ -3518,37 +3701,451 @@ function getAvailableLocales() {
|
|
|
3518
3701
|
return Object.keys(locales);
|
|
3519
3702
|
}
|
|
3520
3703
|
|
|
3521
|
-
// src/plugins/
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
var _g2 = globalThis;
|
|
3530
|
-
var MAX_RERUNS = 100;
|
|
3531
|
-
function flushUserCleanups(ctx) {
|
|
3532
|
-
const list = ctx.userCleanups;
|
|
3533
|
-
if (list.length === 0) return;
|
|
3534
|
-
ctx.userCleanups = [];
|
|
3535
|
-
const scope = ctx.subscriber._scope ?? null;
|
|
3536
|
-
if (scope === getOwnerScope2()) runCleanups(list);
|
|
3537
|
-
else runWithOwnerScope2(scope, () => runCleanups(list));
|
|
3538
|
-
}
|
|
3539
|
-
function runCleanups(list) {
|
|
3540
|
-
for (let i2 = list.length - 1; i2 >= 0; i2--) {
|
|
3541
|
-
try {
|
|
3542
|
-
list[i2]();
|
|
3543
|
-
} catch (err) {
|
|
3544
|
-
reportError(err, { phase: "cleanup" });
|
|
3704
|
+
// src/plugins/modular.ts
|
|
3705
|
+
function createModuleRegistry() {
|
|
3706
|
+
const modules = /* @__PURE__ */ new Map();
|
|
3707
|
+
const resolving = [];
|
|
3708
|
+
function resolveInternal(name) {
|
|
3709
|
+
const entry = modules.get(name);
|
|
3710
|
+
if (!entry) {
|
|
3711
|
+
throw new Error(`[ModuleRegistry] Module "${name}" is not registered.`);
|
|
3545
3712
|
}
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3713
|
+
if (entry.state === "loaded") {
|
|
3714
|
+
return entry.value;
|
|
3715
|
+
}
|
|
3716
|
+
if (entry.state === "resolving") {
|
|
3717
|
+
const cycle = [...resolving.slice(resolving.indexOf(name)), name].join(" -> ");
|
|
3718
|
+
throw new Error(`[ModuleRegistry] Circular dependency detected: ${cycle}`);
|
|
3719
|
+
}
|
|
3720
|
+
entry.state = "resolving";
|
|
3721
|
+
resolving.push(name);
|
|
3722
|
+
try {
|
|
3723
|
+
for (const dep of entry.deps) {
|
|
3724
|
+
resolveInternal(dep);
|
|
3725
|
+
}
|
|
3726
|
+
entry.value = entry.factory();
|
|
3727
|
+
entry.state = "loaded";
|
|
3728
|
+
return entry.value;
|
|
3729
|
+
} catch (err) {
|
|
3730
|
+
entry.state = "unloaded";
|
|
3731
|
+
entry.value = void 0;
|
|
3732
|
+
throw err;
|
|
3733
|
+
} finally {
|
|
3734
|
+
resolving.pop();
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3737
|
+
return {
|
|
3738
|
+
/** Register a module with its factory function and optional dependencies */
|
|
3739
|
+
register(name, factory, deps = []) {
|
|
3740
|
+
modules.set(name, { factory, deps, state: "unloaded" });
|
|
3741
|
+
},
|
|
3742
|
+
/** Resolve a module, loading its dependencies first */
|
|
3743
|
+
resolve(name) {
|
|
3744
|
+
return resolveInternal(name);
|
|
3745
|
+
},
|
|
3746
|
+
/** Check if a module is registered */
|
|
3747
|
+
has(name) {
|
|
3748
|
+
return modules.has(name);
|
|
3749
|
+
},
|
|
3750
|
+
/** List all registered module names */
|
|
3751
|
+
list() {
|
|
3752
|
+
return Array.from(modules.keys());
|
|
3753
|
+
},
|
|
3754
|
+
/** Get the full dependency graph (transitive) for a module */
|
|
3755
|
+
deps(name) {
|
|
3756
|
+
const entry = modules.get(name);
|
|
3757
|
+
if (!entry) {
|
|
3758
|
+
throw new Error(`[ModuleRegistry] Module "${name}" is not registered.`);
|
|
3759
|
+
}
|
|
3760
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3761
|
+
const result = [];
|
|
3762
|
+
function walk(modName) {
|
|
3763
|
+
const mod = modules.get(modName);
|
|
3764
|
+
if (!mod) return;
|
|
3765
|
+
for (const dep of mod.deps) {
|
|
3766
|
+
if (!visited.has(dep)) {
|
|
3767
|
+
visited.add(dep);
|
|
3768
|
+
walk(dep);
|
|
3769
|
+
result.push(dep);
|
|
3770
|
+
}
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
walk(name);
|
|
3774
|
+
return result;
|
|
3775
|
+
},
|
|
3776
|
+
/** Reset all loaded modules back to unloaded state (useful for testing) */
|
|
3777
|
+
reset() {
|
|
3778
|
+
for (const entry of modules.values()) {
|
|
3779
|
+
entry.state = "unloaded";
|
|
3780
|
+
entry.value = void 0;
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
};
|
|
3784
|
+
}
|
|
3785
|
+
function createBundle(modules) {
|
|
3786
|
+
const cache = /* @__PURE__ */ new Map();
|
|
3787
|
+
const bundle = {};
|
|
3788
|
+
for (const key of Object.keys(modules)) {
|
|
3789
|
+
Object.defineProperty(bundle, key, {
|
|
3790
|
+
get() {
|
|
3791
|
+
if (cache.has(key)) {
|
|
3792
|
+
return cache.get(key);
|
|
3793
|
+
}
|
|
3794
|
+
const value = modules[key]();
|
|
3795
|
+
cache.set(key, value);
|
|
3796
|
+
return value;
|
|
3797
|
+
},
|
|
3798
|
+
enumerable: true,
|
|
3799
|
+
configurable: false
|
|
3800
|
+
});
|
|
3801
|
+
}
|
|
3802
|
+
return bundle;
|
|
3803
|
+
}
|
|
3804
|
+
function lazyModule(loader) {
|
|
3805
|
+
let cached;
|
|
3806
|
+
let loadedFlag = false;
|
|
3807
|
+
let inFlight = null;
|
|
3808
|
+
return {
|
|
3809
|
+
get loaded() {
|
|
3810
|
+
return loadedFlag;
|
|
3811
|
+
},
|
|
3812
|
+
get() {
|
|
3813
|
+
if (loadedFlag) return Promise.resolve(cached);
|
|
3814
|
+
if (inFlight) return inFlight;
|
|
3815
|
+
let started;
|
|
3816
|
+
try {
|
|
3817
|
+
started = Promise.resolve(loader());
|
|
3818
|
+
} catch (err) {
|
|
3819
|
+
started = Promise.reject(err);
|
|
3820
|
+
}
|
|
3821
|
+
const attempt = started.then(
|
|
3822
|
+
(value) => {
|
|
3823
|
+
cached = value;
|
|
3824
|
+
loadedFlag = true;
|
|
3825
|
+
if (inFlight === attempt) inFlight = null;
|
|
3826
|
+
return value;
|
|
3827
|
+
},
|
|
3828
|
+
(err) => {
|
|
3829
|
+
if (inFlight === attempt) inFlight = null;
|
|
3830
|
+
throw err;
|
|
3831
|
+
}
|
|
3832
|
+
);
|
|
3833
|
+
inFlight = attempt;
|
|
3834
|
+
return attempt;
|
|
3835
|
+
}
|
|
3836
|
+
};
|
|
3837
|
+
}
|
|
3838
|
+
var MODULE_ENTRY_POINTS = {
|
|
3839
|
+
main: "./index.ts",
|
|
3840
|
+
data: "./data.ts",
|
|
3841
|
+
browser: "./browser.ts",
|
|
3842
|
+
patterns: "./patterns.ts",
|
|
3843
|
+
motion: "./motion.ts",
|
|
3844
|
+
ui: "./ui.ts",
|
|
3845
|
+
widgets: "./widgets.ts",
|
|
3846
|
+
ssr: "./ssr.ts",
|
|
3847
|
+
devtools: "./devtools.ts",
|
|
3848
|
+
performance: "./performance.ts",
|
|
3849
|
+
ecosystem: "./ecosystem.ts",
|
|
3850
|
+
plugins: "./plugins.ts",
|
|
3851
|
+
build: "./build.ts",
|
|
3852
|
+
testing: "./testing.ts",
|
|
3853
|
+
extras: "./extras.ts"
|
|
3854
|
+
};
|
|
3855
|
+
var CDN_ENTRY_POINTS = {
|
|
3856
|
+
cdn: "./dist/cdn.global.js",
|
|
3857
|
+
"cdn-dev": "./dist/cdn.dev.global.js",
|
|
3858
|
+
"cdn-full": "./dist/cdn.full.global.js",
|
|
3859
|
+
"cdn-full-dev": "./dist/cdn.full.dev.global.js"
|
|
3860
|
+
};
|
|
3861
|
+
var packageInfo = {
|
|
3862
|
+
name: "sibujs",
|
|
3863
|
+
version: true ? "4.13.1" : "dev",
|
|
3864
|
+
entryPoints: MODULE_ENTRY_POINTS,
|
|
3865
|
+
/**
|
|
3866
|
+
* Generate the package.json `exports` map. Module entries resolve to the
|
|
3867
|
+
* `.js` (ESM), `.cjs` and `.d.ts` files tsup emits into `dist/`; CDN entries
|
|
3868
|
+
* resolve to their prebuilt global script.
|
|
3869
|
+
*/
|
|
3870
|
+
generateExportsMap() {
|
|
3871
|
+
const exportsMap = {};
|
|
3872
|
+
for (const [name, sourcePath] of Object.entries(MODULE_ENTRY_POINTS)) {
|
|
3873
|
+
const distPath = sourcePath.replace(/^\.\//, "./dist/").replace(/\.ts$/, "");
|
|
3874
|
+
const subpath = name === "main" ? "." : `./${name}`;
|
|
3875
|
+
exportsMap[subpath] = {
|
|
3876
|
+
types: `${distPath}.d.ts`,
|
|
3877
|
+
import: `${distPath}.js`,
|
|
3878
|
+
require: `${distPath}.cjs`
|
|
3879
|
+
};
|
|
3880
|
+
}
|
|
3881
|
+
for (const [name, file] of Object.entries(CDN_ENTRY_POINTS)) {
|
|
3882
|
+
exportsMap[`./${name}`] = { default: file };
|
|
3883
|
+
}
|
|
3884
|
+
return exportsMap;
|
|
3885
|
+
}
|
|
3886
|
+
};
|
|
3887
|
+
|
|
3888
|
+
// src/plugins/plugin.ts
|
|
3889
|
+
init_dev();
|
|
3890
|
+
init_errors();
|
|
3891
|
+
|
|
3892
|
+
// src/utils/adoptThenable.ts
|
|
3893
|
+
function adoptThenable(value) {
|
|
3894
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return null;
|
|
3895
|
+
let then;
|
|
3896
|
+
try {
|
|
3897
|
+
then = value.then;
|
|
3898
|
+
} catch (error) {
|
|
3899
|
+
return Promise.reject(error);
|
|
3900
|
+
}
|
|
3901
|
+
if (typeof then !== "function") return null;
|
|
3902
|
+
return new Promise((resolve, reject) => {
|
|
3903
|
+
queueMicrotask(() => {
|
|
3904
|
+
try {
|
|
3905
|
+
Reflect.apply(then, value, [resolve, reject]);
|
|
3906
|
+
} catch (error) {
|
|
3907
|
+
reject(error);
|
|
3908
|
+
}
|
|
3909
|
+
});
|
|
3910
|
+
});
|
|
3911
|
+
}
|
|
3912
|
+
|
|
3913
|
+
// src/plugins/plugin.ts
|
|
3914
|
+
init_globalSingleton();
|
|
3915
|
+
var CANCELLED_BRAND = /* @__PURE__ */ Symbol.for("sibujs.plugins.installCancelled.v1");
|
|
3916
|
+
var _a;
|
|
3917
|
+
var PluginInstallCancelledError = class extends Error {
|
|
3918
|
+
constructor(pluginName) {
|
|
3919
|
+
super(`[Plugin] Installation of "${pluginName}" was cancelled before it was committed (registry reset).`);
|
|
3920
|
+
/**
|
|
3921
|
+
* Brand, not identity: the default registry is shared across duplicate copies
|
|
3922
|
+
* of this module, so the error a caller receives may come from another copy's
|
|
3923
|
+
* constructor. `instanceof` is taught to recognise the brand instead.
|
|
3924
|
+
*/
|
|
3925
|
+
this[_a] = true;
|
|
3926
|
+
this.name = "PluginInstallCancelledError";
|
|
3927
|
+
this.pluginName = pluginName;
|
|
3928
|
+
}
|
|
3929
|
+
static [(_a = CANCELLED_BRAND, Symbol.hasInstance)](value) {
|
|
3930
|
+
return isPluginInstallCancelledError(value);
|
|
3931
|
+
}
|
|
3932
|
+
};
|
|
3933
|
+
function isPluginInstallCancelledError(value) {
|
|
3934
|
+
return typeof value === "object" && value !== null && value[CANCELLED_BRAND] === true;
|
|
3935
|
+
}
|
|
3936
|
+
function createPluginRegistry() {
|
|
3937
|
+
const installedPlugins = /* @__PURE__ */ new Set();
|
|
3938
|
+
const hooks = { init: [], mount: [], unmount: [], error: [] };
|
|
3939
|
+
const provided = /* @__PURE__ */ new Map();
|
|
3940
|
+
const installStack = /* @__PURE__ */ new Set();
|
|
3941
|
+
const pendingInstalls = /* @__PURE__ */ new Map();
|
|
3942
|
+
let generation = 0;
|
|
3943
|
+
const registry = {
|
|
3944
|
+
installedPlugins,
|
|
3945
|
+
hooks,
|
|
3946
|
+
provided,
|
|
3947
|
+
/**
|
|
3948
|
+
* Install a plugin as a transaction.
|
|
3949
|
+
*
|
|
3950
|
+
* Hooks and providers registered through `ctx` are staged and committed
|
|
3951
|
+
* only if `install()` returns; a throwing install leaves the registry
|
|
3952
|
+
* exactly as it found it (and can simply be retried). The plugin is marked
|
|
3953
|
+
* installed at commit, before its init hooks run.
|
|
3954
|
+
*
|
|
3955
|
+
* Each `plugin()` call is its own transaction: a dependency installed by a
|
|
3956
|
+
* nested `plugin()` call commits on its own and stays installed even if the
|
|
3957
|
+
* outer installation later fails.
|
|
3958
|
+
*/
|
|
3959
|
+
plugin(p2, options) {
|
|
3960
|
+
if (installedPlugins.has(p2.name)) {
|
|
3961
|
+
console.warn(`[Plugin] "${p2.name}" is already installed.`);
|
|
3962
|
+
return;
|
|
3963
|
+
}
|
|
3964
|
+
if (installStack.has(p2.name)) {
|
|
3965
|
+
throw new Error(`[Plugin] "${p2.name}" is already being installed (recursive installation).`);
|
|
3966
|
+
}
|
|
3967
|
+
if (pendingInstalls.has(p2.name)) {
|
|
3968
|
+
throw new Error(`[Plugin] "${p2.name}" is already being installed (asynchronous installation in flight).`);
|
|
3969
|
+
}
|
|
3970
|
+
const staged = { init: [], mount: [], unmount: [], error: [] };
|
|
3971
|
+
const stagedProvided = /* @__PURE__ */ new Map();
|
|
3972
|
+
let committed = false;
|
|
3973
|
+
const myGeneration = generation;
|
|
3974
|
+
const stale = () => {
|
|
3975
|
+
if (myGeneration === generation) return false;
|
|
3976
|
+
if (DEV) devWarn(`plugin: "${p2.name}" registered after the registry was reset; the registration was ignored.`);
|
|
3977
|
+
return true;
|
|
3978
|
+
};
|
|
3979
|
+
const target = () => stale() ? null : committed ? hooks : staged;
|
|
3980
|
+
const ctx = {
|
|
3981
|
+
onInit: (cb) => void target()?.init.push(cb),
|
|
3982
|
+
onMount: (cb) => void target()?.mount.push(cb),
|
|
3983
|
+
onUnmount: (cb) => void target()?.unmount.push(cb),
|
|
3984
|
+
onError: (cb) => void target()?.error.push(cb),
|
|
3985
|
+
provide: (key, value) => {
|
|
3986
|
+
if (stale()) return;
|
|
3987
|
+
(committed ? provided : stagedProvided).set(key, value);
|
|
3988
|
+
}
|
|
3989
|
+
};
|
|
3990
|
+
const commit = () => {
|
|
3991
|
+
if (myGeneration !== generation) return false;
|
|
3992
|
+
hooks.init.push(...staged.init);
|
|
3993
|
+
hooks.mount.push(...staged.mount);
|
|
3994
|
+
hooks.unmount.push(...staged.unmount);
|
|
3995
|
+
hooks.error.push(...staged.error);
|
|
3996
|
+
for (const [key, value] of stagedProvided) provided.set(key, value);
|
|
3997
|
+
installedPlugins.add(p2.name);
|
|
3998
|
+
committed = true;
|
|
3999
|
+
if (pendingInstalls.get(p2.name) === myGeneration) pendingInstalls.delete(p2.name);
|
|
4000
|
+
for (const cb of staged.init.slice()) {
|
|
4001
|
+
try {
|
|
4002
|
+
cb();
|
|
4003
|
+
} catch (e) {
|
|
4004
|
+
console.error(`[Plugin] "${p2.name}" init error:`, e);
|
|
4005
|
+
}
|
|
4006
|
+
}
|
|
4007
|
+
return true;
|
|
4008
|
+
};
|
|
4009
|
+
installStack.add(p2.name);
|
|
4010
|
+
let pending;
|
|
4011
|
+
try {
|
|
4012
|
+
pending = adoptThenable(p2.install(ctx, options));
|
|
4013
|
+
} finally {
|
|
4014
|
+
installStack.delete(p2.name);
|
|
4015
|
+
}
|
|
4016
|
+
if (!pending) {
|
|
4017
|
+
if (!commit()) throw new PluginInstallCancelledError(p2.name);
|
|
4018
|
+
return;
|
|
4019
|
+
}
|
|
4020
|
+
if (myGeneration === generation) pendingInstalls.set(p2.name, myGeneration);
|
|
4021
|
+
const settled = pending.then(
|
|
4022
|
+
() => {
|
|
4023
|
+
if (commit()) return;
|
|
4024
|
+
if (pendingInstalls.get(p2.name) === myGeneration) pendingInstalls.delete(p2.name);
|
|
4025
|
+
throw new PluginInstallCancelledError(p2.name);
|
|
4026
|
+
},
|
|
4027
|
+
(err) => {
|
|
4028
|
+
if (pendingInstalls.get(p2.name) === myGeneration) pendingInstalls.delete(p2.name);
|
|
4029
|
+
reportError(err, { phase: "async", name: `plugin(${p2.name})` });
|
|
4030
|
+
throw err;
|
|
4031
|
+
}
|
|
4032
|
+
);
|
|
4033
|
+
settled.catch(() => {
|
|
4034
|
+
});
|
|
4035
|
+
return settled;
|
|
4036
|
+
},
|
|
4037
|
+
inject(key, defaultValue) {
|
|
4038
|
+
if (provided.has(key)) return provided.get(key);
|
|
4039
|
+
if (defaultValue !== void 0) return defaultValue;
|
|
4040
|
+
throw new Error(`[Plugin] No provider found for key "${key}"`);
|
|
4041
|
+
},
|
|
4042
|
+
triggerMount(element) {
|
|
4043
|
+
const snapshot = hooks.mount.slice();
|
|
4044
|
+
for (const hook of snapshot) {
|
|
4045
|
+
try {
|
|
4046
|
+
hook(element);
|
|
4047
|
+
} catch (e) {
|
|
4048
|
+
console.error("[Plugin] Mount hook error:", e);
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
},
|
|
4052
|
+
triggerUnmount(element) {
|
|
4053
|
+
const snapshot = hooks.unmount.slice();
|
|
4054
|
+
for (const hook of snapshot) {
|
|
4055
|
+
try {
|
|
4056
|
+
hook(element);
|
|
4057
|
+
} catch (e) {
|
|
4058
|
+
console.error("[Plugin] Unmount hook error:", e);
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
4061
|
+
},
|
|
4062
|
+
triggerError(error) {
|
|
4063
|
+
const snapshot = hooks.error.slice();
|
|
4064
|
+
for (const hook of snapshot) {
|
|
4065
|
+
try {
|
|
4066
|
+
hook(error);
|
|
4067
|
+
} catch (e) {
|
|
4068
|
+
console.error("[Plugin] Error hook error:", e);
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
},
|
|
4072
|
+
reset() {
|
|
4073
|
+
generation++;
|
|
4074
|
+
pendingInstalls.clear();
|
|
4075
|
+
installedPlugins.clear();
|
|
4076
|
+
hooks.init.length = 0;
|
|
4077
|
+
hooks.mount.length = 0;
|
|
4078
|
+
hooks.unmount.length = 0;
|
|
4079
|
+
hooks.error.length = 0;
|
|
4080
|
+
provided.clear();
|
|
4081
|
+
}
|
|
4082
|
+
};
|
|
4083
|
+
return registry;
|
|
4084
|
+
}
|
|
4085
|
+
var _defaults = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.plugins.defaultRegistry.v1"), () => ({
|
|
4086
|
+
registry: createPluginRegistry(),
|
|
4087
|
+
touched: false
|
|
4088
|
+
}));
|
|
4089
|
+
function createPlugin(name, install) {
|
|
4090
|
+
return { name, install };
|
|
4091
|
+
}
|
|
4092
|
+
function plugin(plugin2, options) {
|
|
4093
|
+
_defaults.touched = true;
|
|
4094
|
+
return _defaults.registry.plugin(plugin2, options);
|
|
4095
|
+
}
|
|
4096
|
+
function inject(key, defaultValue) {
|
|
4097
|
+
return _defaults.registry.inject(key, defaultValue);
|
|
4098
|
+
}
|
|
4099
|
+
function triggerPluginMount(element) {
|
|
4100
|
+
_defaults.registry.triggerMount(element);
|
|
4101
|
+
}
|
|
4102
|
+
function triggerPluginUnmount(element) {
|
|
4103
|
+
_defaults.registry.triggerUnmount(element);
|
|
4104
|
+
}
|
|
4105
|
+
function triggerPluginError(error) {
|
|
4106
|
+
_defaults.registry.triggerError(error);
|
|
4107
|
+
}
|
|
4108
|
+
function resetPlugins() {
|
|
4109
|
+
_defaults.registry.reset();
|
|
4110
|
+
_defaults.touched = false;
|
|
4111
|
+
}
|
|
4112
|
+
function setDefaultPluginRegistry(registry) {
|
|
4113
|
+
if (_defaults.touched && _defaults.registry.installedPlugins.size > 0) {
|
|
4114
|
+
console.warn(
|
|
4115
|
+
"[Plugin] Replacing default plugin registry while plugins are already installed on the singleton. This may indicate mixed singleton/registry usage."
|
|
4116
|
+
);
|
|
4117
|
+
}
|
|
4118
|
+
_defaults.registry = registry;
|
|
4119
|
+
_defaults.touched = true;
|
|
4120
|
+
}
|
|
4121
|
+
|
|
4122
|
+
// src/core/signals/effect.ts
|
|
4123
|
+
init_dev();
|
|
4124
|
+
init_errors();
|
|
4125
|
+
init_ssr_context();
|
|
4126
|
+
var _g2 = globalThis;
|
|
4127
|
+
var MAX_RERUNS = 100;
|
|
4128
|
+
function flushUserCleanups(ctx) {
|
|
4129
|
+
const list = ctx.userCleanups;
|
|
4130
|
+
if (list.length === 0) return;
|
|
4131
|
+
ctx.userCleanups = [];
|
|
4132
|
+
const scope = ctx.subscriber._scope ?? null;
|
|
4133
|
+
if (scope === getOwnerScope2()) runCleanups(list);
|
|
4134
|
+
else runWithOwnerScope2(scope, () => runCleanups(list));
|
|
4135
|
+
}
|
|
4136
|
+
function runCleanups(list) {
|
|
4137
|
+
for (let i2 = list.length - 1; i2 >= 0; i2--) {
|
|
4138
|
+
try {
|
|
4139
|
+
list[i2]();
|
|
4140
|
+
} catch (err) {
|
|
4141
|
+
reportError(err, { phase: "cleanup" });
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
function drainReruns(ctx) {
|
|
4146
|
+
let reruns = 1;
|
|
4147
|
+
do {
|
|
4148
|
+
ctx.rerunPending = false;
|
|
3552
4149
|
if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
|
|
3553
4150
|
retrack2(ctx.bodyFn, ctx.subscriber);
|
|
3554
4151
|
} while (ctx.rerunPending && ++reruns <= MAX_RERUNS);
|
|
@@ -3659,6 +4256,324 @@ function effect(effectFn, options) {
|
|
|
3659
4256
|
return () => disposeEffect(ctx);
|
|
3660
4257
|
}
|
|
3661
4258
|
|
|
4259
|
+
// src/utils/documentResources.ts
|
|
4260
|
+
init_globalSingleton();
|
|
4261
|
+
|
|
4262
|
+
// src/utils/singletonResource.ts
|
|
4263
|
+
function singletonResource(io) {
|
|
4264
|
+
let original = null;
|
|
4265
|
+
let captured = false;
|
|
4266
|
+
const stack = [];
|
|
4267
|
+
function apply() {
|
|
4268
|
+
if (stack.length > 0) {
|
|
4269
|
+
io.write(stack[stack.length - 1].value);
|
|
4270
|
+
return;
|
|
4271
|
+
}
|
|
4272
|
+
if (captured) {
|
|
4273
|
+
io.write(original);
|
|
4274
|
+
captured = false;
|
|
4275
|
+
original = null;
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4278
|
+
return {
|
|
4279
|
+
acquire(value) {
|
|
4280
|
+
if (!captured) {
|
|
4281
|
+
original = io.read();
|
|
4282
|
+
captured = true;
|
|
4283
|
+
}
|
|
4284
|
+
const entry = { value, released: false };
|
|
4285
|
+
stack.push(entry);
|
|
4286
|
+
apply();
|
|
4287
|
+
return {
|
|
4288
|
+
set(next) {
|
|
4289
|
+
if (entry.released) return;
|
|
4290
|
+
entry.value = next;
|
|
4291
|
+
apply();
|
|
4292
|
+
},
|
|
4293
|
+
release() {
|
|
4294
|
+
if (entry.released) return;
|
|
4295
|
+
entry.released = true;
|
|
4296
|
+
const index = stack.indexOf(entry);
|
|
4297
|
+
if (index !== -1) stack.splice(index, 1);
|
|
4298
|
+
apply();
|
|
4299
|
+
}
|
|
4300
|
+
};
|
|
4301
|
+
},
|
|
4302
|
+
ownerCount() {
|
|
4303
|
+
return stack.length;
|
|
4304
|
+
}
|
|
4305
|
+
};
|
|
4306
|
+
}
|
|
4307
|
+
|
|
4308
|
+
// src/utils/documentResources.ts
|
|
4309
|
+
var INERT_LEASE = {
|
|
4310
|
+
set() {
|
|
4311
|
+
},
|
|
4312
|
+
release() {
|
|
4313
|
+
}
|
|
4314
|
+
};
|
|
4315
|
+
function inertLease() {
|
|
4316
|
+
return INERT_LEASE;
|
|
4317
|
+
}
|
|
4318
|
+
var titleResource = globalSingleton(
|
|
4319
|
+
/* @__PURE__ */ Symbol.for("sibujs.documentTitle.v1"),
|
|
4320
|
+
() => singletonResource({
|
|
4321
|
+
read: () => document.title,
|
|
4322
|
+
write: (value) => {
|
|
4323
|
+
document.title = value;
|
|
4324
|
+
}
|
|
4325
|
+
})
|
|
4326
|
+
);
|
|
4327
|
+
var baseResource = globalSingleton(
|
|
4328
|
+
/* @__PURE__ */ Symbol.for("sibujs.documentBase.v1"),
|
|
4329
|
+
() => singletonResource({
|
|
4330
|
+
read: () => {
|
|
4331
|
+
const el = document.head.querySelector("base");
|
|
4332
|
+
if (!el) return null;
|
|
4333
|
+
return {
|
|
4334
|
+
href: el.getAttribute("href") ?? void 0,
|
|
4335
|
+
target: el.getAttribute("target") ?? void 0
|
|
4336
|
+
};
|
|
4337
|
+
},
|
|
4338
|
+
write: (spec) => {
|
|
4339
|
+
const existing = document.head.querySelector("base");
|
|
4340
|
+
if (spec === null) {
|
|
4341
|
+
existing?.remove();
|
|
4342
|
+
return;
|
|
4343
|
+
}
|
|
4344
|
+
const el = existing ?? document.head.appendChild(document.createElement("base"));
|
|
4345
|
+
if (spec.href === void 0) el.removeAttribute("href");
|
|
4346
|
+
else el.setAttribute("href", spec.href);
|
|
4347
|
+
if (spec.target === void 0) el.removeAttribute("target");
|
|
4348
|
+
else el.setAttribute("target", spec.target);
|
|
4349
|
+
}
|
|
4350
|
+
})
|
|
4351
|
+
);
|
|
4352
|
+
var scrollRestorationResource = globalSingleton(
|
|
4353
|
+
/* @__PURE__ */ Symbol.for("sibujs.historyScrollRestoration.v1"),
|
|
4354
|
+
() => singletonResource({
|
|
4355
|
+
read: () => history.scrollRestoration,
|
|
4356
|
+
write: (mode) => {
|
|
4357
|
+
history.scrollRestoration = mode;
|
|
4358
|
+
}
|
|
4359
|
+
})
|
|
4360
|
+
);
|
|
4361
|
+
function acquireTitle(value) {
|
|
4362
|
+
if (typeof document === "undefined") return inertLease();
|
|
4363
|
+
return titleResource.acquire(value);
|
|
4364
|
+
}
|
|
4365
|
+
|
|
4366
|
+
// src/plugins/routeHead.ts
|
|
4367
|
+
init_headEntry();
|
|
4368
|
+
init_sanitize();
|
|
4369
|
+
var OG_FIELDS = [
|
|
4370
|
+
["title", "og:title"],
|
|
4371
|
+
["description", "og:description"],
|
|
4372
|
+
["image", "og:image"],
|
|
4373
|
+
["url", "og:url"],
|
|
4374
|
+
["type", "og:type"],
|
|
4375
|
+
["siteName", "og:site_name"]
|
|
4376
|
+
];
|
|
4377
|
+
var OG_URL_PROPERTIES = /* @__PURE__ */ new Set(["og:image", "og:url"]);
|
|
4378
|
+
var ROUTE_HEAD_ATTR = "data-sibu-head";
|
|
4379
|
+
var BASE_TITLE_ATTR = "data-sibu-base-title";
|
|
4380
|
+
function routeHasHead(matched, defaults) {
|
|
4381
|
+
if (defaults) return true;
|
|
4382
|
+
for (const record of matched) if (record.head) return true;
|
|
4383
|
+
return false;
|
|
4384
|
+
}
|
|
4385
|
+
function resolveValue(value, route2) {
|
|
4386
|
+
if (value == null) return null;
|
|
4387
|
+
const v = typeof value === "function" ? value(route2) : value;
|
|
4388
|
+
return v == null ? null : String(v);
|
|
4389
|
+
}
|
|
4390
|
+
function mergeHeads(route2, defaults) {
|
|
4391
|
+
const layers = [];
|
|
4392
|
+
if (defaults) layers.push(defaults);
|
|
4393
|
+
for (const record of route2.matched) {
|
|
4394
|
+
const head2 = record.head;
|
|
4395
|
+
if (head2) layers.push(head2);
|
|
4396
|
+
}
|
|
4397
|
+
const merged = {};
|
|
4398
|
+
const og = {};
|
|
4399
|
+
const meta2 = /* @__PURE__ */ new Map();
|
|
4400
|
+
for (const layer of layers) {
|
|
4401
|
+
if (layer.title !== void 0) merged.title = layer.title;
|
|
4402
|
+
if (layer.description !== void 0) merged.description = layer.description;
|
|
4403
|
+
if (layer.canonical !== void 0) merged.canonical = layer.canonical;
|
|
4404
|
+
if (layer.og) {
|
|
4405
|
+
for (const [field] of OG_FIELDS) if (layer.og[field] !== void 0) og[field] = layer.og[field];
|
|
4406
|
+
}
|
|
4407
|
+
for (const entry of layer.meta ?? []) {
|
|
4408
|
+
const id = metaIdentity(entry);
|
|
4409
|
+
if (id) meta2.set(id, entry);
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4412
|
+
merged.og = og;
|
|
4413
|
+
merged.meta = Array.from(meta2.values());
|
|
4414
|
+
return merged;
|
|
4415
|
+
}
|
|
4416
|
+
function metaIdentity(entry) {
|
|
4417
|
+
const name = typeof entry.name === "string" ? entry.name : null;
|
|
4418
|
+
if (name) return `name:${name.toLowerCase()}`;
|
|
4419
|
+
const property = typeof entry.property === "string" ? entry.property : null;
|
|
4420
|
+
if (property) return `property:${property.toLowerCase()}`;
|
|
4421
|
+
return null;
|
|
4422
|
+
}
|
|
4423
|
+
function applyTemplate(title2, template2) {
|
|
4424
|
+
if (!template2) return title2;
|
|
4425
|
+
return typeof template2 === "function" ? template2(title2) : template2.replace("%s", title2);
|
|
4426
|
+
}
|
|
4427
|
+
function resolveRouteHead(route2, defaults) {
|
|
4428
|
+
const merged = mergeHeads(route2, defaults);
|
|
4429
|
+
const ownTitle = resolveValue(merged.title, route2);
|
|
4430
|
+
const routeSetTitle = route2.matched.some((r) => r.head?.title != null);
|
|
4431
|
+
const title2 = ownTitle === null ? null : routeSetTitle ? applyTemplate(ownTitle, defaults?.titleTemplate) : ownTitle;
|
|
4432
|
+
const description = resolveValue(merged.description, route2);
|
|
4433
|
+
const canonical = resolveValue(merged.canonical, route2);
|
|
4434
|
+
const tags = [];
|
|
4435
|
+
const push2 = (key, tag, attrs) => {
|
|
4436
|
+
const plan = tag === "meta" ? planMetaEntry(attrs, STATIC_VALUE_RESOLVER) : planHeadElementEntry(attrs, STATIC_VALUE_RESOLVER);
|
|
4437
|
+
if (plan.kind === "drop") return;
|
|
4438
|
+
tags.push({ key, tag, attrs: Object.fromEntries(plan.attributes) });
|
|
4439
|
+
};
|
|
4440
|
+
if (description !== null) push2("meta:name:description", "meta", { name: "description", content: description });
|
|
4441
|
+
if (canonical !== null) push2("link:rel:canonical", "link", { rel: "canonical", href: canonical });
|
|
4442
|
+
const og = merged.og ?? {};
|
|
4443
|
+
for (const [field, property] of OG_FIELDS) {
|
|
4444
|
+
let value = og[field] === void 0 ? void 0 : resolveValue(og[field], route2);
|
|
4445
|
+
if (value === void 0) {
|
|
4446
|
+
if (field === "title") value = ownTitle;
|
|
4447
|
+
else if (field === "description") value = description;
|
|
4448
|
+
else if (field === "url") value = canonical;
|
|
4449
|
+
else value = null;
|
|
4450
|
+
}
|
|
4451
|
+
if (value === null) continue;
|
|
4452
|
+
if (OG_URL_PROPERTIES.has(property)) {
|
|
4453
|
+
value = sanitizeUrl(value);
|
|
4454
|
+
if (value === "") continue;
|
|
4455
|
+
}
|
|
4456
|
+
push2(`meta:property:${property}`, "meta", { property, content: value });
|
|
4457
|
+
}
|
|
4458
|
+
for (const entry of merged.meta ?? []) {
|
|
4459
|
+
const id = metaIdentity(entry);
|
|
4460
|
+
if (!id) continue;
|
|
4461
|
+
const attrs = {};
|
|
4462
|
+
for (const [name, v] of Object.entries(entry)) {
|
|
4463
|
+
const resolved = resolveValue(v, route2);
|
|
4464
|
+
if (resolved !== null) attrs[name] = resolved;
|
|
4465
|
+
}
|
|
4466
|
+
push2(`meta:${id}`, "meta", attrs);
|
|
4467
|
+
}
|
|
4468
|
+
return { title: title2, tags };
|
|
4469
|
+
}
|
|
4470
|
+
function escapeText(value) {
|
|
4471
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
4472
|
+
}
|
|
4473
|
+
function routeHeadToHTML(head2) {
|
|
4474
|
+
const parts = [];
|
|
4475
|
+
if (head2.title !== null) parts.push(`<title>${escapeText(head2.title)}</title>`);
|
|
4476
|
+
for (const t2 of head2.tags) {
|
|
4477
|
+
const html2 = serializeHeadEntry(t2.tag, t2.attrs);
|
|
4478
|
+
if (html2) parts.push(html2.replace(/ \/>$/, ` ${ROUTE_HEAD_ATTR}="" />`));
|
|
4479
|
+
}
|
|
4480
|
+
return parts.join("\n");
|
|
4481
|
+
}
|
|
4482
|
+
function selectorFor(key) {
|
|
4483
|
+
const [tag, attr, ...rest] = key.split(":");
|
|
4484
|
+
const value = rest.join(":").replace(/["\\]/g, "\\$&");
|
|
4485
|
+
return `${tag}[${attr}="${value}" i]`;
|
|
4486
|
+
}
|
|
4487
|
+
function createRouteHeadController(defaults) {
|
|
4488
|
+
const [current, setCurrent] = signal(null);
|
|
4489
|
+
const owned = /* @__PURE__ */ new Map();
|
|
4490
|
+
const initial = new Set(Array.from(document.head.children));
|
|
4491
|
+
const titleEl = document.head.querySelector("title");
|
|
4492
|
+
const baseTitle = titleEl?.getAttribute(BASE_TITLE_ATTR) ?? document.title;
|
|
4493
|
+
let titleLease = null;
|
|
4494
|
+
let firstApply = true;
|
|
4495
|
+
const publish = (tag) => {
|
|
4496
|
+
const existing = owned.get(tag.key);
|
|
4497
|
+
if (existing && sameAttrs(existing, tag.attrs)) return;
|
|
4498
|
+
if (!existing) {
|
|
4499
|
+
for (const el of Array.from(document.head.querySelectorAll(selectorFor(tag.key)))) {
|
|
4500
|
+
if (initial.has(el)) {
|
|
4501
|
+
el.remove();
|
|
4502
|
+
initial.delete(el);
|
|
4503
|
+
}
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
const next = document.createElement(tag.tag);
|
|
4507
|
+
for (const [name, value] of Object.entries(tag.attrs)) next.setAttribute(name, value);
|
|
4508
|
+
next.setAttribute(ROUTE_HEAD_ATTR, "");
|
|
4509
|
+
if (existing?.parentNode) existing.replaceWith(next);
|
|
4510
|
+
else document.head.appendChild(next);
|
|
4511
|
+
owned.set(tag.key, next);
|
|
4512
|
+
};
|
|
4513
|
+
const apply = (head2) => {
|
|
4514
|
+
if (firstApply) {
|
|
4515
|
+
firstApply = false;
|
|
4516
|
+
for (const el of Array.from(document.head.querySelectorAll(`[${ROUTE_HEAD_ATTR}]`))) {
|
|
4517
|
+
if (initial.has(el) && !head2.tags.some((t2) => el.matches(selectorFor(t2.key)))) {
|
|
4518
|
+
el.remove();
|
|
4519
|
+
initial.delete(el);
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
4522
|
+
}
|
|
4523
|
+
const keep = /* @__PURE__ */ new Set();
|
|
4524
|
+
for (const tag of head2.tags) {
|
|
4525
|
+
keep.add(tag.key);
|
|
4526
|
+
publish(tag);
|
|
4527
|
+
}
|
|
4528
|
+
for (const [key, el] of owned) {
|
|
4529
|
+
if (keep.has(key)) continue;
|
|
4530
|
+
el.remove();
|
|
4531
|
+
owned.delete(key);
|
|
4532
|
+
}
|
|
4533
|
+
const title2 = head2.title ?? baseTitle;
|
|
4534
|
+
if (titleLease) titleLease.set(title2);
|
|
4535
|
+
else titleLease = acquireTitle(title2);
|
|
4536
|
+
};
|
|
4537
|
+
const stop2 = effect(() => {
|
|
4538
|
+
const route2 = current();
|
|
4539
|
+
if (route2 === null) return;
|
|
4540
|
+
const head2 = resolveRouteHead(route2, defaults);
|
|
4541
|
+
untracked2(() => apply(head2));
|
|
4542
|
+
});
|
|
4543
|
+
return {
|
|
4544
|
+
update(route2) {
|
|
4545
|
+
setCurrent(route2);
|
|
4546
|
+
},
|
|
4547
|
+
dispose() {
|
|
4548
|
+
stop2();
|
|
4549
|
+
for (const el of owned.values()) el.remove();
|
|
4550
|
+
owned.clear();
|
|
4551
|
+
titleLease?.release();
|
|
4552
|
+
titleLease = null;
|
|
4553
|
+
}
|
|
4554
|
+
};
|
|
4555
|
+
}
|
|
4556
|
+
function sameAttrs(el, attrs) {
|
|
4557
|
+
const names = Object.keys(attrs);
|
|
4558
|
+
if (el.attributes.length !== names.length + 1) return false;
|
|
4559
|
+
for (const name of names) if (el.getAttribute(name) !== attrs[name]) return false;
|
|
4560
|
+
return true;
|
|
4561
|
+
}
|
|
4562
|
+
|
|
4563
|
+
// src/plugins/router.ts
|
|
4564
|
+
init_dev();
|
|
4565
|
+
init_dispose();
|
|
4566
|
+
|
|
4567
|
+
// src/utils/prerenderHook.ts
|
|
4568
|
+
var HOST_KEY = /* @__PURE__ */ Symbol.for("sibujs.prerender.v1");
|
|
4569
|
+
function host() {
|
|
4570
|
+
return globalThis[HOST_KEY];
|
|
4571
|
+
}
|
|
4572
|
+
function prerenderWait(promise) {
|
|
4573
|
+
host()?.wait(promise);
|
|
4574
|
+
return promise;
|
|
4575
|
+
}
|
|
4576
|
+
|
|
3662
4577
|
// src/plugins/router.ts
|
|
3663
4578
|
init_sanitize();
|
|
3664
4579
|
function splitRouteUrl(url) {
|
|
@@ -4338,6 +5253,15 @@ var _SibuRouter = class _SibuRouter {
|
|
|
4338
5253
|
// to superseded work. The router's own initial location resolution is
|
|
4339
5254
|
// excluded — it establishes the bootstrap route rather than superseding it.
|
|
4340
5255
|
this.navEpoch = 0;
|
|
5256
|
+
// Created the first time a committed route needs a managed <head>.
|
|
5257
|
+
this.headController = null;
|
|
5258
|
+
// `readyPromise` plus the matched components loaded; created on the first
|
|
5259
|
+
// `routerReady()` call only, so an app that never asks pays nothing and its
|
|
5260
|
+
// outlets load exactly as before.
|
|
5261
|
+
this.loadedPromise = null;
|
|
5262
|
+
this.readyPromise = new Promise((resolve) => {
|
|
5263
|
+
this.resolveReady = resolve;
|
|
5264
|
+
});
|
|
4341
5265
|
this.options = {
|
|
4342
5266
|
mode: "history",
|
|
4343
5267
|
base: "",
|
|
@@ -4375,12 +5299,31 @@ var _SibuRouter = class _SibuRouter {
|
|
|
4375
5299
|
}
|
|
4376
5300
|
}
|
|
4377
5301
|
queueMicrotask(() => {
|
|
5302
|
+
let initial = Promise.resolve();
|
|
4378
5303
|
if (!this.navigator.isNavigating) {
|
|
4379
|
-
this.handleLocationChange(true, true);
|
|
5304
|
+
initial = this.handleLocationChange(true, true);
|
|
4380
5305
|
}
|
|
4381
5306
|
this.isReadySetter(true);
|
|
5307
|
+
prerenderWait(initial.then(this.resolveReady, this.resolveReady));
|
|
4382
5308
|
});
|
|
4383
5309
|
}
|
|
5310
|
+
/** Load the component of every record the current route matched, without instantiating any. */
|
|
5311
|
+
async preloadMatched() {
|
|
5312
|
+
const current = untracked2(() => this.currentRouteGetter());
|
|
5313
|
+
for (const record of current.matched) {
|
|
5314
|
+
if ("redirect" in record) continue;
|
|
5315
|
+
try {
|
|
5316
|
+
await this.loader.preloadPlan(record, current.path);
|
|
5317
|
+
} catch {
|
|
5318
|
+
this.loader.clearErrors();
|
|
5319
|
+
}
|
|
5320
|
+
}
|
|
5321
|
+
}
|
|
5322
|
+
/** Settles after the initial navigation and its component loads; see `routerReady()`. */
|
|
5323
|
+
whenReady() {
|
|
5324
|
+
this.loadedPromise ?? (this.loadedPromise = this.readyPromise.then(() => this.destroyed ? void 0 : this.preloadMatched()));
|
|
5325
|
+
return this.loadedPromise;
|
|
5326
|
+
}
|
|
4384
5327
|
createInitialRoute() {
|
|
4385
5328
|
return {
|
|
4386
5329
|
path: "/",
|
|
@@ -4394,7 +5337,7 @@ var _SibuRouter = class _SibuRouter {
|
|
|
4394
5337
|
}
|
|
4395
5338
|
handleLocationChange(skipHistory = true, initialResolution = false) {
|
|
4396
5339
|
const path2 = this.getCurrentPath();
|
|
4397
|
-
this.navigate(path2, { replace: true, skipHistory, initialResolution }).catch((err) => {
|
|
5340
|
+
return this.navigate(path2, { replace: true, skipHistory, initialResolution }).catch((err) => {
|
|
4398
5341
|
console.error("[Router] Error during location change navigation:", err);
|
|
4399
5342
|
});
|
|
4400
5343
|
}
|
|
@@ -4551,9 +5494,18 @@ var _SibuRouter = class _SibuRouter {
|
|
|
4551
5494
|
}
|
|
4552
5495
|
if (!options.initialResolution) this.navEpoch++;
|
|
4553
5496
|
this.currentRouteSetter(to);
|
|
5497
|
+
this.updateHead(to);
|
|
4554
5498
|
this.guards.runAfterEach(to, from);
|
|
4555
5499
|
this.handleScrollBehavior(to, from);
|
|
4556
5500
|
}
|
|
5501
|
+
updateHead(to) {
|
|
5502
|
+
if (typeof document === "undefined" || this.destroyed) return;
|
|
5503
|
+
if (this.headController === null) {
|
|
5504
|
+
if (!routeHasHead(to.matched, this.options.head)) return;
|
|
5505
|
+
this.headController = createRouteHeadController(this.options.head);
|
|
5506
|
+
}
|
|
5507
|
+
this.headController.update(to);
|
|
5508
|
+
}
|
|
4557
5509
|
resolvePath(to) {
|
|
4558
5510
|
if (typeof to === "string") return to;
|
|
4559
5511
|
let path2 = to.path || "";
|
|
@@ -4642,14 +5594,14 @@ var _SibuRouter = class _SibuRouter {
|
|
|
4642
5594
|
* anything. Pair with {@link instantiateComponent} at the commit boundary.
|
|
4643
5595
|
*/
|
|
4644
5596
|
async loadPlan(route2, routePath) {
|
|
4645
|
-
return this.loader.loadPlan(route2, routePath);
|
|
5597
|
+
return prerenderWait(this.loader.loadPlan(route2, routePath));
|
|
4646
5598
|
}
|
|
4647
5599
|
/**
|
|
4648
5600
|
* Create exactly one real instance from an already-resolved plan. With a
|
|
4649
5601
|
* `scope`, the factory runs in it (see `RouteScope`).
|
|
4650
5602
|
*/
|
|
4651
5603
|
async instantiateComponent(plan, route2, routePath, scope) {
|
|
4652
|
-
return this.loader.instantiate(plan, route2, routePath, scope);
|
|
5604
|
+
return prerenderWait(this.loader.instantiate(plan, route2, routePath, scope));
|
|
4653
5605
|
}
|
|
4654
5606
|
/** Resolve a route's module/factory without creating any component instance. */
|
|
4655
5607
|
async preloadPlan(route2, routePath) {
|
|
@@ -4705,6 +5657,9 @@ var _SibuRouter = class _SibuRouter {
|
|
|
4705
5657
|
this.guards.clear();
|
|
4706
5658
|
this.loader.clearCache();
|
|
4707
5659
|
this.isReadySetter(false);
|
|
5660
|
+
this.headController?.dispose();
|
|
5661
|
+
this.headController = null;
|
|
5662
|
+
this.resolveReady();
|
|
4708
5663
|
}
|
|
4709
5664
|
// Cache management
|
|
4710
5665
|
clearCache() {
|
|
@@ -4943,6 +5898,10 @@ function router() {
|
|
|
4943
5898
|
afterEach: (hook) => _routerRef.current?.afterEach(hook)
|
|
4944
5899
|
};
|
|
4945
5900
|
}
|
|
5901
|
+
function routerReady() {
|
|
5902
|
+
if (!_routerRef.current) throw new Error("Router not initialized. Call createRouter() first.");
|
|
5903
|
+
return _routerRef.current.whenReady();
|
|
5904
|
+
}
|
|
4946
5905
|
function navigate(to, options) {
|
|
4947
5906
|
if (!_routerRef.current) throw new Error("Router not initialized. Call createRouter() first.");
|
|
4948
5907
|
return _routerRef.current.navigate(to, options);
|
|
@@ -5965,570 +6924,278 @@ function hydrateRouter(routes, options) {
|
|
|
5965
6924
|
replaceChildrenSafely2(container);
|
|
5966
6925
|
}).catch((err) => {
|
|
5967
6926
|
if (typeof console !== "undefined") {
|
|
5968
|
-
console.error("[SibuJS routerSSR] failed to load hydrate:", err);
|
|
5969
|
-
}
|
|
5970
|
-
});
|
|
5971
|
-
}
|
|
5972
|
-
function createSSRRouter(routes) {
|
|
5973
|
-
return {
|
|
5974
|
-
resolve(url) {
|
|
5975
|
-
return resolveServerRoute(url, routes);
|
|
5976
|
-
},
|
|
5977
|
-
renderToString(url) {
|
|
5978
|
-
return renderRouteToString(url, routes);
|
|
5979
|
-
},
|
|
5980
|
-
renderToDocument(url, options) {
|
|
5981
|
-
return renderRouteToDocument(url, routes, options);
|
|
5982
|
-
}
|
|
5983
|
-
};
|
|
5984
|
-
}
|
|
5985
|
-
function escapeHtmlLocal(str) {
|
|
5986
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
5987
|
-
}
|
|
5988
|
-
function escapeAttrLocal(str) {
|
|
5989
|
-
return str.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
5990
|
-
}
|
|
5991
|
-
|
|
5992
|
-
// src/plugins/plugin.ts
|
|
5993
|
-
init_dev();
|
|
5994
|
-
init_errors();
|
|
5995
|
-
|
|
5996
|
-
// src/utils/adoptThenable.ts
|
|
5997
|
-
function adoptThenable(value) {
|
|
5998
|
-
if (value === null || typeof value !== "object" && typeof value !== "function") return null;
|
|
5999
|
-
let then;
|
|
6000
|
-
try {
|
|
6001
|
-
then = value.then;
|
|
6002
|
-
} catch (error) {
|
|
6003
|
-
return Promise.reject(error);
|
|
6004
|
-
}
|
|
6005
|
-
if (typeof then !== "function") return null;
|
|
6006
|
-
return new Promise((resolve, reject) => {
|
|
6007
|
-
queueMicrotask(() => {
|
|
6008
|
-
try {
|
|
6009
|
-
Reflect.apply(then, value, [resolve, reject]);
|
|
6010
|
-
} catch (error) {
|
|
6011
|
-
reject(error);
|
|
6012
|
-
}
|
|
6013
|
-
});
|
|
6014
|
-
});
|
|
6015
|
-
}
|
|
6016
|
-
|
|
6017
|
-
// src/plugins/plugin.ts
|
|
6018
|
-
init_globalSingleton();
|
|
6019
|
-
var CANCELLED_BRAND = /* @__PURE__ */ Symbol.for("sibujs.plugins.installCancelled.v1");
|
|
6020
|
-
var _a;
|
|
6021
|
-
var PluginInstallCancelledError = class extends Error {
|
|
6022
|
-
constructor(pluginName) {
|
|
6023
|
-
super(`[Plugin] Installation of "${pluginName}" was cancelled before it was committed (registry reset).`);
|
|
6024
|
-
/**
|
|
6025
|
-
* Brand, not identity: the default registry is shared across duplicate copies
|
|
6026
|
-
* of this module, so the error a caller receives may come from another copy's
|
|
6027
|
-
* constructor. `instanceof` is taught to recognise the brand instead.
|
|
6028
|
-
*/
|
|
6029
|
-
this[_a] = true;
|
|
6030
|
-
this.name = "PluginInstallCancelledError";
|
|
6031
|
-
this.pluginName = pluginName;
|
|
6032
|
-
}
|
|
6033
|
-
static [(_a = CANCELLED_BRAND, Symbol.hasInstance)](value) {
|
|
6034
|
-
return isPluginInstallCancelledError(value);
|
|
6035
|
-
}
|
|
6036
|
-
};
|
|
6037
|
-
function isPluginInstallCancelledError(value) {
|
|
6038
|
-
return typeof value === "object" && value !== null && value[CANCELLED_BRAND] === true;
|
|
6039
|
-
}
|
|
6040
|
-
function createPluginRegistry() {
|
|
6041
|
-
const installedPlugins = /* @__PURE__ */ new Set();
|
|
6042
|
-
const hooks = { init: [], mount: [], unmount: [], error: [] };
|
|
6043
|
-
const provided = /* @__PURE__ */ new Map();
|
|
6044
|
-
const installStack = /* @__PURE__ */ new Set();
|
|
6045
|
-
const pendingInstalls = /* @__PURE__ */ new Map();
|
|
6046
|
-
let generation = 0;
|
|
6047
|
-
const registry = {
|
|
6048
|
-
installedPlugins,
|
|
6049
|
-
hooks,
|
|
6050
|
-
provided,
|
|
6051
|
-
/**
|
|
6052
|
-
* Install a plugin as a transaction.
|
|
6053
|
-
*
|
|
6054
|
-
* Hooks and providers registered through `ctx` are staged and committed
|
|
6055
|
-
* only if `install()` returns; a throwing install leaves the registry
|
|
6056
|
-
* exactly as it found it (and can simply be retried). The plugin is marked
|
|
6057
|
-
* installed at commit, before its init hooks run.
|
|
6058
|
-
*
|
|
6059
|
-
* Each `plugin()` call is its own transaction: a dependency installed by a
|
|
6060
|
-
* nested `plugin()` call commits on its own and stays installed even if the
|
|
6061
|
-
* outer installation later fails.
|
|
6062
|
-
*/
|
|
6063
|
-
plugin(p2, options) {
|
|
6064
|
-
if (installedPlugins.has(p2.name)) {
|
|
6065
|
-
console.warn(`[Plugin] "${p2.name}" is already installed.`);
|
|
6066
|
-
return;
|
|
6067
|
-
}
|
|
6068
|
-
if (installStack.has(p2.name)) {
|
|
6069
|
-
throw new Error(`[Plugin] "${p2.name}" is already being installed (recursive installation).`);
|
|
6070
|
-
}
|
|
6071
|
-
if (pendingInstalls.has(p2.name)) {
|
|
6072
|
-
throw new Error(`[Plugin] "${p2.name}" is already being installed (asynchronous installation in flight).`);
|
|
6073
|
-
}
|
|
6074
|
-
const staged = { init: [], mount: [], unmount: [], error: [] };
|
|
6075
|
-
const stagedProvided = /* @__PURE__ */ new Map();
|
|
6076
|
-
let committed = false;
|
|
6077
|
-
const myGeneration = generation;
|
|
6078
|
-
const stale = () => {
|
|
6079
|
-
if (myGeneration === generation) return false;
|
|
6080
|
-
if (DEV) devWarn(`plugin: "${p2.name}" registered after the registry was reset; the registration was ignored.`);
|
|
6081
|
-
return true;
|
|
6082
|
-
};
|
|
6083
|
-
const target = () => stale() ? null : committed ? hooks : staged;
|
|
6084
|
-
const ctx = {
|
|
6085
|
-
onInit: (cb) => void target()?.init.push(cb),
|
|
6086
|
-
onMount: (cb) => void target()?.mount.push(cb),
|
|
6087
|
-
onUnmount: (cb) => void target()?.unmount.push(cb),
|
|
6088
|
-
onError: (cb) => void target()?.error.push(cb),
|
|
6089
|
-
provide: (key, value) => {
|
|
6090
|
-
if (stale()) return;
|
|
6091
|
-
(committed ? provided : stagedProvided).set(key, value);
|
|
6092
|
-
}
|
|
6093
|
-
};
|
|
6094
|
-
const commit = () => {
|
|
6095
|
-
if (myGeneration !== generation) return false;
|
|
6096
|
-
hooks.init.push(...staged.init);
|
|
6097
|
-
hooks.mount.push(...staged.mount);
|
|
6098
|
-
hooks.unmount.push(...staged.unmount);
|
|
6099
|
-
hooks.error.push(...staged.error);
|
|
6100
|
-
for (const [key, value] of stagedProvided) provided.set(key, value);
|
|
6101
|
-
installedPlugins.add(p2.name);
|
|
6102
|
-
committed = true;
|
|
6103
|
-
if (pendingInstalls.get(p2.name) === myGeneration) pendingInstalls.delete(p2.name);
|
|
6104
|
-
for (const cb of staged.init.slice()) {
|
|
6105
|
-
try {
|
|
6106
|
-
cb();
|
|
6107
|
-
} catch (e) {
|
|
6108
|
-
console.error(`[Plugin] "${p2.name}" init error:`, e);
|
|
6109
|
-
}
|
|
6110
|
-
}
|
|
6111
|
-
return true;
|
|
6112
|
-
};
|
|
6113
|
-
installStack.add(p2.name);
|
|
6114
|
-
let pending;
|
|
6115
|
-
try {
|
|
6116
|
-
pending = adoptThenable(p2.install(ctx, options));
|
|
6117
|
-
} finally {
|
|
6118
|
-
installStack.delete(p2.name);
|
|
6119
|
-
}
|
|
6120
|
-
if (!pending) {
|
|
6121
|
-
if (!commit()) throw new PluginInstallCancelledError(p2.name);
|
|
6122
|
-
return;
|
|
6123
|
-
}
|
|
6124
|
-
if (myGeneration === generation) pendingInstalls.set(p2.name, myGeneration);
|
|
6125
|
-
const settled = pending.then(
|
|
6126
|
-
() => {
|
|
6127
|
-
if (commit()) return;
|
|
6128
|
-
if (pendingInstalls.get(p2.name) === myGeneration) pendingInstalls.delete(p2.name);
|
|
6129
|
-
throw new PluginInstallCancelledError(p2.name);
|
|
6130
|
-
},
|
|
6131
|
-
(err) => {
|
|
6132
|
-
if (pendingInstalls.get(p2.name) === myGeneration) pendingInstalls.delete(p2.name);
|
|
6133
|
-
reportError(err, { phase: "async", name: `plugin(${p2.name})` });
|
|
6134
|
-
throw err;
|
|
6135
|
-
}
|
|
6136
|
-
);
|
|
6137
|
-
settled.catch(() => {
|
|
6138
|
-
});
|
|
6139
|
-
return settled;
|
|
6140
|
-
},
|
|
6141
|
-
inject(key, defaultValue) {
|
|
6142
|
-
if (provided.has(key)) return provided.get(key);
|
|
6143
|
-
if (defaultValue !== void 0) return defaultValue;
|
|
6144
|
-
throw new Error(`[Plugin] No provider found for key "${key}"`);
|
|
6145
|
-
},
|
|
6146
|
-
triggerMount(element) {
|
|
6147
|
-
const snapshot = hooks.mount.slice();
|
|
6148
|
-
for (const hook of snapshot) {
|
|
6149
|
-
try {
|
|
6150
|
-
hook(element);
|
|
6151
|
-
} catch (e) {
|
|
6152
|
-
console.error("[Plugin] Mount hook error:", e);
|
|
6153
|
-
}
|
|
6154
|
-
}
|
|
6155
|
-
},
|
|
6156
|
-
triggerUnmount(element) {
|
|
6157
|
-
const snapshot = hooks.unmount.slice();
|
|
6158
|
-
for (const hook of snapshot) {
|
|
6159
|
-
try {
|
|
6160
|
-
hook(element);
|
|
6161
|
-
} catch (e) {
|
|
6162
|
-
console.error("[Plugin] Unmount hook error:", e);
|
|
6163
|
-
}
|
|
6164
|
-
}
|
|
6165
|
-
},
|
|
6166
|
-
triggerError(error) {
|
|
6167
|
-
const snapshot = hooks.error.slice();
|
|
6168
|
-
for (const hook of snapshot) {
|
|
6169
|
-
try {
|
|
6170
|
-
hook(error);
|
|
6171
|
-
} catch (e) {
|
|
6172
|
-
console.error("[Plugin] Error hook error:", e);
|
|
6173
|
-
}
|
|
6174
|
-
}
|
|
6175
|
-
},
|
|
6176
|
-
reset() {
|
|
6177
|
-
generation++;
|
|
6178
|
-
pendingInstalls.clear();
|
|
6179
|
-
installedPlugins.clear();
|
|
6180
|
-
hooks.init.length = 0;
|
|
6181
|
-
hooks.mount.length = 0;
|
|
6182
|
-
hooks.unmount.length = 0;
|
|
6183
|
-
hooks.error.length = 0;
|
|
6184
|
-
provided.clear();
|
|
6185
|
-
}
|
|
6186
|
-
};
|
|
6187
|
-
return registry;
|
|
6188
|
-
}
|
|
6189
|
-
var _defaults = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.plugins.defaultRegistry.v1"), () => ({
|
|
6190
|
-
registry: createPluginRegistry(),
|
|
6191
|
-
touched: false
|
|
6192
|
-
}));
|
|
6193
|
-
function createPlugin(name, install) {
|
|
6194
|
-
return { name, install };
|
|
6195
|
-
}
|
|
6196
|
-
function plugin(plugin2, options) {
|
|
6197
|
-
_defaults.touched = true;
|
|
6198
|
-
return _defaults.registry.plugin(plugin2, options);
|
|
6199
|
-
}
|
|
6200
|
-
function inject(key, defaultValue) {
|
|
6201
|
-
return _defaults.registry.inject(key, defaultValue);
|
|
6202
|
-
}
|
|
6203
|
-
function triggerPluginMount(element) {
|
|
6204
|
-
_defaults.registry.triggerMount(element);
|
|
6205
|
-
}
|
|
6206
|
-
function triggerPluginUnmount(element) {
|
|
6207
|
-
_defaults.registry.triggerUnmount(element);
|
|
6927
|
+
console.error("[SibuJS routerSSR] failed to load hydrate:", err);
|
|
6928
|
+
}
|
|
6929
|
+
});
|
|
6208
6930
|
}
|
|
6209
|
-
function
|
|
6210
|
-
|
|
6931
|
+
function createSSRRouter(routes) {
|
|
6932
|
+
return {
|
|
6933
|
+
resolve(url) {
|
|
6934
|
+
return resolveServerRoute(url, routes);
|
|
6935
|
+
},
|
|
6936
|
+
renderToString(url) {
|
|
6937
|
+
return renderRouteToString(url, routes);
|
|
6938
|
+
},
|
|
6939
|
+
renderToDocument(url, options) {
|
|
6940
|
+
return renderRouteToDocument(url, routes, options);
|
|
6941
|
+
}
|
|
6942
|
+
};
|
|
6211
6943
|
}
|
|
6212
|
-
function
|
|
6213
|
-
|
|
6214
|
-
_defaults.touched = false;
|
|
6944
|
+
function escapeHtmlLocal(str) {
|
|
6945
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
6215
6946
|
}
|
|
6216
|
-
function
|
|
6217
|
-
|
|
6218
|
-
console.warn(
|
|
6219
|
-
"[Plugin] Replacing default plugin registry while plugins are already installed on the singleton. This may indicate mixed singleton/registry usage."
|
|
6220
|
-
);
|
|
6221
|
-
}
|
|
6222
|
-
_defaults.registry = registry;
|
|
6223
|
-
_defaults.touched = true;
|
|
6947
|
+
function escapeAttrLocal(str) {
|
|
6948
|
+
return str.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
6224
6949
|
}
|
|
6225
6950
|
|
|
6226
|
-
// src/plugins/
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6951
|
+
// src/plugins/startup.ts
|
|
6952
|
+
init_errors();
|
|
6953
|
+
init_ssr();
|
|
6954
|
+
init_sanitize();
|
|
6955
|
+
function preloadCritical(resources) {
|
|
6956
|
+
if (typeof document === "undefined") return;
|
|
6957
|
+
for (const resource of resources) {
|
|
6958
|
+
const href = sanitizeUrl(resource.href);
|
|
6959
|
+
if (!href) continue;
|
|
6960
|
+
const safeHref = typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(href) : href.replace(/["\\]/g, "\\$&");
|
|
6961
|
+
const existing = document.querySelector(`link[rel="preload"][href="${safeHref}"]`);
|
|
6962
|
+
if (existing) continue;
|
|
6963
|
+
const link2 = document.createElement("link");
|
|
6964
|
+
link2.rel = "preload";
|
|
6965
|
+
link2.href = href;
|
|
6966
|
+
link2.setAttribute("as", resource.as);
|
|
6967
|
+
if (resource.type) {
|
|
6968
|
+
link2.type = resource.type;
|
|
6241
6969
|
}
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
try {
|
|
6245
|
-
for (const dep of entry.deps) {
|
|
6246
|
-
resolveInternal(dep);
|
|
6247
|
-
}
|
|
6248
|
-
entry.value = entry.factory();
|
|
6249
|
-
entry.state = "loaded";
|
|
6250
|
-
return entry.value;
|
|
6251
|
-
} catch (err) {
|
|
6252
|
-
entry.state = "unloaded";
|
|
6253
|
-
entry.value = void 0;
|
|
6254
|
-
throw err;
|
|
6255
|
-
} finally {
|
|
6256
|
-
resolving.pop();
|
|
6970
|
+
if (resource.crossOrigin) {
|
|
6971
|
+
link2.crossOrigin = resource.crossOrigin;
|
|
6257
6972
|
}
|
|
6973
|
+
document.head.appendChild(link2);
|
|
6258
6974
|
}
|
|
6259
|
-
return {
|
|
6260
|
-
/** Register a module with its factory function and optional dependencies */
|
|
6261
|
-
register(name, factory, deps = []) {
|
|
6262
|
-
modules.set(name, { factory, deps, state: "unloaded" });
|
|
6263
|
-
},
|
|
6264
|
-
/** Resolve a module, loading its dependencies first */
|
|
6265
|
-
resolve(name) {
|
|
6266
|
-
return resolveInternal(name);
|
|
6267
|
-
},
|
|
6268
|
-
/** Check if a module is registered */
|
|
6269
|
-
has(name) {
|
|
6270
|
-
return modules.has(name);
|
|
6271
|
-
},
|
|
6272
|
-
/** List all registered module names */
|
|
6273
|
-
list() {
|
|
6274
|
-
return Array.from(modules.keys());
|
|
6275
|
-
},
|
|
6276
|
-
/** Get the full dependency graph (transitive) for a module */
|
|
6277
|
-
deps(name) {
|
|
6278
|
-
const entry = modules.get(name);
|
|
6279
|
-
if (!entry) {
|
|
6280
|
-
throw new Error(`[ModuleRegistry] Module "${name}" is not registered.`);
|
|
6281
|
-
}
|
|
6282
|
-
const visited = /* @__PURE__ */ new Set();
|
|
6283
|
-
const result = [];
|
|
6284
|
-
function walk(modName) {
|
|
6285
|
-
const mod = modules.get(modName);
|
|
6286
|
-
if (!mod) return;
|
|
6287
|
-
for (const dep of mod.deps) {
|
|
6288
|
-
if (!visited.has(dep)) {
|
|
6289
|
-
visited.add(dep);
|
|
6290
|
-
walk(dep);
|
|
6291
|
-
result.push(dep);
|
|
6292
|
-
}
|
|
6293
|
-
}
|
|
6294
|
-
}
|
|
6295
|
-
walk(name);
|
|
6296
|
-
return result;
|
|
6297
|
-
},
|
|
6298
|
-
/** Reset all loaded modules back to unloaded state (useful for testing) */
|
|
6299
|
-
reset() {
|
|
6300
|
-
for (const entry of modules.values()) {
|
|
6301
|
-
entry.state = "unloaded";
|
|
6302
|
-
entry.value = void 0;
|
|
6303
|
-
}
|
|
6304
|
-
}
|
|
6305
|
-
};
|
|
6306
6975
|
}
|
|
6307
|
-
function
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
for (const key of Object.keys(modules)) {
|
|
6311
|
-
Object.defineProperty(bundle, key, {
|
|
6312
|
-
get() {
|
|
6313
|
-
if (cache.has(key)) {
|
|
6314
|
-
return cache.get(key);
|
|
6315
|
-
}
|
|
6316
|
-
const value = modules[key]();
|
|
6317
|
-
cache.set(key, value);
|
|
6318
|
-
return value;
|
|
6319
|
-
},
|
|
6320
|
-
enumerable: true,
|
|
6321
|
-
configurable: false
|
|
6322
|
-
});
|
|
6976
|
+
function assertCacheSize(name, value) {
|
|
6977
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
6978
|
+
throw new RangeError(`[Startup] ${name} must be a non-negative integer, got ${value}`);
|
|
6323
6979
|
}
|
|
6324
|
-
return bundle;
|
|
6325
6980
|
}
|
|
6326
|
-
function
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
} catch (err) {
|
|
6341
|
-
started = Promise.reject(err);
|
|
6981
|
+
function makeRoomFor(cache, key, maxSize, isValid) {
|
|
6982
|
+
if (maxSize === 0) return false;
|
|
6983
|
+
if (cache.has(key)) return true;
|
|
6984
|
+
if (cache.size < maxSize) return true;
|
|
6985
|
+
for (const [k, entry] of cache) {
|
|
6986
|
+
if (!isValid(entry)) cache.delete(k);
|
|
6987
|
+
}
|
|
6988
|
+
while (cache.size >= maxSize) {
|
|
6989
|
+
let oldestKey = null;
|
|
6990
|
+
let oldestTime = Infinity;
|
|
6991
|
+
for (const [k, entry] of cache) {
|
|
6992
|
+
if (entry.timestamp < oldestTime) {
|
|
6993
|
+
oldestTime = entry.timestamp;
|
|
6994
|
+
oldestKey = k;
|
|
6342
6995
|
}
|
|
6343
|
-
const attempt = started.then(
|
|
6344
|
-
(value) => {
|
|
6345
|
-
cached = value;
|
|
6346
|
-
loadedFlag = true;
|
|
6347
|
-
if (inFlight === attempt) inFlight = null;
|
|
6348
|
-
return value;
|
|
6349
|
-
},
|
|
6350
|
-
(err) => {
|
|
6351
|
-
if (inFlight === attempt) inFlight = null;
|
|
6352
|
-
throw err;
|
|
6353
|
-
}
|
|
6354
|
-
);
|
|
6355
|
-
inFlight = attempt;
|
|
6356
|
-
return attempt;
|
|
6357
6996
|
}
|
|
6358
|
-
|
|
6997
|
+
if (oldestKey === null) break;
|
|
6998
|
+
cache.delete(oldestKey);
|
|
6999
|
+
}
|
|
7000
|
+
return true;
|
|
6359
7001
|
}
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
build: "./build.ts",
|
|
6374
|
-
testing: "./testing.ts",
|
|
6375
|
-
extras: "./extras.ts"
|
|
6376
|
-
};
|
|
6377
|
-
var CDN_ENTRY_POINTS = {
|
|
6378
|
-
cdn: "./dist/cdn.global.js",
|
|
6379
|
-
"cdn-dev": "./dist/cdn.dev.global.js",
|
|
6380
|
-
"cdn-full": "./dist/cdn.full.global.js",
|
|
6381
|
-
"cdn-full-dev": "./dist/cdn.full.dev.global.js"
|
|
6382
|
-
};
|
|
6383
|
-
var packageInfo = {
|
|
6384
|
-
name: "sibujs",
|
|
6385
|
-
version: true ? "4.12.0" : "dev",
|
|
6386
|
-
entryPoints: MODULE_ENTRY_POINTS,
|
|
6387
|
-
/**
|
|
6388
|
-
* Generate the package.json `exports` map. Module entries resolve to the
|
|
6389
|
-
* `.js` (ESM), `.cjs` and `.d.ts` files tsup emits into `dist/`; CDN entries
|
|
6390
|
-
* resolve to their prebuilt global script.
|
|
6391
|
-
*/
|
|
6392
|
-
generateExportsMap() {
|
|
6393
|
-
const exportsMap = {};
|
|
6394
|
-
for (const [name, sourcePath] of Object.entries(MODULE_ENTRY_POINTS)) {
|
|
6395
|
-
const distPath = sourcePath.replace(/^\.\//, "./dist/").replace(/\.ts$/, "");
|
|
6396
|
-
const subpath = name === "main" ? "." : `./${name}`;
|
|
6397
|
-
exportsMap[subpath] = {
|
|
6398
|
-
types: `${distPath}.d.ts`,
|
|
6399
|
-
import: `${distPath}.js`,
|
|
6400
|
-
require: `${distPath}.cjs`
|
|
6401
|
-
};
|
|
6402
|
-
}
|
|
6403
|
-
for (const [name, file] of Object.entries(CDN_ENTRY_POINTS)) {
|
|
6404
|
-
exportsMap[`./${name}`] = { default: file };
|
|
6405
|
-
}
|
|
6406
|
-
return exportsMap;
|
|
7002
|
+
function prerenderRoutes(routes, options) {
|
|
7003
|
+
const maxCacheSize = options?.maxCacheSize ?? 50;
|
|
7004
|
+
const cacheTTL = options?.cacheTTL ?? 0;
|
|
7005
|
+
assertCacheSize("maxCacheSize", maxCacheSize);
|
|
7006
|
+
const cache = /* @__PURE__ */ new Map();
|
|
7007
|
+
function isValid(entry) {
|
|
7008
|
+
if (cacheTTL === 0) return true;
|
|
7009
|
+
return Date.now() - entry.timestamp < cacheTTL;
|
|
7010
|
+
}
|
|
7011
|
+
for (const route2 of routes) {
|
|
7012
|
+
if (!makeRoomFor(cache, route2.path, maxCacheSize, isValid)) break;
|
|
7013
|
+
const html2 = renderToString(route2.component());
|
|
7014
|
+
cache.set(route2.path, { html: html2, timestamp: Date.now() });
|
|
6407
7015
|
}
|
|
6408
|
-
};
|
|
6409
|
-
|
|
6410
|
-
// src/plugins/ecosystem.ts
|
|
6411
|
-
function createTestHarness() {
|
|
6412
|
-
let container;
|
|
6413
7016
|
return {
|
|
6414
|
-
/**
|
|
6415
|
-
|
|
6416
|
-
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
|
|
7017
|
+
/** Get cached HTML for a route, or undefined if not cached or expired */
|
|
7018
|
+
get(path2) {
|
|
7019
|
+
const entry = cache.get(path2);
|
|
7020
|
+
if (!entry) return void 0;
|
|
7021
|
+
if (!isValid(entry)) {
|
|
7022
|
+
cache.delete(path2);
|
|
7023
|
+
return void 0;
|
|
7024
|
+
}
|
|
7025
|
+
return entry.html;
|
|
6420
7026
|
},
|
|
6421
|
-
/**
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
7027
|
+
/** Check if a route has been prerendered and is still valid */
|
|
7028
|
+
has(path2) {
|
|
7029
|
+
const entry = cache.get(path2);
|
|
7030
|
+
if (!entry) return false;
|
|
7031
|
+
if (!isValid(entry)) {
|
|
7032
|
+
cache.delete(path2);
|
|
7033
|
+
return false;
|
|
6425
7034
|
}
|
|
7035
|
+
return true;
|
|
6426
7036
|
},
|
|
6427
|
-
/**
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
container.appendChild(el);
|
|
6431
|
-
return el;
|
|
7037
|
+
/** Invalidate a cached route */
|
|
7038
|
+
invalidate(path2) {
|
|
7039
|
+
cache.delete(path2);
|
|
6432
7040
|
},
|
|
6433
|
-
/**
|
|
6434
|
-
|
|
6435
|
-
|
|
7041
|
+
/** Clear all cached routes */
|
|
7042
|
+
clear() {
|
|
7043
|
+
cache.clear();
|
|
6436
7044
|
},
|
|
6437
|
-
/**
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
7045
|
+
/** Get cache statistics */
|
|
7046
|
+
stats() {
|
|
7047
|
+
if (cacheTTL > 0) {
|
|
7048
|
+
for (const [key, entry] of cache) {
|
|
7049
|
+
if (!isValid(entry)) {
|
|
7050
|
+
cache.delete(key);
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
7053
|
+
}
|
|
7054
|
+
return {
|
|
7055
|
+
size: cache.size,
|
|
7056
|
+
routes: Array.from(cache.keys())
|
|
7057
|
+
};
|
|
7058
|
+
}
|
|
7059
|
+
};
|
|
7060
|
+
}
|
|
7061
|
+
function createSSRCache(config) {
|
|
7062
|
+
const maxSize = config?.maxSize ?? 100;
|
|
7063
|
+
const defaultTTL = config?.defaultTTL ?? 6e4;
|
|
7064
|
+
assertCacheSize("maxSize", maxSize);
|
|
7065
|
+
const cache = /* @__PURE__ */ new Map();
|
|
7066
|
+
let hits = 0;
|
|
7067
|
+
let misses = 0;
|
|
7068
|
+
function isValid(entry) {
|
|
7069
|
+
if (entry.ttl === 0) return true;
|
|
7070
|
+
return Date.now() - entry.timestamp < entry.ttl;
|
|
7071
|
+
}
|
|
7072
|
+
return {
|
|
7073
|
+
/** Get cached HTML for a key, or undefined if not cached or expired */
|
|
7074
|
+
get(key) {
|
|
7075
|
+
const entry = cache.get(key);
|
|
7076
|
+
if (!entry) {
|
|
7077
|
+
misses++;
|
|
7078
|
+
return void 0;
|
|
7079
|
+
}
|
|
7080
|
+
if (!isValid(entry)) {
|
|
7081
|
+
cache.delete(key);
|
|
7082
|
+
misses++;
|
|
7083
|
+
return void 0;
|
|
7084
|
+
}
|
|
7085
|
+
hits++;
|
|
7086
|
+
return entry.html;
|
|
6441
7087
|
},
|
|
6442
|
-
/**
|
|
6443
|
-
|
|
6444
|
-
|
|
7088
|
+
/** Cache an HTML string with an optional TTL override */
|
|
7089
|
+
set(key, html2, ttl) {
|
|
7090
|
+
if (!makeRoomFor(cache, key, maxSize, isValid)) return;
|
|
7091
|
+
cache.set(key, {
|
|
7092
|
+
html: html2,
|
|
7093
|
+
timestamp: Date.now(),
|
|
7094
|
+
ttl: ttl ?? defaultTTL
|
|
7095
|
+
});
|
|
6445
7096
|
},
|
|
6446
|
-
/**
|
|
6447
|
-
|
|
6448
|
-
|
|
7097
|
+
/** Check if a key exists in the cache and is still valid */
|
|
7098
|
+
has(key) {
|
|
7099
|
+
const entry = cache.get(key);
|
|
7100
|
+
if (!entry) return false;
|
|
7101
|
+
if (!isValid(entry)) {
|
|
7102
|
+
cache.delete(key);
|
|
7103
|
+
return false;
|
|
7104
|
+
}
|
|
7105
|
+
return true;
|
|
6449
7106
|
},
|
|
6450
|
-
/**
|
|
6451
|
-
|
|
6452
|
-
|
|
7107
|
+
/** Invalidate a cached entry */
|
|
7108
|
+
invalidate(key) {
|
|
7109
|
+
cache.delete(key);
|
|
6453
7110
|
},
|
|
6454
|
-
/**
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
7111
|
+
/** Clear all cached entries and reset statistics */
|
|
7112
|
+
clear() {
|
|
7113
|
+
cache.clear();
|
|
7114
|
+
hits = 0;
|
|
7115
|
+
misses = 0;
|
|
7116
|
+
},
|
|
7117
|
+
/** Get cache statistics including hit/miss counts */
|
|
7118
|
+
stats() {
|
|
7119
|
+
return { size: cache.size, hits, misses };
|
|
6458
7120
|
}
|
|
6459
7121
|
};
|
|
6460
7122
|
}
|
|
6461
|
-
var
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
7123
|
+
var DEFER_IDLE_TIMEOUT_MS = 2e3;
|
|
7124
|
+
function deferNonCritical(tasks) {
|
|
7125
|
+
if (tasks.length === 0) return;
|
|
7126
|
+
const schedule = typeof requestIdleCallback !== "undefined" ? (cb) => {
|
|
7127
|
+
requestIdleCallback(cb, { timeout: DEFER_IDLE_TIMEOUT_MS });
|
|
7128
|
+
} : (cb) => {
|
|
7129
|
+
setTimeout(cb, 1);
|
|
7130
|
+
};
|
|
7131
|
+
const queue = [...tasks];
|
|
7132
|
+
let index = 0;
|
|
7133
|
+
function processNext(deadline) {
|
|
7134
|
+
let ranOne = false;
|
|
7135
|
+
while (index < queue.length) {
|
|
7136
|
+
if (ranOne && deadline && deadline.timeRemaining() < 1) {
|
|
7137
|
+
schedule(processNext);
|
|
7138
|
+
return;
|
|
7139
|
+
}
|
|
7140
|
+
try {
|
|
7141
|
+
queue[index]();
|
|
7142
|
+
} catch (e) {
|
|
7143
|
+
reportError(e, { phase: "scheduler", name: "deferNonCritical" });
|
|
6479
7144
|
}
|
|
7145
|
+
index++;
|
|
7146
|
+
ranOne = true;
|
|
6480
7147
|
}
|
|
6481
|
-
return map2;
|
|
6482
7148
|
}
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
const
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
name
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
7149
|
+
schedule(processNext);
|
|
7150
|
+
}
|
|
7151
|
+
function createBootSequence() {
|
|
7152
|
+
const criticalTasks = [];
|
|
7153
|
+
const deferredTasks = [];
|
|
7154
|
+
return {
|
|
7155
|
+
/** Add a critical task that runs immediately during boot */
|
|
7156
|
+
critical(name, task) {
|
|
7157
|
+
criticalTasks.push({ name, task });
|
|
7158
|
+
},
|
|
7159
|
+
/** Add a deferred task that runs after all critical tasks complete */
|
|
7160
|
+
defer(name, task) {
|
|
7161
|
+
deferredTasks.push({ name, task });
|
|
7162
|
+
},
|
|
7163
|
+
/** Execute the boot sequence: critical tasks first, then deferred */
|
|
7164
|
+
async boot() {
|
|
7165
|
+
const timing = {};
|
|
7166
|
+
const errors = [];
|
|
7167
|
+
for (const entry of criticalTasks) {
|
|
7168
|
+
const start = Date.now();
|
|
7169
|
+
try {
|
|
7170
|
+
await entry.task();
|
|
7171
|
+
} catch (e) {
|
|
7172
|
+
errors.push({
|
|
7173
|
+
name: entry.name,
|
|
7174
|
+
error: e instanceof Error ? e : new Error(String(e))
|
|
7175
|
+
});
|
|
7176
|
+
}
|
|
7177
|
+
timing[entry.name] = Date.now() - start;
|
|
7178
|
+
}
|
|
7179
|
+
for (const entry of deferredTasks) {
|
|
7180
|
+
const start = Date.now();
|
|
7181
|
+
try {
|
|
7182
|
+
await entry.task();
|
|
7183
|
+
} catch (e) {
|
|
7184
|
+
errors.push({
|
|
7185
|
+
name: entry.name,
|
|
7186
|
+
error: e instanceof Error ? e : new Error(String(e))
|
|
7187
|
+
});
|
|
7188
|
+
}
|
|
7189
|
+
timing[entry.name] = Date.now() - start;
|
|
7190
|
+
}
|
|
7191
|
+
return { timing, errors };
|
|
7192
|
+
}
|
|
7193
|
+
};
|
|
6509
7194
|
}
|
|
6510
|
-
var env = {
|
|
6511
|
-
/** True when running in a browser with a DOM */
|
|
6512
|
-
isBrowser: typeof window !== "undefined" && typeof document !== "undefined",
|
|
6513
|
-
/** True when running in Node.js */
|
|
6514
|
-
isNode: typeof process !== "undefined" && !!process.versions?.node,
|
|
6515
|
-
/** True when running inside a Web Worker */
|
|
6516
|
-
isWorker: typeof self !== "undefined" && typeof self.importScripts === "function",
|
|
6517
|
-
/** True when running inside Deno */
|
|
6518
|
-
isDeno: typeof globalThis.Deno !== "undefined",
|
|
6519
|
-
/** True when running inside Bun */
|
|
6520
|
-
isBun: typeof globalThis.Bun !== "undefined",
|
|
6521
|
-
/** True when no window object is available (server-side rendering) */
|
|
6522
|
-
isSSR: typeof window === "undefined",
|
|
6523
|
-
/** True when NODE_ENV is not "production" */
|
|
6524
|
-
isDev: typeof process !== "undefined" && process.env?.NODE_ENV !== "production",
|
|
6525
|
-
/** True when NODE_ENV is "test" or VITEST is set */
|
|
6526
|
-
isTest: typeof process !== "undefined" && (process.env?.NODE_ENV === "test" || process.env?.VITEST === "true")
|
|
6527
|
-
};
|
|
6528
7195
|
|
|
6529
7196
|
// src/plugins/versioning.ts
|
|
6530
7197
|
init_globalSingleton();
|
|
6531
|
-
var VERSION = true ? "4.
|
|
7198
|
+
var VERSION = true ? "4.13.1" : "dev";
|
|
6532
7199
|
var NUM = "(?:0|[1-9]\\d*)";
|
|
6533
7200
|
var PRE_ID = `(?:${NUM}|\\d*[a-zA-Z-][0-9a-zA-Z-]*)`;
|
|
6534
7201
|
var BUILD_ID = "[0-9a-zA-Z-]+";
|
|
@@ -6806,251 +7473,6 @@ function extractRangeTarget(range) {
|
|
|
6806
7473
|
const match = range.match(/[\d]+\.[\d]+\.[\d]+(?:-[\w.]+)?/);
|
|
6807
7474
|
return match ? match[0] : null;
|
|
6808
7475
|
}
|
|
6809
|
-
|
|
6810
|
-
// src/plugins/startup.ts
|
|
6811
|
-
init_errors();
|
|
6812
|
-
init_ssr();
|
|
6813
|
-
init_sanitize();
|
|
6814
|
-
function preloadCritical(resources) {
|
|
6815
|
-
if (typeof document === "undefined") return;
|
|
6816
|
-
for (const resource of resources) {
|
|
6817
|
-
const href = sanitizeUrl(resource.href);
|
|
6818
|
-
if (!href) continue;
|
|
6819
|
-
const safeHref = typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(href) : href.replace(/["\\]/g, "\\$&");
|
|
6820
|
-
const existing = document.querySelector(`link[rel="preload"][href="${safeHref}"]`);
|
|
6821
|
-
if (existing) continue;
|
|
6822
|
-
const link2 = document.createElement("link");
|
|
6823
|
-
link2.rel = "preload";
|
|
6824
|
-
link2.href = href;
|
|
6825
|
-
link2.setAttribute("as", resource.as);
|
|
6826
|
-
if (resource.type) {
|
|
6827
|
-
link2.type = resource.type;
|
|
6828
|
-
}
|
|
6829
|
-
if (resource.crossOrigin) {
|
|
6830
|
-
link2.crossOrigin = resource.crossOrigin;
|
|
6831
|
-
}
|
|
6832
|
-
document.head.appendChild(link2);
|
|
6833
|
-
}
|
|
6834
|
-
}
|
|
6835
|
-
function assertCacheSize(name, value) {
|
|
6836
|
-
if (!Number.isInteger(value) || value < 0) {
|
|
6837
|
-
throw new RangeError(`[Startup] ${name} must be a non-negative integer, got ${value}`);
|
|
6838
|
-
}
|
|
6839
|
-
}
|
|
6840
|
-
function makeRoomFor(cache, key, maxSize, isValid) {
|
|
6841
|
-
if (maxSize === 0) return false;
|
|
6842
|
-
if (cache.has(key)) return true;
|
|
6843
|
-
if (cache.size < maxSize) return true;
|
|
6844
|
-
for (const [k, entry] of cache) {
|
|
6845
|
-
if (!isValid(entry)) cache.delete(k);
|
|
6846
|
-
}
|
|
6847
|
-
while (cache.size >= maxSize) {
|
|
6848
|
-
let oldestKey = null;
|
|
6849
|
-
let oldestTime = Infinity;
|
|
6850
|
-
for (const [k, entry] of cache) {
|
|
6851
|
-
if (entry.timestamp < oldestTime) {
|
|
6852
|
-
oldestTime = entry.timestamp;
|
|
6853
|
-
oldestKey = k;
|
|
6854
|
-
}
|
|
6855
|
-
}
|
|
6856
|
-
if (oldestKey === null) break;
|
|
6857
|
-
cache.delete(oldestKey);
|
|
6858
|
-
}
|
|
6859
|
-
return true;
|
|
6860
|
-
}
|
|
6861
|
-
function prerenderRoutes(routes, options) {
|
|
6862
|
-
const maxCacheSize = options?.maxCacheSize ?? 50;
|
|
6863
|
-
const cacheTTL = options?.cacheTTL ?? 0;
|
|
6864
|
-
assertCacheSize("maxCacheSize", maxCacheSize);
|
|
6865
|
-
const cache = /* @__PURE__ */ new Map();
|
|
6866
|
-
function isValid(entry) {
|
|
6867
|
-
if (cacheTTL === 0) return true;
|
|
6868
|
-
return Date.now() - entry.timestamp < cacheTTL;
|
|
6869
|
-
}
|
|
6870
|
-
for (const route2 of routes) {
|
|
6871
|
-
if (!makeRoomFor(cache, route2.path, maxCacheSize, isValid)) break;
|
|
6872
|
-
const html2 = renderToString(route2.component());
|
|
6873
|
-
cache.set(route2.path, { html: html2, timestamp: Date.now() });
|
|
6874
|
-
}
|
|
6875
|
-
return {
|
|
6876
|
-
/** Get cached HTML for a route, or undefined if not cached or expired */
|
|
6877
|
-
get(path2) {
|
|
6878
|
-
const entry = cache.get(path2);
|
|
6879
|
-
if (!entry) return void 0;
|
|
6880
|
-
if (!isValid(entry)) {
|
|
6881
|
-
cache.delete(path2);
|
|
6882
|
-
return void 0;
|
|
6883
|
-
}
|
|
6884
|
-
return entry.html;
|
|
6885
|
-
},
|
|
6886
|
-
/** Check if a route has been prerendered and is still valid */
|
|
6887
|
-
has(path2) {
|
|
6888
|
-
const entry = cache.get(path2);
|
|
6889
|
-
if (!entry) return false;
|
|
6890
|
-
if (!isValid(entry)) {
|
|
6891
|
-
cache.delete(path2);
|
|
6892
|
-
return false;
|
|
6893
|
-
}
|
|
6894
|
-
return true;
|
|
6895
|
-
},
|
|
6896
|
-
/** Invalidate a cached route */
|
|
6897
|
-
invalidate(path2) {
|
|
6898
|
-
cache.delete(path2);
|
|
6899
|
-
},
|
|
6900
|
-
/** Clear all cached routes */
|
|
6901
|
-
clear() {
|
|
6902
|
-
cache.clear();
|
|
6903
|
-
},
|
|
6904
|
-
/** Get cache statistics */
|
|
6905
|
-
stats() {
|
|
6906
|
-
if (cacheTTL > 0) {
|
|
6907
|
-
for (const [key, entry] of cache) {
|
|
6908
|
-
if (!isValid(entry)) {
|
|
6909
|
-
cache.delete(key);
|
|
6910
|
-
}
|
|
6911
|
-
}
|
|
6912
|
-
}
|
|
6913
|
-
return {
|
|
6914
|
-
size: cache.size,
|
|
6915
|
-
routes: Array.from(cache.keys())
|
|
6916
|
-
};
|
|
6917
|
-
}
|
|
6918
|
-
};
|
|
6919
|
-
}
|
|
6920
|
-
function createSSRCache(config) {
|
|
6921
|
-
const maxSize = config?.maxSize ?? 100;
|
|
6922
|
-
const defaultTTL = config?.defaultTTL ?? 6e4;
|
|
6923
|
-
assertCacheSize("maxSize", maxSize);
|
|
6924
|
-
const cache = /* @__PURE__ */ new Map();
|
|
6925
|
-
let hits = 0;
|
|
6926
|
-
let misses = 0;
|
|
6927
|
-
function isValid(entry) {
|
|
6928
|
-
if (entry.ttl === 0) return true;
|
|
6929
|
-
return Date.now() - entry.timestamp < entry.ttl;
|
|
6930
|
-
}
|
|
6931
|
-
return {
|
|
6932
|
-
/** Get cached HTML for a key, or undefined if not cached or expired */
|
|
6933
|
-
get(key) {
|
|
6934
|
-
const entry = cache.get(key);
|
|
6935
|
-
if (!entry) {
|
|
6936
|
-
misses++;
|
|
6937
|
-
return void 0;
|
|
6938
|
-
}
|
|
6939
|
-
if (!isValid(entry)) {
|
|
6940
|
-
cache.delete(key);
|
|
6941
|
-
misses++;
|
|
6942
|
-
return void 0;
|
|
6943
|
-
}
|
|
6944
|
-
hits++;
|
|
6945
|
-
return entry.html;
|
|
6946
|
-
},
|
|
6947
|
-
/** Cache an HTML string with an optional TTL override */
|
|
6948
|
-
set(key, html2, ttl) {
|
|
6949
|
-
if (!makeRoomFor(cache, key, maxSize, isValid)) return;
|
|
6950
|
-
cache.set(key, {
|
|
6951
|
-
html: html2,
|
|
6952
|
-
timestamp: Date.now(),
|
|
6953
|
-
ttl: ttl ?? defaultTTL
|
|
6954
|
-
});
|
|
6955
|
-
},
|
|
6956
|
-
/** Check if a key exists in the cache and is still valid */
|
|
6957
|
-
has(key) {
|
|
6958
|
-
const entry = cache.get(key);
|
|
6959
|
-
if (!entry) return false;
|
|
6960
|
-
if (!isValid(entry)) {
|
|
6961
|
-
cache.delete(key);
|
|
6962
|
-
return false;
|
|
6963
|
-
}
|
|
6964
|
-
return true;
|
|
6965
|
-
},
|
|
6966
|
-
/** Invalidate a cached entry */
|
|
6967
|
-
invalidate(key) {
|
|
6968
|
-
cache.delete(key);
|
|
6969
|
-
},
|
|
6970
|
-
/** Clear all cached entries and reset statistics */
|
|
6971
|
-
clear() {
|
|
6972
|
-
cache.clear();
|
|
6973
|
-
hits = 0;
|
|
6974
|
-
misses = 0;
|
|
6975
|
-
},
|
|
6976
|
-
/** Get cache statistics including hit/miss counts */
|
|
6977
|
-
stats() {
|
|
6978
|
-
return { size: cache.size, hits, misses };
|
|
6979
|
-
}
|
|
6980
|
-
};
|
|
6981
|
-
}
|
|
6982
|
-
var DEFER_IDLE_TIMEOUT_MS = 2e3;
|
|
6983
|
-
function deferNonCritical(tasks) {
|
|
6984
|
-
if (tasks.length === 0) return;
|
|
6985
|
-
const schedule = typeof requestIdleCallback !== "undefined" ? (cb) => {
|
|
6986
|
-
requestIdleCallback(cb, { timeout: DEFER_IDLE_TIMEOUT_MS });
|
|
6987
|
-
} : (cb) => {
|
|
6988
|
-
setTimeout(cb, 1);
|
|
6989
|
-
};
|
|
6990
|
-
const queue = [...tasks];
|
|
6991
|
-
let index = 0;
|
|
6992
|
-
function processNext(deadline) {
|
|
6993
|
-
let ranOne = false;
|
|
6994
|
-
while (index < queue.length) {
|
|
6995
|
-
if (ranOne && deadline && deadline.timeRemaining() < 1) {
|
|
6996
|
-
schedule(processNext);
|
|
6997
|
-
return;
|
|
6998
|
-
}
|
|
6999
|
-
try {
|
|
7000
|
-
queue[index]();
|
|
7001
|
-
} catch (e) {
|
|
7002
|
-
reportError(e, { phase: "scheduler", name: "deferNonCritical" });
|
|
7003
|
-
}
|
|
7004
|
-
index++;
|
|
7005
|
-
ranOne = true;
|
|
7006
|
-
}
|
|
7007
|
-
}
|
|
7008
|
-
schedule(processNext);
|
|
7009
|
-
}
|
|
7010
|
-
function createBootSequence() {
|
|
7011
|
-
const criticalTasks = [];
|
|
7012
|
-
const deferredTasks = [];
|
|
7013
|
-
return {
|
|
7014
|
-
/** Add a critical task that runs immediately during boot */
|
|
7015
|
-
critical(name, task) {
|
|
7016
|
-
criticalTasks.push({ name, task });
|
|
7017
|
-
},
|
|
7018
|
-
/** Add a deferred task that runs after all critical tasks complete */
|
|
7019
|
-
defer(name, task) {
|
|
7020
|
-
deferredTasks.push({ name, task });
|
|
7021
|
-
},
|
|
7022
|
-
/** Execute the boot sequence: critical tasks first, then deferred */
|
|
7023
|
-
async boot() {
|
|
7024
|
-
const timing = {};
|
|
7025
|
-
const errors = [];
|
|
7026
|
-
for (const entry of criticalTasks) {
|
|
7027
|
-
const start = Date.now();
|
|
7028
|
-
try {
|
|
7029
|
-
await entry.task();
|
|
7030
|
-
} catch (e) {
|
|
7031
|
-
errors.push({
|
|
7032
|
-
name: entry.name,
|
|
7033
|
-
error: e instanceof Error ? e : new Error(String(e))
|
|
7034
|
-
});
|
|
7035
|
-
}
|
|
7036
|
-
timing[entry.name] = Date.now() - start;
|
|
7037
|
-
}
|
|
7038
|
-
for (const entry of deferredTasks) {
|
|
7039
|
-
const start = Date.now();
|
|
7040
|
-
try {
|
|
7041
|
-
await entry.task();
|
|
7042
|
-
} catch (e) {
|
|
7043
|
-
errors.push({
|
|
7044
|
-
name: entry.name,
|
|
7045
|
-
error: e instanceof Error ? e : new Error(String(e))
|
|
7046
|
-
});
|
|
7047
|
-
}
|
|
7048
|
-
timing[entry.name] = Date.now() - start;
|
|
7049
|
-
}
|
|
7050
|
-
return { timing, errors };
|
|
7051
|
-
}
|
|
7052
|
-
};
|
|
7053
|
-
}
|
|
7054
7476
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7055
7477
|
0 && (module.exports = {
|
|
7056
7478
|
KeepAliveRoute,
|
|
@@ -7117,10 +7539,13 @@ function createBootSequence() {
|
|
|
7117
7539
|
renderRouteToString,
|
|
7118
7540
|
replace,
|
|
7119
7541
|
resetPlugins,
|
|
7542
|
+
resolveRouteHead,
|
|
7120
7543
|
resolveServerRoute,
|
|
7121
7544
|
route,
|
|
7545
|
+
routeHeadToHTML,
|
|
7122
7546
|
router,
|
|
7123
7547
|
routerPlugin,
|
|
7548
|
+
routerReady,
|
|
7124
7549
|
routerState,
|
|
7125
7550
|
satisfies,
|
|
7126
7551
|
serializeRouteState,
|