sibujs 4.7.0 → 4.8.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 +45 -4
- package/dist/browser.d.cts +23 -0
- package/dist/browser.d.ts +23 -0
- package/dist/browser.js +6 -5
- package/dist/build.cjs +513 -78
- 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-3ACAAQIN.js +224 -0
- package/dist/{chunk-DKXRACVN.js → chunk-44MTL7ED.js} +6 -6
- package/dist/{chunk-3QWBSL5R.js → chunk-4WMSTZ7J.js} +8 -5
- package/dist/{chunk-H3SRKIYX.js → chunk-62BDYGAG.js} +8 -0
- package/dist/{chunk-BSY63EM6.js → chunk-C5PEWEGH.js} +20 -5
- package/dist/{chunk-BC2SECJD.js → chunk-C7AA2CZX.js} +1 -1
- package/dist/{chunk-SLM3IA34.js → chunk-CZPRSWSS.js} +1 -1
- package/dist/{chunk-FQRUXCEE.js → chunk-DSID757X.js} +1 -1
- package/dist/{chunk-ZVL7TY4K.js → chunk-EGUQLBHE.js} +22 -8
- package/dist/{chunk-2INLLLMZ.js → chunk-EXXSN3BW.js} +202 -26
- package/dist/{chunk-HURREPU2.js → chunk-FC6KCJSA.js} +87 -150
- package/dist/{chunk-Z3OHK6QT.js → chunk-GSGNX35Q.js} +5 -5
- package/dist/{chunk-XYV3EDB7.js → chunk-J3YQ457H.js} +37 -20
- package/dist/{chunk-VZSG24LS.js → chunk-JUTFX2RM.js} +18 -10
- package/dist/{chunk-RUSSKG6G.js → chunk-KJ3UKABJ.js} +1 -1
- package/dist/{chunk-UNWRJRKC.js → chunk-LI4W3U6C.js} +1 -1
- package/dist/{chunk-FNJXNGYZ.js → chunk-O6TRVMJI.js} +58 -6
- package/dist/{chunk-7LUJQAOJ.js → chunk-Q5J2LVKH.js} +1 -1
- package/dist/{chunk-4AWA2PVD.js → chunk-QGMSESDD.js} +10 -5
- package/dist/{chunk-XZR4PXRE.js → chunk-RGLPEBDE.js} +13 -10
- package/dist/{chunk-JWKYU5GV.js → chunk-TQQUN4WR.js} +1 -1
- package/dist/{chunk-WOLJZUFQ.js → chunk-UCNP3HVM.js} +12 -8
- package/dist/{chunk-WEQ3DMVL.js → chunk-V3LHZSU5.js} +1 -1
- package/dist/{chunk-UOL2ECCS.js → chunk-VWT3VXPL.js} +18 -12
- package/dist/{chunk-2BPG2XDA.js → chunk-ZVLHNEEL.js} +17 -35
- 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 +9 -2
- 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 +621 -252
- package/dist/extras.d.cts +2 -2
- package/dist/extras.d.ts +2 -2
- package/dist/extras.js +24 -23
- package/dist/index.cjs +464 -70
- package/dist/index.d.cts +28 -2
- package/dist/index.d.ts +28 -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 +558 -231
- package/dist/plugins.d.cts +8 -3
- package/dist/plugins.d.ts +8 -3
- package/dist/plugins.js +22 -28
- 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 +457 -131
- package/dist/ssr.d.cts +55 -5
- package/dist/ssr.d.ts +55 -5
- package/dist/ssr.js +11 -9
- package/dist/testing.cjs +3 -3
- package/dist/testing.js +4 -4
- package/dist/ui.cjs +608 -240
- 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.8.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
|
}
|
|
@@ -3075,8 +3079,10 @@ function socket(url, options) {
|
|
|
3075
3079
|
function stripControlChars(value) {
|
|
3076
3080
|
return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
|
|
3077
3081
|
}
|
|
3082
|
+
var ASCII_UPPER = /[A-Z]/;
|
|
3083
|
+
var ASCII_UPPER_G = /[A-Z]/g;
|
|
3078
3084
|
function canonicalAttrName(name) {
|
|
3079
|
-
return name.replace(
|
|
3085
|
+
return ASCII_UPPER.test(name) ? name.replace(ASCII_UPPER_G, (ch) => String.fromCharCode(ch.charCodeAt(0) + 32)) : name;
|
|
3080
3086
|
}
|
|
3081
3087
|
function isEventHandlerAttr(name) {
|
|
3082
3088
|
if (name.length < 3) return false;
|
|
@@ -3089,6 +3095,9 @@ function sanitizeUrl(url) {
|
|
|
3089
3095
|
const probe = stripControlChars(url).trim();
|
|
3090
3096
|
if (!probe) return "";
|
|
3091
3097
|
const output2 = url.replace(OUTER_TRIM, "");
|
|
3098
|
+
if (probe.length >= 2 && (probe[0] === "\\" || probe[0] === "/") && (probe[1] === "\\" || probe[1] === "/") && (probe[0] === "\\" || probe[1] === "\\")) {
|
|
3099
|
+
return "";
|
|
3100
|
+
}
|
|
3092
3101
|
const lower = probe.toLowerCase();
|
|
3093
3102
|
let schemeEnd = -1;
|
|
3094
3103
|
for (let i2 = 0; i2 < lower.length; i2++) {
|
|
@@ -3105,19 +3114,58 @@ function sanitizeUrl(url) {
|
|
|
3105
3114
|
if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
|
|
3106
3115
|
return output2;
|
|
3107
3116
|
}
|
|
3108
|
-
var SRCSET_DESCRIPTOR = /^\
|
|
3117
|
+
var SRCSET_DESCRIPTOR = /^\d+(\.\d+)?[wx]$/;
|
|
3118
|
+
function isSrcsetWhitespace(ch) {
|
|
3119
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
|
|
3120
|
+
}
|
|
3109
3121
|
function sanitizeSrcset(value) {
|
|
3110
|
-
const
|
|
3122
|
+
const input2 = String(value);
|
|
3111
3123
|
const out = [];
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
if (
|
|
3117
|
-
|
|
3118
|
-
|
|
3124
|
+
let i2 = 0;
|
|
3125
|
+
const n = input2.length;
|
|
3126
|
+
while (i2 < n) {
|
|
3127
|
+
while (i2 < n && (isSrcsetWhitespace(input2[i2]) || input2[i2] === ",")) i2++;
|
|
3128
|
+
if (i2 >= n) break;
|
|
3129
|
+
const urlStart = i2;
|
|
3130
|
+
while (i2 < n && !isSrcsetWhitespace(input2[i2])) i2++;
|
|
3131
|
+
let url = input2.slice(urlStart, i2);
|
|
3132
|
+
const descriptors = [];
|
|
3133
|
+
if (url.endsWith(",")) {
|
|
3134
|
+
url = url.replace(/,+$/, "");
|
|
3135
|
+
} else {
|
|
3136
|
+
let current = "";
|
|
3137
|
+
let inParens = false;
|
|
3138
|
+
while (i2 < n) {
|
|
3139
|
+
const ch = input2[i2];
|
|
3140
|
+
if (inParens) {
|
|
3141
|
+
current += ch;
|
|
3142
|
+
if (ch === ")") inParens = false;
|
|
3143
|
+
i2++;
|
|
3144
|
+
continue;
|
|
3145
|
+
}
|
|
3146
|
+
if (isSrcsetWhitespace(ch)) {
|
|
3147
|
+
if (current) descriptors.push(current);
|
|
3148
|
+
current = "";
|
|
3149
|
+
i2++;
|
|
3150
|
+
continue;
|
|
3151
|
+
}
|
|
3152
|
+
if (ch === ",") {
|
|
3153
|
+
i2++;
|
|
3154
|
+
break;
|
|
3155
|
+
}
|
|
3156
|
+
if (ch === "(") inParens = true;
|
|
3157
|
+
current += ch;
|
|
3158
|
+
i2++;
|
|
3159
|
+
}
|
|
3160
|
+
if (current) descriptors.push(current);
|
|
3161
|
+
}
|
|
3162
|
+
if (url === "") continue;
|
|
3163
|
+
if (descriptors.length > 1) continue;
|
|
3164
|
+
if (descriptors.length === 1 && !SRCSET_DESCRIPTOR.test(descriptors[0])) continue;
|
|
3165
|
+
const safe = sanitizeUrl(url);
|
|
3119
3166
|
if (!safe) continue;
|
|
3120
|
-
|
|
3167
|
+
if (safe.startsWith(",") || safe.endsWith(",")) continue;
|
|
3168
|
+
out.push(descriptors.length === 1 ? `${safe} ${descriptors[0]}` : safe);
|
|
3121
3169
|
}
|
|
3122
3170
|
return out.join(", ");
|
|
3123
3171
|
}
|
|
@@ -3176,8 +3224,16 @@ var BLOCKED_CSS_NEEDLES = [
|
|
|
3176
3224
|
"behavior:",
|
|
3177
3225
|
"@import",
|
|
3178
3226
|
"image-set(",
|
|
3179
|
-
"filter:progid"
|
|
3227
|
+
"filter:progid",
|
|
3228
|
+
// CSS Images 4 `image("…")` and CSS Values 5 `src("…")` take a URL as a
|
|
3229
|
+
// plain STRING, so they fetch without ever spelling `url(`. Support is thin
|
|
3230
|
+
// today, which is exactly when a blocklist should get ahead of it.
|
|
3231
|
+
"image(",
|
|
3232
|
+
"src("
|
|
3180
3233
|
];
|
|
3234
|
+
var CSS_REASON_MOZ_BINDING = 4;
|
|
3235
|
+
var CSS_REASON_BEHAVIOR = 5;
|
|
3236
|
+
var CSS_REASON_PROGID = 8;
|
|
3181
3237
|
function describeElement(el) {
|
|
3182
3238
|
if (!el) return "an element";
|
|
3183
3239
|
let out = el.tagName.toLowerCase();
|
|
@@ -3201,7 +3257,9 @@ function warnDroppedDeclaration(value, reason, ctx) {
|
|
|
3201
3257
|
"behavior: loads and runs a remote HTC script",
|
|
3202
3258
|
"@import pulls in a remote stylesheet",
|
|
3203
3259
|
"image-set() fetches remote images, the same exfiltration channel as url()",
|
|
3204
|
-
"filter:progid activates legacy scriptable filters"
|
|
3260
|
+
"filter:progid activates legacy scriptable filters",
|
|
3261
|
+
"image() fetches its string argument as a URL, the same exfiltration channel as url()",
|
|
3262
|
+
"src() fetches its string argument as a URL, the same exfiltration channel as url()"
|
|
3205
3263
|
];
|
|
3206
3264
|
const declaration = ctx?.property ? `${ctx.property}: ${value}` : value;
|
|
3207
3265
|
const where = describeElement(ctx?.element);
|
|
@@ -3216,27 +3274,145 @@ function warnDroppedDeclaration(value, reason, ctx) {
|
|
|
3216
3274
|
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
3275
|
});
|
|
3218
3276
|
}
|
|
3277
|
+
function normalizeCssForScan(value) {
|
|
3278
|
+
const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
|
|
3279
|
+
return normalized.toLowerCase().replace(/\s+/g, "");
|
|
3280
|
+
}
|
|
3219
3281
|
function blockedCssReason(value) {
|
|
3220
3282
|
if (!CSS_DANGER_GATE.test(value)) return -1;
|
|
3221
|
-
const
|
|
3222
|
-
const lower = normalized.toLowerCase().replace(/\s+/g, "");
|
|
3283
|
+
const lower = normalizeCssForScan(value);
|
|
3223
3284
|
for (let i2 = 0; i2 < BLOCKED_CSS_NEEDLES.length; i2++) {
|
|
3224
3285
|
if (lower.includes(BLOCKED_CSS_NEEDLES[i2])) return i2;
|
|
3225
3286
|
}
|
|
3226
3287
|
return -1;
|
|
3227
3288
|
}
|
|
3228
|
-
|
|
3229
|
-
|
|
3289
|
+
var STYLESHEET_BLOCKED_FUNCTIONS = ["url", "image-set", "image", "src", "expression"];
|
|
3290
|
+
function stripCssFunctions(css) {
|
|
3291
|
+
const pattern2 = new RegExp(`(?:-webkit-)?(${STYLESHEET_BLOCKED_FUNCTIONS.join("|")})\\s*\\(`, "gi");
|
|
3292
|
+
let out = "";
|
|
3293
|
+
let last = 0;
|
|
3294
|
+
for (let match = pattern2.exec(css); match !== null; match = pattern2.exec(css)) {
|
|
3295
|
+
const before = match.index > 0 ? css[match.index - 1] : "";
|
|
3296
|
+
if (/[\w-]/.test(before)) continue;
|
|
3297
|
+
let depth = 1;
|
|
3298
|
+
let i2 = pattern2.lastIndex;
|
|
3299
|
+
let quote2 = "";
|
|
3300
|
+
for (; i2 < css.length && depth > 0; i2++) {
|
|
3301
|
+
const ch = css[i2];
|
|
3302
|
+
if (quote2) {
|
|
3303
|
+
if (ch === "\\") i2++;
|
|
3304
|
+
else if (ch === quote2) quote2 = "";
|
|
3305
|
+
} else if (ch === '"' || ch === "'") quote2 = ch;
|
|
3306
|
+
else if (ch === "(") depth++;
|
|
3307
|
+
else if (ch === ")") depth--;
|
|
3308
|
+
}
|
|
3309
|
+
out += `${css.slice(last, match.index)}/* ${match[1].toLowerCase()}() removed */`;
|
|
3310
|
+
last = i2;
|
|
3311
|
+
pattern2.lastIndex = i2;
|
|
3312
|
+
}
|
|
3313
|
+
return out + css.slice(last);
|
|
3314
|
+
}
|
|
3315
|
+
function sanitizeStylesheetText(css) {
|
|
3316
|
+
let text2 = css.includes("\\") ? decodeCssEscapes(css) : css;
|
|
3317
|
+
text2 = text2.replace(/@import\b[^;{}]*;?/gi, "/* @import removed */");
|
|
3318
|
+
text2 = stripCssFunctions(text2);
|
|
3319
|
+
text2 = text2.replace(/(^|[;{\s])behavior\s*:[^;}]*;?/gi, "$1/* behavior removed */");
|
|
3320
|
+
text2 = text2.replace(/(^|[;{\s])-moz-binding\s*:[^;}]*;?/gi, "$1/* -moz-binding removed */");
|
|
3321
|
+
text2 = text2.replace(/(^|[;{\s])(-ms-)?filter\s*:[^;}]*progid[^;}]*;?/gi, "$1/* filter:progid removed */");
|
|
3322
|
+
return text2;
|
|
3323
|
+
}
|
|
3324
|
+
function sanitizeCSSDeclaration(property, value, context) {
|
|
3325
|
+
const reason = blockedDeclarationReason(property, value);
|
|
3230
3326
|
if (reason === -1) return value;
|
|
3231
|
-
warnDroppedDeclaration(value, reason, context);
|
|
3327
|
+
warnDroppedDeclaration(value, reason, { property, element: context?.element });
|
|
3232
3328
|
return "";
|
|
3233
3329
|
}
|
|
3330
|
+
function blockedDeclarationReason(property, value) {
|
|
3331
|
+
const reason = blockedCssReason(value);
|
|
3332
|
+
if (reason !== -1) return reason;
|
|
3333
|
+
const name = canonicalAttrName(property);
|
|
3334
|
+
if (name === "behavior") return CSS_REASON_BEHAVIOR;
|
|
3335
|
+
if (name === "-moz-binding") return CSS_REASON_MOZ_BINDING;
|
|
3336
|
+
if ((name === "filter" || name === "-ms-filter") && normalizeCssForScan(value).includes("progid:")) {
|
|
3337
|
+
return CSS_REASON_PROGID;
|
|
3338
|
+
}
|
|
3339
|
+
return -1;
|
|
3340
|
+
}
|
|
3341
|
+
function parseStyleDeclarations(css) {
|
|
3342
|
+
const chunks = [];
|
|
3343
|
+
let buf = "";
|
|
3344
|
+
let depth = 0;
|
|
3345
|
+
let quote2 = "";
|
|
3346
|
+
for (let i2 = 0; i2 < css.length; i2++) {
|
|
3347
|
+
const ch = css[i2];
|
|
3348
|
+
if (quote2) {
|
|
3349
|
+
buf += ch;
|
|
3350
|
+
if (ch === "\\" && i2 + 1 < css.length) buf += css[++i2];
|
|
3351
|
+
else if (ch === quote2) quote2 = "";
|
|
3352
|
+
continue;
|
|
3353
|
+
}
|
|
3354
|
+
if (ch === "\\") {
|
|
3355
|
+
buf += ch;
|
|
3356
|
+
if (i2 + 1 < css.length) buf += css[++i2];
|
|
3357
|
+
continue;
|
|
3358
|
+
}
|
|
3359
|
+
if (ch === "/" && css[i2 + 1] === "*") {
|
|
3360
|
+
const end = css.indexOf("*/", i2 + 2);
|
|
3361
|
+
if (end === -1) return null;
|
|
3362
|
+
i2 = end + 1;
|
|
3363
|
+
continue;
|
|
3364
|
+
}
|
|
3365
|
+
if (ch === '"' || ch === "'") quote2 = ch;
|
|
3366
|
+
else if (ch === "(" || ch === "[") depth++;
|
|
3367
|
+
else if (ch === ")" || ch === "]") {
|
|
3368
|
+
if (--depth < 0) return null;
|
|
3369
|
+
} else if (ch === "{" || ch === "}") return null;
|
|
3370
|
+
else if (ch === ";" && depth === 0) {
|
|
3371
|
+
chunks.push(buf);
|
|
3372
|
+
buf = "";
|
|
3373
|
+
continue;
|
|
3374
|
+
}
|
|
3375
|
+
buf += ch;
|
|
3376
|
+
}
|
|
3377
|
+
if (quote2 || depth !== 0) return null;
|
|
3378
|
+
chunks.push(buf);
|
|
3379
|
+
const out = [];
|
|
3380
|
+
for (const chunk of chunks) {
|
|
3381
|
+
const colon = chunk.indexOf(":");
|
|
3382
|
+
if (colon === -1) continue;
|
|
3383
|
+
const rawName = chunk.slice(0, colon).trim();
|
|
3384
|
+
if (!/^(--[\w-]+|-?[a-zA-Z_][\w-]*)$/.test(rawName)) continue;
|
|
3385
|
+
let value = chunk.slice(colon + 1).trim();
|
|
3386
|
+
const bang = /!\s*important\s*$/i.exec(value);
|
|
3387
|
+
if (bang) value = value.slice(0, bang.index).trim();
|
|
3388
|
+
if (value === "") continue;
|
|
3389
|
+
const property = rawName.startsWith("--") ? rawName : canonicalAttrName(rawName);
|
|
3390
|
+
out.push([property, value, bang !== null]);
|
|
3391
|
+
}
|
|
3392
|
+
return out;
|
|
3393
|
+
}
|
|
3394
|
+
function sanitizeStyleDeclarationList(cssText, context) {
|
|
3395
|
+
const input2 = String(cssText);
|
|
3396
|
+
const declarations = parseStyleDeclarations(input2);
|
|
3397
|
+
if (declarations === null) {
|
|
3398
|
+
if (blockedCssReason(input2) !== -1) warnDroppedDeclaration(input2, blockedCssReason(input2), context);
|
|
3399
|
+
return "";
|
|
3400
|
+
}
|
|
3401
|
+
const kept = [];
|
|
3402
|
+
for (const [property, value, important] of declarations) {
|
|
3403
|
+
const reason = blockedDeclarationReason(property, value);
|
|
3404
|
+
if (reason !== -1) {
|
|
3405
|
+
warnDroppedDeclaration(value, reason, { property, element: context?.element });
|
|
3406
|
+
continue;
|
|
3407
|
+
}
|
|
3408
|
+
kept.push(`${property}: ${value}${important ? " !important" : ""}`);
|
|
3409
|
+
}
|
|
3410
|
+
return kept.join("; ");
|
|
3411
|
+
}
|
|
3234
3412
|
function sanitizeStyleAttribute(cssText, context) {
|
|
3235
3413
|
const input2 = String(cssText);
|
|
3236
3414
|
if (input2.trim() === "") return "";
|
|
3237
|
-
if (typeof document === "undefined")
|
|
3238
|
-
return sanitizeCSSValue(input2, context) === "" ? "" : input2;
|
|
3239
|
-
}
|
|
3415
|
+
if (typeof document === "undefined") return sanitizeStyleDeclarationList(input2, context);
|
|
3240
3416
|
const probe = document.createElement("div");
|
|
3241
3417
|
try {
|
|
3242
3418
|
probe.style.cssText = input2;
|
|
@@ -3247,8 +3423,7 @@ function sanitizeStyleAttribute(cssText, context) {
|
|
|
3247
3423
|
for (let i2 = 0; i2 < probe.style.length; i2++) {
|
|
3248
3424
|
const property = probe.style[i2];
|
|
3249
3425
|
const value = probe.style.getPropertyValue(property);
|
|
3250
|
-
|
|
3251
|
-
if (reason === -1) reason = blockedCssReason(`${property}:${value}`);
|
|
3426
|
+
const reason = blockedDeclarationReason(property, value);
|
|
3252
3427
|
if (reason !== -1) {
|
|
3253
3428
|
warnDroppedDeclaration(value, reason, { property, element: context?.element });
|
|
3254
3429
|
continue;
|
|
@@ -3296,6 +3471,9 @@ var HTML_CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set(["srcdoc"]);
|
|
|
3296
3471
|
function isHtmlContentAttribute(name) {
|
|
3297
3472
|
return HTML_CONTENT_ATTRIBUTES.has(name.toLowerCase());
|
|
3298
3473
|
}
|
|
3474
|
+
function isUrlAttribute(attr) {
|
|
3475
|
+
return URL_ATTRIBUTES.has(attr.toLowerCase());
|
|
3476
|
+
}
|
|
3299
3477
|
function isPolicyAttribute(name) {
|
|
3300
3478
|
const lower = name.toLowerCase();
|
|
3301
3479
|
return lower === "style" || URL_ATTRIBUTES.has(lower);
|
|
@@ -3307,6 +3485,11 @@ function sanitizeAttributeString(attr, value, context) {
|
|
|
3307
3485
|
if (lower === "style") return sanitizeStyleAttribute(value, context);
|
|
3308
3486
|
return value;
|
|
3309
3487
|
}
|
|
3488
|
+
function resolveAttributeValue(attr, value, context) {
|
|
3489
|
+
if (!isPolicyAttribute(attr)) return value;
|
|
3490
|
+
const safe = sanitizeAttributeString(attr, value, context);
|
|
3491
|
+
return safe === "" ? null : safe;
|
|
3492
|
+
}
|
|
3310
3493
|
|
|
3311
3494
|
// src/ui/stream.ts
|
|
3312
3495
|
function validateSseUrl(raw) {
|
|
@@ -3730,6 +3913,13 @@ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototyp
|
|
|
3730
3913
|
function isUnsafeKey(key) {
|
|
3731
3914
|
return UNSAFE_KEYS.has(key);
|
|
3732
3915
|
}
|
|
3916
|
+
function readOwnGlobal(key) {
|
|
3917
|
+
if (typeof window === "undefined") return void 0;
|
|
3918
|
+
if (!Object.hasOwn(window, key)) return void 0;
|
|
3919
|
+
const value = window[key];
|
|
3920
|
+
if (typeof Node !== "undefined" && value instanceof Node) return void 0;
|
|
3921
|
+
return value;
|
|
3922
|
+
}
|
|
3733
3923
|
function stripUnsafeKeys(obj) {
|
|
3734
3924
|
const out = {};
|
|
3735
3925
|
for (const k of Object.keys(obj)) {
|
|
@@ -4047,13 +4237,19 @@ function colorScheme() {
|
|
|
4047
4237
|
}
|
|
4048
4238
|
|
|
4049
4239
|
// src/browser/format.ts
|
|
4240
|
+
var I18N_STATE = /* @__PURE__ */ Symbol.for("sibujs.i18n.v1");
|
|
4241
|
+
function activeI18nLocale() {
|
|
4242
|
+
const state2 = globalThis[I18N_STATE];
|
|
4243
|
+
if (!state2) return void 0;
|
|
4244
|
+
return state2.getLocale ? state2.getLocale() : state2.locale?.[0]();
|
|
4245
|
+
}
|
|
4050
4246
|
function formatNumber(value, options) {
|
|
4051
4247
|
const { locale, ...formatOptions } = options ?? {};
|
|
4052
|
-
return new Intl.NumberFormat(locale, formatOptions).format(value);
|
|
4248
|
+
return new Intl.NumberFormat(locale ?? activeI18nLocale(), formatOptions).format(value);
|
|
4053
4249
|
}
|
|
4054
4250
|
function formatCurrency(value, currency, options) {
|
|
4055
4251
|
const { locale, ...formatOptions } = options ?? {};
|
|
4056
|
-
return new Intl.NumberFormat(locale, {
|
|
4252
|
+
return new Intl.NumberFormat(locale ?? activeI18nLocale(), {
|
|
4057
4253
|
...formatOptions,
|
|
4058
4254
|
style: "currency",
|
|
4059
4255
|
currency
|
|
@@ -5022,6 +5218,11 @@ function imageLoader(src) {
|
|
|
5022
5218
|
abandonCurrent();
|
|
5023
5219
|
resetState();
|
|
5024
5220
|
if (disposed || token !== startToken) return;
|
|
5221
|
+
const safe = sanitizeUrl(String(url));
|
|
5222
|
+
if (!safe) {
|
|
5223
|
+
setStatus("error");
|
|
5224
|
+
return;
|
|
5225
|
+
}
|
|
5025
5226
|
const img2 = new Image();
|
|
5026
5227
|
current = img2;
|
|
5027
5228
|
currentSettled = false;
|
|
@@ -5040,7 +5241,7 @@ function imageLoader(src) {
|
|
|
5040
5241
|
currentSettled = true;
|
|
5041
5242
|
setStatus("error");
|
|
5042
5243
|
};
|
|
5043
|
-
img2.src =
|
|
5244
|
+
img2.src = safe;
|
|
5044
5245
|
}
|
|
5045
5246
|
let srcEffectTeardown = null;
|
|
5046
5247
|
if (typeof src === "function") {
|
|
@@ -5066,6 +5267,9 @@ function imageLoader(src) {
|
|
|
5066
5267
|
}
|
|
5067
5268
|
|
|
5068
5269
|
// src/patterns/machine.ts
|
|
5270
|
+
function ownEntry(table2, key) {
|
|
5271
|
+
return Object.hasOwn(table2, key) ? table2[key] : void 0;
|
|
5272
|
+
}
|
|
5069
5273
|
function machine(config) {
|
|
5070
5274
|
const [state2, setState] = signal(config.initial);
|
|
5071
5275
|
const [context, setContext] = signal(config.context || {});
|
|
@@ -5087,9 +5291,9 @@ function machine(config) {
|
|
|
5087
5291
|
}
|
|
5088
5292
|
}
|
|
5089
5293
|
function step(event) {
|
|
5090
|
-
const stateDef = config.states
|
|
5294
|
+
const stateDef = ownEntry(config.states, currentState);
|
|
5091
5295
|
if (!stateDef?.on) return;
|
|
5092
|
-
const transition2 = stateDef.on
|
|
5296
|
+
const transition2 = ownEntry(stateDef.on, event);
|
|
5093
5297
|
if (!transition2) return;
|
|
5094
5298
|
let target;
|
|
5095
5299
|
let guard;
|
|
@@ -5117,7 +5321,7 @@ function machine(config) {
|
|
|
5117
5321
|
if (action) setContext(nextContext);
|
|
5118
5322
|
setState(target);
|
|
5119
5323
|
});
|
|
5120
|
-
const targetDef = config.states
|
|
5324
|
+
const targetDef = ownEntry(config.states, target);
|
|
5121
5325
|
if (targetDef?.entry) {
|
|
5122
5326
|
targetDef.entry(currentContext);
|
|
5123
5327
|
}
|
|
@@ -5127,7 +5331,7 @@ function machine(config) {
|
|
|
5127
5331
|
if (processing) return;
|
|
5128
5332
|
drain();
|
|
5129
5333
|
}
|
|
5130
|
-
const initialDef = config.states
|
|
5334
|
+
const initialDef = ownEntry(config.states, config.initial);
|
|
5131
5335
|
if (initialDef?.entry) {
|
|
5132
5336
|
processing = true;
|
|
5133
5337
|
try {
|
|
@@ -5145,9 +5349,9 @@ function machine(config) {
|
|
|
5145
5349
|
}
|
|
5146
5350
|
function can(event) {
|
|
5147
5351
|
const currentState2 = state2();
|
|
5148
|
-
const stateDef = config.states
|
|
5352
|
+
const stateDef = ownEntry(config.states, currentState2);
|
|
5149
5353
|
if (!stateDef?.on) return false;
|
|
5150
|
-
const transition2 = stateDef.on
|
|
5354
|
+
const transition2 = ownEntry(stateDef.on, event);
|
|
5151
5355
|
if (!transition2) return false;
|
|
5152
5356
|
if (typeof transition2 === "string") return true;
|
|
5153
5357
|
if (transition2.guard) {
|
|
@@ -7224,31 +7428,6 @@ function announce(message, priority = "polite") {
|
|
|
7224
7428
|
|
|
7225
7429
|
// src/ui/scopedStyle.ts
|
|
7226
7430
|
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
7431
|
function firstCompoundEnd(selector) {
|
|
7253
7432
|
let parens = 0;
|
|
7254
7433
|
let brackets = 0;
|
|
@@ -7410,7 +7589,7 @@ function scopeStylesheet(css, attr) {
|
|
|
7410
7589
|
function scopedStyle(css) {
|
|
7411
7590
|
const id = `sibu-s${_scope.n++}`;
|
|
7412
7591
|
const attr = `data-${id}`;
|
|
7413
|
-
const safeCss =
|
|
7592
|
+
const safeCss = sanitizeStylesheetText(css);
|
|
7414
7593
|
const scopedCSS = scopeStylesheet(safeCss, attr);
|
|
7415
7594
|
if (typeof document !== "undefined") {
|
|
7416
7595
|
const styleEl = document.createElement("style");
|
|
@@ -7436,26 +7615,246 @@ function removeScopedStyle(scopeId) {
|
|
|
7436
7615
|
if (el) el.remove();
|
|
7437
7616
|
}
|
|
7438
7617
|
|
|
7439
|
-
// src/utils/
|
|
7618
|
+
// src/utils/metaRefresh.ts
|
|
7619
|
+
function isAsciiWhitespace(ch) {
|
|
7620
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
|
|
7621
|
+
}
|
|
7622
|
+
function trimAsciiWhitespace(value) {
|
|
7623
|
+
let start = 0;
|
|
7624
|
+
let end = value.length;
|
|
7625
|
+
while (start < end && isAsciiWhitespace(value[start])) start++;
|
|
7626
|
+
while (end > start && isAsciiWhitespace(value[end - 1])) end--;
|
|
7627
|
+
return value.slice(start, end);
|
|
7628
|
+
}
|
|
7629
|
+
var forbidden = (reason) => ({ kind: "forbidden", reason });
|
|
7630
|
+
function parseMetaRefreshContent(content) {
|
|
7631
|
+
const raw = trimAsciiWhitespace(stripControlChars(content));
|
|
7632
|
+
if (raw === "") return forbidden(DEV ? "empty content" : "");
|
|
7633
|
+
let i2 = 0;
|
|
7634
|
+
while (i2 < raw.length && raw[i2] >= "0" && raw[i2] <= "9") i2++;
|
|
7635
|
+
if (i2 === 0) return forbidden(DEV ? "missing or non-numeric delay" : "");
|
|
7636
|
+
const delay = Number.parseInt(raw.slice(0, i2), 10);
|
|
7637
|
+
if (!Number.isFinite(delay)) return forbidden(DEV ? "unparseable delay" : "");
|
|
7638
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
7639
|
+
if (i2 === raw.length) return { kind: "delay-only", delay };
|
|
7640
|
+
if (raw[i2] !== ";" && raw[i2] !== ",") return forbidden(DEV ? "unexpected text after delay" : "");
|
|
7641
|
+
i2++;
|
|
7642
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
7643
|
+
const keyStart = i2;
|
|
7644
|
+
while (i2 < raw.length && !isAsciiWhitespace(raw[i2]) && raw[i2] !== "=") i2++;
|
|
7645
|
+
const key = raw.slice(keyStart, i2).toLowerCase();
|
|
7646
|
+
if (key !== "url") return forbidden(DEV ? `unsupported refresh key ${JSON.stringify(key)}` : "");
|
|
7647
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
7648
|
+
if (raw[i2] !== "=") return forbidden(DEV ? "missing '=' after url" : "");
|
|
7649
|
+
i2++;
|
|
7650
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
7651
|
+
let destination;
|
|
7652
|
+
const quote2 = raw[i2];
|
|
7653
|
+
if (quote2 === '"' || quote2 === "'") {
|
|
7654
|
+
const close = raw.indexOf(quote2, i2 + 1);
|
|
7655
|
+
if (close === -1) return forbidden(DEV ? "unterminated quoted destination" : "");
|
|
7656
|
+
destination = raw.slice(i2 + 1, close);
|
|
7657
|
+
const rest = trimAsciiWhitespace(raw.slice(close + 1));
|
|
7658
|
+
if (rest !== "") return forbidden(DEV ? "trailing text after quoted destination" : "");
|
|
7659
|
+
} else {
|
|
7660
|
+
destination = trimAsciiWhitespace(raw.slice(i2));
|
|
7661
|
+
if (/[;,]/.test(destination)) return forbidden(DEV ? "multiple refresh assignments" : "");
|
|
7662
|
+
}
|
|
7663
|
+
if (destination === "") return forbidden(DEV ? "empty destination" : "");
|
|
7664
|
+
const sanitizedDestination = sanitizeUrl(destination);
|
|
7665
|
+
if (sanitizedDestination === "") return forbidden(DEV ? "destination uses a disallowed protocol" : "");
|
|
7666
|
+
return { kind: "allowed", delay, destination, sanitizedDestination };
|
|
7667
|
+
}
|
|
7668
|
+
function resolveMetaRefreshPolicy(attributes) {
|
|
7669
|
+
let httpEquiv;
|
|
7670
|
+
let content;
|
|
7671
|
+
let duplicateName;
|
|
7672
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7673
|
+
for (const [key, value] of attributes) {
|
|
7674
|
+
const canonical = canonicalAttrName(key);
|
|
7675
|
+
if (seen.has(canonical)) duplicateName = canonical;
|
|
7676
|
+
seen.add(canonical);
|
|
7677
|
+
if (canonical === "http-equiv") httpEquiv = value;
|
|
7678
|
+
else if (canonical === "content") content = value;
|
|
7679
|
+
}
|
|
7680
|
+
if (duplicateName !== void 0) {
|
|
7681
|
+
return forbidden(DEV ? `duplicate case-insensitive attribute ${JSON.stringify(duplicateName)}` : "");
|
|
7682
|
+
}
|
|
7683
|
+
if (typeof httpEquiv !== "string") return { kind: "not-refresh" };
|
|
7684
|
+
if (trimAsciiWhitespace(stripControlChars(httpEquiv)).toLowerCase() !== "refresh") {
|
|
7685
|
+
return { kind: "not-refresh" };
|
|
7686
|
+
}
|
|
7687
|
+
if (typeof content !== "string") return { kind: "not-refresh" };
|
|
7688
|
+
return parseMetaRefreshContent(content);
|
|
7689
|
+
}
|
|
7690
|
+
function normalizeMetaAttributes(props) {
|
|
7691
|
+
const out = /* @__PURE__ */ new Map();
|
|
7692
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7693
|
+
for (const key of Object.keys(props)) {
|
|
7694
|
+
const canonical = canonicalAttrName(key);
|
|
7695
|
+
if (seen.has(canonical)) return null;
|
|
7696
|
+
seen.add(canonical);
|
|
7697
|
+
out.set(key, props[key]);
|
|
7698
|
+
}
|
|
7699
|
+
return out;
|
|
7700
|
+
}
|
|
7701
|
+
function isForbiddenMetaEntry(props) {
|
|
7702
|
+
const normalized = normalizeMetaAttributes(props);
|
|
7703
|
+
if (normalized === null) return true;
|
|
7704
|
+
return resolveMetaRefreshPolicy(normalized).kind === "forbidden";
|
|
7705
|
+
}
|
|
7706
|
+
|
|
7707
|
+
// src/utils/elementPolicy.ts
|
|
7440
7708
|
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
7441
7709
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
7710
|
+
var BLOCKED_ELEMENTS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
7711
|
+
function canonicalTagName(tag) {
|
|
7712
|
+
return canonicalAttrName(tag);
|
|
7713
|
+
}
|
|
7714
|
+
function isBlockedElement(tag) {
|
|
7715
|
+
return BLOCKED_ELEMENTS.has(canonicalTagName(tag));
|
|
7716
|
+
}
|
|
7717
|
+
var CODE_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
7718
|
+
function isCodeTextElement(tag) {
|
|
7719
|
+
return CODE_TEXT_ELEMENTS.has(canonicalTagName(tag));
|
|
7720
|
+
}
|
|
7721
|
+
var ContextualRefusal = {
|
|
7722
|
+
None: 0,
|
|
7723
|
+
/** The element would carry a refresh directive the shared policy forbids. */
|
|
7724
|
+
MetaRefreshForbidden: 1,
|
|
7725
|
+
/** A `<meta>` with a reactive binding may not carry any refresh directive. */
|
|
7726
|
+
MetaRefreshReactive: 2,
|
|
7727
|
+
/** A runtime value may not choose which program a `<script>` runs. */
|
|
7728
|
+
ScriptSource: 3,
|
|
7729
|
+
/** An SVG animation may not target a URL, handler or document attribute. */
|
|
7730
|
+
AnimationTarget: 4,
|
|
7731
|
+
/** A runtime-written `href` may not become an applied stylesheet. */
|
|
7732
|
+
StylesheetSource: 5
|
|
7733
|
+
};
|
|
7734
|
+
var SCRIPT_SOURCE_ATTRIBUTES = /* @__PURE__ */ new Set(["src", "href", "xlink:href", "type", "language"]);
|
|
7735
|
+
var SVG_ANIMATION_ELEMENTS = /* @__PURE__ */ new Set(["animate", "set", "animateMotion", "animateTransform", "animateColor"]);
|
|
7736
|
+
var reactiveMetaElements = /* @__PURE__ */ new WeakSet();
|
|
7737
|
+
function isHtmlNamespace(el) {
|
|
7738
|
+
return el.namespaceURI === HTML_NS || el.namespaceURI === null;
|
|
7739
|
+
}
|
|
7740
|
+
function metaSnapshot(el, canonical, value) {
|
|
7741
|
+
const snapshot = /* @__PURE__ */ new Map();
|
|
7742
|
+
const attrs = el.attributes;
|
|
7743
|
+
for (let i2 = 0; i2 < attrs.length; i2++) {
|
|
7744
|
+
const attr = attrs[i2];
|
|
7745
|
+
if (attr.name === canonical) continue;
|
|
7746
|
+
snapshot.set(attr.name, attr.value);
|
|
7747
|
+
}
|
|
7748
|
+
if (canonical !== null && value !== null) snapshot.set(canonical, value);
|
|
7749
|
+
return snapshot;
|
|
7750
|
+
}
|
|
7751
|
+
function claimReactiveMeta(el) {
|
|
7752
|
+
if (reactiveMetaElements.has(el)) return;
|
|
7753
|
+
reactiveMetaElements.add(el);
|
|
7754
|
+
if (el.getAttribute("content") === null) return;
|
|
7755
|
+
if (resolveMetaRefreshPolicy(metaSnapshot(el, null, null)).kind !== "not-refresh") {
|
|
7756
|
+
el.removeAttribute("content");
|
|
7757
|
+
}
|
|
7758
|
+
}
|
|
7759
|
+
function metaRefusal(el, name, value, origin) {
|
|
7760
|
+
if (!isHtmlNamespace(el)) return ContextualRefusal.None;
|
|
7761
|
+
const canonical = canonicalAttrName(name);
|
|
7762
|
+
if (canonical !== "http-equiv" && canonical !== "content") return ContextualRefusal.None;
|
|
7763
|
+
if (origin === "reactive") claimReactiveMeta(el);
|
|
7764
|
+
if (value === null) return ContextualRefusal.None;
|
|
7765
|
+
if (canonical === "content" && !el.hasAttribute("http-equiv")) return ContextualRefusal.None;
|
|
7766
|
+
const decision = resolveMetaRefreshPolicy(metaSnapshot(el, canonical, value));
|
|
7767
|
+
if (decision.kind === "forbidden") return ContextualRefusal.MetaRefreshForbidden;
|
|
7768
|
+
if (decision.kind !== "not-refresh" && reactiveMetaElements.has(el)) return ContextualRefusal.MetaRefreshReactive;
|
|
7769
|
+
return ContextualRefusal.None;
|
|
7770
|
+
}
|
|
7771
|
+
function animationRefusal(name, value) {
|
|
7772
|
+
if (value === null || canonicalAttrName(name) !== "attributename") return ContextualRefusal.None;
|
|
7773
|
+
const target = stripControlChars(value);
|
|
7774
|
+
return isUrlAttribute(target) || isEventHandlerAttr(target) || isHtmlContentAttribute(target) ? ContextualRefusal.AnimationTarget : ContextualRefusal.None;
|
|
7775
|
+
}
|
|
7776
|
+
var runtimeHrefLinks = /* @__PURE__ */ new WeakSet();
|
|
7777
|
+
function relHasStylesheet(rel) {
|
|
7778
|
+
if (rel === null) return false;
|
|
7779
|
+
const lower = canonicalAttrName(rel);
|
|
7780
|
+
if (!lower.includes("stylesheet")) return false;
|
|
7781
|
+
const tokens = lower.split(/[\t\n\f\r ]+/);
|
|
7782
|
+
for (let i2 = 0; i2 < tokens.length; i2++) if (tokens[i2] === "stylesheet") return true;
|
|
7783
|
+
return false;
|
|
7784
|
+
}
|
|
7785
|
+
function stylesheetRefusal(el, name, value, origin) {
|
|
7786
|
+
if (!isHtmlNamespace(el)) return ContextualRefusal.None;
|
|
7787
|
+
const canonical = canonicalAttrName(name);
|
|
7788
|
+
if (canonical === "href") {
|
|
7789
|
+
if (origin === "static" || value === null) return ContextualRefusal.None;
|
|
7790
|
+
if (relHasStylesheet(el.getAttribute("rel"))) return ContextualRefusal.StylesheetSource;
|
|
7791
|
+
runtimeHrefLinks.add(el);
|
|
7792
|
+
return ContextualRefusal.None;
|
|
7793
|
+
}
|
|
7794
|
+
if (canonical === "rel") {
|
|
7795
|
+
if (!relHasStylesheet(value)) return ContextualRefusal.None;
|
|
7796
|
+
return runtimeHrefLinks.has(el) && el.hasAttribute("href") ? ContextualRefusal.StylesheetSource : ContextualRefusal.None;
|
|
7797
|
+
}
|
|
7798
|
+
return ContextualRefusal.None;
|
|
7799
|
+
}
|
|
7800
|
+
function contextualAttributeRefusal(el, name, value, origin) {
|
|
7801
|
+
const local = el.localName;
|
|
7802
|
+
if (local === "meta") return metaRefusal(el, name, value, origin);
|
|
7803
|
+
if (local === "link") return stylesheetRefusal(el, name, value, origin);
|
|
7804
|
+
if (local === "script") {
|
|
7805
|
+
if (origin === "static" || value === null) return ContextualRefusal.None;
|
|
7806
|
+
return SCRIPT_SOURCE_ATTRIBUTES.has(canonicalAttrName(name)) ? ContextualRefusal.ScriptSource : ContextualRefusal.None;
|
|
7807
|
+
}
|
|
7808
|
+
if (SVG_ANIMATION_ELEMENTS.has(local) && el.namespaceURI === SVG_NS) return animationRefusal(name, value);
|
|
7809
|
+
return ContextualRefusal.None;
|
|
7810
|
+
}
|
|
7811
|
+
function settleAttributeProvenance(el, name, origin) {
|
|
7812
|
+
if (el.localName !== "link" || canonicalAttrName(name) !== "href") return;
|
|
7813
|
+
if (origin !== "static" && el.hasAttribute("href")) runtimeHrefLinks.add(el);
|
|
7814
|
+
else runtimeHrefLinks.delete(el);
|
|
7815
|
+
}
|
|
7816
|
+
function isForbiddenMetaSnapshot(attributes) {
|
|
7817
|
+
return resolveMetaRefreshPolicy(attributes).kind === "forbidden";
|
|
7818
|
+
}
|
|
7819
|
+
|
|
7820
|
+
// src/utils/setSafeAttribute.ts
|
|
7821
|
+
var HTML_NS2 = "http://www.w3.org/1999/xhtml";
|
|
7822
|
+
var SVG_NS2 = "http://www.w3.org/2000/svg";
|
|
7442
7823
|
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
7443
7824
|
var XML_NS = "http://www.w3.org/XML/1998/namespace";
|
|
7444
7825
|
var BOOLEAN_IDL_ATTRS = /* @__PURE__ */ new Set(["checked", "disabled", "selected"]);
|
|
7445
7826
|
function isHtmlElement(el) {
|
|
7446
|
-
return el.namespaceURI === null || el.namespaceURI ===
|
|
7827
|
+
return el.namespaceURI === null || el.namespaceURI === HTML_NS2;
|
|
7828
|
+
}
|
|
7829
|
+
function warnContextualRefusal(label2, name, refusal) {
|
|
7830
|
+
devWarnLazy(() => {
|
|
7831
|
+
const reasons = [
|
|
7832
|
+
"",
|
|
7833
|
+
'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)',
|
|
7834
|
+
"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",
|
|
7835
|
+
"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",
|
|
7836
|
+
"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",
|
|
7837
|
+
'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'
|
|
7838
|
+
];
|
|
7839
|
+
return `${label2}: refusing "${name}" in this element's context \u2014 ${reasons[refusal]}. The write was not performed.`;
|
|
7840
|
+
});
|
|
7447
7841
|
}
|
|
7448
7842
|
function setProp(el, key, val) {
|
|
7449
7843
|
el[key] = val;
|
|
7450
7844
|
}
|
|
7451
7845
|
function namespaceFor(el, name) {
|
|
7452
|
-
if (el.namespaceURI !==
|
|
7846
|
+
if (el.namespaceURI !== SVG_NS2) return null;
|
|
7453
7847
|
const lower = name.toLowerCase();
|
|
7454
7848
|
if (lower.startsWith("xlink:")) return XLINK_NS;
|
|
7455
7849
|
if (lower.startsWith("xml:")) return XML_NS;
|
|
7456
7850
|
return null;
|
|
7457
7851
|
}
|
|
7458
7852
|
function setSafeAttribute(el, name, value, options = {}) {
|
|
7853
|
+
const written = commitSafeAttribute(el, name, value, options);
|
|
7854
|
+
if (el.localName === "link") settleAttributeProvenance(el, name, options.reactive ? "reactive" : "runtime");
|
|
7855
|
+
return written;
|
|
7856
|
+
}
|
|
7857
|
+
function commitSafeAttribute(el, name, value, options) {
|
|
7459
7858
|
const ns = namespaceFor(el, name);
|
|
7460
7859
|
const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
|
|
7461
7860
|
if (isEventHandlerAttr(name)) {
|
|
@@ -7468,6 +7867,14 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
7468
7867
|
else el.removeAttribute(name);
|
|
7469
7868
|
return false;
|
|
7470
7869
|
}
|
|
7870
|
+
const pending = value == null || value === false ? null : value === true ? "" : String(value);
|
|
7871
|
+
const refusal = contextualAttributeRefusal(el, name, pending, options.reactive ? "reactive" : "runtime");
|
|
7872
|
+
if (refusal !== ContextualRefusal.None) {
|
|
7873
|
+
warnContextualRefusal(options.label ?? "setSafeAttribute", name, refusal);
|
|
7874
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
7875
|
+
else el.removeAttribute(name);
|
|
7876
|
+
return false;
|
|
7877
|
+
}
|
|
7471
7878
|
if (value == null) {
|
|
7472
7879
|
if (ns) el.removeAttributeNS(ns, localName);
|
|
7473
7880
|
else el.removeAttribute(name);
|
|
@@ -7511,7 +7918,12 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
7511
7918
|
setProp(el, idlName, idlName === "checked" ? Boolean(value) : str);
|
|
7512
7919
|
return true;
|
|
7513
7920
|
}
|
|
7514
|
-
const safe =
|
|
7921
|
+
const safe = str === "" ? "" : resolveAttributeValue(name, str, { element: el });
|
|
7922
|
+
if (safe === null) {
|
|
7923
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
7924
|
+
else el.removeAttribute(name);
|
|
7925
|
+
return true;
|
|
7926
|
+
}
|
|
7515
7927
|
const current = ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name);
|
|
7516
7928
|
if (current === safe) return true;
|
|
7517
7929
|
if (ns) el.setAttributeNS(ns, name, safe);
|
|
@@ -7534,7 +7946,7 @@ function bindAttribute(el, attr, getter) {
|
|
|
7534
7946
|
reportError(err, { phase: "binding", name: `bindAttribute("${attr}")`, node: el });
|
|
7535
7947
|
return;
|
|
7536
7948
|
}
|
|
7537
|
-
setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")
|
|
7949
|
+
setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")`, reactive: true });
|
|
7538
7950
|
}
|
|
7539
7951
|
return reactiveBinding2(commit, el);
|
|
7540
7952
|
}
|
|
@@ -7571,7 +7983,7 @@ function bindBoolAttr(el, attr, getter) {
|
|
|
7571
7983
|
reportError(err, { phase: "binding", name: "bindBoolAttr", node: el });
|
|
7572
7984
|
return;
|
|
7573
7985
|
}
|
|
7574
|
-
setSafeAttribute(el, attr, Boolean(value), { label: "bindBoolAttr" });
|
|
7986
|
+
setSafeAttribute(el, attr, Boolean(value), { label: "bindBoolAttr", reactive: true });
|
|
7575
7987
|
}
|
|
7576
7988
|
return reactiveBinding2(commit, el);
|
|
7577
7989
|
}
|
|
@@ -8124,6 +8536,9 @@ var DOMPool = class {
|
|
|
8124
8536
|
* Get a recycled element or create a new one.
|
|
8125
8537
|
*/
|
|
8126
8538
|
acquire(tag) {
|
|
8539
|
+
if (isBlockedElement(tag)) {
|
|
8540
|
+
throw new Error(`DOMPool: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
|
|
8541
|
+
}
|
|
8127
8542
|
const pool = this.pools.get(tag);
|
|
8128
8543
|
if (pool && pool.length > 0) {
|
|
8129
8544
|
const el = pool.pop();
|
|
@@ -8229,10 +8644,19 @@ function prefetch(url) {
|
|
|
8229
8644
|
}
|
|
8230
8645
|
function preloadImage(src) {
|
|
8231
8646
|
return new Promise((resolve, reject) => {
|
|
8647
|
+
const safe = sanitizeUrl(String(src));
|
|
8648
|
+
if (!safe) {
|
|
8649
|
+
reject(
|
|
8650
|
+
new Error(
|
|
8651
|
+
String(src).trim() === "" ? "preloadImage: no image URL was given." : "preloadImage: refusing an image URL outside the URL policy."
|
|
8652
|
+
)
|
|
8653
|
+
);
|
|
8654
|
+
return;
|
|
8655
|
+
}
|
|
8232
8656
|
const img2 = new Image();
|
|
8233
8657
|
img2.onload = () => resolve(img2);
|
|
8234
8658
|
img2.onerror = reject;
|
|
8235
|
-
img2.src =
|
|
8659
|
+
img2.src = safe;
|
|
8236
8660
|
});
|
|
8237
8661
|
}
|
|
8238
8662
|
|
|
@@ -8258,95 +8682,6 @@ function noSideEffect(fn) {
|
|
|
8258
8682
|
return fn;
|
|
8259
8683
|
}
|
|
8260
8684
|
|
|
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
8685
|
// src/utils/headEntry.ts
|
|
8351
8686
|
var SAFE_HEAD_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
|
|
8352
8687
|
function isEmittableHeadAttrName(name) {
|
|
@@ -8357,9 +8692,7 @@ function isEmittableHeadAttrName(name) {
|
|
|
8357
8692
|
return true;
|
|
8358
8693
|
}
|
|
8359
8694
|
function sanitizeHeadAttrValue(canonical, value) {
|
|
8360
|
-
|
|
8361
|
-
const safe = sanitizeAttributeString(canonical, value);
|
|
8362
|
-
return safe === "" ? null : safe;
|
|
8695
|
+
return resolveAttributeValue(canonical, value);
|
|
8363
8696
|
}
|
|
8364
8697
|
function findDuplicateAttributeName(names) {
|
|
8365
8698
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -8416,15 +8749,9 @@ function serializeHeadEntry(tag, attrs) {
|
|
|
8416
8749
|
}
|
|
8417
8750
|
|
|
8418
8751
|
// src/platform/ssr.ts
|
|
8419
|
-
function isPolicyAttr(lowerName) {
|
|
8420
|
-
return isPolicyAttribute(lowerName);
|
|
8421
|
-
}
|
|
8422
8752
|
function isForbiddenSsrAttr(lowerName) {
|
|
8423
8753
|
return isHtmlContentAttribute(lowerName);
|
|
8424
8754
|
}
|
|
8425
|
-
function sanitizeSsrAttributeValue(lowerName, value) {
|
|
8426
|
-
return sanitizeAttributeString(lowerName, value);
|
|
8427
|
-
}
|
|
8428
8755
|
var SAFE_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
|
|
8429
8756
|
function isSafeAttrName(name) {
|
|
8430
8757
|
return SAFE_ATTR_NAME.test(name);
|
|
@@ -8455,6 +8782,64 @@ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
|
8455
8782
|
"track",
|
|
8456
8783
|
"wbr"
|
|
8457
8784
|
]);
|
|
8785
|
+
function findNativeGetter(proto, name) {
|
|
8786
|
+
for (let p2 = proto; p2; p2 = Object.getPrototypeOf(p2)) {
|
|
8787
|
+
const get = Object.getOwnPropertyDescriptor(p2, name)?.get;
|
|
8788
|
+
if (get) return get;
|
|
8789
|
+
}
|
|
8790
|
+
return null;
|
|
8791
|
+
}
|
|
8792
|
+
var nativeAccessorsByRealm = /* @__PURE__ */ new WeakMap();
|
|
8793
|
+
function nativeAccessors() {
|
|
8794
|
+
const realm = Element;
|
|
8795
|
+
let accessors = nativeAccessorsByRealm.get(realm);
|
|
8796
|
+
if (!accessors) {
|
|
8797
|
+
accessors = {
|
|
8798
|
+
attributes: findNativeGetter(Element.prototype, "attributes"),
|
|
8799
|
+
tagName: findNativeGetter(Element.prototype, "tagName"),
|
|
8800
|
+
childNodes: findNativeGetter(Node.prototype, "childNodes"),
|
|
8801
|
+
getAttribute: Element.prototype.getAttribute
|
|
8802
|
+
};
|
|
8803
|
+
nativeAccessorsByRealm.set(realm, accessors);
|
|
8804
|
+
}
|
|
8805
|
+
return accessors;
|
|
8806
|
+
}
|
|
8807
|
+
function attributesOf(el) {
|
|
8808
|
+
const get = nativeAccessors().attributes;
|
|
8809
|
+
return get ? get.call(el) : el.attributes;
|
|
8810
|
+
}
|
|
8811
|
+
function tagNameOf(el) {
|
|
8812
|
+
const get = nativeAccessors().tagName;
|
|
8813
|
+
return get ? get.call(el) : el.tagName;
|
|
8814
|
+
}
|
|
8815
|
+
function childNodesOf(node) {
|
|
8816
|
+
const get = nativeAccessors().childNodes;
|
|
8817
|
+
return get ? get.call(node) : node.childNodes;
|
|
8818
|
+
}
|
|
8819
|
+
function getAttributeOf(el, name) {
|
|
8820
|
+
return nativeAccessors().getAttribute.call(el, name);
|
|
8821
|
+
}
|
|
8822
|
+
function serializeOpenTag(element, tag) {
|
|
8823
|
+
let html2 = `<${tag}`;
|
|
8824
|
+
const meta2 = tag === "meta" ? /* @__PURE__ */ new Map() : null;
|
|
8825
|
+
const attrs = attributesOf(element);
|
|
8826
|
+
for (let i2 = 0; i2 < attrs.length; i2++) {
|
|
8827
|
+
const attr = attrs[i2];
|
|
8828
|
+
const rawName = attr.name;
|
|
8829
|
+
if (!isSafeAttrName(rawName)) continue;
|
|
8830
|
+
if (isEventHandlerAttr(rawName)) continue;
|
|
8831
|
+
if (isForbiddenSsrAttr(rawName)) continue;
|
|
8832
|
+
const value = resolveAttributeValue(rawName.toLowerCase(), attr.value);
|
|
8833
|
+
if (value === null) continue;
|
|
8834
|
+
meta2?.set(rawName, value);
|
|
8835
|
+
html2 += ` ${rawName}="${escapeAttr(value)}"`;
|
|
8836
|
+
}
|
|
8837
|
+
if (meta2 && isForbiddenMetaSnapshot(meta2)) return null;
|
|
8838
|
+
if (!getAttributeOf(element, "data-sibu-hydrate")) {
|
|
8839
|
+
html2 += ` data-sibu-ssr="true"`;
|
|
8840
|
+
}
|
|
8841
|
+
return html2;
|
|
8842
|
+
}
|
|
8458
8843
|
function renderToString(element) {
|
|
8459
8844
|
if (element instanceof DocumentFragment) {
|
|
8460
8845
|
return Array.from(element.childNodes).map((child) => {
|
|
@@ -8474,35 +8859,21 @@ function renderToString(element) {
|
|
|
8474
8859
|
if (!(element instanceof HTMLElement)) {
|
|
8475
8860
|
return escapeHtml(element.textContent || "");
|
|
8476
8861
|
}
|
|
8477
|
-
const tag = element.
|
|
8478
|
-
if (tag
|
|
8862
|
+
const tag = tagNameOf(element).toLowerCase();
|
|
8863
|
+
if (isCodeTextElement(tag)) {
|
|
8479
8864
|
return DEV ? `<!--ssr:${tag}-stripped-->` : "";
|
|
8480
8865
|
}
|
|
8481
8866
|
if (!/^[a-z][a-z0-9-]*$/i.test(tag)) {
|
|
8482
8867
|
return DEV ? "<!--ssr:invalid-tag-->" : "";
|
|
8483
8868
|
}
|
|
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
|
-
}
|
|
8869
|
+
const openTag = serializeOpenTag(element, tag);
|
|
8870
|
+
if (openTag === null) return DEV ? `<!--ssr:${tag}-stripped-->` : "";
|
|
8871
|
+
let html2 = openTag;
|
|
8501
8872
|
if (VOID_ELEMENTS.has(tag)) {
|
|
8502
8873
|
return `${html2} />`;
|
|
8503
8874
|
}
|
|
8504
8875
|
html2 += ">";
|
|
8505
|
-
for (const child of Array.from(element
|
|
8876
|
+
for (const child of Array.from(childNodesOf(element))) {
|
|
8506
8877
|
try {
|
|
8507
8878
|
html2 += renderToString(child);
|
|
8508
8879
|
} catch (err) {
|
|
@@ -8652,12 +9023,8 @@ function buildAttrString(attrs, { allowEventHandlers = false } = {}) {
|
|
|
8652
9023
|
if (!isSafeAttrName(rawKey)) continue;
|
|
8653
9024
|
if (!allowEventHandlers && isEventHandlerAttr(rawKey)) continue;
|
|
8654
9025
|
if (isForbiddenSsrAttr(rawKey)) continue;
|
|
8655
|
-
const
|
|
8656
|
-
|
|
8657
|
-
if (isPolicyAttr(lowerKey)) {
|
|
8658
|
-
value = sanitizeSsrAttributeValue(lowerKey, value);
|
|
8659
|
-
if (!value) continue;
|
|
8660
|
-
}
|
|
9026
|
+
const value = resolveAttributeValue(rawKey.toLowerCase(), String(attrs[rawKey]));
|
|
9027
|
+
if (value === null) continue;
|
|
8661
9028
|
out.push(`${rawKey}="${escapeAttr(value)}"`);
|
|
8662
9029
|
}
|
|
8663
9030
|
return out.join(" ");
|
|
@@ -8720,8 +9087,8 @@ async function* renderToStream(element) {
|
|
|
8720
9087
|
yield escapeHtml(element.textContent || "");
|
|
8721
9088
|
return;
|
|
8722
9089
|
}
|
|
8723
|
-
const tag = element.
|
|
8724
|
-
if (tag
|
|
9090
|
+
const tag = tagNameOf(element).toLowerCase();
|
|
9091
|
+
if (isCodeTextElement(tag)) {
|
|
8725
9092
|
if (DEV) yield `<!--ssr:${tag}-stripped-->`;
|
|
8726
9093
|
return;
|
|
8727
9094
|
}
|
|
@@ -8729,29 +9096,17 @@ async function* renderToStream(element) {
|
|
|
8729
9096
|
if (DEV) yield "<!--ssr:invalid-tag-->";
|
|
8730
9097
|
return;
|
|
8731
9098
|
}
|
|
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"`;
|
|
9099
|
+
const openTag = serializeOpenTag(element, tag);
|
|
9100
|
+
if (openTag === null) {
|
|
9101
|
+
if (DEV) yield `<!--ssr:${tag}-stripped-->`;
|
|
9102
|
+
return;
|
|
8748
9103
|
}
|
|
8749
9104
|
if (VOID_ELEMENTS.has(tag)) {
|
|
8750
9105
|
yield `${openTag} />`;
|
|
8751
9106
|
return;
|
|
8752
9107
|
}
|
|
8753
9108
|
yield `${openTag}>`;
|
|
8754
|
-
for (const child of Array.from(element
|
|
9109
|
+
for (const child of Array.from(childNodesOf(element))) {
|
|
8755
9110
|
try {
|
|
8756
9111
|
yield* renderToStream(child);
|
|
8757
9112
|
} catch (err) {
|
|
@@ -8936,8 +9291,7 @@ function deserializeState(validate) {
|
|
|
8936
9291
|
"[SibuJS SSR] deserializeState() called without a validate guard \u2014 tampered SSR payloads will not be detected."
|
|
8937
9292
|
);
|
|
8938
9293
|
}
|
|
8939
|
-
const
|
|
8940
|
-
const raw = w[SSR_DATA_ATTR];
|
|
9294
|
+
const raw = readOwnGlobal(SSR_DATA_ATTR);
|
|
8941
9295
|
if (raw === void 0) return void 0;
|
|
8942
9296
|
if (validate && !validate(raw)) return void 0;
|
|
8943
9297
|
return raw;
|
|
@@ -9524,7 +9878,7 @@ function setCanonical(url) {
|
|
|
9524
9878
|
}
|
|
9525
9879
|
|
|
9526
9880
|
// src/platform/customElement.ts
|
|
9527
|
-
var
|
|
9881
|
+
var SVG_NS3 = "http://www.w3.org/2000/svg";
|
|
9528
9882
|
var MAX_RENDER_PASSES = 10;
|
|
9529
9883
|
var ABANDONED_RENDER = /* @__PURE__ */ Symbol("sibujs.defineElement.abandonedRender");
|
|
9530
9884
|
function defineElement(name, component, options = {}) {
|
|
@@ -9673,7 +10027,10 @@ function defineElement(name, component, options = {}) {
|
|
|
9673
10027
|
customElements.define(name, SibuElement);
|
|
9674
10028
|
}
|
|
9675
10029
|
function svgElement(tag, props = {}, ...nodes) {
|
|
9676
|
-
|
|
10030
|
+
if (isBlockedElement(tag)) {
|
|
10031
|
+
throw new Error(`svgElement: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
|
|
10032
|
+
}
|
|
10033
|
+
const el = document.createElementNS(SVG_NS3, tag);
|
|
9677
10034
|
for (const [key, value] of Object.entries(props)) {
|
|
9678
10035
|
if (key === "nodes") continue;
|
|
9679
10036
|
if (typeof value === "function" && isEventHandlerAttr(key)) {
|
|
@@ -9698,7 +10055,16 @@ function toError(err) {
|
|
|
9698
10055
|
if (err !== null && typeof err === "object" && "name" in err && "message" in err) return err;
|
|
9699
10056
|
return new Error(String(err));
|
|
9700
10057
|
}
|
|
10058
|
+
function workerSource(fn, api) {
|
|
10059
|
+
if (typeof fn !== "function") {
|
|
10060
|
+
throw new TypeError(
|
|
10061
|
+
`${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.`
|
|
10062
|
+
);
|
|
10063
|
+
}
|
|
10064
|
+
return Function.prototype.toString.call(fn);
|
|
10065
|
+
}
|
|
9701
10066
|
function worker(workerFn2) {
|
|
10067
|
+
const fnBody = workerSource(workerFn2, "worker");
|
|
9702
10068
|
const [result, setResult] = signal(null);
|
|
9703
10069
|
const [error, setError] = signal(null);
|
|
9704
10070
|
const [loading, setLoading] = signal(false);
|
|
@@ -9714,7 +10080,6 @@ function worker(workerFn2) {
|
|
|
9714
10080
|
if (typeof Worker === "undefined") {
|
|
9715
10081
|
throw new Error("Web Workers are not supported in this environment");
|
|
9716
10082
|
}
|
|
9717
|
-
const fnBody = workerFn2.toString();
|
|
9718
10083
|
const blob = new Blob([`self.onmessage = ${fnBody};`], { type: "application/javascript" });
|
|
9719
10084
|
blobUrl = URL.createObjectURL(blob);
|
|
9720
10085
|
worker2 = new Worker(blobUrl);
|
|
@@ -9763,6 +10128,7 @@ function worker(workerFn2) {
|
|
|
9763
10128
|
return { post, result, error, loading, terminate };
|
|
9764
10129
|
}
|
|
9765
10130
|
function workerFn(fn) {
|
|
10131
|
+
const fnStr = workerSource(fn, "workerFn");
|
|
9766
10132
|
const [loading, setLoading] = signal(false);
|
|
9767
10133
|
let worker2 = null;
|
|
9768
10134
|
let blobUrl = null;
|
|
@@ -9777,7 +10143,6 @@ function workerFn(fn) {
|
|
|
9777
10143
|
if (typeof Worker === "undefined") {
|
|
9778
10144
|
throw new Error("Web Workers are not supported in this environment");
|
|
9779
10145
|
}
|
|
9780
|
-
const fnStr = fn.toString();
|
|
9781
10146
|
const blob = new Blob(
|
|
9782
10147
|
[
|
|
9783
10148
|
`self.onmessage = function(e) {
|
|
@@ -9837,6 +10202,7 @@ function workerFn(fn) {
|
|
|
9837
10202
|
return { run, loading, terminate };
|
|
9838
10203
|
}
|
|
9839
10204
|
function createWorkerPool(workerFn2, poolSize) {
|
|
10205
|
+
const fnBody = workerSource(workerFn2, "createWorkerPool");
|
|
9840
10206
|
const size = poolSize || typeof navigator !== "undefined" && navigator.hardwareConcurrency || 4;
|
|
9841
10207
|
const workers = [];
|
|
9842
10208
|
const queues = [];
|
|
@@ -9895,7 +10261,6 @@ function createWorkerPool(workerFn2, poolSize) {
|
|
|
9895
10261
|
if (typeof Worker === "undefined") {
|
|
9896
10262
|
throw new Error("Web Workers are not supported in this environment");
|
|
9897
10263
|
}
|
|
9898
|
-
const fnBody = workerFn2.toString();
|
|
9899
10264
|
const blob = new Blob([`self.onmessage = ${fnBody};`], { type: "application/javascript" });
|
|
9900
10265
|
blobUrl = URL.createObjectURL(blob);
|
|
9901
10266
|
for (let i2 = 0; i2 < size; i2++) {
|
|
@@ -10292,11 +10657,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
10292
10657
|
}
|
|
10293
10658
|
|
|
10294
10659
|
// 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
|
-
}
|
|
10660
|
+
var SVG_NS4 = "http://www.w3.org/2000/svg";
|
|
10300
10661
|
var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
|
|
10301
10662
|
"config",
|
|
10302
10663
|
"location",
|
|
@@ -10341,11 +10702,12 @@ function applyStyle(el, style2) {
|
|
|
10341
10702
|
}
|
|
10342
10703
|
const next = [];
|
|
10343
10704
|
for (const prop in value) {
|
|
10705
|
+
if (!Object.hasOwn(value, prop)) continue;
|
|
10344
10706
|
const val = value[prop];
|
|
10345
10707
|
if (val == null) continue;
|
|
10346
10708
|
const name = toKebab(prop);
|
|
10347
10709
|
next.push(name);
|
|
10348
|
-
decl.setProperty(name,
|
|
10710
|
+
decl.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
|
|
10349
10711
|
}
|
|
10350
10712
|
for (let i2 = 0; i2 < written.length; i2++) {
|
|
10351
10713
|
if (next.indexOf(written[i2]) === -1) decl.removeProperty(written[i2]);
|
|
@@ -10361,16 +10723,17 @@ function applyStyle(el, style2) {
|
|
|
10361
10723
|
}
|
|
10362
10724
|
const htmlEl = el;
|
|
10363
10725
|
for (const prop in style2) {
|
|
10726
|
+
if (!Object.hasOwn(style2, prop)) continue;
|
|
10364
10727
|
const val = style2[prop];
|
|
10365
10728
|
const name = toKebab(prop);
|
|
10366
10729
|
if (typeof val === "function") {
|
|
10367
10730
|
const getter = val;
|
|
10368
10731
|
const teardown = reactiveBinding2(() => {
|
|
10369
|
-
htmlEl.style.setProperty(name,
|
|
10732
|
+
htmlEl.style.setProperty(name, sanitizeCSSDeclaration(name, String(getter()), { element: el }));
|
|
10370
10733
|
}, el);
|
|
10371
10734
|
registerDisposer(el, teardown);
|
|
10372
10735
|
} else {
|
|
10373
|
-
htmlEl.style.setProperty(name,
|
|
10736
|
+
htmlEl.style.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
|
|
10374
10737
|
}
|
|
10375
10738
|
}
|
|
10376
10739
|
}
|
|
@@ -10392,6 +10755,7 @@ function applyClass(el, cls) {
|
|
|
10392
10755
|
let hasReactive = false;
|
|
10393
10756
|
let result = "";
|
|
10394
10757
|
for (const name in obj) {
|
|
10758
|
+
if (!Object.hasOwn(obj, name)) continue;
|
|
10395
10759
|
const val = obj[name];
|
|
10396
10760
|
if (typeof val === "function") {
|
|
10397
10761
|
hasReactive = true;
|
|
@@ -10403,6 +10767,7 @@ function applyClass(el, cls) {
|
|
|
10403
10767
|
const update = () => {
|
|
10404
10768
|
let r = "";
|
|
10405
10769
|
for (const name in obj) {
|
|
10770
|
+
if (!Object.hasOwn(obj, name)) continue;
|
|
10406
10771
|
const val = obj[name];
|
|
10407
10772
|
const active = typeof val === "function" ? val() : val;
|
|
10408
10773
|
if (active) r = r ? `${r} ${name}` : name;
|
|
@@ -10466,7 +10831,7 @@ function appendChildren(el, nodes) {
|
|
|
10466
10831
|
}
|
|
10467
10832
|
}
|
|
10468
10833
|
function tagFactory(tag, ns) {
|
|
10469
|
-
const blocked =
|
|
10834
|
+
const blocked = isBlockedElement(tag);
|
|
10470
10835
|
return (first, second) => {
|
|
10471
10836
|
if (blocked) {
|
|
10472
10837
|
throw new Error(`tagFactory: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
|
|
@@ -10529,6 +10894,7 @@ function tagFactory(tag, ns) {
|
|
|
10529
10894
|
const pOn = props.on;
|
|
10530
10895
|
if (pOn) {
|
|
10531
10896
|
for (const ev in pOn) {
|
|
10897
|
+
if (!Object.hasOwn(pOn, ev)) continue;
|
|
10532
10898
|
const handler = pOn[ev];
|
|
10533
10899
|
if (typeof handler === "function") {
|
|
10534
10900
|
el.addEventListener(ev, handler);
|
|
@@ -10555,6 +10921,7 @@ function tagFactory(tag, ns) {
|
|
|
10555
10921
|
continue;
|
|
10556
10922
|
// already handled above / below
|
|
10557
10923
|
default: {
|
|
10924
|
+
if (!Object.hasOwn(props, key)) continue;
|
|
10558
10925
|
const value = props[key];
|
|
10559
10926
|
if (value == null) continue;
|
|
10560
10927
|
if (isEventHandlerAttr(key)) continue;
|
|
@@ -10644,7 +11011,7 @@ var param = tagFactory("param");
|
|
|
10644
11011
|
var picture = tagFactory("picture");
|
|
10645
11012
|
var portal = tagFactory("portal");
|
|
10646
11013
|
var source = tagFactory("source");
|
|
10647
|
-
var svg = tagFactory("svg",
|
|
11014
|
+
var svg = tagFactory("svg", SVG_NS4);
|
|
10648
11015
|
var math = tagFactory("math");
|
|
10649
11016
|
var canvas = tagFactory("canvas");
|
|
10650
11017
|
var noscript = tagFactory("noscript");
|
|
@@ -10685,26 +11052,26 @@ var base = tagFactory("base");
|
|
|
10685
11052
|
var link = tagFactory("link");
|
|
10686
11053
|
var meta = tagFactory("meta");
|
|
10687
11054
|
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",
|
|
11055
|
+
var circle = tagFactory("circle", SVG_NS4);
|
|
11056
|
+
var ellipse = tagFactory("ellipse", SVG_NS4);
|
|
11057
|
+
var g = tagFactory("g", SVG_NS4);
|
|
11058
|
+
var line = tagFactory("line", SVG_NS4);
|
|
11059
|
+
var path = tagFactory("path", SVG_NS4);
|
|
11060
|
+
var polygon = tagFactory("polygon", SVG_NS4);
|
|
11061
|
+
var polyline = tagFactory("polyline", SVG_NS4);
|
|
11062
|
+
var rect = tagFactory("rect", SVG_NS4);
|
|
11063
|
+
var text = tagFactory("text", SVG_NS4);
|
|
11064
|
+
var tspan = tagFactory("tspan", SVG_NS4);
|
|
11065
|
+
var defs = tagFactory("defs", SVG_NS4);
|
|
11066
|
+
var clipPath = tagFactory("clipPath", SVG_NS4);
|
|
11067
|
+
var mask = tagFactory("mask", SVG_NS4);
|
|
11068
|
+
var pattern = tagFactory("pattern", SVG_NS4);
|
|
11069
|
+
var linearGradient = tagFactory("linearGradient", SVG_NS4);
|
|
11070
|
+
var radialGradient = tagFactory("radialGradient", SVG_NS4);
|
|
11071
|
+
var stop = tagFactory("stop", SVG_NS4);
|
|
11072
|
+
var use = tagFactory("use", SVG_NS4);
|
|
11073
|
+
var symbol = tagFactory("symbol", SVG_NS4);
|
|
11074
|
+
var marker = tagFactory("marker", SVG_NS4);
|
|
10708
11075
|
var center = tagFactory("center");
|
|
10709
11076
|
var font = tagFactory("font");
|
|
10710
11077
|
var marquee = tagFactory("marquee");
|
|
@@ -11580,7 +11947,7 @@ var CDN_ENTRY_POINTS = {
|
|
|
11580
11947
|
};
|
|
11581
11948
|
var packageInfo = {
|
|
11582
11949
|
name: "sibujs",
|
|
11583
|
-
version: true ? "4.
|
|
11950
|
+
version: true ? "4.8.0" : "dev",
|
|
11584
11951
|
entryPoints: MODULE_ENTRY_POINTS,
|
|
11585
11952
|
/**
|
|
11586
11953
|
* Generate the package.json `exports` map. Module entries resolve to the
|
|
@@ -11725,7 +12092,7 @@ var env = {
|
|
|
11725
12092
|
};
|
|
11726
12093
|
|
|
11727
12094
|
// src/plugins/versioning.ts
|
|
11728
|
-
var VERSION = true ? "4.
|
|
12095
|
+
var VERSION = true ? "4.8.0" : "dev";
|
|
11729
12096
|
var NUM = "(?:0|[1-9]\\d*)";
|
|
11730
12097
|
var PRE_ID = `(?:${NUM}|\\d*[a-zA-Z-][0-9a-zA-Z-]*)`;
|
|
11731
12098
|
var BUILD_ID = "[0-9a-zA-Z-]+";
|
|
@@ -12008,12 +12375,14 @@ function extractRangeTarget(range) {
|
|
|
12008
12375
|
function preloadCritical(resources) {
|
|
12009
12376
|
if (typeof document === "undefined") return;
|
|
12010
12377
|
for (const resource2 of resources) {
|
|
12011
|
-
const
|
|
12378
|
+
const href = sanitizeUrl(resource2.href);
|
|
12379
|
+
if (!href) continue;
|
|
12380
|
+
const safeHref = typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(href) : href.replace(/["\\]/g, "\\$&");
|
|
12012
12381
|
const existing = document.querySelector(`link[rel="preload"][href="${safeHref}"]`);
|
|
12013
12382
|
if (existing) continue;
|
|
12014
12383
|
const link2 = document.createElement("link");
|
|
12015
12384
|
link2.rel = "preload";
|
|
12016
|
-
link2.href =
|
|
12385
|
+
link2.href = href;
|
|
12017
12386
|
link2.setAttribute("as", resource2.as);
|
|
12018
12387
|
if (resource2.type) {
|
|
12019
12388
|
link2.type = resource2.type;
|
|
@@ -15017,7 +15386,7 @@ var _themeLayers = globalSingleton(
|
|
|
15017
15386
|
function commitThemeProperty(root, name, record) {
|
|
15018
15387
|
const top = record.layers[record.layers.length - 1];
|
|
15019
15388
|
if (top) {
|
|
15020
|
-
root.style.setProperty(name, top.value);
|
|
15389
|
+
root.style.setProperty(name, sanitizeCSSDeclaration(name, String(top.value), { element: root }));
|
|
15021
15390
|
return;
|
|
15022
15391
|
}
|
|
15023
15392
|
_themeLayers.get(root)?.delete(name);
|