import { z } from 'zod'; // This file and its fixtures are copied byte-for-byte to the backend by the // sync script. Keep policy independent of React, storage, transport and Node. export const MAX_REGISTRY_CHARS = 250_000; const date = z.string().regex(/^\d{4}-\d{2}-\d{2}$/).refine((value) => !Number.isNaN(Date.parse(value)) && new Date(value).toISOString().slice(0, 10) === value); const id = z.string().min(1).max(100); const status = z.enum(['source_checked', 'needs_verification', 'withdrawn']); const contactSchema = z.object({ id, dialNumber: z.string().regex(/^\d{2,15}$/), service: z.enum(['medical', 'general']), channel: z.literal('voice'), domesticUseOnly: z.literal(true), phoneAccess: z.enum(['not_specified', 'mobile_only', 'fixed_and_mobile']), coverage: z.object({ type: z.enum(['country', 'region']), regionCodes: z.array(z.string().max(20)).max(100), label: z.string().min(1).max(100) }).strict(), evidenceStatus: status, sourceIds: z.array(id).min(1).max(20), }).strict(); const countrySchema = z.object({ countryCode: z.string().regex(/^[A-Z]{2}$/), name: z.string().min(1).max(100), selectionStatus: z.enum(['source_checked', 'region_required', 'needs_verification', 'withdrawn']), defaultMedicalContactId: id.nullable(), contacts: z.array(contactSchema).max(30), notes: z.array(z.string().max(2000)).max(20), }).strict(); const registrySchema = z.object({ schemaVersion: z.literal(1), datasetVersion: z.string().min(1).max(100), revision: z.number().int().positive().max(Number.MAX_SAFE_INTEGER), researchedAt: date, release: z.object({ status: z.literal('approved'), approvedBy: z.string().min(1).max(200), approvedAt: date }).strict(), scope: z.string().max(2000), unknownCountryContactId: z.null(), verification: z.object({ method: z.literal('public_web_sources'), liveCallsMade: z.boolean(), meaning: z.string().max(2000) }).strict(), countries: z.array(countrySchema).min(1).max(300), sources: z.record(id, z.object({ publisher: z.string().min(1).max(300), url: z.string().url().max(3000).refine((s) => s.startsWith('https://')), kind: z.enum(['local_authority', 'emergency_provider', 'supranational_authority', 'government_travel_advice', 'historical_research']), checkedAt: date, evidence: z.string().min(1).max(3000) }).strict()), }).strict(); export type EmergencyRegistry = z.infer; export type EmergencyContact = z.infer; export const envelopeSchema = z.object({ keyId: id, payload: z.string().min(1).max(MAX_REGISTRY_CHARS), signature: z.string().regex(/^[a-f0-9]{128}$/) }).strict(); export type SignedRegistry = z.infer; export function parseRegistry(input: unknown): EmergencyRegistry { const r = registrySchema.parse(input); if (r.release.approvedAt < r.researchedAt || Object.values(r.sources).some((source) => source.checkedAt > r.researchedAt)) throw new Error('Invalid emergency review dates'); const countries = new Set(), contacts = new Set(); for (const c of r.countries) { if (countries.has(c.countryCode)) throw new Error('Duplicate emergency country'); countries.add(c.countryCode); for (const n of c.contacts) { if (contacts.has(n.id) || !n.id.startsWith(c.countryCode.toLowerCase() + '-')) throw new Error('Invalid emergency contact ID'); contacts.add(n.id); if (n.sourceIds.some((s) => !r.sources[s])) throw new Error('Missing emergency source'); if (n.coverage.type === 'region' ? !n.coverage.regionCodes.length || n.coverage.regionCodes.some((v) => !v.startsWith(c.countryCode + '-')) : n.coverage.regionCodes.length !== 0) throw new Error('Invalid emergency region'); } if (c.selectionStatus === 'source_checked') { const n = c.contacts.find((n) => n.id === c.defaultMedicalContactId); if (!n || n.evidenceStatus !== 'source_checked' || n.coverage.type !== 'country' || n.phoneAccess === 'mobile_only') throw new Error('Unsafe emergency default'); } else if (c.defaultMedicalContactId !== null) throw new Error('Unresolved emergency default'); } return r; } export function readSignedRegistry(input: unknown, verify: (envelope: SignedRegistry) => boolean): { envelope: SignedRegistry; registry: EmergencyRegistry } { const envelope = envelopeSchema.parse(input); if (!verify(envelope)) throw new Error('Invalid emergency signature'); return { envelope, registry: parseRegistry(JSON.parse(envelope.payload)) }; } export function assertSuccessor(next: EmergencyRegistry, current: EmergencyRegistry) { if (next.revision <= current.revision) throw new Error('Emergency revision did not increase'); for (const previous of current.countries) { const country = next.countries.find((c) => c.countryCode === previous.countryCode); if (!country) throw new Error('Emergency update omitted a country'); if (previous.selectionStatus === 'withdrawn' && country.selectionStatus !== 'withdrawn') throw new Error('Emergency country withdrawal removed'); for (const old of previous.contacts) { const contact = country.contacts.find((n) => n.id === old.id); if (!contact) throw new Error('Emergency update omitted a contact; retain a withdrawal'); if (old.evidenceStatus === 'withdrawn' && contact.evidenceStatus !== 'withdrawn') throw new Error('Emergency withdrawal removed'); } } } export interface EmergencyLocation { countryCode?: string | null; regionCode?: string | null; callerWithPatient?: boolean } export function resolveEmergency(registry: EmergencyRegistry | null, location: EmergencyLocation): EmergencyContact | null { if (!registry || location.callerWithPatient === false) return null; const country = registry.countries.find((c) => c.countryCode === location.countryCode?.trim().toUpperCase()); if (!country || !['source_checked', 'region_required'].includes(country.selectionStatus)) return null; const regional = country.contacts.find((n) => n.evidenceStatus === 'source_checked' && n.coverage.type === 'region' && n.coverage.regionCodes.includes(location.regionCode?.toUpperCase() ?? '')); const contact = regional ?? country.contacts.find((n) => n.id === country.defaultMedicalContactId); return contact?.evidenceStatus === 'source_checked' ? contact : null; } export const GENERIC_EMERGENCY_ACTION = 'Contact local emergency services now, or go to the nearest hospital emergency unit.'; export interface EmergencyAdvice { number: string | null; extra: string | null; countryCode?: string | null; contactId?: string | null; locationLabel?: string | null; registryRevision?: number | null; action?: string } export function emergencyAction(advice: EmergencyAdvice): string { return advice.action ?? (advice.number ? `Call ${advice.number} now${advice.extra ? `, ${advice.extra}` : ''}.` : GENERIC_EMERGENCY_ACTION); } export function registryAdvice(registry: EmergencyRegistry | null, countryCode?: string | null): EmergencyAdvice { const code = countryCode?.trim().toUpperCase() ?? null; const contact = resolveEmergency(registry, { countryCode: code }); const name = contact?.coverage.label; return { number: contact?.dialNumber ?? null, extra: null, countryCode: code, contactId: contact?.id ?? null, locationLabel: name ?? null, registryRevision: registry?.revision ?? null, // A saved home country is only a suggestion. Do not direct a traveller or // caregiver abroad to a domestic short code without saying where it applies. action: contact ? `If the emergency is in ${name}, call ${contact.dialNumber} from there now. Otherwise, contact local emergency services or the nearest hospital emergency unit.` : GENERIC_EMERGENCY_ACTION }; }