/** * Booking selection V1 schemas — what the buyer has chosen so far. * * The selection is the counterpart of `bookingRequirementsV1`: requirements * say what a booking of this target *needs*, the selection says what has been * *picked*. It is the state that survives across journey step transitions. * * It is declared in three parts so that privilege is a property of the schema * rather than of a denylist someone has to remember to extend: * * - `bookingSelectionPublicV1` — what any caller may send. * - `bookingSelectionStaffOnlyV1` — operator-only commercial authority. * - `bookingSelectionEngineOwnedV1` — what the engine writes, never a caller. * * `bookingSelectionV1` is the union of the three: the full draft an operator * surface edits in place. */ import { z } from "zod"; /** The canonical traveler categories a pax band can belong to. */ export declare const paxBandCodeSchema: z.ZodEnum<{ other: "other"; adult: "adult"; child: "child"; infant: "infant"; senior: "senior"; student: "student"; }>; export type PaxBandCode = z.infer; /** * A band code as it travels on the wire. Either a canonical code or a * tier-qualified one (`"child:pricing_categories_01j…"`) for a product * selling several tiers of one category — see `paxBandBaseCode` in * `requirements-defaults.ts`. * * Deliberately open: the wizard learns the active bands off the * requirements, and the requirements are per product. Narrowing this to * an enum is what made a second child tier unrepresentable (voyant#4121). * Every canonical code stays valid, so selections written before tiers * existed still parse. */ export declare const travelerBandCodeSchema: z.ZodString; /** * How long each free-text billing value may be, keyed by its path inside the * selection's `billing` block. * * **One table, because three paths need the same number and only one of them * used to have it.** The `max()` calls below are a parse the Session never * runs — `normalizeBookingSelection` projects the billing block value by value * rather than parsing it, so every bound declared here was decorative and the * write path accepted anything. The commit's own `contact_*` write did not, * and a 25-character postal code was therefore accepted a dozen times at the * step where it could still be edited and refused once, after the card was * captured, under a field name (`contactPostalCode`) the client never sent * (voyant#4734). * * So the same table now drives all three: * * 1. the schema below, so a caller that does parse sees the bound; * 2. the Session's selection normalizer, which refuses at `PATCH` naming the * path the caller wrote; * 3. `requirements.bookingFields[].maxLength`, so a client can refuse before * the shopper leaves the step. * * Every width is the one the Booking's own create accepts * (`convertProductSchema` in `@voyant-travel/bookings-contracts`). A value * this table admits cannot be rejected by the commit, which is the property * the widths were introduced to have. */ export declare const BOOKING_SELECTION_BILLING_MAX_LENGTHS: { readonly "contact.firstName": 255; readonly "contact.lastName": 255; readonly "contact.phone": 50; readonly "address.line1": 500; readonly "address.line2": 500; readonly "address.city": 100; readonly "address.region": 100; readonly "address.postal": 20; readonly "address.country": 2; }; export type BookingSelectionBillingFieldKey = keyof typeof BOOKING_SELECTION_BILLING_MAX_LENGTHS; /** * The same table for a traveler row, keyed by the field key * `requirements.travelerFields` publishes. * * Widths come from `insertTravelerSchema` in * `@voyant-travel/bookings-contracts`, which is what the commit writes each * row through. `email` is absent because it is bounded by shape rather than * length, and `band` is a code the requirements enumerate rather than free * text. */ export declare const BOOKING_SELECTION_TRAVELER_MAX_LENGTHS: { readonly firstName: 255; readonly lastName: 255; readonly phone: 50; }; export type BookingSelectionTravelerFieldKey = keyof typeof BOOKING_SELECTION_TRAVELER_MAX_LENGTHS; export declare const travelerEntryV1: z.ZodObject<{ rowId: z.ZodOptional; firstName: z.ZodString; lastName: z.ZodString; email: z.ZodOptional, z.ZodEmail]>>; phone: z.ZodOptional; personId: z.ZodOptional; band: z.ZodDefault; dateOfBirth: z.ZodOptional; documents: z.ZodOptional>; preferredLanguage: z.ZodOptional; specialRequests: z.ZodOptional; isPrimary: z.ZodOptional; }, z.core.$strip>; export type TravelerEntryV1 = z.infer; /** * What the engine writes onto a selection, never the caller. * * A Booking Session derives the entity from its own target, so a Session * selection that carries one is either stale or an attempt to book something * other than what the Session was opened against. */ export declare const bookingSelectionEngineOwnedV1: z.ZodObject<{ entity: z.ZodObject<{ module: z.ZodString; id: z.ZodString; sourceKind: z.ZodString; sourceConnectionId: z.ZodOptional; sourceRef: z.ZodOptional; }, z.core.$strip>; }, z.core.$strip>; /** * The public selection — everything any caller may send. * * This is the authoritative list of selection keys, not a suggestion: the * Booking Session rejects a top-level key this schema does not declare rather * than dropping it, so a field added here is admitted deliberately and a field * added anywhere else is denied by default. */ export declare const bookingSelectionPublicV1: z.ZodObject<{ contractAcceptance: z.ZodOptional; templateId: z.ZodString; templateVersionId: z.ZodString; contentDigest: z.ZodString; }, z.core.$strip>>; configure: z.ZodDefault; departureDate: z.ZodOptional; departureAirportCode: z.ZodOptional; nights: z.ZodOptional; departureTime: z.ZodOptional; pax: z.ZodDefault>; variantId: z.ZodOptional; optionSelections: z.ZodOptional; optionUnitId: z.ZodOptional; optionUnitName: z.ZodOptional; quantity: z.ZodNumber; }, z.core.$strip>>>; cabinCategoryId: z.ZodOptional; sailingId: z.ZodOptional; occupancy: z.ZodOptional; passengerComposition: z.ZodOptional; childAges: z.ZodOptional>; infants: z.ZodOptional; seniors: z.ZodOptional; }, z.core.$strip>>; fareCode: z.ZodNullable>; fareVariant: z.ZodNullable>>; bookingTerms: z.ZodNullable>>; cabinNumberId: z.ZodOptional; roomTypeId: z.ZodOptional; ratePlanId: z.ZodOptional; board: z.ZodOptional; dateRange: z.ZodOptional>; airArrangement: z.ZodOptional>; }, z.core.$strip>>; billing: z.ZodDefault>; organizationId: z.ZodOptional; contact: z.ZodObject<{ firstName: z.ZodDefault; lastName: z.ZodDefault; email: z.ZodDefault, z.ZodEmail]>>; phone: z.ZodOptional; personId: z.ZodOptional; }, z.core.$strip>; address: z.ZodDefault; line2: z.ZodOptional; city: z.ZodOptional; region: z.ZodOptional; postal: z.ZodOptional; country: z.ZodOptional; }, z.core.$strip>>; company: z.ZodOptional; registrationNumber: z.ZodOptional; }, z.core.$strip>>; saveAsDefault: z.ZodOptional; }, z.core.$strip>>; travelers: z.ZodDefault; firstName: z.ZodString; lastName: z.ZodString; email: z.ZodOptional, z.ZodEmail]>>; phone: z.ZodOptional; personId: z.ZodOptional; band: z.ZodDefault; dateOfBirth: z.ZodOptional; documents: z.ZodOptional>; preferredLanguage: z.ZodOptional; specialRequests: z.ZodOptional; isPrimary: z.ZodOptional; }, z.core.$strip>>>; accommodation: z.ZodOptional; occupancy: z.ZodOptional; childrenAges: z.ZodOptional>; infants: z.ZodOptional; }, z.core.$strict>>; }, z.core.$strip>>; travelerAssignments: z.ZodDefault>; sharedRoom: z.ZodOptional; groupId: z.ZodOptional; label: z.ZodOptional; }, z.core.$strip>>; }, z.core.$strip>>; addons: z.ZodDefault>>; ancillaries: z.ZodDefault; offerId: z.ZodOptional; sourceId: z.ZodOptional; providerId: z.ZodOptional; quoteRef: z.ZodOptional; acceptedPriceMinor: z.ZodOptional; acceptedCurrency: z.ZodOptional; travelers: z.ZodDefault>; }, z.core.$strict>>>; selectedOptionIds: z.ZodDefault>; acceptedDisclosures: z.ZodDefault>>; }, z.core.$strict>>>; payment: z.ZodDefault>; schedule: z.ZodOptional; }, z.core.$strip>>; paymentSchedules: z.ZodOptional; status: z.ZodEnum<{ pending: "pending"; cancelled: "cancelled"; due: "due"; paid: "paid"; waived: "waived"; expired: "expired"; }>; dueDate: z.ZodString; currency: z.ZodString; amountCents: z.ZodNumber; notes: z.ZodOptional>; }, z.core.$strip>>>; promotionCode: z.ZodOptional; customerNotes: z.ZodOptional; }, z.core.$strip>; export type BookingSelectionPublicV1 = z.infer; /** * Operator-only selection fields — commercial authority a buyer must never * hold: overriding the price, redeeming an operator-held Travel Credit, * silencing the confirmation email, choosing which documents are issued, * writing notes the customer never sees, or landing the booking as a draft. * * They are not part of `bookingSelectionPublicV1` and are never accepted from * a public payload at any depth. On the v1 Booking Session they arrive under * `selection.staffBooking`, behind the staff booking authority gate; the * authoritative shape of that payload is finance's * `bookingSessionStaffSelectionV1`, which supersets these fields with the rest * of the manual-booking operator input. They are declared here so the public * schema can be stated as their complement and the Session's default-deny * boundary can be derived from a schema instead of hand-maintained. */ export declare const bookingSelectionStaffOnlyV1: z.ZodObject<{ documentGeneration: z.ZodOptional; invoiceDocument: z.ZodOptional; invoiceType: z.ZodOptional>; }, z.core.$strip>>; suppressNotifications: z.ZodOptional; priceOverride: z.ZodOptional>; travelCreditRedemption: z.ZodOptional>; internalNotes: z.ZodOptional; saveAsDraft: z.ZodOptional; }, z.core.$strip>; export type BookingSelectionStaffOnlyV1 = z.infer; /** * The full journey draft an operator surface edits in place: the public * selection plus the engine-owned entity plus the operator-only fields. * * This is the client-side draft type, not what a Booking Session accepts — * the Session takes `bookingSelectionPublicV1` and receives operator choices * only under `selection.staffBooking`. */ export declare const bookingSelectionV1: z.ZodObject<{ contractAcceptance: z.ZodOptional; templateId: z.ZodString; templateVersionId: z.ZodString; contentDigest: z.ZodString; }, z.core.$strip>>; configure: z.ZodDefault; departureDate: z.ZodOptional; departureAirportCode: z.ZodOptional; nights: z.ZodOptional; departureTime: z.ZodOptional; pax: z.ZodDefault>; variantId: z.ZodOptional; optionSelections: z.ZodOptional; optionUnitId: z.ZodOptional; optionUnitName: z.ZodOptional; quantity: z.ZodNumber; }, z.core.$strip>>>; cabinCategoryId: z.ZodOptional; sailingId: z.ZodOptional; occupancy: z.ZodOptional; passengerComposition: z.ZodOptional; childAges: z.ZodOptional>; infants: z.ZodOptional; seniors: z.ZodOptional; }, z.core.$strip>>; fareCode: z.ZodNullable>; fareVariant: z.ZodNullable>>; bookingTerms: z.ZodNullable>>; cabinNumberId: z.ZodOptional; roomTypeId: z.ZodOptional; ratePlanId: z.ZodOptional; board: z.ZodOptional; dateRange: z.ZodOptional>; airArrangement: z.ZodOptional>; }, z.core.$strip>>; billing: z.ZodDefault>; organizationId: z.ZodOptional; contact: z.ZodObject<{ firstName: z.ZodDefault; lastName: z.ZodDefault; email: z.ZodDefault, z.ZodEmail]>>; phone: z.ZodOptional; personId: z.ZodOptional; }, z.core.$strip>; address: z.ZodDefault; line2: z.ZodOptional; city: z.ZodOptional; region: z.ZodOptional; postal: z.ZodOptional; country: z.ZodOptional; }, z.core.$strip>>; company: z.ZodOptional; registrationNumber: z.ZodOptional; }, z.core.$strip>>; saveAsDefault: z.ZodOptional; }, z.core.$strip>>; travelers: z.ZodDefault; firstName: z.ZodString; lastName: z.ZodString; email: z.ZodOptional, z.ZodEmail]>>; phone: z.ZodOptional; personId: z.ZodOptional; band: z.ZodDefault; dateOfBirth: z.ZodOptional; documents: z.ZodOptional>; preferredLanguage: z.ZodOptional; specialRequests: z.ZodOptional; isPrimary: z.ZodOptional; }, z.core.$strip>>>; accommodation: z.ZodOptional; occupancy: z.ZodOptional; childrenAges: z.ZodOptional>; infants: z.ZodOptional; }, z.core.$strict>>; }, z.core.$strip>>; travelerAssignments: z.ZodDefault>; sharedRoom: z.ZodOptional; groupId: z.ZodOptional; label: z.ZodOptional; }, z.core.$strip>>; }, z.core.$strip>>; addons: z.ZodDefault>>; ancillaries: z.ZodDefault; offerId: z.ZodOptional; sourceId: z.ZodOptional; providerId: z.ZodOptional; quoteRef: z.ZodOptional; acceptedPriceMinor: z.ZodOptional; acceptedCurrency: z.ZodOptional; travelers: z.ZodDefault>; }, z.core.$strict>>>; selectedOptionIds: z.ZodDefault>; acceptedDisclosures: z.ZodDefault>>; }, z.core.$strict>>>; payment: z.ZodDefault>; schedule: z.ZodOptional; }, z.core.$strip>>; paymentSchedules: z.ZodOptional; status: z.ZodEnum<{ pending: "pending"; cancelled: "cancelled"; due: "due"; paid: "paid"; waived: "waived"; expired: "expired"; }>; dueDate: z.ZodString; currency: z.ZodString; amountCents: z.ZodNumber; notes: z.ZodOptional>; }, z.core.$strip>>>; promotionCode: z.ZodOptional; customerNotes: z.ZodOptional; entity: z.ZodObject<{ module: z.ZodString; id: z.ZodString; sourceKind: z.ZodString; sourceConnectionId: z.ZodOptional; sourceRef: z.ZodOptional; }, z.core.$strip>; documentGeneration: z.ZodOptional; invoiceDocument: z.ZodOptional; invoiceType: z.ZodOptional>; }, z.core.$strip>>; suppressNotifications: z.ZodOptional; priceOverride: z.ZodOptional>; travelCreditRedemption: z.ZodOptional>; internalNotes: z.ZodOptional; saveAsDraft: z.ZodOptional; }, z.core.$strip>; export type BookingSelectionV1 = z.infer; /** * Selection keys any caller may write. Derived from the public schema so that * adding a field there — and only there — widens what a Session admits. */ export declare const BOOKING_SELECTION_PUBLIC_KEYS: ReadonlySet; /** * Selection keys a public caller may never write, at any depth. * * The engine-owned and operator-only entries are derived from the two schemas * that own them, so extending either schema extends the boundary without * anyone remembering to also deny the new field — the inversion this replaces * a hand-maintained denylist for. * * The reserved tail is Booking-record and supplier-result vocabulary that no * selection schema describes (there is no shape to derive from). Reserving the * names keeps a nested payload from smuggling one through into the commit-side * command merge, where a stray `status` or `sellAmountCentsOverride` would be * read as authoritative. */ export declare const BOOKING_SELECTION_PRIVILEGED_KEYS: ReadonlySet;