Files
flights_web/src/shared/storage.ts
T
gnezim a9dacf0b97
CI / ci (push) Failing after 57s
Deploy / build-and-deploy (push) Failing after 5s
Clear lint backlog so make check runs green
ESLint had 30 findings (13 errors, 17 warnings) that had accumulated
across the codebase. Most came out of --fix; the rest needed small
manual cleanups:

- storage.ts: replace import('zod') type annotations with the already-
  imported ZodSchema type
- CityPickerPopup.tsx: drop a stale jsx-a11y disable directive for a
  rule that isn't in the shared config, and narrow row.city1 so the
  explicit non-null assertions are no longer needed
- keyboardLayoutConverter.ts: guard the per-index reads so we can drop
  the trailing ! from the string indexing
- TimeGroup.tsx: narrow actual via the hasDelay condition and default
  the day-change numbers to 0 instead of asserting non-null
- seo.ts: throw on the unreachable empty-flightIds branch rather than
  fabricating a partial SeoHeadProps
- Various test files: remove captured-but-unused onCity/shouldApply
  refs and stale makeStation/emptyCity locals that drifted during
  earlier refactors

make check now passes typecheck + lint; the one remaining test
failure is the pre-existing OnlineBoardSearchPage timeout test that
flakes under the full suite and passes in isolation.
2026-04-22 15:13:43 +03:00

119 lines
3.1 KiB
TypeScript

import type { ZodSchema } from "zod";
const PREFIX = "afl_";
function prefixed(key: string): string {
return `${PREFIX}${key}`;
}
export const storage = {
get<T>(key: string, schema: ZodSchema<T>): T | null {
try {
const raw = localStorage.getItem(prefixed(key));
if (raw === null) return null;
const parsed: unknown = JSON.parse(raw);
const result = schema.safeParse(parsed);
return result.success ? result.data : null;
} catch {
return null;
}
},
set<T>(key: string, value: T, schema: ZodSchema<T>): void {
schema.parse(value);
localStorage.setItem(prefixed(key), JSON.stringify(value));
},
delete(key: string): void {
localStorage.removeItem(prefixed(key));
},
clear(): void {
const keysToRemove: string[] = [];
for (let i = 0; i < localStorage.length; i++) {
const k = localStorage.key(i);
if (k?.startsWith(PREFIX)) {
keysToRemove.push(k);
}
}
for (const k of keysToRemove) {
localStorage.removeItem(k);
}
},
};
/**
* Thin wrapper over `sessionStorage` for same-tab ephemeral state —
* cross-page prefill handoff, non-persistent UI flags, etc. No schema
* validation; callers own their key namespace (e.g. `afl-prefill:*`)
* and serialize/deserialize JSON themselves. All operations no-op
* when `sessionStorage` is undefined (SSR-safe).
*
* Exists so the rest of the codebase can stay under the
* `no-restricted-globals` rule that blocks direct sessionStorage access.
*/
const SESSION_PREFIX = "afl_";
export const sessionStore = {
getRaw(key: string): string | null {
if (typeof sessionStorage === "undefined") return null;
try {
return sessionStorage.getItem(key);
} catch {
return null;
}
},
setRaw(key: string, value: string): void {
if (typeof sessionStorage === "undefined") return;
try {
sessionStorage.setItem(key, value);
} catch {
// ignore quota/disabled
}
},
delete(key: string): void {
if (typeof sessionStorage === "undefined") return;
try {
sessionStorage.removeItem(key);
} catch {
// ignore disabled
}
},
clear(): void {
if (typeof sessionStorage === "undefined") return;
try {
sessionStorage.clear();
} catch {
// ignore disabled
}
},
/** Schema-validated get from sessionStorage under the `afl_` namespace. */
get<T>(key: string, schema: ZodSchema<T>): T | null {
try {
const raw = this.getRaw(SESSION_PREFIX + key);
if (raw === null) return null;
const parsed: unknown = JSON.parse(raw);
const result = schema.safeParse(parsed);
return result.success ? result.data : null;
} catch {
return null;
}
},
/** Schema-validated set into sessionStorage under the `afl_` namespace. */
set<T>(key: string, value: T, schema: ZodSchema<T>): void {
schema.parse(value);
this.setRaw(SESSION_PREFIX + key, JSON.stringify(value));
},
/** Delete a key from the `afl_` namespace in sessionStorage. */
deleteNs(key: string): void {
this.delete(SESSION_PREFIX + key);
},
};