fix: make relay-probe timers and effect hooks lint-clean across ESLint versions

- Replace single-assignment `let timer` with a `timers[]` array in
  citrine.ts and relayProbe.ts so stricter prefer-const builds pass
  (the newer ESLint pulled in by `npm audit fix` flagged the let as
  never-reassigned).
- Drop two now-redundant `eslint-disable react-hooks/exhaustive-deps`
  directives in NostrProvider and MapPage. Newer react-hooks no longer
  reports those lines, so the directives were flagged as unused errors
  under reportUnusedDisableDirectives; removing them is safe in both
  old (warning only) and new (silent) ESLint.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy 2026-09-24 19:55:38 +07:00
parent 8d464a05f3
commit ef86d858c2
4 changed files with 8 additions and 10 deletions

View file

@ -103,7 +103,6 @@ const NostrProvider: React.FC<NostrProviderProps> = (props) => {
}
// Intentionally run once on mount; relay changes are handled by the
// invalidation effects above and lazy-open on demand.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// Initialize NPool only once

View file

@ -132,12 +132,12 @@ export function probeCitrine(
let settled = false;
let opened = false;
let ws: WebSocket | undefined;
let timer: ReturnType<typeof setTimeout> | undefined;
const timers: ReturnType<typeof setTimeout>[] = [];
const done = (ok: boolean, reason: string) => {
if (settled) return;
settled = true;
if (timer) clearTimeout(timer);
for (const t of timers) clearTimeout(t);
try {
ws?.close();
} catch {
@ -160,10 +160,10 @@ export function probeCitrine(
const subId = `citrine-probe-${Math.random().toString(36).slice(2, 10)}`;
timer = setTimeout(() => {
timers.push(setTimeout(() => {
// Distinguish "never opened" (blocked/refused) from "opened but silent".
done(false, opened ? 'opened-but-no-nostr-reply' : 'timeout-no-open');
}, timeoutMs);
}, timeoutMs));
ws.onopen = () => {
opened = true;

View file

@ -29,12 +29,12 @@ export function probeRelay(url: string, timeoutMs = 4000): Promise<RelayProbeRes
let settled = false;
let opened = false;
let ws: WebSocket | undefined;
let timer: ReturnType<typeof setTimeout> | undefined;
const timers: ReturnType<typeof setTimeout>[] = [];
const done = (ok: boolean, reason: string) => {
if (settled) return;
settled = true;
if (timer) clearTimeout(timer);
for (const t of timers) clearTimeout(t);
try {
ws?.close();
} catch {
@ -55,9 +55,9 @@ export function probeRelay(url: string, timeoutMs = 4000): Promise<RelayProbeRes
const subId = `probe-${Math.random().toString(36).slice(2, 10)}`;
timer = setTimeout(() => {
timers.push(setTimeout(() => {
done(false, opened ? 'opened-but-no-nostr-reply' : 'timeout-no-open');
}, timeoutMs);
}, timeoutMs));
ws.onopen = () => {
opened = true;

View file

@ -813,7 +813,6 @@ export default function MapPage() {
return () => {
cancelled = true;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// Combine spots and shops into unified list for map display