import { useCallback, useRef } from 'react'; import { defineChannel } from 'hooks/usePanelChannel'; /** * "The connection changed — anyone reading NPM should read it again." * * ── Why a channel and not the URL ── * * `docs/navigation-audit.md` draws the line: anything ADDRESSABLE goes in the URL, and a channel is only * for a signal — "something changed, re-read it". This is the second kind. Nobody wants to link to "the * moment after the connection was saved", and there is nothing to select. * * ── Why it is needed at all ── * * The panels are siblings in a workspace layout. `ConnectionPanel` cannot call into `CertificatesPanel` * and should not try — they are mounted independently and neither owns the other. Before this, saving a * connection left both panels showing whatever they had failed to load a minute earlier, and the only fix * a person had was a manual refresh. Reported on 2026-08-25 the first time a connection was saved through * the form. * * ── The nonce is a plain counter, and that is not an accident ── * * Copied deliberately from `officerdev/src/channels.ts`, which records why. `setSignal(n => n + 1)` is * WRONG here: the functional setter applies against the value captured at render, so two bumps inside one * render window both compute `snapshot + 1` and the second silently overwrites the first — nobody * re-reads. `Date.now()` has the same flaw in miniature, two bumps in one millisecond being one number. * A module counter never reads React state, so it cannot be wrong however often it is called. */ const useConnectionChangedChannel = defineChannel('proxy-manager:connection-changed', 0); let nonce = 0; export const useConnectionChanged = () => { const [signal, setSignal] = useConnectionChangedChannel(); // The setter is a fresh closure every render and this `bump` goes into dependency lists, so it is read // through a ref — stable identity without freezing the first render's setter. const setRef = useRef(setSignal); setRef.current = setSignal; const bump = useCallback(() => setRef.current(++nonce), []); return [signal, bump] as const; };