/** * Booking PII redaction. * * Booking rows and traveler rows store contact identifiers (name, email, * phone) as plaintext columns so the operator UI can search and sort. The * `bookings-pii:*` scope (or `*` superuser scope) gates the right to see * those identifiers verbatim. Callers without that scope receive a redacted * shape that retains enough signal for operational triage but not enough to * exfiltrate a full contact list. * * **Scope of this module:** route-layer redaction at the API boundary. * Internal callers (cron jobs, workflows, in-process tasks) bypass redaction * because they need the full record to do their job. * * **What this does NOT do:** encrypt the columns at rest. That is a * follow-up requiring a schema migration + a search-tokenisation strategy * (see issue #283 follow-up). For now plaintext-on-disk + redact-in-flight * is the documented posture. */ export interface PiiAccessContext { actor?: string | null; scopes?: string[] | null; callerType?: string | null; isInternalRequest?: boolean; /** * When true, staff sessions are gated by the PII scope like everyone else * (member-rbac-rfc, voyant#2085). Defaults off, preserving the historical * "staff always sees PII" posture until a deployment enables RBAC. */ enforceRbac?: boolean; } /** * Returns true when the caller has earned the right to see PII in the clear. * * Internal requests (server-to-server inside the trust boundary) always reveal. * Otherwise the caller needs an explicit `bookings-pii:read`/`bookings-pii:*` * scope or superuser `*`. Staff dashboard sessions historically revealed * unconditionally; under RBAC enforcement they too need the scope (full-access * members hold `*`, so they keep access; restricted members do not). */ export declare function shouldRevealBookingPii(ctx: PiiAccessContext): boolean; /** * Mask the local-part of an email, preserving the domain so the operator * can tell at a glance which provider is involved. * * `alice@example.com` → `a***e@example.com` * `bo@example.com` → `**@example.com` */ export declare function redactEmail(email: string | null | undefined): string | null; /** * Mask all but the last four digits of a phone number, dropping * non-digit characters from the masked region so the result is recognisable * as a phone fragment. * * `+40 712 345 678` → `***5678` */ export declare function redactPhone(phone: string | null | undefined): string | null; /** * Masks an arbitrary identifier like a postal address or city to a single- * char marker. We keep the field present so client schemas don't break, * but the value is effectively absent. */ export declare function redactString(value: string | null | undefined): string | null; /** * Booking row contact-PII redaction. Returns a shallow copy with the * `contact*` columns masked. Caller is responsible for not running this on * already-redacted rows. */ export declare function redactBookingContact(row: T): T; /** * Traveler row redaction. Same shape as `redactBookingContact` but for * traveler identity columns. * * `accessibilityNeeds` is intentionally NOT in the redacted set — it was * moved to the encrypted `bookingTravelerTravelDetails` table (#283) and * is only ever returned through `createBookingPiiService` after * decryption + audit. It's never present on this row shape. */ export declare function redactTravelerIdentity(row: T): T;