import { useCallback } from 'react'; import { environment } from '../environments/environment.ts'; import { resolveHistoryBaseUrl } from '../utils/fieldHistory/useFieldHistoryFetch'; import { useHttpService } from './HttpService.tsx'; import { parseMyHistoryResponse, type MyHistoryResponse } from '../utils/history/parseMyHistoryResponse'; export type { MyHistoryResponse }; // / My History -- the patient's own record of who accessed and who changed their data. // // The route lives on the GUARDIANSHIP gateway alongside my-proxies and proxy-access, NOT on // fhirBaseApi. Pointing at the wrong base silently 404s rather than failing loudly, which has bitten // this codebase before -- see the reference-api-base-url-routing memory. export const useMyHistoryService = () => { const { get } = useHttpService(); // `before` is a time CURSOR for paging older: pass the oldest row already held and the server // returns the next page back, lifting its own 90-day default floor. Design ยง5 - 90 days is a // default, not a cap. // `agent` narrows the feed to one actor on the server, before paging, with no 90-day floor. const fetchMyHistory = useCallback( async (before?: string, only: { agent?: string; count?: number } = {}, request: { signal?: AbortSignal; admit?: () => void } = {}): Promise => { const params = new URLSearchParams(); if (only.agent) params.set('agent', only.agent); if (only.count) params.set('_count', String(only.count)); if (before) params.set('before', before); const query = params.toString() ? `?${params.toString()}` : ''; // Read before it is returned: a success this client cannot read is an error, never an empty feed. return parseMyHistoryResponse(await get(`${environment.fhirGuardianshipApi}/my-history${query}`, request)); }, [get], ); // - the version history behind a CHANGE row, so the expansion can say what actually // changed rather than merely that something did. // // A DIFFERENT BASE FROM fetchMyHistory ABOVE. The feed lives on the guardianship gateway; // a resource's own `_history` lives on whichever gateway holds that resource. // // THE HOST IS RESOLVED FROM THE RESOURCE TYPE, AND IT USED TO BE HARDCODED TO fhirBaseApi. // The comment that stood here named the landmine - using the wrong base fails instead of // failing loudly - and then stepped on it: the four PEOPLE resources moved to the identity // gateway in the stack split, so `Patient/{id}/_history` on fhirBase has no route at all. // // It does not 404. API Gateway answers the browser's PREFLIGHT with 403 // MissingAuthenticationTokenException, a preflight must be 2xx, so the request is never made // and there is no network entry to find - only a console line. On screen the patient pressed // "What changed?" and read "The details of this change could not be loaded." // // Shared with the field-history reader rather than copied, because that resolver already knew // the answer and a second copy of a host map is a second thing to forget at the next split. const fetchResourceHistory = useCallback( (resourceType: string, resourceId: string, request: { signal?: AbortSignal; admit?: () => void } = {}): Promise<{ entry?: { resource?: unknown }[]; link?: { relation?: string }[] }> => // A Consent's generic history route belongs to a practice; the patient reads their own here. get(resourceType === 'Consent' ? `${environment.fhirGuardianshipApi}/my-history/consent/${resourceId}` : `${resolveHistoryBaseUrl(resourceType)}/${resourceType}/${resourceId}/_history`, request), [get], ); return { fetchMyHistory, fetchResourceHistory }; };