sibujs 4.7.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.cjs +48 -6
- package/dist/browser.d.cts +26 -2
- package/dist/browser.d.ts +26 -2
- package/dist/browser.js +6 -5
- package/dist/build.cjs +539 -96
- package/dist/build.d.cts +22 -8
- package/dist/build.d.ts +22 -8
- package/dist/build.js +68 -21
- package/dist/cdn.dev.global.js +15 -13
- package/dist/cdn.full.dev.global.js +15 -13
- package/dist/cdn.full.global.js +14 -12
- package/dist/cdn.global.js +14 -12
- package/dist/{chunk-Z3OHK6QT.js → chunk-2K3Z3XO4.js} +5 -5
- package/dist/chunk-3ACAAQIN.js +224 -0
- package/dist/{chunk-WOLJZUFQ.js → chunk-562UVHMM.js} +32 -15
- package/dist/{chunk-UOL2ECCS.js → chunk-5MLWTIQE.js} +18 -12
- package/dist/{chunk-H3SRKIYX.js → chunk-62BDYGAG.js} +8 -0
- package/dist/{chunk-3QWBSL5R.js → chunk-7OV5Q2UU.js} +8 -5
- package/dist/{chunk-SLM3IA34.js → chunk-CDBKFGXN.js} +1 -1
- package/dist/{chunk-4AWA2PVD.js → chunk-CF2KCWRE.js} +10 -5
- package/dist/{chunk-BSY63EM6.js → chunk-DRMLIF6M.js} +20 -5
- package/dist/{chunk-2INLLLMZ.js → chunk-EXXSN3BW.js} +202 -26
- package/dist/{chunk-HURREPU2.js → chunk-FC6KCJSA.js} +87 -150
- package/dist/{chunk-BC2SECJD.js → chunk-FHCZMHHE.js} +1 -1
- package/dist/{chunk-XYV3EDB7.js → chunk-FNOK662L.js} +63 -38
- package/dist/{chunk-JWKYU5GV.js → chunk-G2WHYEL7.js} +1 -1
- package/dist/{chunk-DKXRACVN.js → chunk-K6K5ACO6.js} +6 -6
- package/dist/{chunk-VZSG24LS.js → chunk-KG25XMGP.js} +45 -17
- package/dist/{chunk-FNJXNGYZ.js → chunk-MPWDSTYK.js} +58 -6
- package/dist/{chunk-UNWRJRKC.js → chunk-NQMKWBKU.js} +1 -1
- package/dist/{chunk-7LUJQAOJ.js → chunk-QBKCK6MJ.js} +1 -1
- package/dist/{chunk-WEQ3DMVL.js → chunk-SBTZEYNI.js} +1 -1
- package/dist/{chunk-FQRUXCEE.js → chunk-SYHGGDNW.js} +1 -1
- package/dist/{chunk-XZR4PXRE.js → chunk-TV464N2M.js} +13 -10
- package/dist/{chunk-RUSSKG6G.js → chunk-X7NRHFZR.js} +1 -1
- package/dist/{chunk-2BPG2XDA.js → chunk-XJVTQUIV.js} +18 -36
- package/dist/{chunk-ZVL7TY4K.js → chunk-YW6HQKGO.js} +25 -10
- package/dist/{customElement-MmInOW1U.d.ts → customElement-pYDKUzWl.d.cts} +11 -3
- package/dist/{customElement-MmInOW1U.d.cts → customElement-pYDKUzWl.d.ts} +11 -3
- package/dist/data.cjs +29 -9
- package/dist/data.d.cts +23 -4
- package/dist/data.d.ts +23 -4
- package/dist/data.js +6 -6
- package/dist/devtools.cjs +1 -1
- package/dist/devtools.js +5 -5
- package/dist/ecosystem.cjs +400 -37
- package/dist/ecosystem.js +9 -8
- package/dist/extras.cjs +672 -269
- package/dist/extras.d.cts +2 -2
- package/dist/extras.d.ts +2 -2
- package/dist/extras.js +24 -23
- package/dist/index.cjs +490 -88
- package/dist/index.d.cts +34 -2
- package/dist/index.d.ts +34 -2
- package/dist/index.js +16 -12
- package/dist/motion.cjs +1 -1
- package/dist/motion.js +3 -3
- package/dist/patterns.cjs +10 -7
- package/dist/patterns.js +6 -6
- package/dist/performance.cjs +31 -2
- package/dist/performance.d.cts +12 -2
- package/dist/performance.d.ts +12 -2
- package/dist/performance.js +8 -6
- package/dist/plugins.cjs +571 -240
- package/dist/plugins.d.cts +14 -3
- package/dist/plugins.d.ts +14 -3
- package/dist/plugins.js +35 -37
- package/dist/{ssr-XOTUASDO.js → ssr-5OWAH3U2.js} +4 -2
- package/dist/{ssr-Bli9XRW5.d.ts → ssr-C8hgIAw7.d.cts} +6 -0
- package/dist/{ssr-Bli9XRW5.d.cts → ssr-C8hgIAw7.d.ts} +6 -0
- package/dist/ssr.cjs +484 -138
- package/dist/ssr.d.cts +59 -5
- package/dist/ssr.d.ts +59 -5
- package/dist/ssr.js +11 -9
- package/dist/testing.cjs +3 -3
- package/dist/testing.js +4 -4
- package/dist/ui.cjs +609 -241
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +9 -8
- package/dist/widgets.cjs +1 -1
- package/dist/widgets.js +7 -7
- package/package.json +5 -4
package/dist/extras.cjs
CHANGED
|
@@ -1077,7 +1077,7 @@ function forEachSubscriber(signal2, visit) {
|
|
|
1077
1077
|
}
|
|
1078
1078
|
|
|
1079
1079
|
// src/reactivity/track.ts
|
|
1080
|
-
var _runtimeVersion = true ? "4.
|
|
1080
|
+
var _runtimeVersion = true ? "4.9.0" : "dev";
|
|
1081
1081
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
1082
1082
|
function resolveReactiveApi() {
|
|
1083
1083
|
const g2 = globalThis;
|
|
@@ -1710,7 +1710,11 @@ function reconcile(prev, next, depth, walk, newRoot) {
|
|
|
1710
1710
|
const nextChild = nextRecord[key];
|
|
1711
1711
|
const hasPrev = Object.hasOwn(prevRecord, key);
|
|
1712
1712
|
const shared = hasPrev ? reconcile(prevRecord[key], nextChild, depth + 1, walk, false) : nextChild;
|
|
1713
|
-
|
|
1713
|
+
if (key === "__proto__") {
|
|
1714
|
+
Object.defineProperty(copy, key, { value: shared, writable: true, enumerable: true, configurable: true });
|
|
1715
|
+
} else {
|
|
1716
|
+
copy[key] = shared;
|
|
1717
|
+
}
|
|
1714
1718
|
if (!hasPrev || !Object.is(shared, prevRecord[key])) allFromPrev = false;
|
|
1715
1719
|
if (!Object.is(shared, nextChild)) allFromNext = false;
|
|
1716
1720
|
}
|
|
@@ -1801,6 +1805,8 @@ function query(key, fetcher, options = {}) {
|
|
|
1801
1805
|
structuralSharing = true
|
|
1802
1806
|
} = options;
|
|
1803
1807
|
const resolveKey = typeof key === "function" ? key : () => key;
|
|
1808
|
+
const enabledGate = typeof enabled === "function" ? derived(() => Boolean(enabled())) : null;
|
|
1809
|
+
const isEnabled = enabledGate ?? (() => enabled);
|
|
1804
1810
|
const cache = getActiveQueryCache();
|
|
1805
1811
|
const [data2, setData] = signal(initialData);
|
|
1806
1812
|
const [isFetching, setIsFetching] = signal(false);
|
|
@@ -1915,7 +1921,7 @@ function query(key, fetcher, options = {}) {
|
|
|
1915
1921
|
}
|
|
1916
1922
|
}
|
|
1917
1923
|
async function doFetch() {
|
|
1918
|
-
if (disposed || !currentKey || !
|
|
1924
|
+
if (disposed || !currentKey || !untracked2(isEnabled)) return;
|
|
1919
1925
|
const key2 = currentKey;
|
|
1920
1926
|
const entry = getOrCreateEntry(cache, key2);
|
|
1921
1927
|
attachToEntry(entry, key2);
|
|
@@ -2017,10 +2023,17 @@ function query(key, fetcher, options = {}) {
|
|
|
2017
2023
|
}
|
|
2018
2024
|
const effectCleanup = effect(() => {
|
|
2019
2025
|
const key2 = resolveKey();
|
|
2026
|
+
const on = isEnabled();
|
|
2020
2027
|
const keyChanged = currentKey !== key2;
|
|
2021
2028
|
currentKey = key2;
|
|
2029
|
+
if (key2 === "") {
|
|
2030
|
+
detachFromEntry();
|
|
2031
|
+
setIsFetching(false);
|
|
2032
|
+
return;
|
|
2033
|
+
}
|
|
2022
2034
|
const entry = getOrCreateEntry(cache, key2, initialData);
|
|
2023
2035
|
attachToEntry(entry, key2);
|
|
2036
|
+
if (keyChanged) setIsFetching(entry.promise !== null);
|
|
2024
2037
|
if (entry.data !== void 0) {
|
|
2025
2038
|
const view = viewOf(entry);
|
|
2026
2039
|
batch(() => {
|
|
@@ -2031,17 +2044,17 @@ function query(key, fetcher, options = {}) {
|
|
|
2031
2044
|
}
|
|
2032
2045
|
if (!keyChanged && currentKey === key2 && entry.data !== void 0) {
|
|
2033
2046
|
const isDataStale2 = entry.dataUpdatedAt === 0 || Date.now() - entry.dataUpdatedAt >= staleTime;
|
|
2034
|
-
if (
|
|
2047
|
+
if (on && isDataStale2 && !entry.promise) doFetch();
|
|
2035
2048
|
return;
|
|
2036
2049
|
}
|
|
2037
2050
|
const isDataStale = entry.dataUpdatedAt === 0 || Date.now() - entry.dataUpdatedAt >= staleTime;
|
|
2038
|
-
if (
|
|
2051
|
+
if (on && (entry.data === void 0 || isDataStale)) {
|
|
2039
2052
|
doFetch();
|
|
2040
2053
|
}
|
|
2041
2054
|
});
|
|
2042
2055
|
if (refetchInterval && refetchInterval > 0) {
|
|
2043
2056
|
intervalTimer = setInterval(() => {
|
|
2044
|
-
if (!disposed && currentKey
|
|
2057
|
+
if (!disposed && currentKey) doFetch();
|
|
2045
2058
|
}, refetchInterval);
|
|
2046
2059
|
}
|
|
2047
2060
|
let focusHandler = null;
|
|
@@ -2049,13 +2062,13 @@ function query(key, fetcher, options = {}) {
|
|
|
2049
2062
|
if (typeof globalThis !== "undefined" && typeof globalThis.addEventListener === "function") {
|
|
2050
2063
|
if (refetchOnWindowFocus) {
|
|
2051
2064
|
focusHandler = () => {
|
|
2052
|
-
if (!disposed && currentKey
|
|
2065
|
+
if (!disposed && currentKey) doFetch();
|
|
2053
2066
|
};
|
|
2054
2067
|
globalThis.addEventListener("focus", focusHandler);
|
|
2055
2068
|
}
|
|
2056
2069
|
if (refetchOnReconnect) {
|
|
2057
2070
|
onlineHandler = () => {
|
|
2058
|
-
if (!disposed && currentKey
|
|
2071
|
+
if (!disposed && currentKey) doFetch();
|
|
2059
2072
|
};
|
|
2060
2073
|
globalThis.addEventListener("online", onlineHandler);
|
|
2061
2074
|
}
|
|
@@ -2067,6 +2080,7 @@ function query(key, fetcher, options = {}) {
|
|
|
2067
2080
|
stopSelect?.();
|
|
2068
2081
|
loading.dispose();
|
|
2069
2082
|
isStale.dispose();
|
|
2083
|
+
enabledGate?.dispose();
|
|
2070
2084
|
if (intervalTimer) clearInterval(intervalTimer);
|
|
2071
2085
|
detachFromEntry();
|
|
2072
2086
|
if (focusHandler && typeof globalThis.removeEventListener === "function") {
|
|
@@ -2246,6 +2260,8 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
2246
2260
|
onError
|
|
2247
2261
|
} = options;
|
|
2248
2262
|
const resolveKey = typeof key === "function" ? key : () => key;
|
|
2263
|
+
const enabledGate = typeof enabled === "function" ? derived(() => Boolean(enabled())) : null;
|
|
2264
|
+
const isEnabled = enabledGate ?? (() => enabled);
|
|
2249
2265
|
const [pages, setPages] = signal([]);
|
|
2250
2266
|
const [isFetching, setIsFetching] = signal(false);
|
|
2251
2267
|
const [isFetchingNext, setIsFetchingNext] = signal(false);
|
|
@@ -2324,7 +2340,7 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
2324
2340
|
}
|
|
2325
2341
|
const effectCleanup = effect(() => {
|
|
2326
2342
|
resolveKey();
|
|
2327
|
-
if (
|
|
2343
|
+
if (isEnabled()) {
|
|
2328
2344
|
abortController?.abort();
|
|
2329
2345
|
batch(() => {
|
|
2330
2346
|
setPages([]);
|
|
@@ -2365,6 +2381,7 @@ function infiniteQuery(key, fetcher, options) {
|
|
|
2365
2381
|
loading.dispose();
|
|
2366
2382
|
hasNextPage.dispose();
|
|
2367
2383
|
hasPreviousPage.dispose();
|
|
2384
|
+
enabledGate?.dispose();
|
|
2368
2385
|
}
|
|
2369
2386
|
return {
|
|
2370
2387
|
data: data2,
|
|
@@ -3075,8 +3092,10 @@ function socket(url, options) {
|
|
|
3075
3092
|
function stripControlChars(value) {
|
|
3076
3093
|
return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
|
|
3077
3094
|
}
|
|
3095
|
+
var ASCII_UPPER = /[A-Z]/;
|
|
3096
|
+
var ASCII_UPPER_G = /[A-Z]/g;
|
|
3078
3097
|
function canonicalAttrName(name) {
|
|
3079
|
-
return name.replace(
|
|
3098
|
+
return ASCII_UPPER.test(name) ? name.replace(ASCII_UPPER_G, (ch) => String.fromCharCode(ch.charCodeAt(0) + 32)) : name;
|
|
3080
3099
|
}
|
|
3081
3100
|
function isEventHandlerAttr(name) {
|
|
3082
3101
|
if (name.length < 3) return false;
|
|
@@ -3089,6 +3108,9 @@ function sanitizeUrl(url) {
|
|
|
3089
3108
|
const probe = stripControlChars(url).trim();
|
|
3090
3109
|
if (!probe) return "";
|
|
3091
3110
|
const output2 = url.replace(OUTER_TRIM, "");
|
|
3111
|
+
if (probe.length >= 2 && (probe[0] === "\\" || probe[0] === "/") && (probe[1] === "\\" || probe[1] === "/") && (probe[0] === "\\" || probe[1] === "\\")) {
|
|
3112
|
+
return "";
|
|
3113
|
+
}
|
|
3092
3114
|
const lower = probe.toLowerCase();
|
|
3093
3115
|
let schemeEnd = -1;
|
|
3094
3116
|
for (let i2 = 0; i2 < lower.length; i2++) {
|
|
@@ -3105,19 +3127,58 @@ function sanitizeUrl(url) {
|
|
|
3105
3127
|
if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
|
|
3106
3128
|
return output2;
|
|
3107
3129
|
}
|
|
3108
|
-
var SRCSET_DESCRIPTOR = /^\
|
|
3130
|
+
var SRCSET_DESCRIPTOR = /^\d+(\.\d+)?[wx]$/;
|
|
3131
|
+
function isSrcsetWhitespace(ch) {
|
|
3132
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
|
|
3133
|
+
}
|
|
3109
3134
|
function sanitizeSrcset(value) {
|
|
3110
|
-
const
|
|
3135
|
+
const input2 = String(value);
|
|
3111
3136
|
const out = [];
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
if (
|
|
3117
|
-
|
|
3118
|
-
|
|
3137
|
+
let i2 = 0;
|
|
3138
|
+
const n = input2.length;
|
|
3139
|
+
while (i2 < n) {
|
|
3140
|
+
while (i2 < n && (isSrcsetWhitespace(input2[i2]) || input2[i2] === ",")) i2++;
|
|
3141
|
+
if (i2 >= n) break;
|
|
3142
|
+
const urlStart = i2;
|
|
3143
|
+
while (i2 < n && !isSrcsetWhitespace(input2[i2])) i2++;
|
|
3144
|
+
let url = input2.slice(urlStart, i2);
|
|
3145
|
+
const descriptors = [];
|
|
3146
|
+
if (url.endsWith(",")) {
|
|
3147
|
+
url = url.replace(/,+$/, "");
|
|
3148
|
+
} else {
|
|
3149
|
+
let current = "";
|
|
3150
|
+
let inParens = false;
|
|
3151
|
+
while (i2 < n) {
|
|
3152
|
+
const ch = input2[i2];
|
|
3153
|
+
if (inParens) {
|
|
3154
|
+
current += ch;
|
|
3155
|
+
if (ch === ")") inParens = false;
|
|
3156
|
+
i2++;
|
|
3157
|
+
continue;
|
|
3158
|
+
}
|
|
3159
|
+
if (isSrcsetWhitespace(ch)) {
|
|
3160
|
+
if (current) descriptors.push(current);
|
|
3161
|
+
current = "";
|
|
3162
|
+
i2++;
|
|
3163
|
+
continue;
|
|
3164
|
+
}
|
|
3165
|
+
if (ch === ",") {
|
|
3166
|
+
i2++;
|
|
3167
|
+
break;
|
|
3168
|
+
}
|
|
3169
|
+
if (ch === "(") inParens = true;
|
|
3170
|
+
current += ch;
|
|
3171
|
+
i2++;
|
|
3172
|
+
}
|
|
3173
|
+
if (current) descriptors.push(current);
|
|
3174
|
+
}
|
|
3175
|
+
if (url === "") continue;
|
|
3176
|
+
if (descriptors.length > 1) continue;
|
|
3177
|
+
if (descriptors.length === 1 && !SRCSET_DESCRIPTOR.test(descriptors[0])) continue;
|
|
3178
|
+
const safe = sanitizeUrl(url);
|
|
3119
3179
|
if (!safe) continue;
|
|
3120
|
-
|
|
3180
|
+
if (safe.startsWith(",") || safe.endsWith(",")) continue;
|
|
3181
|
+
out.push(descriptors.length === 1 ? `${safe} ${descriptors[0]}` : safe);
|
|
3121
3182
|
}
|
|
3122
3183
|
return out.join(", ");
|
|
3123
3184
|
}
|
|
@@ -3176,8 +3237,16 @@ var BLOCKED_CSS_NEEDLES = [
|
|
|
3176
3237
|
"behavior:",
|
|
3177
3238
|
"@import",
|
|
3178
3239
|
"image-set(",
|
|
3179
|
-
"filter:progid"
|
|
3240
|
+
"filter:progid",
|
|
3241
|
+
// CSS Images 4 `image("…")` and CSS Values 5 `src("…")` take a URL as a
|
|
3242
|
+
// plain STRING, so they fetch without ever spelling `url(`. Support is thin
|
|
3243
|
+
// today, which is exactly when a blocklist should get ahead of it.
|
|
3244
|
+
"image(",
|
|
3245
|
+
"src("
|
|
3180
3246
|
];
|
|
3247
|
+
var CSS_REASON_MOZ_BINDING = 4;
|
|
3248
|
+
var CSS_REASON_BEHAVIOR = 5;
|
|
3249
|
+
var CSS_REASON_PROGID = 8;
|
|
3181
3250
|
function describeElement(el) {
|
|
3182
3251
|
if (!el) return "an element";
|
|
3183
3252
|
let out = el.tagName.toLowerCase();
|
|
@@ -3201,7 +3270,9 @@ function warnDroppedDeclaration(value, reason, ctx) {
|
|
|
3201
3270
|
"behavior: loads and runs a remote HTC script",
|
|
3202
3271
|
"@import pulls in a remote stylesheet",
|
|
3203
3272
|
"image-set() fetches remote images, the same exfiltration channel as url()",
|
|
3204
|
-
"filter:progid activates legacy scriptable filters"
|
|
3273
|
+
"filter:progid activates legacy scriptable filters",
|
|
3274
|
+
"image() fetches its string argument as a URL, the same exfiltration channel as url()",
|
|
3275
|
+
"src() fetches its string argument as a URL, the same exfiltration channel as url()"
|
|
3205
3276
|
];
|
|
3206
3277
|
const declaration = ctx?.property ? `${ctx.property}: ${value}` : value;
|
|
3207
3278
|
const where = describeElement(ctx?.element);
|
|
@@ -3216,27 +3287,145 @@ function warnDroppedDeclaration(value, reason, ctx) {
|
|
|
3216
3287
|
return `style declaration "${declaration}" was dropped by the style sanitizer on ${where} \u2014 ${reasons[reason]}. The element renders without it, which usually looks like a missing image rather than an error. Sanctioned alternatives: for a content image use an <img> element (or a <picture>); for decoration, put the rule in a stylesheet and set a class instead \u2014 stylesheet CSS is not sanitized, only inline style attributes are. If this declaration is not yours, it came from untrusted data and the drop just prevented an exfiltration.`;
|
|
3217
3288
|
});
|
|
3218
3289
|
}
|
|
3290
|
+
function normalizeCssForScan(value) {
|
|
3291
|
+
const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
|
|
3292
|
+
return normalized.toLowerCase().replace(/\s+/g, "");
|
|
3293
|
+
}
|
|
3219
3294
|
function blockedCssReason(value) {
|
|
3220
3295
|
if (!CSS_DANGER_GATE.test(value)) return -1;
|
|
3221
|
-
const
|
|
3222
|
-
const lower = normalized.toLowerCase().replace(/\s+/g, "");
|
|
3296
|
+
const lower = normalizeCssForScan(value);
|
|
3223
3297
|
for (let i2 = 0; i2 < BLOCKED_CSS_NEEDLES.length; i2++) {
|
|
3224
3298
|
if (lower.includes(BLOCKED_CSS_NEEDLES[i2])) return i2;
|
|
3225
3299
|
}
|
|
3226
3300
|
return -1;
|
|
3227
3301
|
}
|
|
3228
|
-
|
|
3229
|
-
|
|
3302
|
+
var STYLESHEET_BLOCKED_FUNCTIONS = ["url", "image-set", "image", "src", "expression"];
|
|
3303
|
+
function stripCssFunctions(css) {
|
|
3304
|
+
const pattern2 = new RegExp(`(?:-webkit-)?(${STYLESHEET_BLOCKED_FUNCTIONS.join("|")})\\s*\\(`, "gi");
|
|
3305
|
+
let out = "";
|
|
3306
|
+
let last = 0;
|
|
3307
|
+
for (let match = pattern2.exec(css); match !== null; match = pattern2.exec(css)) {
|
|
3308
|
+
const before = match.index > 0 ? css[match.index - 1] : "";
|
|
3309
|
+
if (/[\w-]/.test(before)) continue;
|
|
3310
|
+
let depth = 1;
|
|
3311
|
+
let i2 = pattern2.lastIndex;
|
|
3312
|
+
let quote2 = "";
|
|
3313
|
+
for (; i2 < css.length && depth > 0; i2++) {
|
|
3314
|
+
const ch = css[i2];
|
|
3315
|
+
if (quote2) {
|
|
3316
|
+
if (ch === "\\") i2++;
|
|
3317
|
+
else if (ch === quote2) quote2 = "";
|
|
3318
|
+
} else if (ch === '"' || ch === "'") quote2 = ch;
|
|
3319
|
+
else if (ch === "(") depth++;
|
|
3320
|
+
else if (ch === ")") depth--;
|
|
3321
|
+
}
|
|
3322
|
+
out += `${css.slice(last, match.index)}/* ${match[1].toLowerCase()}() removed */`;
|
|
3323
|
+
last = i2;
|
|
3324
|
+
pattern2.lastIndex = i2;
|
|
3325
|
+
}
|
|
3326
|
+
return out + css.slice(last);
|
|
3327
|
+
}
|
|
3328
|
+
function sanitizeStylesheetText(css) {
|
|
3329
|
+
let text2 = css.includes("\\") ? decodeCssEscapes(css) : css;
|
|
3330
|
+
text2 = text2.replace(/@import\b[^;{}]*;?/gi, "/* @import removed */");
|
|
3331
|
+
text2 = stripCssFunctions(text2);
|
|
3332
|
+
text2 = text2.replace(/(^|[;{\s])behavior\s*:[^;}]*;?/gi, "$1/* behavior removed */");
|
|
3333
|
+
text2 = text2.replace(/(^|[;{\s])-moz-binding\s*:[^;}]*;?/gi, "$1/* -moz-binding removed */");
|
|
3334
|
+
text2 = text2.replace(/(^|[;{\s])(-ms-)?filter\s*:[^;}]*progid[^;}]*;?/gi, "$1/* filter:progid removed */");
|
|
3335
|
+
return text2;
|
|
3336
|
+
}
|
|
3337
|
+
function sanitizeCSSDeclaration(property, value, context) {
|
|
3338
|
+
const reason = blockedDeclarationReason(property, value);
|
|
3230
3339
|
if (reason === -1) return value;
|
|
3231
|
-
warnDroppedDeclaration(value, reason, context);
|
|
3340
|
+
warnDroppedDeclaration(value, reason, { property, element: context?.element });
|
|
3232
3341
|
return "";
|
|
3233
3342
|
}
|
|
3343
|
+
function blockedDeclarationReason(property, value) {
|
|
3344
|
+
const reason = blockedCssReason(value);
|
|
3345
|
+
if (reason !== -1) return reason;
|
|
3346
|
+
const name = canonicalAttrName(property);
|
|
3347
|
+
if (name === "behavior") return CSS_REASON_BEHAVIOR;
|
|
3348
|
+
if (name === "-moz-binding") return CSS_REASON_MOZ_BINDING;
|
|
3349
|
+
if ((name === "filter" || name === "-ms-filter") && normalizeCssForScan(value).includes("progid:")) {
|
|
3350
|
+
return CSS_REASON_PROGID;
|
|
3351
|
+
}
|
|
3352
|
+
return -1;
|
|
3353
|
+
}
|
|
3354
|
+
function parseStyleDeclarations(css) {
|
|
3355
|
+
const chunks = [];
|
|
3356
|
+
let buf = "";
|
|
3357
|
+
let depth = 0;
|
|
3358
|
+
let quote2 = "";
|
|
3359
|
+
for (let i2 = 0; i2 < css.length; i2++) {
|
|
3360
|
+
const ch = css[i2];
|
|
3361
|
+
if (quote2) {
|
|
3362
|
+
buf += ch;
|
|
3363
|
+
if (ch === "\\" && i2 + 1 < css.length) buf += css[++i2];
|
|
3364
|
+
else if (ch === quote2) quote2 = "";
|
|
3365
|
+
continue;
|
|
3366
|
+
}
|
|
3367
|
+
if (ch === "\\") {
|
|
3368
|
+
buf += ch;
|
|
3369
|
+
if (i2 + 1 < css.length) buf += css[++i2];
|
|
3370
|
+
continue;
|
|
3371
|
+
}
|
|
3372
|
+
if (ch === "/" && css[i2 + 1] === "*") {
|
|
3373
|
+
const end = css.indexOf("*/", i2 + 2);
|
|
3374
|
+
if (end === -1) return null;
|
|
3375
|
+
i2 = end + 1;
|
|
3376
|
+
continue;
|
|
3377
|
+
}
|
|
3378
|
+
if (ch === '"' || ch === "'") quote2 = ch;
|
|
3379
|
+
else if (ch === "(" || ch === "[") depth++;
|
|
3380
|
+
else if (ch === ")" || ch === "]") {
|
|
3381
|
+
if (--depth < 0) return null;
|
|
3382
|
+
} else if (ch === "{" || ch === "}") return null;
|
|
3383
|
+
else if (ch === ";" && depth === 0) {
|
|
3384
|
+
chunks.push(buf);
|
|
3385
|
+
buf = "";
|
|
3386
|
+
continue;
|
|
3387
|
+
}
|
|
3388
|
+
buf += ch;
|
|
3389
|
+
}
|
|
3390
|
+
if (quote2 || depth !== 0) return null;
|
|
3391
|
+
chunks.push(buf);
|
|
3392
|
+
const out = [];
|
|
3393
|
+
for (const chunk of chunks) {
|
|
3394
|
+
const colon = chunk.indexOf(":");
|
|
3395
|
+
if (colon === -1) continue;
|
|
3396
|
+
const rawName = chunk.slice(0, colon).trim();
|
|
3397
|
+
if (!/^(--[\w-]+|-?[a-zA-Z_][\w-]*)$/.test(rawName)) continue;
|
|
3398
|
+
let value = chunk.slice(colon + 1).trim();
|
|
3399
|
+
const bang = /!\s*important\s*$/i.exec(value);
|
|
3400
|
+
if (bang) value = value.slice(0, bang.index).trim();
|
|
3401
|
+
if (value === "") continue;
|
|
3402
|
+
const property = rawName.startsWith("--") ? rawName : canonicalAttrName(rawName);
|
|
3403
|
+
out.push([property, value, bang !== null]);
|
|
3404
|
+
}
|
|
3405
|
+
return out;
|
|
3406
|
+
}
|
|
3407
|
+
function sanitizeStyleDeclarationList(cssText, context) {
|
|
3408
|
+
const input2 = String(cssText);
|
|
3409
|
+
const declarations = parseStyleDeclarations(input2);
|
|
3410
|
+
if (declarations === null) {
|
|
3411
|
+
if (blockedCssReason(input2) !== -1) warnDroppedDeclaration(input2, blockedCssReason(input2), context);
|
|
3412
|
+
return "";
|
|
3413
|
+
}
|
|
3414
|
+
const kept = [];
|
|
3415
|
+
for (const [property, value, important] of declarations) {
|
|
3416
|
+
const reason = blockedDeclarationReason(property, value);
|
|
3417
|
+
if (reason !== -1) {
|
|
3418
|
+
warnDroppedDeclaration(value, reason, { property, element: context?.element });
|
|
3419
|
+
continue;
|
|
3420
|
+
}
|
|
3421
|
+
kept.push(`${property}: ${value}${important ? " !important" : ""}`);
|
|
3422
|
+
}
|
|
3423
|
+
return kept.join("; ");
|
|
3424
|
+
}
|
|
3234
3425
|
function sanitizeStyleAttribute(cssText, context) {
|
|
3235
3426
|
const input2 = String(cssText);
|
|
3236
3427
|
if (input2.trim() === "") return "";
|
|
3237
|
-
if (typeof document === "undefined")
|
|
3238
|
-
return sanitizeCSSValue(input2, context) === "" ? "" : input2;
|
|
3239
|
-
}
|
|
3428
|
+
if (typeof document === "undefined") return sanitizeStyleDeclarationList(input2, context);
|
|
3240
3429
|
const probe = document.createElement("div");
|
|
3241
3430
|
try {
|
|
3242
3431
|
probe.style.cssText = input2;
|
|
@@ -3247,8 +3436,7 @@ function sanitizeStyleAttribute(cssText, context) {
|
|
|
3247
3436
|
for (let i2 = 0; i2 < probe.style.length; i2++) {
|
|
3248
3437
|
const property = probe.style[i2];
|
|
3249
3438
|
const value = probe.style.getPropertyValue(property);
|
|
3250
|
-
|
|
3251
|
-
if (reason === -1) reason = blockedCssReason(`${property}:${value}`);
|
|
3439
|
+
const reason = blockedDeclarationReason(property, value);
|
|
3252
3440
|
if (reason !== -1) {
|
|
3253
3441
|
warnDroppedDeclaration(value, reason, { property, element: context?.element });
|
|
3254
3442
|
continue;
|
|
@@ -3296,6 +3484,9 @@ var HTML_CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set(["srcdoc"]);
|
|
|
3296
3484
|
function isHtmlContentAttribute(name) {
|
|
3297
3485
|
return HTML_CONTENT_ATTRIBUTES.has(name.toLowerCase());
|
|
3298
3486
|
}
|
|
3487
|
+
function isUrlAttribute(attr) {
|
|
3488
|
+
return URL_ATTRIBUTES.has(attr.toLowerCase());
|
|
3489
|
+
}
|
|
3299
3490
|
function isPolicyAttribute(name) {
|
|
3300
3491
|
const lower = name.toLowerCase();
|
|
3301
3492
|
return lower === "style" || URL_ATTRIBUTES.has(lower);
|
|
@@ -3307,6 +3498,11 @@ function sanitizeAttributeString(attr, value, context) {
|
|
|
3307
3498
|
if (lower === "style") return sanitizeStyleAttribute(value, context);
|
|
3308
3499
|
return value;
|
|
3309
3500
|
}
|
|
3501
|
+
function resolveAttributeValue(attr, value, context) {
|
|
3502
|
+
if (!isPolicyAttribute(attr)) return value;
|
|
3503
|
+
const safe = sanitizeAttributeString(attr, value, context);
|
|
3504
|
+
return safe === "" ? null : safe;
|
|
3505
|
+
}
|
|
3310
3506
|
|
|
3311
3507
|
// src/ui/stream.ts
|
|
3312
3508
|
function validateSseUrl(raw) {
|
|
@@ -3730,6 +3926,13 @@ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototyp
|
|
|
3730
3926
|
function isUnsafeKey(key) {
|
|
3731
3927
|
return UNSAFE_KEYS.has(key);
|
|
3732
3928
|
}
|
|
3929
|
+
function readOwnGlobal(key) {
|
|
3930
|
+
if (typeof window === "undefined") return void 0;
|
|
3931
|
+
if (!Object.hasOwn(window, key)) return void 0;
|
|
3932
|
+
const value = window[key];
|
|
3933
|
+
if (typeof Node !== "undefined" && value instanceof Node) return void 0;
|
|
3934
|
+
return value;
|
|
3935
|
+
}
|
|
3733
3936
|
function stripUnsafeKeys(obj) {
|
|
3734
3937
|
const out = {};
|
|
3735
3938
|
for (const k of Object.keys(obj)) {
|
|
@@ -4047,13 +4250,19 @@ function colorScheme() {
|
|
|
4047
4250
|
}
|
|
4048
4251
|
|
|
4049
4252
|
// src/browser/format.ts
|
|
4253
|
+
var I18N_STATE = /* @__PURE__ */ Symbol.for("sibujs.i18n.v1");
|
|
4254
|
+
function activeI18nLocale() {
|
|
4255
|
+
const state2 = globalThis[I18N_STATE];
|
|
4256
|
+
if (!state2) return void 0;
|
|
4257
|
+
return state2.getLocale ? state2.getLocale() : state2.locale?.[0]();
|
|
4258
|
+
}
|
|
4050
4259
|
function formatNumber(value, options) {
|
|
4051
4260
|
const { locale, ...formatOptions } = options ?? {};
|
|
4052
|
-
return new Intl.NumberFormat(locale, formatOptions).format(value);
|
|
4261
|
+
return new Intl.NumberFormat(locale ?? activeI18nLocale(), formatOptions).format(value);
|
|
4053
4262
|
}
|
|
4054
4263
|
function formatCurrency(value, currency, options) {
|
|
4055
4264
|
const { locale, ...formatOptions } = options ?? {};
|
|
4056
|
-
return new Intl.NumberFormat(locale, {
|
|
4265
|
+
return new Intl.NumberFormat(locale ?? activeI18nLocale(), {
|
|
4057
4266
|
...formatOptions,
|
|
4058
4267
|
style: "currency",
|
|
4059
4268
|
currency
|
|
@@ -4647,6 +4856,7 @@ function keyboard(options = {}) {
|
|
|
4647
4856
|
};
|
|
4648
4857
|
}
|
|
4649
4858
|
const target = options.target ?? window;
|
|
4859
|
+
const view = options.target?.ownerDocument?.defaultView ?? window;
|
|
4650
4860
|
const filter = options.keys ? new Set(options.keys) : null;
|
|
4651
4861
|
const onDown = (e) => {
|
|
4652
4862
|
if (filter && !filter.has(e.key)) return;
|
|
@@ -4669,14 +4879,14 @@ function keyboard(options = {}) {
|
|
|
4669
4879
|
const onBlur = () => setPressed(/* @__PURE__ */ new Set());
|
|
4670
4880
|
target.addEventListener("keydown", onDown);
|
|
4671
4881
|
target.addEventListener("keyup", onUp);
|
|
4672
|
-
|
|
4882
|
+
view.addEventListener("blur", onBlur);
|
|
4673
4883
|
function isPressed(key) {
|
|
4674
4884
|
return pressed().has(key);
|
|
4675
4885
|
}
|
|
4676
4886
|
function dispose2() {
|
|
4677
4887
|
target.removeEventListener("keydown", onDown);
|
|
4678
4888
|
target.removeEventListener("keyup", onUp);
|
|
4679
|
-
|
|
4889
|
+
view.removeEventListener("blur", onBlur);
|
|
4680
4890
|
}
|
|
4681
4891
|
return { pressed, isPressed, dispose: dispose2 };
|
|
4682
4892
|
}
|
|
@@ -5022,6 +5232,11 @@ function imageLoader(src) {
|
|
|
5022
5232
|
abandonCurrent();
|
|
5023
5233
|
resetState();
|
|
5024
5234
|
if (disposed || token !== startToken) return;
|
|
5235
|
+
const safe = sanitizeUrl(String(url));
|
|
5236
|
+
if (!safe) {
|
|
5237
|
+
setStatus("error");
|
|
5238
|
+
return;
|
|
5239
|
+
}
|
|
5025
5240
|
const img2 = new Image();
|
|
5026
5241
|
current = img2;
|
|
5027
5242
|
currentSettled = false;
|
|
@@ -5040,7 +5255,7 @@ function imageLoader(src) {
|
|
|
5040
5255
|
currentSettled = true;
|
|
5041
5256
|
setStatus("error");
|
|
5042
5257
|
};
|
|
5043
|
-
img2.src =
|
|
5258
|
+
img2.src = safe;
|
|
5044
5259
|
}
|
|
5045
5260
|
let srcEffectTeardown = null;
|
|
5046
5261
|
if (typeof src === "function") {
|
|
@@ -5066,6 +5281,9 @@ function imageLoader(src) {
|
|
|
5066
5281
|
}
|
|
5067
5282
|
|
|
5068
5283
|
// src/patterns/machine.ts
|
|
5284
|
+
function ownEntry(table2, key) {
|
|
5285
|
+
return Object.hasOwn(table2, key) ? table2[key] : void 0;
|
|
5286
|
+
}
|
|
5069
5287
|
function machine(config) {
|
|
5070
5288
|
const [state2, setState] = signal(config.initial);
|
|
5071
5289
|
const [context, setContext] = signal(config.context || {});
|
|
@@ -5087,9 +5305,9 @@ function machine(config) {
|
|
|
5087
5305
|
}
|
|
5088
5306
|
}
|
|
5089
5307
|
function step(event) {
|
|
5090
|
-
const stateDef = config.states
|
|
5308
|
+
const stateDef = ownEntry(config.states, currentState);
|
|
5091
5309
|
if (!stateDef?.on) return;
|
|
5092
|
-
const transition2 = stateDef.on
|
|
5310
|
+
const transition2 = ownEntry(stateDef.on, event);
|
|
5093
5311
|
if (!transition2) return;
|
|
5094
5312
|
let target;
|
|
5095
5313
|
let guard;
|
|
@@ -5117,7 +5335,7 @@ function machine(config) {
|
|
|
5117
5335
|
if (action) setContext(nextContext);
|
|
5118
5336
|
setState(target);
|
|
5119
5337
|
});
|
|
5120
|
-
const targetDef = config.states
|
|
5338
|
+
const targetDef = ownEntry(config.states, target);
|
|
5121
5339
|
if (targetDef?.entry) {
|
|
5122
5340
|
targetDef.entry(currentContext);
|
|
5123
5341
|
}
|
|
@@ -5127,7 +5345,7 @@ function machine(config) {
|
|
|
5127
5345
|
if (processing) return;
|
|
5128
5346
|
drain();
|
|
5129
5347
|
}
|
|
5130
|
-
const initialDef = config.states
|
|
5348
|
+
const initialDef = ownEntry(config.states, config.initial);
|
|
5131
5349
|
if (initialDef?.entry) {
|
|
5132
5350
|
processing = true;
|
|
5133
5351
|
try {
|
|
@@ -5145,9 +5363,9 @@ function machine(config) {
|
|
|
5145
5363
|
}
|
|
5146
5364
|
function can(event) {
|
|
5147
5365
|
const currentState2 = state2();
|
|
5148
|
-
const stateDef = config.states
|
|
5366
|
+
const stateDef = ownEntry(config.states, currentState2);
|
|
5149
5367
|
if (!stateDef?.on) return false;
|
|
5150
|
-
const transition2 = stateDef.on
|
|
5368
|
+
const transition2 = ownEntry(stateDef.on, event);
|
|
5151
5369
|
if (!transition2) return false;
|
|
5152
5370
|
if (typeof transition2 === "string") return true;
|
|
5153
5371
|
if (transition2.guard) {
|
|
@@ -7224,31 +7442,6 @@ function announce(message, priority = "polite") {
|
|
|
7224
7442
|
|
|
7225
7443
|
// src/ui/scopedStyle.ts
|
|
7226
7444
|
var _scope = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.scopedStyle.v1"), () => ({ n: 0 }));
|
|
7227
|
-
function decodeCssEscapes2(css) {
|
|
7228
|
-
return css.replace(/\\([0-9a-f]{1,6})[ \t\n\r\f]?|\\([^\n])/gi, (_match, hex, ch) => {
|
|
7229
|
-
if (hex) {
|
|
7230
|
-
const code2 = Number.parseInt(hex, 16);
|
|
7231
|
-
if (Number.isFinite(code2) && code2 > 0 && code2 <= 1114111) {
|
|
7232
|
-
try {
|
|
7233
|
-
return String.fromCodePoint(code2);
|
|
7234
|
-
} catch {
|
|
7235
|
-
return "";
|
|
7236
|
-
}
|
|
7237
|
-
}
|
|
7238
|
-
return "";
|
|
7239
|
-
}
|
|
7240
|
-
return ch || "";
|
|
7241
|
-
});
|
|
7242
|
-
}
|
|
7243
|
-
function sanitizeCSS(css) {
|
|
7244
|
-
let sanitized = decodeCssEscapes2(css);
|
|
7245
|
-
sanitized = sanitized.replace(/@import\s+[^;]+;/gi, "/* @import removed */");
|
|
7246
|
-
sanitized = sanitized.replace(/url\s*\(\s*(?:"[^"]*"|'[^']*'|[^)]*)\s*\)/gi, "/* url() removed */");
|
|
7247
|
-
sanitized = sanitized.replace(/expression\s*\(\s*(?:"[^"]*"|'[^']*'|[^)]*)\s*\)/gi, "/* expression() removed */");
|
|
7248
|
-
sanitized = sanitized.replace(/-moz-binding\s*:[^;]+;/gi, "/* -moz-binding removed */");
|
|
7249
|
-
sanitized = sanitized.replace(/behavior\s*:[^;]+;/gi, "/* behavior removed */");
|
|
7250
|
-
return sanitized;
|
|
7251
|
-
}
|
|
7252
7445
|
function firstCompoundEnd(selector) {
|
|
7253
7446
|
let parens = 0;
|
|
7254
7447
|
let brackets = 0;
|
|
@@ -7410,7 +7603,7 @@ function scopeStylesheet(css, attr) {
|
|
|
7410
7603
|
function scopedStyle(css) {
|
|
7411
7604
|
const id = `sibu-s${_scope.n++}`;
|
|
7412
7605
|
const attr = `data-${id}`;
|
|
7413
|
-
const safeCss =
|
|
7606
|
+
const safeCss = sanitizeStylesheetText(css);
|
|
7414
7607
|
const scopedCSS = scopeStylesheet(safeCss, attr);
|
|
7415
7608
|
if (typeof document !== "undefined") {
|
|
7416
7609
|
const styleEl = document.createElement("style");
|
|
@@ -7436,26 +7629,246 @@ function removeScopedStyle(scopeId) {
|
|
|
7436
7629
|
if (el) el.remove();
|
|
7437
7630
|
}
|
|
7438
7631
|
|
|
7439
|
-
// src/utils/
|
|
7632
|
+
// src/utils/metaRefresh.ts
|
|
7633
|
+
function isAsciiWhitespace(ch) {
|
|
7634
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
|
|
7635
|
+
}
|
|
7636
|
+
function trimAsciiWhitespace(value) {
|
|
7637
|
+
let start = 0;
|
|
7638
|
+
let end = value.length;
|
|
7639
|
+
while (start < end && isAsciiWhitespace(value[start])) start++;
|
|
7640
|
+
while (end > start && isAsciiWhitespace(value[end - 1])) end--;
|
|
7641
|
+
return value.slice(start, end);
|
|
7642
|
+
}
|
|
7643
|
+
var forbidden = (reason) => ({ kind: "forbidden", reason });
|
|
7644
|
+
function parseMetaRefreshContent(content) {
|
|
7645
|
+
const raw = trimAsciiWhitespace(stripControlChars(content));
|
|
7646
|
+
if (raw === "") return forbidden(DEV ? "empty content" : "");
|
|
7647
|
+
let i2 = 0;
|
|
7648
|
+
while (i2 < raw.length && raw[i2] >= "0" && raw[i2] <= "9") i2++;
|
|
7649
|
+
if (i2 === 0) return forbidden(DEV ? "missing or non-numeric delay" : "");
|
|
7650
|
+
const delay = Number.parseInt(raw.slice(0, i2), 10);
|
|
7651
|
+
if (!Number.isFinite(delay)) return forbidden(DEV ? "unparseable delay" : "");
|
|
7652
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
7653
|
+
if (i2 === raw.length) return { kind: "delay-only", delay };
|
|
7654
|
+
if (raw[i2] !== ";" && raw[i2] !== ",") return forbidden(DEV ? "unexpected text after delay" : "");
|
|
7655
|
+
i2++;
|
|
7656
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
7657
|
+
const keyStart = i2;
|
|
7658
|
+
while (i2 < raw.length && !isAsciiWhitespace(raw[i2]) && raw[i2] !== "=") i2++;
|
|
7659
|
+
const key = raw.slice(keyStart, i2).toLowerCase();
|
|
7660
|
+
if (key !== "url") return forbidden(DEV ? `unsupported refresh key ${JSON.stringify(key)}` : "");
|
|
7661
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
7662
|
+
if (raw[i2] !== "=") return forbidden(DEV ? "missing '=' after url" : "");
|
|
7663
|
+
i2++;
|
|
7664
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
7665
|
+
let destination;
|
|
7666
|
+
const quote2 = raw[i2];
|
|
7667
|
+
if (quote2 === '"' || quote2 === "'") {
|
|
7668
|
+
const close = raw.indexOf(quote2, i2 + 1);
|
|
7669
|
+
if (close === -1) return forbidden(DEV ? "unterminated quoted destination" : "");
|
|
7670
|
+
destination = raw.slice(i2 + 1, close);
|
|
7671
|
+
const rest = trimAsciiWhitespace(raw.slice(close + 1));
|
|
7672
|
+
if (rest !== "") return forbidden(DEV ? "trailing text after quoted destination" : "");
|
|
7673
|
+
} else {
|
|
7674
|
+
destination = trimAsciiWhitespace(raw.slice(i2));
|
|
7675
|
+
if (/[;,]/.test(destination)) return forbidden(DEV ? "multiple refresh assignments" : "");
|
|
7676
|
+
}
|
|
7677
|
+
if (destination === "") return forbidden(DEV ? "empty destination" : "");
|
|
7678
|
+
const sanitizedDestination = sanitizeUrl(destination);
|
|
7679
|
+
if (sanitizedDestination === "") return forbidden(DEV ? "destination uses a disallowed protocol" : "");
|
|
7680
|
+
return { kind: "allowed", delay, destination, sanitizedDestination };
|
|
7681
|
+
}
|
|
7682
|
+
function resolveMetaRefreshPolicy(attributes) {
|
|
7683
|
+
let httpEquiv;
|
|
7684
|
+
let content;
|
|
7685
|
+
let duplicateName;
|
|
7686
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7687
|
+
for (const [key, value] of attributes) {
|
|
7688
|
+
const canonical = canonicalAttrName(key);
|
|
7689
|
+
if (seen.has(canonical)) duplicateName = canonical;
|
|
7690
|
+
seen.add(canonical);
|
|
7691
|
+
if (canonical === "http-equiv") httpEquiv = value;
|
|
7692
|
+
else if (canonical === "content") content = value;
|
|
7693
|
+
}
|
|
7694
|
+
if (duplicateName !== void 0) {
|
|
7695
|
+
return forbidden(DEV ? `duplicate case-insensitive attribute ${JSON.stringify(duplicateName)}` : "");
|
|
7696
|
+
}
|
|
7697
|
+
if (typeof httpEquiv !== "string") return { kind: "not-refresh" };
|
|
7698
|
+
if (trimAsciiWhitespace(stripControlChars(httpEquiv)).toLowerCase() !== "refresh") {
|
|
7699
|
+
return { kind: "not-refresh" };
|
|
7700
|
+
}
|
|
7701
|
+
if (typeof content !== "string") return { kind: "not-refresh" };
|
|
7702
|
+
return parseMetaRefreshContent(content);
|
|
7703
|
+
}
|
|
7704
|
+
function normalizeMetaAttributes(props) {
|
|
7705
|
+
const out = /* @__PURE__ */ new Map();
|
|
7706
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7707
|
+
for (const key of Object.keys(props)) {
|
|
7708
|
+
const canonical = canonicalAttrName(key);
|
|
7709
|
+
if (seen.has(canonical)) return null;
|
|
7710
|
+
seen.add(canonical);
|
|
7711
|
+
out.set(key, props[key]);
|
|
7712
|
+
}
|
|
7713
|
+
return out;
|
|
7714
|
+
}
|
|
7715
|
+
function isForbiddenMetaEntry(props) {
|
|
7716
|
+
const normalized = normalizeMetaAttributes(props);
|
|
7717
|
+
if (normalized === null) return true;
|
|
7718
|
+
return resolveMetaRefreshPolicy(normalized).kind === "forbidden";
|
|
7719
|
+
}
|
|
7720
|
+
|
|
7721
|
+
// src/utils/elementPolicy.ts
|
|
7440
7722
|
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
7441
7723
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
7724
|
+
var BLOCKED_ELEMENTS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
7725
|
+
function canonicalTagName(tag) {
|
|
7726
|
+
return canonicalAttrName(tag);
|
|
7727
|
+
}
|
|
7728
|
+
function isBlockedElement(tag) {
|
|
7729
|
+
return BLOCKED_ELEMENTS.has(canonicalTagName(tag));
|
|
7730
|
+
}
|
|
7731
|
+
var CODE_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
7732
|
+
function isCodeTextElement(tag) {
|
|
7733
|
+
return CODE_TEXT_ELEMENTS.has(canonicalTagName(tag));
|
|
7734
|
+
}
|
|
7735
|
+
var ContextualRefusal = {
|
|
7736
|
+
None: 0,
|
|
7737
|
+
/** The element would carry a refresh directive the shared policy forbids. */
|
|
7738
|
+
MetaRefreshForbidden: 1,
|
|
7739
|
+
/** A `<meta>` with a reactive binding may not carry any refresh directive. */
|
|
7740
|
+
MetaRefreshReactive: 2,
|
|
7741
|
+
/** A runtime value may not choose which program a `<script>` runs. */
|
|
7742
|
+
ScriptSource: 3,
|
|
7743
|
+
/** An SVG animation may not target a URL, handler or document attribute. */
|
|
7744
|
+
AnimationTarget: 4,
|
|
7745
|
+
/** A runtime-written `href` may not become an applied stylesheet. */
|
|
7746
|
+
StylesheetSource: 5
|
|
7747
|
+
};
|
|
7748
|
+
var SCRIPT_SOURCE_ATTRIBUTES = /* @__PURE__ */ new Set(["src", "href", "xlink:href", "type", "language"]);
|
|
7749
|
+
var SVG_ANIMATION_ELEMENTS = /* @__PURE__ */ new Set(["animate", "set", "animateMotion", "animateTransform", "animateColor"]);
|
|
7750
|
+
var reactiveMetaElements = /* @__PURE__ */ new WeakSet();
|
|
7751
|
+
function isHtmlNamespace(el) {
|
|
7752
|
+
return el.namespaceURI === HTML_NS || el.namespaceURI === null;
|
|
7753
|
+
}
|
|
7754
|
+
function metaSnapshot(el, canonical, value) {
|
|
7755
|
+
const snapshot = /* @__PURE__ */ new Map();
|
|
7756
|
+
const attrs = el.attributes;
|
|
7757
|
+
for (let i2 = 0; i2 < attrs.length; i2++) {
|
|
7758
|
+
const attr = attrs[i2];
|
|
7759
|
+
if (attr.name === canonical) continue;
|
|
7760
|
+
snapshot.set(attr.name, attr.value);
|
|
7761
|
+
}
|
|
7762
|
+
if (canonical !== null && value !== null) snapshot.set(canonical, value);
|
|
7763
|
+
return snapshot;
|
|
7764
|
+
}
|
|
7765
|
+
function claimReactiveMeta(el) {
|
|
7766
|
+
if (reactiveMetaElements.has(el)) return;
|
|
7767
|
+
reactiveMetaElements.add(el);
|
|
7768
|
+
if (el.getAttribute("content") === null) return;
|
|
7769
|
+
if (resolveMetaRefreshPolicy(metaSnapshot(el, null, null)).kind !== "not-refresh") {
|
|
7770
|
+
el.removeAttribute("content");
|
|
7771
|
+
}
|
|
7772
|
+
}
|
|
7773
|
+
function metaRefusal(el, name, value, origin) {
|
|
7774
|
+
if (!isHtmlNamespace(el)) return ContextualRefusal.None;
|
|
7775
|
+
const canonical = canonicalAttrName(name);
|
|
7776
|
+
if (canonical !== "http-equiv" && canonical !== "content") return ContextualRefusal.None;
|
|
7777
|
+
if (origin === "reactive") claimReactiveMeta(el);
|
|
7778
|
+
if (value === null) return ContextualRefusal.None;
|
|
7779
|
+
if (canonical === "content" && !el.hasAttribute("http-equiv")) return ContextualRefusal.None;
|
|
7780
|
+
const decision = resolveMetaRefreshPolicy(metaSnapshot(el, canonical, value));
|
|
7781
|
+
if (decision.kind === "forbidden") return ContextualRefusal.MetaRefreshForbidden;
|
|
7782
|
+
if (decision.kind !== "not-refresh" && reactiveMetaElements.has(el)) return ContextualRefusal.MetaRefreshReactive;
|
|
7783
|
+
return ContextualRefusal.None;
|
|
7784
|
+
}
|
|
7785
|
+
function animationRefusal(name, value) {
|
|
7786
|
+
if (value === null || canonicalAttrName(name) !== "attributename") return ContextualRefusal.None;
|
|
7787
|
+
const target = stripControlChars(value);
|
|
7788
|
+
return isUrlAttribute(target) || isEventHandlerAttr(target) || isHtmlContentAttribute(target) ? ContextualRefusal.AnimationTarget : ContextualRefusal.None;
|
|
7789
|
+
}
|
|
7790
|
+
var runtimeHrefLinks = /* @__PURE__ */ new WeakSet();
|
|
7791
|
+
function relHasStylesheet(rel) {
|
|
7792
|
+
if (rel === null) return false;
|
|
7793
|
+
const lower = canonicalAttrName(rel);
|
|
7794
|
+
if (!lower.includes("stylesheet")) return false;
|
|
7795
|
+
const tokens = lower.split(/[\t\n\f\r ]+/);
|
|
7796
|
+
for (let i2 = 0; i2 < tokens.length; i2++) if (tokens[i2] === "stylesheet") return true;
|
|
7797
|
+
return false;
|
|
7798
|
+
}
|
|
7799
|
+
function stylesheetRefusal(el, name, value, origin) {
|
|
7800
|
+
if (!isHtmlNamespace(el)) return ContextualRefusal.None;
|
|
7801
|
+
const canonical = canonicalAttrName(name);
|
|
7802
|
+
if (canonical === "href") {
|
|
7803
|
+
if (origin === "static" || value === null) return ContextualRefusal.None;
|
|
7804
|
+
if (relHasStylesheet(el.getAttribute("rel"))) return ContextualRefusal.StylesheetSource;
|
|
7805
|
+
runtimeHrefLinks.add(el);
|
|
7806
|
+
return ContextualRefusal.None;
|
|
7807
|
+
}
|
|
7808
|
+
if (canonical === "rel") {
|
|
7809
|
+
if (!relHasStylesheet(value)) return ContextualRefusal.None;
|
|
7810
|
+
return runtimeHrefLinks.has(el) && el.hasAttribute("href") ? ContextualRefusal.StylesheetSource : ContextualRefusal.None;
|
|
7811
|
+
}
|
|
7812
|
+
return ContextualRefusal.None;
|
|
7813
|
+
}
|
|
7814
|
+
function contextualAttributeRefusal(el, name, value, origin) {
|
|
7815
|
+
const local = el.localName;
|
|
7816
|
+
if (local === "meta") return metaRefusal(el, name, value, origin);
|
|
7817
|
+
if (local === "link") return stylesheetRefusal(el, name, value, origin);
|
|
7818
|
+
if (local === "script") {
|
|
7819
|
+
if (origin === "static" || value === null) return ContextualRefusal.None;
|
|
7820
|
+
return SCRIPT_SOURCE_ATTRIBUTES.has(canonicalAttrName(name)) ? ContextualRefusal.ScriptSource : ContextualRefusal.None;
|
|
7821
|
+
}
|
|
7822
|
+
if (SVG_ANIMATION_ELEMENTS.has(local) && el.namespaceURI === SVG_NS) return animationRefusal(name, value);
|
|
7823
|
+
return ContextualRefusal.None;
|
|
7824
|
+
}
|
|
7825
|
+
function settleAttributeProvenance(el, name, origin) {
|
|
7826
|
+
if (el.localName !== "link" || canonicalAttrName(name) !== "href") return;
|
|
7827
|
+
if (origin !== "static" && el.hasAttribute("href")) runtimeHrefLinks.add(el);
|
|
7828
|
+
else runtimeHrefLinks.delete(el);
|
|
7829
|
+
}
|
|
7830
|
+
function isForbiddenMetaSnapshot(attributes) {
|
|
7831
|
+
return resolveMetaRefreshPolicy(attributes).kind === "forbidden";
|
|
7832
|
+
}
|
|
7833
|
+
|
|
7834
|
+
// src/utils/setSafeAttribute.ts
|
|
7835
|
+
var HTML_NS2 = "http://www.w3.org/1999/xhtml";
|
|
7836
|
+
var SVG_NS2 = "http://www.w3.org/2000/svg";
|
|
7442
7837
|
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
7443
7838
|
var XML_NS = "http://www.w3.org/XML/1998/namespace";
|
|
7444
7839
|
var BOOLEAN_IDL_ATTRS = /* @__PURE__ */ new Set(["checked", "disabled", "selected"]);
|
|
7445
7840
|
function isHtmlElement(el) {
|
|
7446
|
-
return el.namespaceURI === null || el.namespaceURI ===
|
|
7841
|
+
return el.namespaceURI === null || el.namespaceURI === HTML_NS2;
|
|
7842
|
+
}
|
|
7843
|
+
function warnContextualRefusal(label2, name, refusal) {
|
|
7844
|
+
devWarnLazy(() => {
|
|
7845
|
+
const reasons = [
|
|
7846
|
+
"",
|
|
7847
|
+
'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)',
|
|
7848
|
+
"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",
|
|
7849
|
+
"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",
|
|
7850
|
+
"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",
|
|
7851
|
+
'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'
|
|
7852
|
+
];
|
|
7853
|
+
return `${label2}: refusing "${name}" in this element's context \u2014 ${reasons[refusal]}. The write was not performed.`;
|
|
7854
|
+
});
|
|
7447
7855
|
}
|
|
7448
7856
|
function setProp(el, key, val) {
|
|
7449
7857
|
el[key] = val;
|
|
7450
7858
|
}
|
|
7451
7859
|
function namespaceFor(el, name) {
|
|
7452
|
-
if (el.namespaceURI !==
|
|
7860
|
+
if (el.namespaceURI !== SVG_NS2) return null;
|
|
7453
7861
|
const lower = name.toLowerCase();
|
|
7454
7862
|
if (lower.startsWith("xlink:")) return XLINK_NS;
|
|
7455
7863
|
if (lower.startsWith("xml:")) return XML_NS;
|
|
7456
7864
|
return null;
|
|
7457
7865
|
}
|
|
7458
7866
|
function setSafeAttribute(el, name, value, options = {}) {
|
|
7867
|
+
const written = commitSafeAttribute(el, name, value, options);
|
|
7868
|
+
if (el.localName === "link") settleAttributeProvenance(el, name, options.reactive ? "reactive" : "runtime");
|
|
7869
|
+
return written;
|
|
7870
|
+
}
|
|
7871
|
+
function commitSafeAttribute(el, name, value, options) {
|
|
7459
7872
|
const ns = namespaceFor(el, name);
|
|
7460
7873
|
const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
|
|
7461
7874
|
if (isEventHandlerAttr(name)) {
|
|
@@ -7468,6 +7881,14 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
7468
7881
|
else el.removeAttribute(name);
|
|
7469
7882
|
return false;
|
|
7470
7883
|
}
|
|
7884
|
+
const pending = value == null || value === false ? null : value === true ? "" : String(value);
|
|
7885
|
+
const refusal = contextualAttributeRefusal(el, name, pending, options.reactive ? "reactive" : "runtime");
|
|
7886
|
+
if (refusal !== ContextualRefusal.None) {
|
|
7887
|
+
warnContextualRefusal(options.label ?? "setSafeAttribute", name, refusal);
|
|
7888
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
7889
|
+
else el.removeAttribute(name);
|
|
7890
|
+
return false;
|
|
7891
|
+
}
|
|
7471
7892
|
if (value == null) {
|
|
7472
7893
|
if (ns) el.removeAttributeNS(ns, localName);
|
|
7473
7894
|
else el.removeAttribute(name);
|
|
@@ -7511,7 +7932,12 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
7511
7932
|
setProp(el, idlName, idlName === "checked" ? Boolean(value) : str);
|
|
7512
7933
|
return true;
|
|
7513
7934
|
}
|
|
7514
|
-
const safe =
|
|
7935
|
+
const safe = str === "" ? "" : resolveAttributeValue(name, str, { element: el });
|
|
7936
|
+
if (safe === null) {
|
|
7937
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
7938
|
+
else el.removeAttribute(name);
|
|
7939
|
+
return true;
|
|
7940
|
+
}
|
|
7515
7941
|
const current = ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name);
|
|
7516
7942
|
if (current === safe) return true;
|
|
7517
7943
|
if (ns) el.setAttributeNS(ns, name, safe);
|
|
@@ -7534,7 +7960,7 @@ function bindAttribute(el, attr, getter) {
|
|
|
7534
7960
|
reportError(err, { phase: "binding", name: `bindAttribute("${attr}")`, node: el });
|
|
7535
7961
|
return;
|
|
7536
7962
|
}
|
|
7537
|
-
setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")
|
|
7963
|
+
setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")`, reactive: true });
|
|
7538
7964
|
}
|
|
7539
7965
|
return reactiveBinding2(commit, el);
|
|
7540
7966
|
}
|
|
@@ -7571,7 +7997,7 @@ function bindBoolAttr(el, attr, getter) {
|
|
|
7571
7997
|
reportError(err, { phase: "binding", name: "bindBoolAttr", node: el });
|
|
7572
7998
|
return;
|
|
7573
7999
|
}
|
|
7574
|
-
setSafeAttribute(el, attr, Boolean(value), { label: "bindBoolAttr" });
|
|
8000
|
+
setSafeAttribute(el, attr, Boolean(value), { label: "bindBoolAttr", reactive: true });
|
|
7575
8001
|
}
|
|
7576
8002
|
return reactiveBinding2(commit, el);
|
|
7577
8003
|
}
|
|
@@ -8124,6 +8550,9 @@ var DOMPool = class {
|
|
|
8124
8550
|
* Get a recycled element or create a new one.
|
|
8125
8551
|
*/
|
|
8126
8552
|
acquire(tag) {
|
|
8553
|
+
if (isBlockedElement(tag)) {
|
|
8554
|
+
throw new Error(`DOMPool: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
|
|
8555
|
+
}
|
|
8127
8556
|
const pool = this.pools.get(tag);
|
|
8128
8557
|
if (pool && pool.length > 0) {
|
|
8129
8558
|
const el = pool.pop();
|
|
@@ -8229,10 +8658,19 @@ function prefetch(url) {
|
|
|
8229
8658
|
}
|
|
8230
8659
|
function preloadImage(src) {
|
|
8231
8660
|
return new Promise((resolve, reject) => {
|
|
8661
|
+
const safe = sanitizeUrl(String(src));
|
|
8662
|
+
if (!safe) {
|
|
8663
|
+
reject(
|
|
8664
|
+
new Error(
|
|
8665
|
+
String(src).trim() === "" ? "preloadImage: no image URL was given." : "preloadImage: refusing an image URL outside the URL policy."
|
|
8666
|
+
)
|
|
8667
|
+
);
|
|
8668
|
+
return;
|
|
8669
|
+
}
|
|
8232
8670
|
const img2 = new Image();
|
|
8233
8671
|
img2.onload = () => resolve(img2);
|
|
8234
8672
|
img2.onerror = reject;
|
|
8235
|
-
img2.src =
|
|
8673
|
+
img2.src = safe;
|
|
8236
8674
|
});
|
|
8237
8675
|
}
|
|
8238
8676
|
|
|
@@ -8258,95 +8696,6 @@ function noSideEffect(fn) {
|
|
|
8258
8696
|
return fn;
|
|
8259
8697
|
}
|
|
8260
8698
|
|
|
8261
|
-
// src/utils/metaRefresh.ts
|
|
8262
|
-
function isAsciiWhitespace(ch) {
|
|
8263
|
-
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
|
|
8264
|
-
}
|
|
8265
|
-
function trimAsciiWhitespace(value) {
|
|
8266
|
-
let start = 0;
|
|
8267
|
-
let end = value.length;
|
|
8268
|
-
while (start < end && isAsciiWhitespace(value[start])) start++;
|
|
8269
|
-
while (end > start && isAsciiWhitespace(value[end - 1])) end--;
|
|
8270
|
-
return value.slice(start, end);
|
|
8271
|
-
}
|
|
8272
|
-
var forbidden = (reason) => ({ kind: "forbidden", reason });
|
|
8273
|
-
function parseMetaRefreshContent(content) {
|
|
8274
|
-
const raw = trimAsciiWhitespace(stripControlChars(content));
|
|
8275
|
-
if (raw === "") return forbidden("empty content");
|
|
8276
|
-
let i2 = 0;
|
|
8277
|
-
while (i2 < raw.length && raw[i2] >= "0" && raw[i2] <= "9") i2++;
|
|
8278
|
-
if (i2 === 0) return forbidden("missing or non-numeric delay");
|
|
8279
|
-
const delay = Number.parseInt(raw.slice(0, i2), 10);
|
|
8280
|
-
if (!Number.isFinite(delay)) return forbidden("unparseable delay");
|
|
8281
|
-
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
8282
|
-
if (i2 === raw.length) return { kind: "delay-only", delay };
|
|
8283
|
-
if (raw[i2] !== ";" && raw[i2] !== ",") return forbidden("unexpected text after delay");
|
|
8284
|
-
i2++;
|
|
8285
|
-
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
8286
|
-
const keyStart = i2;
|
|
8287
|
-
while (i2 < raw.length && !isAsciiWhitespace(raw[i2]) && raw[i2] !== "=") i2++;
|
|
8288
|
-
const key = raw.slice(keyStart, i2).toLowerCase();
|
|
8289
|
-
if (key !== "url") return forbidden(`unsupported refresh key ${JSON.stringify(key)}`);
|
|
8290
|
-
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
8291
|
-
if (raw[i2] !== "=") return forbidden("missing '=' after url");
|
|
8292
|
-
i2++;
|
|
8293
|
-
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
8294
|
-
let destination;
|
|
8295
|
-
const quote2 = raw[i2];
|
|
8296
|
-
if (quote2 === '"' || quote2 === "'") {
|
|
8297
|
-
const close = raw.indexOf(quote2, i2 + 1);
|
|
8298
|
-
if (close === -1) return forbidden("unterminated quoted destination");
|
|
8299
|
-
destination = raw.slice(i2 + 1, close);
|
|
8300
|
-
const rest = trimAsciiWhitespace(raw.slice(close + 1));
|
|
8301
|
-
if (rest !== "") return forbidden("trailing text after quoted destination");
|
|
8302
|
-
} else {
|
|
8303
|
-
destination = trimAsciiWhitespace(raw.slice(i2));
|
|
8304
|
-
if (/[;,]/.test(destination)) return forbidden("multiple refresh assignments");
|
|
8305
|
-
}
|
|
8306
|
-
if (destination === "") return forbidden("empty destination");
|
|
8307
|
-
const sanitizedDestination = sanitizeUrl(destination);
|
|
8308
|
-
if (sanitizedDestination === "") return forbidden("destination uses a disallowed protocol");
|
|
8309
|
-
return { kind: "allowed", delay, destination, sanitizedDestination };
|
|
8310
|
-
}
|
|
8311
|
-
function resolveMetaRefreshPolicy(attributes) {
|
|
8312
|
-
let httpEquiv;
|
|
8313
|
-
let content;
|
|
8314
|
-
let duplicateName;
|
|
8315
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8316
|
-
for (const [key, value] of attributes) {
|
|
8317
|
-
const canonical = canonicalAttrName(key);
|
|
8318
|
-
if (seen.has(canonical)) duplicateName = canonical;
|
|
8319
|
-
seen.add(canonical);
|
|
8320
|
-
if (canonical === "http-equiv") httpEquiv = value;
|
|
8321
|
-
else if (canonical === "content") content = value;
|
|
8322
|
-
}
|
|
8323
|
-
if (duplicateName !== void 0) {
|
|
8324
|
-
return forbidden(`duplicate case-insensitive attribute ${JSON.stringify(duplicateName)}`);
|
|
8325
|
-
}
|
|
8326
|
-
if (typeof httpEquiv !== "string") return { kind: "not-refresh" };
|
|
8327
|
-
if (trimAsciiWhitespace(stripControlChars(httpEquiv)).toLowerCase() !== "refresh") {
|
|
8328
|
-
return { kind: "not-refresh" };
|
|
8329
|
-
}
|
|
8330
|
-
if (typeof content !== "string") return { kind: "not-refresh" };
|
|
8331
|
-
return parseMetaRefreshContent(content);
|
|
8332
|
-
}
|
|
8333
|
-
function normalizeMetaAttributes(props) {
|
|
8334
|
-
const out = /* @__PURE__ */ new Map();
|
|
8335
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8336
|
-
for (const key of Object.keys(props)) {
|
|
8337
|
-
const canonical = canonicalAttrName(key);
|
|
8338
|
-
if (seen.has(canonical)) return null;
|
|
8339
|
-
seen.add(canonical);
|
|
8340
|
-
out.set(key, props[key]);
|
|
8341
|
-
}
|
|
8342
|
-
return out;
|
|
8343
|
-
}
|
|
8344
|
-
function isForbiddenMetaEntry(props) {
|
|
8345
|
-
const normalized = normalizeMetaAttributes(props);
|
|
8346
|
-
if (normalized === null) return true;
|
|
8347
|
-
return resolveMetaRefreshPolicy(normalized).kind === "forbidden";
|
|
8348
|
-
}
|
|
8349
|
-
|
|
8350
8699
|
// src/utils/headEntry.ts
|
|
8351
8700
|
var SAFE_HEAD_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
|
|
8352
8701
|
function isEmittableHeadAttrName(name) {
|
|
@@ -8357,9 +8706,7 @@ function isEmittableHeadAttrName(name) {
|
|
|
8357
8706
|
return true;
|
|
8358
8707
|
}
|
|
8359
8708
|
function sanitizeHeadAttrValue(canonical, value) {
|
|
8360
|
-
|
|
8361
|
-
const safe = sanitizeAttributeString(canonical, value);
|
|
8362
|
-
return safe === "" ? null : safe;
|
|
8709
|
+
return resolveAttributeValue(canonical, value);
|
|
8363
8710
|
}
|
|
8364
8711
|
function findDuplicateAttributeName(names) {
|
|
8365
8712
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -8416,15 +8763,9 @@ function serializeHeadEntry(tag, attrs) {
|
|
|
8416
8763
|
}
|
|
8417
8764
|
|
|
8418
8765
|
// src/platform/ssr.ts
|
|
8419
|
-
function isPolicyAttr(lowerName) {
|
|
8420
|
-
return isPolicyAttribute(lowerName);
|
|
8421
|
-
}
|
|
8422
8766
|
function isForbiddenSsrAttr(lowerName) {
|
|
8423
8767
|
return isHtmlContentAttribute(lowerName);
|
|
8424
8768
|
}
|
|
8425
|
-
function sanitizeSsrAttributeValue(lowerName, value) {
|
|
8426
|
-
return sanitizeAttributeString(lowerName, value);
|
|
8427
|
-
}
|
|
8428
8769
|
var SAFE_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
|
|
8429
8770
|
function isSafeAttrName(name) {
|
|
8430
8771
|
return SAFE_ATTR_NAME.test(name);
|
|
@@ -8455,6 +8796,64 @@ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
|
8455
8796
|
"track",
|
|
8456
8797
|
"wbr"
|
|
8457
8798
|
]);
|
|
8799
|
+
function findNativeGetter(proto, name) {
|
|
8800
|
+
for (let p2 = proto; p2; p2 = Object.getPrototypeOf(p2)) {
|
|
8801
|
+
const get = Object.getOwnPropertyDescriptor(p2, name)?.get;
|
|
8802
|
+
if (get) return get;
|
|
8803
|
+
}
|
|
8804
|
+
return null;
|
|
8805
|
+
}
|
|
8806
|
+
var nativeAccessorsByRealm = /* @__PURE__ */ new WeakMap();
|
|
8807
|
+
function nativeAccessors() {
|
|
8808
|
+
const realm = Element;
|
|
8809
|
+
let accessors = nativeAccessorsByRealm.get(realm);
|
|
8810
|
+
if (!accessors) {
|
|
8811
|
+
accessors = {
|
|
8812
|
+
attributes: findNativeGetter(Element.prototype, "attributes"),
|
|
8813
|
+
tagName: findNativeGetter(Element.prototype, "tagName"),
|
|
8814
|
+
childNodes: findNativeGetter(Node.prototype, "childNodes"),
|
|
8815
|
+
getAttribute: Element.prototype.getAttribute
|
|
8816
|
+
};
|
|
8817
|
+
nativeAccessorsByRealm.set(realm, accessors);
|
|
8818
|
+
}
|
|
8819
|
+
return accessors;
|
|
8820
|
+
}
|
|
8821
|
+
function attributesOf(el) {
|
|
8822
|
+
const get = nativeAccessors().attributes;
|
|
8823
|
+
return get ? get.call(el) : el.attributes;
|
|
8824
|
+
}
|
|
8825
|
+
function tagNameOf(el) {
|
|
8826
|
+
const get = nativeAccessors().tagName;
|
|
8827
|
+
return get ? get.call(el) : el.tagName;
|
|
8828
|
+
}
|
|
8829
|
+
function childNodesOf(node) {
|
|
8830
|
+
const get = nativeAccessors().childNodes;
|
|
8831
|
+
return get ? get.call(node) : node.childNodes;
|
|
8832
|
+
}
|
|
8833
|
+
function getAttributeOf(el, name) {
|
|
8834
|
+
return nativeAccessors().getAttribute.call(el, name);
|
|
8835
|
+
}
|
|
8836
|
+
function serializeOpenTag(element, tag) {
|
|
8837
|
+
let html2 = `<${tag}`;
|
|
8838
|
+
const meta2 = tag === "meta" ? /* @__PURE__ */ new Map() : null;
|
|
8839
|
+
const attrs = attributesOf(element);
|
|
8840
|
+
for (let i2 = 0; i2 < attrs.length; i2++) {
|
|
8841
|
+
const attr = attrs[i2];
|
|
8842
|
+
const rawName = attr.name;
|
|
8843
|
+
if (!isSafeAttrName(rawName)) continue;
|
|
8844
|
+
if (isEventHandlerAttr(rawName)) continue;
|
|
8845
|
+
if (isForbiddenSsrAttr(rawName)) continue;
|
|
8846
|
+
const value = resolveAttributeValue(rawName.toLowerCase(), attr.value);
|
|
8847
|
+
if (value === null) continue;
|
|
8848
|
+
meta2?.set(rawName, value);
|
|
8849
|
+
html2 += ` ${rawName}="${escapeAttr(value)}"`;
|
|
8850
|
+
}
|
|
8851
|
+
if (meta2 && isForbiddenMetaSnapshot(meta2)) return null;
|
|
8852
|
+
if (!getAttributeOf(element, "data-sibu-hydrate")) {
|
|
8853
|
+
html2 += ` data-sibu-ssr="true"`;
|
|
8854
|
+
}
|
|
8855
|
+
return html2;
|
|
8856
|
+
}
|
|
8458
8857
|
function renderToString(element) {
|
|
8459
8858
|
if (element instanceof DocumentFragment) {
|
|
8460
8859
|
return Array.from(element.childNodes).map((child) => {
|
|
@@ -8474,35 +8873,21 @@ function renderToString(element) {
|
|
|
8474
8873
|
if (!(element instanceof HTMLElement)) {
|
|
8475
8874
|
return escapeHtml(element.textContent || "");
|
|
8476
8875
|
}
|
|
8477
|
-
const tag = element.
|
|
8478
|
-
if (tag
|
|
8876
|
+
const tag = tagNameOf(element).toLowerCase();
|
|
8877
|
+
if (isCodeTextElement(tag)) {
|
|
8479
8878
|
return DEV ? `<!--ssr:${tag}-stripped-->` : "";
|
|
8480
8879
|
}
|
|
8481
8880
|
if (!/^[a-z][a-z0-9-]*$/i.test(tag)) {
|
|
8482
8881
|
return DEV ? "<!--ssr:invalid-tag-->" : "";
|
|
8483
8882
|
}
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
if (!isSafeAttrName(rawName)) continue;
|
|
8488
|
-
if (isEventHandlerAttr(rawName)) continue;
|
|
8489
|
-
if (isForbiddenSsrAttr(rawName)) continue;
|
|
8490
|
-
const lowerName = rawName.toLowerCase();
|
|
8491
|
-
let value = attr.value;
|
|
8492
|
-
if (isPolicyAttr(lowerName)) {
|
|
8493
|
-
value = sanitizeSsrAttributeValue(lowerName, value);
|
|
8494
|
-
if (!value) continue;
|
|
8495
|
-
}
|
|
8496
|
-
html2 += ` ${rawName}="${escapeAttr(value)}"`;
|
|
8497
|
-
}
|
|
8498
|
-
if (element.dataset && !element.dataset.sibuHydrate) {
|
|
8499
|
-
html2 += ` data-sibu-ssr="true"`;
|
|
8500
|
-
}
|
|
8883
|
+
const openTag = serializeOpenTag(element, tag);
|
|
8884
|
+
if (openTag === null) return DEV ? `<!--ssr:${tag}-stripped-->` : "";
|
|
8885
|
+
let html2 = openTag;
|
|
8501
8886
|
if (VOID_ELEMENTS.has(tag)) {
|
|
8502
8887
|
return `${html2} />`;
|
|
8503
8888
|
}
|
|
8504
8889
|
html2 += ">";
|
|
8505
|
-
for (const child of Array.from(element
|
|
8890
|
+
for (const child of Array.from(childNodesOf(element))) {
|
|
8506
8891
|
try {
|
|
8507
8892
|
html2 += renderToString(child);
|
|
8508
8893
|
} catch (err) {
|
|
@@ -8652,12 +9037,8 @@ function buildAttrString(attrs, { allowEventHandlers = false } = {}) {
|
|
|
8652
9037
|
if (!isSafeAttrName(rawKey)) continue;
|
|
8653
9038
|
if (!allowEventHandlers && isEventHandlerAttr(rawKey)) continue;
|
|
8654
9039
|
if (isForbiddenSsrAttr(rawKey)) continue;
|
|
8655
|
-
const
|
|
8656
|
-
|
|
8657
|
-
if (isPolicyAttr(lowerKey)) {
|
|
8658
|
-
value = sanitizeSsrAttributeValue(lowerKey, value);
|
|
8659
|
-
if (!value) continue;
|
|
8660
|
-
}
|
|
9040
|
+
const value = resolveAttributeValue(rawKey.toLowerCase(), String(attrs[rawKey]));
|
|
9041
|
+
if (value === null) continue;
|
|
8661
9042
|
out.push(`${rawKey}="${escapeAttr(value)}"`);
|
|
8662
9043
|
}
|
|
8663
9044
|
return out.join(" ");
|
|
@@ -8720,8 +9101,8 @@ async function* renderToStream(element) {
|
|
|
8720
9101
|
yield escapeHtml(element.textContent || "");
|
|
8721
9102
|
return;
|
|
8722
9103
|
}
|
|
8723
|
-
const tag = element.
|
|
8724
|
-
if (tag
|
|
9104
|
+
const tag = tagNameOf(element).toLowerCase();
|
|
9105
|
+
if (isCodeTextElement(tag)) {
|
|
8725
9106
|
if (DEV) yield `<!--ssr:${tag}-stripped-->`;
|
|
8726
9107
|
return;
|
|
8727
9108
|
}
|
|
@@ -8729,29 +9110,17 @@ async function* renderToStream(element) {
|
|
|
8729
9110
|
if (DEV) yield "<!--ssr:invalid-tag-->";
|
|
8730
9111
|
return;
|
|
8731
9112
|
}
|
|
8732
|
-
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
|
|
8736
|
-
if (isEventHandlerAttr(rawName)) continue;
|
|
8737
|
-
if (isForbiddenSsrAttr(rawName)) continue;
|
|
8738
|
-
const lowerName = rawName.toLowerCase();
|
|
8739
|
-
let value = attr.value;
|
|
8740
|
-
if (isPolicyAttr(lowerName)) {
|
|
8741
|
-
value = sanitizeSsrAttributeValue(lowerName, value);
|
|
8742
|
-
if (!value) continue;
|
|
8743
|
-
}
|
|
8744
|
-
openTag += ` ${rawName}="${escapeAttr(value)}"`;
|
|
8745
|
-
}
|
|
8746
|
-
if (element.dataset && !element.dataset.sibuHydrate) {
|
|
8747
|
-
openTag += ` data-sibu-ssr="true"`;
|
|
9113
|
+
const openTag = serializeOpenTag(element, tag);
|
|
9114
|
+
if (openTag === null) {
|
|
9115
|
+
if (DEV) yield `<!--ssr:${tag}-stripped-->`;
|
|
9116
|
+
return;
|
|
8748
9117
|
}
|
|
8749
9118
|
if (VOID_ELEMENTS.has(tag)) {
|
|
8750
9119
|
yield `${openTag} />`;
|
|
8751
9120
|
return;
|
|
8752
9121
|
}
|
|
8753
9122
|
yield `${openTag}>`;
|
|
8754
|
-
for (const child of Array.from(element
|
|
9123
|
+
for (const child of Array.from(childNodesOf(element))) {
|
|
8755
9124
|
try {
|
|
8756
9125
|
yield* renderToStream(child);
|
|
8757
9126
|
} catch (err) {
|
|
@@ -8936,8 +9305,7 @@ function deserializeState(validate) {
|
|
|
8936
9305
|
"[SibuJS SSR] deserializeState() called without a validate guard \u2014 tampered SSR payloads will not be detected."
|
|
8937
9306
|
);
|
|
8938
9307
|
}
|
|
8939
|
-
const
|
|
8940
|
-
const raw = w[SSR_DATA_ATTR];
|
|
9308
|
+
const raw = readOwnGlobal(SSR_DATA_ATTR);
|
|
8941
9309
|
if (raw === void 0) return void 0;
|
|
8942
9310
|
if (validate && !validate(raw)) return void 0;
|
|
8943
9311
|
return raw;
|
|
@@ -9524,7 +9892,7 @@ function setCanonical(url) {
|
|
|
9524
9892
|
}
|
|
9525
9893
|
|
|
9526
9894
|
// src/platform/customElement.ts
|
|
9527
|
-
var
|
|
9895
|
+
var SVG_NS3 = "http://www.w3.org/2000/svg";
|
|
9528
9896
|
var MAX_RENDER_PASSES = 10;
|
|
9529
9897
|
var ABANDONED_RENDER = /* @__PURE__ */ Symbol("sibujs.defineElement.abandonedRender");
|
|
9530
9898
|
function defineElement(name, component, options = {}) {
|
|
@@ -9673,7 +10041,10 @@ function defineElement(name, component, options = {}) {
|
|
|
9673
10041
|
customElements.define(name, SibuElement);
|
|
9674
10042
|
}
|
|
9675
10043
|
function svgElement(tag, props = {}, ...nodes) {
|
|
9676
|
-
|
|
10044
|
+
if (isBlockedElement(tag)) {
|
|
10045
|
+
throw new Error(`svgElement: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
|
|
10046
|
+
}
|
|
10047
|
+
const el = document.createElementNS(SVG_NS3, tag);
|
|
9677
10048
|
for (const [key, value] of Object.entries(props)) {
|
|
9678
10049
|
if (key === "nodes") continue;
|
|
9679
10050
|
if (typeof value === "function" && isEventHandlerAttr(key)) {
|
|
@@ -9685,7 +10056,7 @@ function svgElement(tag, props = {}, ...nodes) {
|
|
|
9685
10056
|
for (const child of nodes) {
|
|
9686
10057
|
if (typeof child === "string") {
|
|
9687
10058
|
el.appendChild(document.createTextNode(child));
|
|
9688
|
-
} else if (child
|
|
10059
|
+
} else if (typeof child?.nodeType === "number") {
|
|
9689
10060
|
el.appendChild(child);
|
|
9690
10061
|
}
|
|
9691
10062
|
}
|
|
@@ -9698,7 +10069,16 @@ function toError(err) {
|
|
|
9698
10069
|
if (err !== null && typeof err === "object" && "name" in err && "message" in err) return err;
|
|
9699
10070
|
return new Error(String(err));
|
|
9700
10071
|
}
|
|
10072
|
+
function workerSource(fn, api) {
|
|
10073
|
+
if (typeof fn !== "function") {
|
|
10074
|
+
throw new TypeError(
|
|
10075
|
+
`${api}: expected a function, got ${typeof fn}. Worker code must be a function defined in your source \u2014 a string would be evaluated as code.`
|
|
10076
|
+
);
|
|
10077
|
+
}
|
|
10078
|
+
return Function.prototype.toString.call(fn);
|
|
10079
|
+
}
|
|
9701
10080
|
function worker(workerFn2) {
|
|
10081
|
+
const fnBody = workerSource(workerFn2, "worker");
|
|
9702
10082
|
const [result, setResult] = signal(null);
|
|
9703
10083
|
const [error, setError] = signal(null);
|
|
9704
10084
|
const [loading, setLoading] = signal(false);
|
|
@@ -9714,7 +10094,6 @@ function worker(workerFn2) {
|
|
|
9714
10094
|
if (typeof Worker === "undefined") {
|
|
9715
10095
|
throw new Error("Web Workers are not supported in this environment");
|
|
9716
10096
|
}
|
|
9717
|
-
const fnBody = workerFn2.toString();
|
|
9718
10097
|
const blob = new Blob([`self.onmessage = ${fnBody};`], { type: "application/javascript" });
|
|
9719
10098
|
blobUrl = URL.createObjectURL(blob);
|
|
9720
10099
|
worker2 = new Worker(blobUrl);
|
|
@@ -9763,6 +10142,7 @@ function worker(workerFn2) {
|
|
|
9763
10142
|
return { post, result, error, loading, terminate };
|
|
9764
10143
|
}
|
|
9765
10144
|
function workerFn(fn) {
|
|
10145
|
+
const fnStr = workerSource(fn, "workerFn");
|
|
9766
10146
|
const [loading, setLoading] = signal(false);
|
|
9767
10147
|
let worker2 = null;
|
|
9768
10148
|
let blobUrl = null;
|
|
@@ -9777,7 +10157,6 @@ function workerFn(fn) {
|
|
|
9777
10157
|
if (typeof Worker === "undefined") {
|
|
9778
10158
|
throw new Error("Web Workers are not supported in this environment");
|
|
9779
10159
|
}
|
|
9780
|
-
const fnStr = fn.toString();
|
|
9781
10160
|
const blob = new Blob(
|
|
9782
10161
|
[
|
|
9783
10162
|
`self.onmessage = function(e) {
|
|
@@ -9837,6 +10216,7 @@ function workerFn(fn) {
|
|
|
9837
10216
|
return { run, loading, terminate };
|
|
9838
10217
|
}
|
|
9839
10218
|
function createWorkerPool(workerFn2, poolSize) {
|
|
10219
|
+
const fnBody = workerSource(workerFn2, "createWorkerPool");
|
|
9840
10220
|
const size = poolSize || typeof navigator !== "undefined" && navigator.hardwareConcurrency || 4;
|
|
9841
10221
|
const workers = [];
|
|
9842
10222
|
const queues = [];
|
|
@@ -9895,7 +10275,6 @@ function createWorkerPool(workerFn2, poolSize) {
|
|
|
9895
10275
|
if (typeof Worker === "undefined") {
|
|
9896
10276
|
throw new Error("Web Workers are not supported in this environment");
|
|
9897
10277
|
}
|
|
9898
|
-
const fnBody = workerFn2.toString();
|
|
9899
10278
|
const blob = new Blob([`self.onmessage = ${fnBody};`], { type: "application/javascript" });
|
|
9900
10279
|
blobUrl = URL.createObjectURL(blob);
|
|
9901
10280
|
for (let i2 = 0; i2 < size; i2++) {
|
|
@@ -10292,11 +10671,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
10292
10671
|
}
|
|
10293
10672
|
|
|
10294
10673
|
// src/core/rendering/tagFactory.ts
|
|
10295
|
-
var
|
|
10296
|
-
var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
10297
|
-
function isBlockedTag(tag) {
|
|
10298
|
-
return BLOCKED_TAGS.has(tag.toLowerCase());
|
|
10299
|
-
}
|
|
10674
|
+
var SVG_NS4 = "http://www.w3.org/2000/svg";
|
|
10300
10675
|
var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
|
|
10301
10676
|
"config",
|
|
10302
10677
|
"location",
|
|
@@ -10341,11 +10716,12 @@ function applyStyle(el, style2) {
|
|
|
10341
10716
|
}
|
|
10342
10717
|
const next = [];
|
|
10343
10718
|
for (const prop in value) {
|
|
10719
|
+
if (!Object.hasOwn(value, prop)) continue;
|
|
10344
10720
|
const val = value[prop];
|
|
10345
10721
|
if (val == null) continue;
|
|
10346
10722
|
const name = toKebab(prop);
|
|
10347
10723
|
next.push(name);
|
|
10348
|
-
decl.setProperty(name,
|
|
10724
|
+
decl.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
|
|
10349
10725
|
}
|
|
10350
10726
|
for (let i2 = 0; i2 < written.length; i2++) {
|
|
10351
10727
|
if (next.indexOf(written[i2]) === -1) decl.removeProperty(written[i2]);
|
|
@@ -10361,16 +10737,17 @@ function applyStyle(el, style2) {
|
|
|
10361
10737
|
}
|
|
10362
10738
|
const htmlEl = el;
|
|
10363
10739
|
for (const prop in style2) {
|
|
10740
|
+
if (!Object.hasOwn(style2, prop)) continue;
|
|
10364
10741
|
const val = style2[prop];
|
|
10365
10742
|
const name = toKebab(prop);
|
|
10366
10743
|
if (typeof val === "function") {
|
|
10367
10744
|
const getter = val;
|
|
10368
10745
|
const teardown = reactiveBinding2(() => {
|
|
10369
|
-
htmlEl.style.setProperty(name,
|
|
10746
|
+
htmlEl.style.setProperty(name, sanitizeCSSDeclaration(name, String(getter()), { element: el }));
|
|
10370
10747
|
}, el);
|
|
10371
10748
|
registerDisposer(el, teardown);
|
|
10372
10749
|
} else {
|
|
10373
|
-
htmlEl.style.setProperty(name,
|
|
10750
|
+
htmlEl.style.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
|
|
10374
10751
|
}
|
|
10375
10752
|
}
|
|
10376
10753
|
}
|
|
@@ -10392,6 +10769,7 @@ function applyClass(el, cls) {
|
|
|
10392
10769
|
let hasReactive = false;
|
|
10393
10770
|
let result = "";
|
|
10394
10771
|
for (const name in obj) {
|
|
10772
|
+
if (!Object.hasOwn(obj, name)) continue;
|
|
10395
10773
|
const val = obj[name];
|
|
10396
10774
|
if (typeof val === "function") {
|
|
10397
10775
|
hasReactive = true;
|
|
@@ -10403,6 +10781,7 @@ function applyClass(el, cls) {
|
|
|
10403
10781
|
const update = () => {
|
|
10404
10782
|
let r = "";
|
|
10405
10783
|
for (const name in obj) {
|
|
10784
|
+
if (!Object.hasOwn(obj, name)) continue;
|
|
10406
10785
|
const val = obj[name];
|
|
10407
10786
|
const active = typeof val === "function" ? val() : val;
|
|
10408
10787
|
if (active) r = r ? `${r} ${name}` : name;
|
|
@@ -10466,7 +10845,7 @@ function appendChildren(el, nodes) {
|
|
|
10466
10845
|
}
|
|
10467
10846
|
}
|
|
10468
10847
|
function tagFactory(tag, ns) {
|
|
10469
|
-
const blocked =
|
|
10848
|
+
const blocked = isBlockedElement(tag);
|
|
10470
10849
|
return (first, second) => {
|
|
10471
10850
|
if (blocked) {
|
|
10472
10851
|
throw new Error(`tagFactory: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
|
|
@@ -10529,6 +10908,7 @@ function tagFactory(tag, ns) {
|
|
|
10529
10908
|
const pOn = props.on;
|
|
10530
10909
|
if (pOn) {
|
|
10531
10910
|
for (const ev in pOn) {
|
|
10911
|
+
if (!Object.hasOwn(pOn, ev)) continue;
|
|
10532
10912
|
const handler = pOn[ev];
|
|
10533
10913
|
if (typeof handler === "function") {
|
|
10534
10914
|
el.addEventListener(ev, handler);
|
|
@@ -10555,6 +10935,7 @@ function tagFactory(tag, ns) {
|
|
|
10555
10935
|
continue;
|
|
10556
10936
|
// already handled above / below
|
|
10557
10937
|
default: {
|
|
10938
|
+
if (!Object.hasOwn(props, key)) continue;
|
|
10558
10939
|
const value = props[key];
|
|
10559
10940
|
if (value == null) continue;
|
|
10560
10941
|
if (isEventHandlerAttr(key)) continue;
|
|
@@ -10644,7 +11025,7 @@ var param = tagFactory("param");
|
|
|
10644
11025
|
var picture = tagFactory("picture");
|
|
10645
11026
|
var portal = tagFactory("portal");
|
|
10646
11027
|
var source = tagFactory("source");
|
|
10647
|
-
var svg = tagFactory("svg",
|
|
11028
|
+
var svg = tagFactory("svg", SVG_NS4);
|
|
10648
11029
|
var math = tagFactory("math");
|
|
10649
11030
|
var canvas = tagFactory("canvas");
|
|
10650
11031
|
var noscript = tagFactory("noscript");
|
|
@@ -10685,26 +11066,26 @@ var base = tagFactory("base");
|
|
|
10685
11066
|
var link = tagFactory("link");
|
|
10686
11067
|
var meta = tagFactory("meta");
|
|
10687
11068
|
var style = tagFactory("style");
|
|
10688
|
-
var circle = tagFactory("circle",
|
|
10689
|
-
var ellipse = tagFactory("ellipse",
|
|
10690
|
-
var g = tagFactory("g",
|
|
10691
|
-
var line = tagFactory("line",
|
|
10692
|
-
var path = tagFactory("path",
|
|
10693
|
-
var polygon = tagFactory("polygon",
|
|
10694
|
-
var polyline = tagFactory("polyline",
|
|
10695
|
-
var rect = tagFactory("rect",
|
|
10696
|
-
var text = tagFactory("text",
|
|
10697
|
-
var tspan = tagFactory("tspan",
|
|
10698
|
-
var defs = tagFactory("defs",
|
|
10699
|
-
var clipPath = tagFactory("clipPath",
|
|
10700
|
-
var mask = tagFactory("mask",
|
|
10701
|
-
var pattern = tagFactory("pattern",
|
|
10702
|
-
var linearGradient = tagFactory("linearGradient",
|
|
10703
|
-
var radialGradient = tagFactory("radialGradient",
|
|
10704
|
-
var stop = tagFactory("stop",
|
|
10705
|
-
var use = tagFactory("use",
|
|
10706
|
-
var symbol = tagFactory("symbol",
|
|
10707
|
-
var marker = tagFactory("marker",
|
|
11069
|
+
var circle = tagFactory("circle", SVG_NS4);
|
|
11070
|
+
var ellipse = tagFactory("ellipse", SVG_NS4);
|
|
11071
|
+
var g = tagFactory("g", SVG_NS4);
|
|
11072
|
+
var line = tagFactory("line", SVG_NS4);
|
|
11073
|
+
var path = tagFactory("path", SVG_NS4);
|
|
11074
|
+
var polygon = tagFactory("polygon", SVG_NS4);
|
|
11075
|
+
var polyline = tagFactory("polyline", SVG_NS4);
|
|
11076
|
+
var rect = tagFactory("rect", SVG_NS4);
|
|
11077
|
+
var text = tagFactory("text", SVG_NS4);
|
|
11078
|
+
var tspan = tagFactory("tspan", SVG_NS4);
|
|
11079
|
+
var defs = tagFactory("defs", SVG_NS4);
|
|
11080
|
+
var clipPath = tagFactory("clipPath", SVG_NS4);
|
|
11081
|
+
var mask = tagFactory("mask", SVG_NS4);
|
|
11082
|
+
var pattern = tagFactory("pattern", SVG_NS4);
|
|
11083
|
+
var linearGradient = tagFactory("linearGradient", SVG_NS4);
|
|
11084
|
+
var radialGradient = tagFactory("radialGradient", SVG_NS4);
|
|
11085
|
+
var stop = tagFactory("stop", SVG_NS4);
|
|
11086
|
+
var use = tagFactory("use", SVG_NS4);
|
|
11087
|
+
var symbol = tagFactory("symbol", SVG_NS4);
|
|
11088
|
+
var marker = tagFactory("marker", SVG_NS4);
|
|
10708
11089
|
var center = tagFactory("center");
|
|
10709
11090
|
var font = tagFactory("font");
|
|
10710
11091
|
var marquee = tagFactory("marquee");
|
|
@@ -11007,7 +11388,7 @@ function createISR(options) {
|
|
|
11007
11388
|
const [data2, setData] = signal(initialData);
|
|
11008
11389
|
const [stale, setStale] = signal(initialData === void 0);
|
|
11009
11390
|
const controller = new AbortController();
|
|
11010
|
-
let inFlight =
|
|
11391
|
+
let inFlight = null;
|
|
11011
11392
|
let disposed = false;
|
|
11012
11393
|
let deadline;
|
|
11013
11394
|
const clearDeadline = () => {
|
|
@@ -11027,10 +11408,7 @@ function createISR(options) {
|
|
|
11027
11408
|
});
|
|
11028
11409
|
}, revalidateAfter);
|
|
11029
11410
|
};
|
|
11030
|
-
const
|
|
11031
|
-
if (disposed || inFlight) return;
|
|
11032
|
-
if (controller.signal.aborted) return;
|
|
11033
|
-
inFlight = true;
|
|
11411
|
+
const run = async () => {
|
|
11034
11412
|
try {
|
|
11035
11413
|
const result = await fetcher({ signal: controller.signal });
|
|
11036
11414
|
if (disposed || controller.signal.aborted) return;
|
|
@@ -11042,10 +11420,33 @@ function createISR(options) {
|
|
|
11042
11420
|
} catch (err) {
|
|
11043
11421
|
if (!disposed && !controller.signal.aborted) armDeadline();
|
|
11044
11422
|
throw err;
|
|
11045
|
-
} finally {
|
|
11046
|
-
inFlight = false;
|
|
11047
11423
|
}
|
|
11048
11424
|
};
|
|
11425
|
+
const revalidate = () => {
|
|
11426
|
+
if (disposed || controller.signal.aborted) return Promise.resolve();
|
|
11427
|
+
if (inFlight) return inFlight;
|
|
11428
|
+
let resolve;
|
|
11429
|
+
let reject;
|
|
11430
|
+
const current = new Promise((res, rej) => {
|
|
11431
|
+
resolve = res;
|
|
11432
|
+
reject = rej;
|
|
11433
|
+
});
|
|
11434
|
+
inFlight = current;
|
|
11435
|
+
const release = () => {
|
|
11436
|
+
if (inFlight === current) inFlight = null;
|
|
11437
|
+
};
|
|
11438
|
+
run().then(
|
|
11439
|
+
() => {
|
|
11440
|
+
release();
|
|
11441
|
+
resolve();
|
|
11442
|
+
},
|
|
11443
|
+
(err) => {
|
|
11444
|
+
release();
|
|
11445
|
+
reject(err);
|
|
11446
|
+
}
|
|
11447
|
+
);
|
|
11448
|
+
return current;
|
|
11449
|
+
};
|
|
11049
11450
|
if (initialData === void 0) {
|
|
11050
11451
|
revalidate().catch((err) => {
|
|
11051
11452
|
if (typeof console !== "undefined") console.warn("[SibuJS ISR] initial fetch failed", err);
|
|
@@ -11580,7 +11981,7 @@ var CDN_ENTRY_POINTS = {
|
|
|
11580
11981
|
};
|
|
11581
11982
|
var packageInfo = {
|
|
11582
11983
|
name: "sibujs",
|
|
11583
|
-
version: true ? "4.
|
|
11984
|
+
version: true ? "4.9.0" : "dev",
|
|
11584
11985
|
entryPoints: MODULE_ENTRY_POINTS,
|
|
11585
11986
|
/**
|
|
11586
11987
|
* Generate the package.json `exports` map. Module entries resolve to the
|
|
@@ -11725,7 +12126,7 @@ var env = {
|
|
|
11725
12126
|
};
|
|
11726
12127
|
|
|
11727
12128
|
// src/plugins/versioning.ts
|
|
11728
|
-
var VERSION = true ? "4.
|
|
12129
|
+
var VERSION = true ? "4.9.0" : "dev";
|
|
11729
12130
|
var NUM = "(?:0|[1-9]\\d*)";
|
|
11730
12131
|
var PRE_ID = `(?:${NUM}|\\d*[a-zA-Z-][0-9a-zA-Z-]*)`;
|
|
11731
12132
|
var BUILD_ID = "[0-9a-zA-Z-]+";
|
|
@@ -12008,12 +12409,14 @@ function extractRangeTarget(range) {
|
|
|
12008
12409
|
function preloadCritical(resources) {
|
|
12009
12410
|
if (typeof document === "undefined") return;
|
|
12010
12411
|
for (const resource2 of resources) {
|
|
12011
|
-
const
|
|
12412
|
+
const href = sanitizeUrl(resource2.href);
|
|
12413
|
+
if (!href) continue;
|
|
12414
|
+
const safeHref = typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(href) : href.replace(/["\\]/g, "\\$&");
|
|
12012
12415
|
const existing = document.querySelector(`link[rel="preload"][href="${safeHref}"]`);
|
|
12013
12416
|
if (existing) continue;
|
|
12014
12417
|
const link2 = document.createElement("link");
|
|
12015
12418
|
link2.rel = "preload";
|
|
12016
|
-
link2.href =
|
|
12419
|
+
link2.href = href;
|
|
12017
12420
|
link2.setAttribute("as", resource2.as);
|
|
12018
12421
|
if (resource2.type) {
|
|
12019
12422
|
link2.type = resource2.type;
|
|
@@ -15017,7 +15420,7 @@ var _themeLayers = globalSingleton(
|
|
|
15017
15420
|
function commitThemeProperty(root, name, record) {
|
|
15018
15421
|
const top = record.layers[record.layers.length - 1];
|
|
15019
15422
|
if (top) {
|
|
15020
|
-
root.style.setProperty(name, top.value);
|
|
15423
|
+
root.style.setProperty(name, sanitizeCSSDeclaration(name, String(top.value), { element: root }));
|
|
15021
15424
|
return;
|
|
15022
15425
|
}
|
|
15023
15426
|
_themeLayers.get(root)?.delete(name);
|