refactor: simplify admin code — extract shared helpers, fix quality issues

- Extract KEBAB_RE, SESSION_COOKIE, SESSION_MAX_AGE_MS, COOKIE_MAX_AGE,
  authRequest(), and sessionResponse() to auth.ts — eliminating 4 copies
  of the auth() wrapper and 3 copies of KEBAB_RE across admin API routes
- Remove timing side-channel: drop a.length !== b.length early-return
  before timingSafeEqual in verifySession (SHA-256 HMAC always 64 chars)
- Fix YOLO localStorage write-before-read race using initialization guard
- Fix admin layout /api/ bypass to return {} instead of {authenticated:true}
- Extract extractError() helper in admin page — removes 4 inline patterns
- Parallel Promise.all in admin loadData() — halves round-trip latency
- Parallel Promise.all in moveCheckedUnits() + surface per-request errors
- Hoist Big(inputValue) above .map() in converter — one alloc per recompute
- O(n) single-pass orderedResults using Map instead of O(n*groups) filters
- Fix expandedGroups.add() mutation — use Set assignment for consistency

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Falkan
2026-03-17 14:04:33 -04:00
parent d1f51c141e
commit aeeae1e7ce
10 changed files with 144 additions and 162 deletions

View File

@@ -33,14 +33,19 @@
});
// ── Load YOLO preference from localStorage ──────────────────────────────────
// Single effect: read on mount, then write on every change.
// The `initialized` guard prevents the write from firing before the read on mount.
let yoloInitialized = $state(false);
$effect(() => {
if (!browser) return;
const stored = localStorage.getItem('yolo-mode');
if (stored === 'true') yoloMode = true;
});
$effect(() => {
if (!browser) return;
if (!yoloInitialized) {
// First run: read stored value
const stored = localStorage.getItem('yolo-mode');
if (stored === 'true') yoloMode = true;
yoloInitialized = true;
return;
}
// Subsequent runs: persist change
localStorage.setItem('yolo-mode', String(yoloMode));
});
@@ -66,32 +71,20 @@
// ── Derived: results for ALL units ─────────────────────────────────────────
let fromUnit = $derived(units.find((u) => u.id === fromUnitId) ?? units[0]);
let results: ResultItem[] = $derived(
fromUnit
? units.map((u) => {
const sameGroup = canConvert(fromUnit, u);
if (sameGroup) {
return {
unit: u,
convertedValue: convert(Big(inputValue), fromUnit, u),
isYolo: false
};
} else if (yoloMode) {
return {
unit: u,
convertedValue: convertYolo(Big(inputValue), fromUnit, u, groups),
isYolo: true
};
} else {
return {
unit: u,
convertedValue: null,
isYolo: false
};
}
})
: []
);
let results: ResultItem[] = $derived.by(() => {
if (!fromUnit) return [];
const bigInput = Big(inputValue); // hoist — one allocation per recompute, not per unit
return units.map((u) => {
const sameGroup = canConvert(fromUnit, u);
if (sameGroup) {
return { unit: u, convertedValue: convert(bigInput, fromUnit, u), isYolo: false };
} else if (yoloMode) {
return { unit: u, convertedValue: convertYolo(bigInput, fromUnit, u, groups), isYolo: true };
} else {
return { unit: u, convertedValue: null, isYolo: false };
}
});
});
// ── Derived: highlighted result ─────────────────────────────────────────────
let highlightedResult = $derived(
@@ -136,19 +129,24 @@
fromUnitId = id;
}
// ── Group units for display ─────────────────────────────────────────────────
// ── Group units for display — single O(n) pass ──────────────────────────────
let orderedResults: { groupLabel: string | null; items: ResultItem[] }[] = $derived.by(() => {
// Build a Map of groupId → items in a single pass over results
const byGroup = new Map<string | null, ResultItem[]>();
for (const r of results) {
const key = r.unit.group ?? null;
let bucket = byGroup.get(key);
if (!bucket) { bucket = []; byGroup.set(key, bucket); }
bucket.push(r);
}
// Emit sections in group-definition order, then orphaned at end
const sections: { groupLabel: string | null; items: ResultItem[] }[] = [];
for (const group of groups) {
const items = results.filter((r) => r.unit.group === group.id);
if (items.length > 0) {
sections.push({ groupLabel: group.label, items });
}
}
const orphaned = results.filter((r) => r.unit.group === null);
if (orphaned.length > 0) {
sections.push({ groupLabel: 'Ungrouped', items: orphaned });
const items = byGroup.get(group.id);
if (items?.length) sections.push({ groupLabel: group.label, items });
}
const orphaned = byGroup.get(null);
if (orphaned?.length) sections.push({ groupLabel: 'Ungrouped', items: orphaned });
return sections;
});
</script>