mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: harden against three production Sentry crashes (#328)
Three production crashes from the snapotter/node Sentry project.
feature-status (NODE-12): a valid-JSON-but-wrong-shape installed.json
crashed boot via Object.keys(data.bundles). readInstalled() now
normalizes any unusable shape to { bundles: {} }, and the boot recovery
call is wrapped so cleanup can never fatal startup.
image-viewer (NODE-15/17/18): drag-to-pan read .x off an undefined
use-gesture memo on pointerUp or a pinch-into-pan. A guarded pure helper
(resolvePanStart) now falls back to the live pan offset.
Fastify (NODE-14): raised pluginTimeout to 60s so slow self-hosted boots
do not fatal at @fastify/static.
This commit is contained in:
@@ -91,6 +91,25 @@ interface InstalledData {
|
||||
|
||||
let installedCache: InstalledData | null = null;
|
||||
|
||||
/**
|
||||
* Coerce a parsed installed.json into a well-formed InstalledData. The file can
|
||||
* be valid JSON but the wrong shape (`{}`, `{"bundles": null}`, a bare array,
|
||||
* a number, or an older format) which would otherwise crash callers that do
|
||||
* `Object.keys(data.bundles)`, `id in data.bundles`, or `data.bundles[id]`
|
||||
* (seen in production as a fatal boot TypeError, "Cannot convert undefined or
|
||||
* null to object"). Any unusable shape degrades to an empty install set,
|
||||
* matching the corrupt-JSON fallback below.
|
||||
*/
|
||||
function normalizeInstalled(parsed: unknown): InstalledData {
|
||||
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
||||
const bundles = (parsed as { bundles?: unknown }).bundles;
|
||||
if (typeof bundles === "object" && bundles !== null && !Array.isArray(bundles)) {
|
||||
return parsed as InstalledData;
|
||||
}
|
||||
}
|
||||
return { bundles: {} };
|
||||
}
|
||||
|
||||
function readInstalled(): InstalledData {
|
||||
if (installedCache) return installedCache;
|
||||
|
||||
@@ -101,7 +120,7 @@ function readInstalled(): InstalledData {
|
||||
|
||||
try {
|
||||
const raw = readFileSync(INSTALLED_PATH, "utf-8");
|
||||
installedCache = JSON.parse(raw) as InstalledData;
|
||||
installedCache = normalizeInstalled(JSON.parse(raw));
|
||||
} catch {
|
||||
console.warn("[feature-status] installed.json is corrupt or unreadable, treating as empty");
|
||||
installedCache = { bundles: {} };
|
||||
|
||||
Reference in New Issue
Block a user