@@ -68,7 +68,8 @@ GraphQL) and gateway routing (`cng_backoffice_api-v1` /
6868 resolution).
6969- Optional config: ` mode ` (` "v2" ` — see below), ` baseUrl ` , ` tokenTtlSeconds ` (3600), ` tokenRefreshLeewaySeconds `
7070 (60), ` retryDelaysMs ` (` [1000, 2000, 4000] ` ), ` logger ` (no-op default),
71- ` fetch ` (global default), ` itemOptionsPageSize ` (50).
71+ ` fetch ` (global default), ` itemOptionsPageSize ` (50), and ` accessOptions `
72+ (see "Access options / PII" below).
7273- ** v2 mode** (` mode: "v2" ` ): routes requests through the app-registry
7374 installations API. The endpoint URL becomes
7475 ` baseUrl/appId/peek_backoffice_api-v1/endpointName ` and the default ` baseUrl `
@@ -229,15 +230,62 @@ Recurring patterns inside services:
229230 rejected. Validating pre-normalization is deliberate: normalization would
230231 erase the case/separator distinction the check relies on.
231232
233+ ### 4b. Access options / PII
234+ ` src/access-options.ts `
235+
236+ Every access service (` PeekAccessService ` , ` CngAccessService ` , ` AcmeAccessService ` )
237+ accepts an optional ` accessOptions ` config object — the public ` AccessOptions `
238+ type. Today it carries one flag, ` fullCustomerAccess ` (default ` false ` ); it is an object
239+ rather than a bare boolean so future cross-cutting flags slot in without changing
240+ any downstream signatures. Each access service resolves it once
241+ (` resolveAccessOptions ` , which fills defaults) and threads the resolved value
242+ into the resource services that read customer data.
243+
244+ When ` fullCustomerAccess ` is ` false ` (the default), two things happen:
245+
246+ 1 . ** PII is never requested (filtered at the GraphQL layer, not in the
247+ converters).** The query * builders* omit the PII fields entirely, so the
248+ gateway never returns them and the pure converters map the now-absent fields
249+ to ` null ` /empty — the converters stay PII-agnostic. Affected:
250+ - ** Bookings** (` booking-queries.ts ` ): ` buildBookingQueryFields ` /
251+ ` buildBookingGuestsFields ` / ` buildBookingGuestsQuery ` /
252+ ` buildBookingsListingQuery ` drop the primary-guest block
253+ (` customerName ` /` email ` /` phone ` ), the guest identity fields
254+ (name/country/DOB/email/phone/postalCode/` isGdpr ` /` fieldResponses ` — the
255+ guest list keeps only ids + participation/opt-in flags), the custom
256+ question answers (booking- and ticket-level), and the customer
257+ ` bookingPortalUrl ` . Operator-facing fields (notes, the Peek Pro deep link,
258+ money, resources) always stay.
259+ - ** Reviews** (` buildReviewsQuery ` ): drops the reviewer ` name ` /` email ` ; the
260+ review ` comment ` , rating, dates, and credited guides always stay.
261+ - ** Waivers** (` parseWaiverWebhook ` ): the webhook delivers a * fixed* payload
262+ with no GraphQL selection to trim, so this is the one place filtering is
263+ applied at parse time — the participant ` guestName ` and the signed-document
264+ ` fileUrl ` are nulled. ` parseWaiverWebhook(body, options?) ` takes the same
265+ ` AccessOptions ` ; ` fromWaiverNode ` stays a pure full mapping.
266+
267+ 2 . ** Payment / booking-modification operations are disabled.** ` BookingService `
268+ gates the operations that touch customer financial data —
269+ ` getPaymentsOnFile ` , ` makePayment ` , ` refund ` , ` createInvoiceLink ` ,
270+ ` addAddon ` , ` removeAddon ` — throwing ` PiiAccessDisabledError ` (an exported
271+ typed error) before any network call. Non-payment reads/mutations
272+ (` getById ` , ` getGuests ` , ` cancel ` , ` appendNote ` , ` setCheckinStatus ` ) and
273+ ` create ` (** including ` markAsPaid ` ** ) remain available.
274+
275+ The webhook ** registration** query (` BOOKING_WEBHOOK_GQL_QUERY ` ) is deliberately
276+ unaffected — it is the maximal selection built from the full field fragments and
277+ pinned by the drift-guard test; ` fullCustomerAccess ` governs only the runtime read path.
278+
232279### 5. Public API surface
233280` src/index.ts `
234281
235282The barrel re-exports only the public contract: ` PeekAccessService ` + its config,
236- each resource service class (and the options/result types callers need), all
237- data-model ** types** (including ` PeekAuthTokenClaims ` and ` PeekAuthTokenUser ` ),
238- the ` Logger ` interface + ` noopLogger ` , and the typed error classes
239- (` AdminAccountRequiredError ` , ` RateLimitError ` , ` PeekGraphQLError ` ,
240- ` CngApiError ` , ` AcmeApiError ` ). Query strings and raw response interfaces are deliberately kept
283+ the ` AccessOptions ` type (see §4b), each resource service class (and the
284+ options/result types callers need), all data-model ** types** (including
285+ ` PeekAuthTokenClaims ` and ` PeekAuthTokenUser ` ), the ` Logger ` interface +
286+ ` noopLogger ` , and the typed error classes (` AdminAccountRequiredError ` ,
287+ ` RateLimitError ` , ` PeekGraphQLError ` , ` PiiAccessDisabledError ` , ` CngApiError ` ,
288+ ` AcmeApiError ` ). Query strings and raw response interfaces are deliberately kept
241289internal — including the booking-webhook registration query
242290(` BOOKING_WEBHOOK_GQL_QUERY ` stays internal, documented via ` docs/webhooks.md ` ).
243291The webhook-related public exports are the two parsers ` parseBookingWebhook ` and
0 commit comments