import type { OrgAuthorizationStatusValue } from '../services/OrgAuthorizationService.tsx'; // HealthLake search is eventually consistent, so for a short window after an attest the status route // cannot find the Consent it just wrote and honestly answers 'none'. A row that mounts inside that // window - reopening a Quick View is enough - would tell the desk the signature it just took did not // land, on the instrument that authorises treatment. // // So the ANSWER THE SERVER ALREADY GAVE US is remembered here, outside React, and replayed while the // index settles. This is a 200 we hold, not a guess: a failed attest records nothing, so a real // refusal still reads Not authorized. Same shape as the settling rule on a lagging clinician count - // say what you know rather than assert from a read that cannot see the write yet. // The documented lag is around thirty seconds; doubled so a slow index does not reopen the defect. const SETTLE_WINDOW_MS = 60_000; // One signed packet can record several agreements from one dialog, and each agreement's row holds its // own status. Rows listen here so the ones recorded from a sibling's dialog stop showing as outstanding. type AttestedListener = (patientId: string, instrument: string, status: OrgAuthorizationStatusValue, organizationId?: string) => void; const listeners = new Set(); export const subscribeAttested = (listener: AttestedListener): (() => void) => { listeners.add(listener); return () => { listeners.delete(listener); }; }; const recorded = new Map(); // An answer is the practice's own: another practice's rows never replay it. const keyFor = (patientId: string, instrument: string, organizationId = '') => `${organizationId}|${patientId}|${instrument}`; // Called only with an answer the server gave: an attest that resolved, or its refusal naming the patient's decline. // Any other refused attest never reaches here, so a real refusal still reads Not authorized (control 3). export const rememberAttestedStatus = ( patientId: string, instrument: string, status: OrgAuthorizationStatusValue, organizationId?: string, ): void => { recorded.set(keyFor(patientId, instrument, organizationId), { status, at: Date.now() }); listeners.forEach((listener) => listener(patientId, instrument, status, organizationId)); }; // The recorded answer, while it is still newer than the index can be trusted to be. Expired entries // are dropped on the way past, so a long-lived tab cannot replay a stale answer forever. export const attestedStatusStillSettling = ( patientId: string, instrument: string, organizationId?: string, ): OrgAuthorizationStatusValue | undefined => { const key = keyFor(patientId, instrument, organizationId); const entry = recorded.get(key); if (!entry) return undefined; if (Date.now() - entry.at > SETTLE_WINDOW_MS) { recorded.delete(key); return undefined; } return entry.status; }; // Tests only: the module keeps process-wide state, so a suite that does not clear it leaks one case // into the next - the same shape as a test file with no cleanup between renders. export const forgetAttestedStatuses = (): void => { recorded.clear(); };