Ensure KefinTweaks urls are properly normalized so that duplicate scripts are never loaded

This commit is contained in:
HighImKevin
2026-10-11 02:34:55 -04:00
parent a1faf72cc4
commit db257efbfb
+44 -9
View File
@@ -671,11 +671,17 @@
return normalizeRoot(cfg.kefinTweaksRootResolved || cfg.kefinTweaksRoot || '');
}
function resolveAssetUrl(root, relativePath) {
/**
* Join kefin root + scripts/ + relativePath, collapsing . / .. for site-absolute roots.
* Shared by live resolveAssetUrl and the baked KefinTweaks-injector joinAssetUrl.
*/
function joinAssetUrlForRoot(resolvedRoot, relativePath) {
if (!relativePath) return null;
if (/^https?:\/\//i.test(relativePath)) return relativePath;
const normalizedRoot = normalizeRoot(root);
const normalizedRoot = normalizeRoot(resolvedRoot);
if (!normalizedRoot) return null;
const base = normalizedRoot + 'scripts/';
const joined = (base + relativePath).replace(/\\/g, '/');
@@ -684,7 +690,7 @@
try {
return new URL(relativePath, base).href;
} catch (e) {
/* fall through */
/* fall through to collapse */
}
}
@@ -704,6 +710,39 @@
return isSiteAbsolute ? '/' + resolved : resolved;
}
function resolveAssetUrl(root, relativePath) {
return joinAssetUrlForRoot(root, relativePath);
}
/**
* ES5 joinAssetUrl source for buildInjectorScript (closes over resolvedRoot).
* Must stay algorithmically identical to joinAssetUrlForRoot.
*/
function getJoinAssetUrlRuntimeSource() {
return [
' function joinAssetUrl(relativePath) {',
' if (!relativePath) return null;',
' if (/^https?:\\/\\//i.test(relativePath)) return relativePath;',
' var base = resolvedRoot + \'scripts/\';',
' var joined = (base + relativePath).replace(/\\\\/g, \'/\');',
' if (/^https?:\\/\\//i.test(resolvedRoot)) {',
' try { return new URL(relativePath, base).href; } catch (e) {}',
' }',
' var isSiteAbsolute = joined.charAt(0) === \'/\';',
' var parts = joined.split(\'/\');',
' var stack = [];',
' for (var pi = 0; pi < parts.length; pi++) {',
' var p = parts[pi];',
' if (!p || p === \'.\') continue;',
' if (p === \'..\') { stack.pop(); continue; }',
' stack.push(p);',
' }',
' var resolved = stack.join(\'/\');',
' return isSiteAbsolute ? \'/\' + resolved : resolved;',
' }'
].join('\n');
}
function expandScriptToAssets(scriptDef, root, urlSuffix, thirdParty) {
const assets = [];
const suffix = urlSuffix || '';
@@ -989,12 +1028,7 @@
' var resolvedRoot = String(cfg.kefinTweaksRootResolved || cfg.kefinTweaksRoot || \'\').trim();',
' if (!resolvedRoot) return;',
' if (resolvedRoot.charAt(resolvedRoot.length - 1) !== \'/\') resolvedRoot += \'/\';',
' function joinAssetUrl(relativePath) {',
' if (!relativePath) return null;',
' if (/^https?:\\/\\//i.test(relativePath)) return relativePath;',
' var base = resolvedRoot + \'scripts/\';',
' try { return new URL(relativePath, base).href; } catch (e) { return base + relativePath; }',
' }',
getJoinAssetUrlRuntimeSource(),
' window.KefinTweaksScriptsPreloaded = true;',
' window.KefinTweaksInjectorStamp = ' + stampJson + ';',
' var SCRIPT_DEFINITIONS_BAKED = ' + defsJson + ';',
@@ -1260,6 +1294,7 @@
mergeEnabledScripts: mergeEnabledScripts,
normalizeRoot: normalizeRoot,
getResolvedKefinRoot: getResolvedKefinRoot,
joinAssetUrlForRoot: joinAssetUrlForRoot,
resolveAssetUrl: resolveAssetUrl,
buildLoadPlan: buildLoadPlan,
buildInjectorScript: buildInjectorScript,