@peektravel/app-utilities 0.9.2 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/index.cjs +547 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +296 -4
- package/dist/index.d.ts +296 -4
- package/dist/index.js +547 -70
- package/dist/index.js.map +1 -1
- package/docs/webhooks.md +1 -1
- package/llms.txt +26 -4
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/api-endpoints.ts","../src/internal/peek/gateway-endpoints.ts","../src/internal/peek/account-users/account-user-converter.ts","../src/internal/peek/account-users/account-user-queries.ts","../src/internal/peek/account-users/account-user-service.ts","../src/internal/peek/availability/availability-queries.ts","../src/internal/peek/availability/availability-service.ts","../src/access-options.ts","../src/errors.ts","../src/models/peek/product.ts","../src/internal/peek/bookings/booking-queries.ts","../src/internal/peek/bookings/booking-converter.ts","../src/internal/peek/bookings/booking-guest-converter.ts","../src/internal/peek/bookings/payments-on-file-converter.ts","../src/internal/peek/bookings/addon-queries.ts","../src/internal/peek/bookings/addon-converter.ts","../src/internal/peek/bookings/custom-question-answer.ts","../src/internal/peek/bookings/booking-service.ts","../src/internal/peek/daily-notes/daily-note-converter.ts","../src/internal/peek/daily-notes/daily-note-queries.ts","../src/internal/peek/daily-notes/daily-note-service.ts","../src/internal/token-manager.ts","../src/access-service-config.ts","../src/internal/http-transport.ts","../src/internal/sdk-headers.ts","../src/internal/peek/graphql-client.ts","../src/models/peek/auth-token.ts","../src/internal/peek/peek-auth-token.ts","../src/internal/peek/memberships/membership-converter.ts","../src/internal/peek/memberships/membership-queries.ts","../src/internal/peek/memberships/membership-service.ts","../src/internal/peek/resellers/channel-converter.ts","../src/internal/peek/resellers/channel-queries.ts","../src/internal/peek/resellers/reseller-service.ts","../src/internal/peek/resource-pools/resource-pool-converter.ts","../src/internal/peek/resource-pools/resource-pool-queries.ts","../src/internal/peek/resource-pools/resource-pool-service.ts","../src/internal/peek/reviews/review-converter.ts","../src/internal/peek/reviews/review-cursor.ts","../src/internal/peek/reviews/review-queries.ts","../src/internal/peek/reviews/review-service.ts","../src/internal/peek/timeslots/timeslot-converter.ts","../src/internal/peek/timeslots/guide-matcher.ts","../src/internal/peek/timeslots/resource-allocation-queries.ts","../src/internal/peek/timeslots/timeslot-queries.ts","../src/internal/peek/timeslots/timeslot-service.ts","../src/internal/peek/money.ts","../src/internal/peek/products/product-converter.ts","../src/internal/peek/products/custom-question-converter.ts","../src/internal/peek/products/product-queries.ts","../src/internal/peek/products/custom-question-queries.ts","../src/internal/peek/products/product-service.ts","../src/internal/peek/promo-codes/promo-code-queries.ts","../src/internal/peek/promo-codes/promo-code-service.ts","../src/internal/peek/pricing/pricing-queries.ts","../src/internal/peek/pricing/pricing-converter.ts","../src/internal/peek/pricing/pricing-service.ts","../src/logger.ts","../src/peek-access-service.ts","../src/internal/cng/endpoints.ts","../src/models/cng/product.ts","../src/internal/cng/products/product-converter.ts","../src/internal/cng/products/product-service.ts","../src/internal/cng/rest-client.ts","../src/cng-access-service.ts","../src/internal/acme/endpoints.ts","../src/models/acme/product.ts","../src/internal/acme/products/product-queries.ts","../src/internal/acme/products/product-converter.ts","../src/internal/acme/products/product-service.ts","../src/internal/acme/rest-client.ts","../src/acme-access-service.ts","../src/access-service-factory.ts","../src/internal/peek/bookings/booking-webhook.ts","../src/internal/peek/waivers/waiver-webhook.ts","../src/models/peek/install.ts","../src/internal/peek/installs/install-converter.ts","../src/internal/peek/installs/install-webhook.ts"],"names":["DEFAULT_PAGE_SIZE","randomUUID","jwt","jwt2","CREATE_QUOTE_V2_MUTATION","ERROR_PRODUCT_ID_REQUIRED","CURRENCY_PATTERN","ACTIVITY_PRODUCT_TYPE","DEFAULT_BASE_URL","RestClient"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * A platform's tiny map of **API endpoint key → relative path** (the \"slug\"\n * inserted between the install's base API URL and the endpoint's own path).\n *\n * The base API URL is the install's app endpoint with no routing segment — the\n * install webhook's `apiUrl` (with any slug stripped back off), or\n * `baseUrl/appId` when built from the deprecated defaults. Each service class\n * resolves *its own* slug through this lookup, so two services on the same\n * platform can route through different slugs. Adding a new API — even one on a\n * different slug than its siblings — is a single entry here.\n *\n * An empty-string path means the endpoint sits directly on the base with no\n * slug (e.g. the legacy Peek v1 GraphQL gateway, which has no extendable slug).\n */\nexport class ApiEndpoints<Key extends string = string> {\n constructor(private readonly paths: Readonly<Record<Key, string>>) {}\n\n /** The relative path (slug) for `endpoint`, appended to the base API URL. */\n pathFor(endpoint: Key): string {\n return this.paths[endpoint];\n }\n}\n\n/**\n * Joins URL path parts with single slashes, dropping empty parts so an absent\n * slug never produces a `//`. The base keeps its scheme's `//` intact because\n * it is passed as one already-joined part.\n */\nexport function joinUrl(...parts: string[]): string {\n return parts.filter((part) => part.length > 0).join(\"/\");\n}\n","/**\n * Endpoint routing for the backoffice GraphQL gateway. Every current operation\n * routes through the `sales` endpoint; the endpoint key and slugs live here so\n * they sit in exactly one place, and {@link peekApiEndpoints} is the simple\n * lookup a new Peek API extends.\n */\nimport { ApiEndpoints } from \"../api-endpoints.js\";\n\n/** The GraphQL endpoint key every current Peek operation routes through. */\nexport const SALES_ENDPOINT = \"sales\";\n\n/** Registry routing slug for the `sales` endpoint (v2 / app-endpoint mode). */\nexport const V2_EXTENDABLE_SLUG = \"peek_backoffice_api-v1\";\n\n/** The endpoint keys the Peek GraphQL transport knows how to route. */\nexport type PeekEndpointKey = typeof SALES_ENDPOINT;\n\n/**\n * Builds the Peek endpoint lookup for a transport generation.\n *\n * - **Registry mode** (`useRegistrySlug` — v2 or an app-endpoint `apiUrl`): the\n * `sales` endpoint routes through the `peek_backoffice_api-v1` slug appended\n * to the base API URL, and the GraphQL POST hits that slug directly.\n * - **Legacy v1 mode**: the backoffice-GraphQL gateway has no extendable slug,\n * so `sales` sits directly under the base (`base/sales`).\n *\n * Add a new Peek API by adding one entry — with its own slug when it needs one.\n */\nexport function peekApiEndpoints(\n useRegistrySlug: boolean,\n): ApiEndpoints<PeekEndpointKey> {\n return new ApiEndpoints({\n [SALES_ENDPOINT]: useRegistrySlug ? V2_EXTENDABLE_SLUG : SALES_ENDPOINT,\n });\n}\n","/**\n * Pure functions mapping raw account-user nodes into the clean\n * {@link AccountUser} model. Inactive users are dropped (mapped to `null`).\n */\nimport type { AccountUser } from \"../../../models/peek/account-user.js\";\nimport type { AccountUserNode } from \"./account-user-queries.js\";\n\n/** Only users in this status are surfaced. */\nconst ACTIVE_STATUS = \"ACTIVE\";\n\n/**\n * Converts a single node into an {@link AccountUser}, or `null` when the node is\n * missing or the user is not active.\n */\nexport function fromAccountUserNode(\n node: AccountUserNode | null | undefined,\n): AccountUser | null {\n if (!node || node.status !== ACTIVE_STATUS) {\n return null;\n }\n\n return {\n id: node.id,\n name: node.name,\n email: node.email,\n phone: node.phone,\n assignedActivities: (node.assignedActivities ?? []).map((activity) => ({\n id: activity.id,\n name: activity.name,\n })),\n };\n}\n\n/** Converts a list of nodes into active {@link AccountUser}s, dropping the rest. */\nexport function fromAccountUserNodes(\n nodes: Array<AccountUserNode | null | undefined>,\n): AccountUser[] {\n const users: AccountUser[] = [];\n for (const node of nodes) {\n const user = fromAccountUserNode(node);\n if (user) {\n users.push(user);\n }\n }\n return users;\n}\n","/**\n * Raw Peek GraphQL queries and response shapes for account users. Internal —\n * not re-exported from the public entry point.\n */\n\n/** Fetches a cursor-paginated page of account users. */\nexport const USER_QUERY = `\n query Sales($first: Int, $after: String) {\n accountUsers(first: $first, after: $after) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n id\n name\n email\n phone\n status\n assignedActivities {\n id\n name\n }\n }\n }\n }\n }\n`;\n\n/** Fetches account users matching a filter (e.g. by id). */\nexport const USER_BY_FILTER_QUERY = `\n query Sales($first: Int, $filter: AccountUsersFilter) {\n accountUsers(first: $first, filter: $filter) {\n edges {\n cursor\n node {\n id\n name\n email\n phone\n status\n assignedActivities {\n id\n name\n }\n }\n }\n }\n }\n`;\n\n/** A single account-user node as returned by the account-user queries. */\nexport interface AccountUserNode {\n id: string;\n name: string;\n email: string;\n phone: string;\n status: string;\n assignedActivities: Array<{ id: string; name: string }>;\n}\n\n/** The `data` payload of the account-user queries. */\nexport interface AccountUsersResponse {\n accountUsers: {\n pageInfo?: { endCursor: string | null; hasNextPage: boolean };\n edges: Array<{ cursor: string; node: AccountUserNode }>;\n };\n}\n","/**\n * Account-user operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getAccountUserService}. Only\n * active users are returned.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type { AccountUser } from \"../../../models/peek/account-user.js\";\nimport {\n fromAccountUserNode,\n fromAccountUserNodes,\n} from \"./account-user-converter.js\";\nimport {\n USER_BY_FILTER_QUERY,\n USER_QUERY,\n type AccountUsersResponse,\n} from \"./account-user-queries.js\";\n\n/** Default page size for cursor-paginated account users. */\nconst DEFAULT_PAGE_SIZE = 50;\n\n/** Tuning options for an {@link AccountUserService}. */\nexport interface AccountUserServiceOptions {\n /** Page size for cursor pagination. Default: 50. */\n pageSize?: number;\n}\n\nexport class AccountUserService {\n private readonly pageSize: number;\n\n constructor(\n private readonly client: GraphQLClient,\n options: AccountUserServiceOptions = {},\n ) {\n this.pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;\n }\n\n /**\n * Returns all active account users, walking the cursor pagination to the end.\n * Inactive users are omitted.\n */\n async getAll(): Promise<AccountUser[]> {\n const users: AccountUser[] = [];\n let after: string | null = null;\n\n for (;;) {\n const body: GraphQLBody<AccountUsersResponse> =\n await this.client.request<AccountUsersResponse>(SALES_ENDPOINT, USER_QUERY, {\n first: this.pageSize,\n after,\n });\n\n const connection = body.data?.accountUsers;\n const edges = connection?.edges ?? [];\n if (edges.length === 0) {\n break;\n }\n\n users.push(...fromAccountUserNodes(edges.map((edge) => edge.node)));\n\n const pageInfo = connection?.pageInfo;\n if (pageInfo?.hasNextPage && pageInfo.endCursor) {\n after = pageInfo.endCursor;\n } else {\n break;\n }\n }\n\n return users;\n }\n\n /**\n * Returns a single active account user by id, or `null` when no active user\n * matches.\n */\n async getById(userId: string): Promise<AccountUser | null> {\n const body: GraphQLBody<AccountUsersResponse> =\n await this.client.request<AccountUsersResponse>(\n SALES_ENDPOINT,\n USER_BY_FILTER_QUERY,\n { first: this.pageSize, filter: { ids: [userId] } },\n );\n\n const firstEdge = (body.data?.accountUsers?.edges ?? [])[0];\n if (!firstEdge) {\n return null;\n }\n return fromAccountUserNode(firstEdge.node);\n }\n}\n","/**\n * Raw Peek GraphQL query and response shape for availability times. Internal.\n * The node matches the public {@link AvailabilityTime} model one-to-one.\n */\nimport type { AvailabilityTime } from \"../../../models/peek/availability-time.js\";\n\n/** Fetches availability times for an activity/date and resource-option quantities. */\nexport const AVAILABILITY_TIMES_QUERY = `\n query Sales($activityId: ID!, $resourceOptionQuantities: [ResourceOptionQuantityData!]!, $date: Date!) {\n availabilityTimes(activityId: $activityId, resourceOptionQuantities: $resourceOptionQuantities, date: $date) {\n id\n time\n from\n end\n duration {\n name\n length {\n amount\n unit\n }\n }\n status\n availability {\n qty\n taken\n resourceOptionId\n }\n }\n }\n`;\n\n/** The `data` payload of {@link AVAILABILITY_TIMES_QUERY}. */\nexport interface AvailabilityTimesResponse {\n availabilityTimes: AvailabilityTime[];\n}\n","/**\n * Availability-times operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getAvailabilityService}.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type {\n AvailabilityTime,\n AvailabilityTimesQuery,\n} from \"../../../models/peek/availability-time.js\";\nimport {\n AVAILABILITY_TIMES_QUERY,\n type AvailabilityTimesResponse,\n} from \"./availability-queries.js\";\n\nexport class AvailabilityService {\n constructor(private readonly client: GraphQLClient) {}\n\n /** Returns the availability times for an activity/date and requested quantities. */\n async getAvailabilityTimes(\n query: AvailabilityTimesQuery,\n ): Promise<AvailabilityTime[]> {\n const body: GraphQLBody<AvailabilityTimesResponse> =\n await this.client.request<AvailabilityTimesResponse>(\n SALES_ENDPOINT,\n AVAILABILITY_TIMES_QUERY,\n {\n activityId: query.activityId,\n resourceOptionQuantities: query.resourceOptionQuantities,\n date: query.date,\n },\n );\n return body.data?.availabilityTimes ?? [];\n }\n}\n","/**\n * Cross-cutting options that govern what data an access service will read and\n * expose. Passed once when constructing an access service and threaded down to\n * the resource services (and the webhook parsers) so a single object controls\n * behaviour everywhere, rather than a boolean being passed hand-to-hand.\n *\n * Kept deliberately small — today it carries a single PII toggle, but new\n * cross-cutting flags slot in here without changing any downstream signatures.\n */\n\n/** Options controlling PII exposure across an access service's reads. */\nexport interface AccessOptions {\n /**\n * When `true`, customer PII (guest names/emails/phones, custom question\n * answers, the customer booking-portal URL, waiver participant details, …) is\n * requested and returned, and payment/booking-modification operations are\n * available.\n *\n * When `false` (the default), those PII fields are never requested from the\n * gateway and come back `null`/empty, and the payment/booking-modification\n * operations that touch customer financial data are disabled (they throw a\n * {@link PiiAccessDisabledError}).\n */\n fullCustomerAccess?: boolean;\n}\n\n/** A fully-resolved {@link AccessOptions} with every flag defaulted. */\nexport type ResolvedAccessOptions = Required<AccessOptions>;\n\n/**\n * Resolves a possibly-absent {@link AccessOptions} into a concrete object with\n * every flag defaulted. `fullCustomerAccess` defaults to `false` (PII off).\n */\nexport function resolveAccessOptions(options?: AccessOptions): ResolvedAccessOptions {\n return { fullCustomerAccess: options?.fullCustomerAccess ?? false };\n}\n","/**\n * Typed errors thrown by the package. Each mirrors a failure mode of the Peek\n * GraphQL gateway (or the CNG REST gateway) so callers can branch on the error\n * type rather than parsing messages.\n *\n * `AdminAccountRequiredError` and `RateLimitError` are shared by all gateways.\n * `PeekGraphQLError` is Peek-only; `CngApiError` and `CngPermissionError` are\n * CNG-only; `AcmeApiError` is ACME-only.\n */\n\n/** The HTTP status the CNG gateway uses for a missing-permission rejection. */\nexport const FORBIDDEN_STATUS = 403;\n\nconst PERMISSION_MESSAGE_PREFIX = \"CNG request forbidden: the app is missing the required permission\";\nconst PERMISSION_MESSAGE_UNKNOWN = \"CNG request forbidden: the app is missing a required permission\";\n\n/** Builds the {@link CngPermissionError} message from the named permissions. */\nfunction buildPermissionMessage(permissions: string[]): string {\n if (permissions.length === 0) return PERMISSION_MESSAGE_UNKNOWN;\n return `${PERMISSION_MESSAGE_PREFIX}${permissions.length > 1 ? \"s\" : \"\"}: ${permissions.join(\", \")}`;\n}\n\n/**\n * Thrown when the gateway responds with HTTP 418, indicating the install is not\n * permitted to perform the request because an admin account is required.\n */\nexport class AdminAccountRequiredError extends Error {\n /** The HTTP status that triggered this error. */\n public readonly statusCode = 418;\n\n constructor(message = \"Admin account required\") {\n super(message);\n this.name = \"AdminAccountRequiredError\";\n }\n}\n\n/**\n * Thrown when the gateway responds with HTTP 429 and all configured retries\n * have been exhausted.\n */\nexport class RateLimitError extends Error {\n /** The HTTP status that triggered this error. */\n public readonly statusCode = 429;\n\n constructor(message = \"Rate limit exceeded\") {\n super(message);\n this.name = \"RateLimitError\";\n }\n}\n\n/**\n * Thrown when a GraphQL response contains an `errors` array. The raw errors are\n * preserved on {@link PeekGraphQLError.graphqlErrors} for inspection.\n */\nexport class PeekGraphQLError extends Error {\n /** The raw `errors` array returned by the GraphQL endpoint. */\n public readonly graphqlErrors: unknown[];\n\n constructor(graphqlErrors: unknown[], message = \"GraphQL request failed\") {\n super(message);\n this.name = \"PeekGraphQLError\";\n this.graphqlErrors = graphqlErrors;\n }\n}\n\n/**\n * Thrown when the Peek GraphQL gateway returns a non-2xx HTTP response that is\n * not one of the specifically-handled statuses (418/429) and does not carry a\n * GraphQL `errors` array. This is the transport-level failure — a `401`\n * (auth/secret wrong), `404` (wrong app id / not provisioned), `5xx`, etc. —\n * as opposed to {@link PeekGraphQLError}, which is a resolver-level failure\n * reported inside an otherwise-successful HTTP response.\n *\n * The offending status is preserved on {@link PeekHttpError.statusCode}, the\n * request URL on {@link PeekHttpError.url}, and the raw response body (parsed\n * JSON when possible, otherwise the raw text) on {@link PeekHttpError.body} — so\n * callers can tell \"which config is wrong\" without disassembling the bundle.\n */\nexport class PeekHttpError extends Error {\n /** The HTTP status that triggered this error. */\n public readonly statusCode: number;\n /** The request URL that produced the failing response. */\n public readonly url: string;\n /** The raw response body (parsed JSON when possible, otherwise text). */\n public readonly body: unknown;\n\n constructor(statusCode: number, url: string, body: unknown, message?: string) {\n super(message ?? `Peek request failed with HTTP ${statusCode}`);\n this.name = \"PeekHttpError\";\n this.statusCode = statusCode;\n this.url = url;\n this.body = body;\n }\n}\n\n/**\n * Thrown when a payment or booking-modification operation is called on an\n * access service that was constructed without `fullCustomerAccess` (PII access\n * disabled). These operations — pulling payment sources, charging/refunding,\n * creating invoice links, and adding/removing add-ons — touch customer\n * financial data, so they are gated behind the same flag as customer PII.\n */\nexport class PiiAccessDisabledError extends Error {\n /** The name of the operation that was blocked (e.g. `\"makePayment\"`). */\n public readonly operation: string;\n\n constructor(operation: string) {\n super(\n `\"${operation}\" is disabled because this access service was created ` +\n `without \"fullCustomerAccess\"; enable it to allow payment and booking-modification operations`,\n );\n this.name = \"PiiAccessDisabledError\";\n this.operation = operation;\n }\n}\n\n/**\n * Thrown when the CNG REST gateway returns a non-2xx response that is not one\n * of the specifically-handled statuses (418/429). The offending status is\n * preserved on {@link CngApiError.statusCode}, and the raw response body (parsed\n * JSON when possible, otherwise the raw text) on {@link CngApiError.body}.\n */\nexport class CngApiError extends Error {\n /** The HTTP status that triggered this error. */\n public readonly statusCode: number;\n /** The raw response body (parsed JSON when possible, otherwise text). */\n public readonly body: unknown;\n\n constructor(statusCode: number, body: unknown, message?: string) {\n super(message ?? `CNG request failed with HTTP ${statusCode}`);\n this.name = \"CngApiError\";\n this.statusCode = statusCode;\n this.body = body;\n }\n}\n\n/**\n * Thrown when the CNG REST gateway responds with HTTP 403 because the app lacks\n * a permission the endpoint requires (e.g. `products:read`). This is an\n * **expected** failure for a misconfigured install — not a bug — so the\n * transport logs it at `warn` rather than `error` and leaves presentation to the\n * caller, which can branch on the type and surface the missing permission\n * however its UI prefers.\n *\n * The permission names the gateway named are on\n * {@link CngPermissionError.permissions} (empty when the body does not name\n * any), so a caller can render them without re-parsing the raw body. Thrown in\n * place of {@link CngApiError} for 403s only; every other non-2xx status still\n * throws `CngApiError`.\n */\nexport class CngPermissionError extends Error {\n /** The HTTP status that triggered this error. */\n public readonly statusCode = FORBIDDEN_STATUS;\n /**\n * The permissions the gateway reported as missing, e.g. `[\"products:read\"]`.\n * Empty when the response body did not name any.\n */\n public readonly permissions: string[];\n /** The raw response body (parsed JSON when possible, otherwise text). */\n public readonly body: unknown;\n\n constructor(permissions: string[], body: unknown, message?: string) {\n super(message ?? buildPermissionMessage(permissions));\n this.name = \"CngPermissionError\";\n this.permissions = permissions;\n this.body = body;\n }\n}\n\n/**\n * Thrown when the ACME REST gateway returns a non-2xx response that is not one\n * of the specifically-handled statuses (418/429). The offending status is\n * preserved on {@link AcmeApiError.statusCode}, and the raw response body\n * (parsed JSON when possible, otherwise the raw text) on\n * {@link AcmeApiError.body}.\n */\nexport class AcmeApiError extends Error {\n /** The HTTP status that triggered this error. */\n public readonly statusCode: number;\n /** The raw response body (parsed JSON when possible, otherwise text). */\n public readonly body: unknown;\n\n constructor(statusCode: number, body: unknown, message?: string) {\n super(message ?? `ACME request failed with HTTP ${statusCode}`);\n this.name = \"AcmeApiError\";\n this.statusCode = statusCode;\n this.body = body;\n }\n}\n","/**\n * The clean, transport-agnostic data model for a Peek Pro product.\n *\n * This is the shape consumers of the package work with. It is intentionally\n * decoupled from the underlying Peek GraphQL schema — the raw GraphQL types and\n * the conversion logic live inside the package and are never exposed here.\n */\nimport type { PricingMoney } from \"./pricing.js\";\n\n/**\n * A bookable product in a Peek Pro account.\n *\n * `PeekAccessService.getAllProducts()` returns a single flat list that combines\n * two distinct Peek concepts into one uniform shape:\n *\n * - **Activities** — the primary bookable experiences (tours, rentals, classes,\n * etc.). Their {@link Product.type} is whatever Peek reports for the activity.\n * - **Add-ons** — optional item options offered alongside activities. They are\n * grouped under their parent item and always carry the\n * {@link ADD_ON_PRODUCT_TYPE} (`\"ADD-ON\"`) type, so callers can tell the two\n * apart with a single field check.\n */\nexport interface Product {\n /**\n * Stable unique identifier for the product.\n *\n * - Activities: the primary GraphQL `id` (falls back to the `legacyId`).\n * - Add-ons: the id of the parent item the options belong to.\n */\n productId: string;\n\n /** Human-readable display name. */\n name: string;\n\n /**\n * Product type.\n *\n * For activities this is the type reported by Peek; for add-ons it is always\n * {@link ADD_ON_PRODUCT_TYPE}.\n */\n type: string;\n\n /**\n * Display color as a hex string (e.g. `\"#1A2B3C\"`).\n *\n * Add-ons default to white (`\"#FFFFFF\"`). Empty string when no color is set.\n */\n color: string;\n\n /**\n * ISO 4217 currency code the activity prices in (e.g. `\"USD\"`).\n *\n * Populated for activities and rentals; empty string for add-ons (which carry\n * no currency of their own) and when Peek reports none. Consumers building\n * pricing overrides use this to set the currency on fixed-price adjustments.\n */\n currency: string;\n\n /**\n * URL of the product's primary display image, or `null` when Peek reports\n * none. Populated for activities/rentals; always `null` for add-ons.\n */\n imageUrl: string | null;\n\n /**\n * Long-form product description (may contain HTML), or `null` when Peek\n * reports none. Populated for activities/rentals; always `null` for add-ons.\n */\n description: string | null;\n\n /**\n * Where the experience meets, or `null` when Peek reports no location detail.\n * Populated for activities/rentals; always `null` for add-ons. Each field\n * inside is independently nullable.\n */\n meetingLocation: ProductMeetingLocation | null;\n\n /**\n * The bookable sub-options of this product.\n *\n * - Activities: the activity's resource options.\n * - Add-ons: each individual item option grouped under the parent item.\n */\n tickets: ProductTicket[];\n}\n\n/** The meeting point for a bookable experience. Every field is nullable. */\nexport interface ProductMeetingLocation {\n /** Free-text summary / instructions for the meeting point. */\n summary: string | null;\n /** Formatted postal address of the meeting point. */\n address: string | null;\n /** Map/link URL for the meeting point. */\n url: string | null;\n}\n\n/** A single bookable sub-option (resource option or add-on item option). */\nexport interface ProductTicket {\n /** Unique identifier of the ticket / option. */\n id: string;\n /** Human-readable name of the ticket / option. */\n name: string;\n /**\n * Lowest price this ticket can be sold at, across its price range.\n *\n * Populated for activity/rental resource options that expose a price range;\n * `null` for add-on options (which carry no range) and when Peek reports none.\n */\n minPrice: PricingMoney | null;\n /**\n * Highest price this ticket can be sold at, across its price range.\n *\n * Populated for activity/rental resource options that expose a price range;\n * `null` for add-on options (which carry no range) and when Peek reports none.\n */\n maxPrice: PricingMoney | null;\n}\n\n/** {@link Product.type} for standard bookable activities. */\nexport const ACTIVITY_PRODUCT_TYPE = \"ACTIVITY\";\n\n/** {@link Product.type} for rental products. */\nexport const RENTAL_PRODUCT_TYPE = \"RENTAL\";\n\n/**\n * The {@link Product.type} value assigned to add-on products.\n *\n * Exposed so callers can filter add-ons out of (or in to) the combined list\n * returned by {@link Product} queries without hard-coding the string.\n */\nexport const ADD_ON_PRODUCT_TYPE = \"ADD-ON\";\n","/**\n * Raw Peek GraphQL fields, queries, mutations, variables, and response shapes\n * for bookings. Internal.\n */\nimport type { BookingSearchBy } from \"../../../models/peek/booking.js\";\n\nexport const SEARCH_BY_PURCHASE_DATE: BookingSearchBy = \"purchaseDate\";\nexport const SEARCH_BY_ACTIVITY_DATE: BookingSearchBy = \"activityDate\";\n\n/** Normalizes a booking id to the gateway's expected form. */\nexport function normalizeBookingId(bookingId: string): string {\n return bookingId.toLowerCase().replace(/-/g, \"_\");\n}\n\n/**\n * The customer-identity guest fields (name, contact, DOB, postal code, and the\n * free-text custom field responses). These are PII and are only selected when\n * `fullCustomerAccess` is set; the trailing group sits after the non-PII flags to keep\n * the maximal selection order stable for the webhook drift-guard.\n */\nconst GUEST_IDENTITY_PII_FIELDS = \"name country dateOfBirth email isGdpr\";\nconst GUEST_CONTACT_PII_FIELDS = `phone\n postalCode\n fieldResponses {\n id\n text\n fieldLocation {\n field {\n name\n }\n }\n }`;\n\n/**\n * Builds the guest selection. Without `fullCustomerAccess`, only the structural id and\n * the participation/opt-in flags are requested — the identity fields come back\n * absent (→ `null` in the converter).\n */\nexport function buildGuestFields(fullCustomerAccess: boolean): string {\n return `\n id\n ${fullCustomerAccess ? GUEST_IDENTITY_PII_FIELDS : \"\"}\n isParticipant\n optinSms\n optinMarketing\n ${fullCustomerAccess ? GUEST_CONTACT_PII_FIELDS : \"\"}\n`;\n}\n\n/** Builds the `bookingGuests` + `primaryGuest` guest sections. */\nexport function buildBookingGuestsFields(fullCustomerAccess: boolean): string {\n const guestFields = buildGuestFields(fullCustomerAccess);\n return `\n bookingGuests {\n ${guestFields}\n }\n primaryGuest {\n ${guestFields}\n }\n`;\n}\n\n/** The maximal (PII-included) guest sections — used by the webhook selection. */\nexport const bookingGuestsFields = buildBookingGuestsFields(true);\n\n/**\n * The primary-guest PII block on a booking — drives `customerName`/`email`/\n * `phone`. Selected only when `fullCustomerAccess` is set.\n */\nconst BOOKING_PRIMARY_GUEST_PII_FIELDS = `primaryGuest {\n name\n email\n phone\n optinMarketing\n optinSms\n isGdpr\n postalCode\n }`;\n\n/**\n * Custom question answers captured on the booking and per guest/ticket. These\n * routinely carry PII (address, DOB, captured location), so they are selected\n * only when `fullCustomerAccess` is set.\n */\nconst BOOKING_QUESTION_ANSWERS_PII_FIELDS = `questionAnswers {\n answer\n questionText\n questionLocationSnapshot {\n latitude\n longitude\n }\n }\n tickets {\n questionAnswers {\n answer\n questionText\n }\n }`;\n\n/**\n * Builds the booking selection. Without `fullCustomerAccess` the primary-guest block,\n * the customer booking-portal URL, and the custom question answers are omitted\n * entirely (they come back absent → `null`/empty in the converter). The\n * operator-facing deep link, notes, money, and structural fields always stay.\n */\nexport function buildBookingQueryFields(fullCustomerAccess: boolean): string {\n return `\n displayId\n id\n ${fullCustomerAccess ? BOOKING_PRIMARY_GUEST_PII_FIELDS : \"\"}\n activitySnapshot {\n type\n name\n id\n }\n ticketQuantities {\n quantity\n resourceOptionSnapshot {\n name\n id\n }\n }\n reservationStatus\n checkinStatus\n returnStatus\n fulfillmentStatusOverride {\n status\n }\n timeSnapshot {\n id\n legacyId\n }\n purchasedAt\n purchasedAtUtc\n startsAt\n startsAtUtc\n endsAt\n endsAtUtc\n availabilityTimeId\n ${fullCustomerAccess ? \"bookingPortalUrl\" : \"\"}\n operatorNotes\n value {\n total {\n formatted\n amount\n }\n }\n balance {\n total {\n amount\n formatted\n }\n }\n tips {\n price {\n amount\n formatted\n }\n }\n order {\n displayId\n id\n promoCodes {\n code\n }\n channelSnapshot {\n id\n name\n agent {\n name\n }\n }\n initialQuote {\n source {\n actor {\n app\n name\n }\n }\n }\n }\n ${fullCustomerAccess ? BOOKING_QUESTION_ANSWERS_PII_FIELDS : \"\"}\n resourcePoolAssignments {\n quantity\n resourcePool {\n name\n shortName\n resources {\n name\n }\n }\n resourceAssignments {\n resource {\n id\n name\n }\n }\n }\n`;\n}\n\n/** The maximal (PII-included) booking selection — used by the webhook selection. */\nexport const bookingQueryFields = buildBookingQueryFields(true);\n\nexport const PRICE_BREAKDOWN_FIELDS = `\n convenienceFee { amount formatted }\n deposit { amount formatted }\n discount { amount formatted }\n discountedPrice { amount formatted }\n fees { amount formatted }\n flatPartnerFee { amount formatted }\n price { amount formatted }\n retailPrice { amount formatted }\n taxes { amount formatted }\n tips { amount formatted }\n`;\n\n/**\n * Per-ticket price selection (list price + line total) injected into\n * `ticketQuantities` when the price breakdown is requested.\n */\nexport const TICKET_VALUE_FIELDS = `\n value {\n price { amount formatted }\n total { amount formatted }\n }\n`;\n\n/**\n * Builds the bookings listing query, optionally including guests and price\n * breakdown. When `fullCustomerAccess` is false (default `true` for the raw builder;\n * the service passes the resolved access option), customer PII fields are not\n * requested at all — see {@link buildBookingQueryFields}.\n */\nexport function buildBookingsListingQuery(\n includeGuests: boolean,\n includePriceBreakdown: boolean,\n fullCustomerAccess = true,\n): string {\n const guestsSection = includeGuests ? buildBookingGuestsFields(fullCustomerAccess) : \"\";\n // Inject the booking-level breakdown first: it anchors on the first `value {`,\n // which is the booking node's. The ticket-level `value` (added by the second\n // replace) must go in afterwards, or it would capture that anchor instead.\n const baseFields = buildBookingQueryFields(fullCustomerAccess);\n const fields = includePriceBreakdown\n ? baseFields\n .replace(\"value {\", `value { ${PRICE_BREAKDOWN_FIELDS}`)\n .replace(\"ticketQuantities {\", `ticketQuantities { ${TICKET_VALUE_FIELDS}`)\n : baseFields;\n\n return `\n query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {\n sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {\n pageInfo { endCursor hasNextPage }\n edges {\n node {\n ... on Booking {\n ${fields}\n ${guestsSection}\n }\n }\n }\n }\n }\n `;\n}\n\n/**\n * Builds the query fetching the guests for a booking. Without `fullCustomerAccess` the\n * guest identity fields are omitted (only ids + participation/opt-in flags).\n */\nexport function buildBookingGuestsQuery(fullCustomerAccess: boolean): string {\n return `\n query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {\n sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {\n pageInfo { endCursor hasNextPage }\n edges {\n node {\n ... on Booking {\n displayId\n id\n ${buildBookingGuestsFields(fullCustomerAccess)}\n }\n }\n }\n }\n }\n`;\n}\n\n/** Query fetching a booking's order payments + payment sources. */\nexport const BOOKING_PAYMENTS_ON_FILE_QUERY = `\n query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {\n sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {\n pageInfo { endCursor hasNextPage }\n edges {\n node {\n order {\n payments {\n id\n paymentSource { id }\n appliedAt\n currentAmount { amount currency }\n refundableAmount { amount currency }\n }\n id\n displayId\n paymentSources { description type id }\n }\n ... on Booking {\n displayId\n id\n }\n }\n }\n }\n }\n`;\n\nexport const UPDATE_OPERATOR_NOTES_MUTATION = `\n mutation Account($input: UpdateOperatorNotesForBookingInput!) {\n updateOperatorNotesForBooking(input: $input) {\n booking { operatorNotes }\n }\n }\n`;\n\nexport const UPDATE_BOOKING_CHECKIN_MUTATION = `\n mutation Account($input: UpdateBookingCheckInInput!) {\n updateBookingCheckIn(input: $input) {\n booking { checkinStatus }\n }\n }\n`;\n\nexport const CANCEL_BOOKING_MUTATION = `\n mutation Account($input: CancelBookingInput!) {\n cancelBooking(input: $input) {\n booking { id displayId reservationStatus }\n }\n }\n`;\n\nexport const APPLY_PAYMENT_TO_ORDER_MUTATION = `\n mutation ApplyPaymentToOrder($input: ApplyPaymentToOrderInput!) {\n applyPaymentToOrder(input: $input) {\n transactionId\n errors { code detail value }\n }\n }\n`;\n\nexport const APPLY_REFUND_TO_ORDER_MUTATION = `\n mutation ApplyRefundToOrder($input: ApplyRefundToOrderInput!) {\n applyRefundToOrder(input: $input) {\n transactionId\n errors { code detail value }\n }\n }\n`;\n\nexport const CREATE_INVOICE_LINK_MUTATION = `\n mutation CreateInvoiceLink($input: CreateInvoiceLinkInput!) {\n createInvoiceLink(input: $input) {\n invoiceLink { status url }\n errors { code detail value __typename }\n }\n }\n`;\n\n/** A payment/refund/invoice error entry. */\nexport interface PaymentMutationError {\n code: string;\n detail: string;\n value: string | null;\n}\n\nexport interface ApplyPaymentToOrderResponse {\n applyPaymentToOrder: { transactionId: string | null; errors: PaymentMutationError[] | null };\n}\n\nexport interface ApplyRefundToOrderResponse {\n applyRefundToOrder: { transactionId: string | null; errors: PaymentMutationError[] | null };\n}\n\nexport interface CreateInvoiceLinkResponse {\n createInvoiceLink: {\n invoiceLink: { status: string; url: string } | null;\n errors: PaymentMutationError[] | null;\n };\n}\n\nexport const CREATE_QUOTE_FROM_ORDER_MUTATION = `\n mutation CreateQuoteFromOrder($input: CreateQuoteFromOrderInput!) {\n createQuoteFromOrder(input: $input) {\n errors { detail value code }\n quote {\n id\n saleQuotes { refid reservationStatus }\n }\n }\n }\n`;\n\nexport const UPDATE_QUOTE_V2_MUTATION = `\n mutation UpdateQuoteV2($input: UpdateQuoteV2Input!) {\n updateQuoteV2(input: $input) {\n errors { detail value code }\n quote { id }\n }\n }\n`;\n\nexport const AMEND_ORDER_MUTATION = `\n mutation AmendOrder($input: AmendOrderInput!) {\n amendOrder(input: $input) {\n errors { code detail value }\n order { id }\n }\n }\n`;\n\nexport interface CreateQuoteFromOrderResponse {\n createQuoteFromOrder: {\n errors: PaymentMutationError[] | null;\n quote: { id: string; saleQuotes: Array<{ refid: string; reservationStatus: string }> } | null;\n };\n}\n\nexport interface UpdateQuoteV2Response {\n updateQuoteV2: { errors: PaymentMutationError[] | null; quote: { id: string } | null };\n}\n\nexport interface AmendOrderResponse {\n amendOrder: { errors: PaymentMutationError[] | null; order: { id: string } | null };\n}\n\nexport const CREATE_QUOTE_V2_MUTATION = `\n mutation CreateQuoteV2($input: CreateQuoteV2Input!) {\n createQuoteV2(input: $input) {\n errors { detail value code }\n quote { id }\n }\n }\n`;\n\nexport const CREATE_ORDER_FROM_QUOTE_MUTATION = `\n mutation CreateOrderFromQuote($input: CreateOrderFromQuoteInput!) {\n createOrderFromQuote(input: $input) {\n errors { code detail value }\n order {\n id\n sales {\n id\n displayId\n ... on Booking {\n balance { total { amount currency formatted } }\n }\n }\n }\n }\n }\n`;\n\nexport interface CreateQuoteV2Response {\n createQuoteV2: { errors: PaymentMutationError[] | null; quote: { id: string } | null };\n}\n\nexport interface CreateOrderFromQuoteResponse {\n createOrderFromQuote: {\n errors: PaymentMutationError[] | null;\n order: {\n id: string;\n sales: Array<{\n id: string;\n displayId: string;\n balance?: { total: { amount: string; currency: string; formatted: string } } | null;\n }>;\n } | null;\n };\n}\n\n/** Builds the variables for the bookings/guests/payments sales queries. */\nexport function buildBookingsVariables(params: {\n pageSize: number;\n after: string | null;\n startDateTime?: string;\n endDateTime?: string;\n timeslotId?: string;\n searchBy?: BookingSearchBy;\n productId?: string;\n bookingId?: string;\n email?: string;\n searchString?: string;\n}): object {\n const filter: Record<string, unknown> = {};\n const bookingFilter: Record<string, unknown> = {};\n\n if (params.bookingId) {\n bookingFilter.ids = [normalizeBookingId(params.bookingId)];\n } else if (params.timeslotId) {\n bookingFilter.timeslotRefid = params.timeslotId;\n } else {\n if (params.searchBy === SEARCH_BY_ACTIVITY_DATE) {\n bookingFilter.overlapsRange = `[${params.startDateTime},${params.endDateTime}]`;\n } else if (params.searchBy === SEARCH_BY_PURCHASE_DATE) {\n filter.purchasedAtRangeUtc = `[${params.startDateTime},${params.endDateTime}]`;\n }\n if (params.productId) {\n bookingFilter.activityIds = [params.productId];\n }\n }\n\n if (params.email) {\n filter.primaryGuestEmail = params.email;\n }\n if (params.searchString && params.searchString.length > 0) {\n filter.searchString = params.searchString;\n }\n if (Object.keys(bookingFilter).length > 0) {\n filter.bookingFilter = bookingFilter;\n }\n\n return {\n first: params.pageSize,\n after: params.after,\n orderBy: { direction: \"ASC\", field: \"STARTS_AT\" },\n filter,\n };\n}\n\n// ---- Raw response shapes -------------------------------------------------\n\nexport interface BookingNode {\n displayId?: string;\n id?: string;\n // Base bookings query selects name/email/phone; when guests are requested the\n // full guest fields (id, fieldResponses, …) are merged in as well.\n primaryGuest?: BookingGuestNode | null;\n activitySnapshot?: { type?: string; name?: string; id?: string } | null;\n ticketQuantities?: Array<{\n quantity?: number;\n resourceOptionSnapshot?: { name?: string; id?: string } | null;\n // Present only when the price breakdown is requested (see TICKET_VALUE_FIELDS).\n value?: {\n price?: { amount?: string; formatted?: string };\n total?: { amount?: string; formatted?: string };\n };\n }>;\n reservationStatus?: string;\n checkinStatus?: string;\n returnStatus?: string;\n fulfillmentStatusOverride?: { status?: string } | null;\n timeSnapshot?: { id?: string; legacyId?: string | null } | null;\n purchasedAt?: string;\n purchasedAtUtc?: string;\n startsAt?: string;\n startsAtUtc?: string;\n endsAt?: string;\n endsAtUtc?: string;\n availabilityTimeId?: string;\n bookingPortalUrl?: string;\n operatorNotes?: string | null;\n value?: Record<string, { amount?: string; formatted?: string } | undefined> & {\n total?: { amount?: string; formatted?: string };\n };\n balance?: { total?: { amount?: string; formatted?: string } } | null;\n tips?: Array<{ price?: { amount?: string; formatted?: string } }>;\n order?: {\n id?: string;\n promoCodes?: Array<{ code: string }>;\n channelSnapshot?: { id?: string; name?: string; agent?: { name?: string } | null } | null;\n initialQuote?: {\n source?: { actor?: { app?: string; name?: string } | null } | null;\n } | null;\n } | null;\n questionAnswers?: Array<{\n answer: string;\n questionText: string;\n questionLocationSnapshot?: { latitude?: string; longitude?: string } | null;\n }>;\n tickets?: Array<{\n questionAnswers?: Array<{ answer: string; questionText: string }> | null;\n }> | null;\n resourcePoolAssignments?: Array<{\n quantity?: number;\n resourcePool?: { name?: string; shortName?: string } | null;\n resourceAssignments?: Array<{ resource?: { id?: string; name?: string } | null }>;\n }>;\n // Present when guests are requested.\n bookingGuests?: BookingGuestNode[];\n}\n\nexport interface BookingsResponse {\n sales: {\n pageInfo: { endCursor: string | null; hasNextPage: boolean };\n edges: Array<{ node: BookingNode }>;\n };\n}\n\nexport interface BookingGuestFieldResponse {\n id: string;\n text: string | null;\n fieldLocation?: { field?: { name?: string } | null } | null;\n}\n\nexport interface BookingGuestNode {\n id: string;\n name?: string | null;\n country?: string | null;\n dateOfBirth?: string | null;\n phone?: string | null;\n email?: string | null;\n isGdpr?: boolean;\n isParticipant?: boolean;\n optinSms?: boolean;\n optinMarketing?: boolean;\n postalCode?: string | null;\n fieldResponses?: BookingGuestFieldResponse[];\n}\n\nexport interface BookingGuestsResponse {\n sales: {\n edges: Array<{\n node: {\n displayId: string;\n id: string;\n bookingGuests?: BookingGuestNode[];\n primaryGuest?: BookingGuestNode | null;\n };\n }>;\n };\n}\n\nexport interface BookingPaymentsOnFileResponse {\n sales: {\n edges: Array<{\n node: {\n order?: {\n id?: string;\n displayId?: string;\n payments?: Array<{\n id: string;\n paymentSource?: { id?: string } | null;\n appliedAt: string;\n currentAmount: { amount: string; currency: string };\n refundableAmount: { amount: string; currency: string };\n }>;\n paymentSources?: Array<{ description: string; id: string; type: string }>;\n } | null;\n };\n }>;\n };\n}\n","/**\n * Pure functions mapping a raw booking node into the clean {@link Booking}\n * model. Ported from the connector's BookingConverter.\n */\nimport type {\n Booking,\n CustomQuestionAnswer,\n Guest,\n GuestMetadata,\n Price,\n ResourcePoolAssignment,\n Ticket,\n} from \"../../../models/peek/booking.js\";\nimport { normalizeBookingId } from \"./booking-queries.js\";\nimport type { BookingGuestNode, BookingNode } from \"./booking-queries.js\";\n\nconst UNKNOWN = \"unknown\";\n\nconst PEEK_PRO_DEEP_LINK_BASE = \"http://pro-app.peek.com/-/order\";\n\nconst SOURCE_SOURCE_MAP: Record<string, string> = {\n APP_REGISTRY: \"app\",\n BOOKING_IMPORTER_FUTURE: \"importer\",\n BOOKING_IMPORTER_HISTORIC: \"importer\",\n EXPEDIA: \"expedia\",\n GROUPON: \"groupon\",\n GYG: \"getyourguide\",\n HOOK: \"internal\",\n INTERNAL_TOOLS: \"internal\",\n IOS_PP: \"ios\",\n OCTO: \"octo\",\n PDC: \"peekcom\",\n PEEK_PLUS: \"peekcom\",\n PP: \"backend\",\n RWG: \"rwg\",\n SELF_SERVE: \"internal\",\n SYSTEM: \"internal\",\n VIATOR: \"viator\",\n WIDGET: \"website\",\n YELP: \"yelp\",\n};\n\nconst SOURCE_DESC_MAP: Record<string, string> = {\n APP_REGISTRY: \"App Store App\",\n BOOKING_IMPORTER_FUTURE: \"Booking Importer\",\n BOOKING_IMPORTER_HISTORIC: \"Booking Importer\",\n EXPEDIA: \"Expedia\",\n GROUPON: \"Groupon\",\n GYG: \"GetYourGuide\",\n HOOK: \"Internal\",\n INTERNAL_TOOLS: \"Internal\",\n IOS_PP: \"Peek Pro: iOS App\",\n OCTO: \"OCTO\",\n PDC: \"Peek.com\",\n PEEK_PLUS: \"Peek.com\",\n PP: \"Peek Pro: Backend\",\n RWG: \"Reserve with Google\",\n SELF_SERVE: \"Internal\",\n SYSTEM: \"Internal\",\n VIATOR: \"Viator\",\n WIDGET: \"Website Booking Flow\",\n YELP: \"Yelp\",\n};\n\n/** Converts a raw booking node into a {@link Booking}. */\nexport function fromBookingNode(\n node: BookingNode | null | undefined,\n includeGuests = false,\n includePriceBreakdown = false,\n): Booking {\n const data = node ?? {};\n const ticketQuantities = data.ticketQuantities ?? [];\n const app = data.order?.initialQuote?.source?.actor?.app ?? null;\n const sourceDetails = data.order?.initialQuote?.source?.actor?.name ?? null;\n\n const customQuestionAnswers: CustomQuestionAnswer[] = (data.questionAnswers ?? []).map(\n (answer) => {\n const base: CustomQuestionAnswer = {\n question: answer.questionText,\n answer: answer.answer,\n };\n const location = answer.questionLocationSnapshot;\n if (location && location.latitude && location.longitude) {\n base.latitude = location.latitude;\n base.longitude = location.longitude;\n }\n return base;\n },\n );\n\n const customGuestQuestionAnswers: CustomQuestionAnswer[] = Array.isArray(data.tickets)\n ? data.tickets.flatMap((ticket) =>\n Array.isArray(ticket?.questionAnswers)\n ? ticket.questionAnswers\n .filter((qa) => qa && qa.answer !== undefined && qa.questionText !== undefined)\n .map((qa) => ({ question: qa.questionText, answer: qa.answer }))\n : [],\n )\n : [];\n\n return {\n bookingId: data.id || \"\",\n displayId: data.displayId || \"\",\n\n source: sourceFromApp(app),\n sourceApp: app || UNKNOWN,\n sourceDescription: sourceDescriptionFromApp(app),\n sourceDetails,\n\n customerName: data.primaryGuest?.name || \"\",\n customerEmail: data.primaryGuest?.email || null,\n customerPhone: data.primaryGuest?.phone || null,\n\n productId: data.activitySnapshot?.id || UNKNOWN,\n productName: data.activitySnapshot?.name || UNKNOWN,\n isRentalProduct: data.activitySnapshot?.type === \"RENTAL\",\n\n timeslotId: data.timeSnapshot?.legacyId || null,\n totalTickets: ticketQuantity(ticketQuantities),\n ticketDescription: formatTickets(ticketQuantities),\n tickets: ticketsToTicketArray(ticketQuantities, includePriceBreakdown),\n\n isCanceled: data.reservationStatus === \"CANCELED\",\n isNoShow: data.fulfillmentStatusOverride?.status === \"NO_SHOW\",\n isCheckedIn: data.checkinStatus !== \"NONE\",\n isReturned: data.returnStatus !== \"NONE\",\n\n purchasedAt: data.purchasedAt || null,\n purchasedAtUtc: data.purchasedAtUtc || null,\n startsAt: data.startsAt || null,\n startsAtUtc: data.startsAtUtc || null,\n endsAt: data.endsAt || null,\n endsAtUtc: data.endsAtUtc || null,\n durationMin: durationInMin(data.startsAt || null, data.endsAt || null),\n availabilityTimeId: data.availabilityTimeId || null,\n\n portalUrl: data.bookingPortalUrl || null,\n notes: data.operatorNotes || \"\",\n\n valueDisplay: data.value?.total?.formatted || \"\",\n valueAmount: data.value?.total?.amount || \"\",\n\n outstandingBalanceAmount: data.balance?.total?.amount || \"\",\n outstandingBalanceDisplay: data.balance?.total?.formatted || \"\",\n promoCodes: data.order?.promoCodes?.map((promo) => promo.code) ?? [],\n tips: (data.tips ?? []).map((tip) => ({\n display: tip.price?.formatted || \"\",\n amount: tip.price?.amount || \"\",\n })),\n\n customQuestionAnswers,\n customGuestQuestionAnswers,\n\n resources: (data.resourcePoolAssignments ?? []).map((resource) => ({\n quantity: resource.quantity || 0,\n name: resource.resourcePool?.name || \"\",\n shortName: resource.resourcePool?.shortName || \"\",\n })),\n\n resourcePoolAssignments: mapResourcePoolAssignments(data.resourcePoolAssignments),\n\n resellerId: data.order?.channelSnapshot?.id || null,\n resellerName: resellerNameFromChannelSnapshot(data.order?.channelSnapshot),\n\n orderId: data.order?.id || \"\",\n peekProBookingDeepLink: buildPeekProBookingDeepLink(data.order?.id, data.id),\n\n convenienceFee: includePriceBreakdown ? mapPrice(data.value?.convenienceFee) : undefined,\n deposit: includePriceBreakdown ? mapPrice(data.value?.deposit) : undefined,\n discount: includePriceBreakdown ? mapPrice(data.value?.discount) : undefined,\n discountedPrice: includePriceBreakdown ? mapPrice(data.value?.discountedPrice) : undefined,\n fees: includePriceBreakdown ? mapPrice(data.value?.fees) : undefined,\n flatPartnerFee: includePriceBreakdown ? mapPrice(data.value?.flatPartnerFee) : undefined,\n price: includePriceBreakdown ? mapPrice(data.value?.price) : undefined,\n retailPrice: includePriceBreakdown ? mapPrice(data.value?.retailPrice) : undefined,\n taxes: includePriceBreakdown ? mapPrice(data.value?.taxes) : undefined,\n tipsBreakdown: includePriceBreakdown ? mapPrice(data.value?.tips) : undefined,\n\n guests: includeGuests ? convertGuests(data) : undefined,\n };\n}\n\n/** Merges a booking node's `bookingGuests` + `primaryGuest` into a guest list. */\nexport function convertGuests(data: BookingNode): Guest[] {\n const bookingGuestsNodes = Array.isArray(data.bookingGuests) ? data.bookingGuests : [];\n const primaryGuestNode = data.primaryGuest;\n const primaryId = primaryGuestNode?.id;\n\n const guests: Guest[] = [];\n for (const guestNode of bookingGuestsNodes) {\n guests.push(mapGuestNode(guestNode, primaryId ? guestNode.id === primaryId : false));\n }\n\n const hasPrimaryInGuests = primaryId\n ? bookingGuestsNodes.some((guest) => guest.id === primaryId)\n : false;\n if (!hasPrimaryInGuests && primaryGuestNode?.id) {\n guests.push(mapGuestNode(primaryGuestNode, true));\n }\n\n return guests;\n}\n\n/** Maps a single raw guest node into a {@link Guest}. */\nexport function mapGuestNode(guestNode: BookingGuestNode, isPrimary: boolean): Guest {\n const fieldResponses = Array.isArray(guestNode.fieldResponses) ? guestNode.fieldResponses : [];\n const metadata: GuestMetadata[] = fieldResponses.map((response) => ({\n id: response.id,\n name: response.fieldLocation?.field?.name ?? \"\",\n value: response.text ?? \"\",\n }));\n\n return {\n id: guestNode.id,\n name: guestNode.name ?? null,\n country: guestNode.country ?? null,\n dateOfBirth: guestNode.dateOfBirth ? new Date(guestNode.dateOfBirth) : null,\n phone: guestNode.phone ?? null,\n email: guestNode.email ?? null,\n isGdpr: Boolean(guestNode.isGdpr),\n isParticipant: Boolean(guestNode.isParticipant),\n isPrimary,\n optinSms: Boolean(guestNode.optinSms),\n optinMarketing: Boolean(guestNode.optinMarketing),\n postalCode: guestNode.postalCode ?? null,\n metadata,\n };\n}\n\n/**\n * Builds the Peek Pro app deep link from an order id and booking id. Both ids\n * are normalized (lowercased, `-` → `_`); returns `\"\"` when either is absent.\n */\nfunction buildPeekProBookingDeepLink(\n orderId: string | null | undefined,\n bookingId: string | null | undefined,\n): string {\n if (!orderId || !bookingId) return \"\";\n return `${PEEK_PRO_DEEP_LINK_BASE}%2F${normalizeBookingId(orderId)}%3FsaleId=${normalizeBookingId(bookingId)}`;\n}\n\nfunction sourceFromApp(app: string | null): string {\n if (!app) return UNKNOWN;\n return SOURCE_SOURCE_MAP[app] ?? UNKNOWN;\n}\n\nfunction sourceDescriptionFromApp(app: string | null): string {\n if (!app) return UNKNOWN;\n return SOURCE_DESC_MAP[app] ?? UNKNOWN;\n}\n\nfunction resellerNameFromChannelSnapshot(\n channelSnapshot: { name?: string; agent?: { name?: string } | null } | null | undefined,\n): string | null {\n if (!channelSnapshot) return null;\n let out = channelSnapshot.name ?? \"\";\n if (channelSnapshot.agent?.name) {\n out += \" - \" + channelSnapshot.agent.name;\n }\n return out;\n}\n\nfunction ticketsToTicketArray(\n ticketQuantities: BookingNode[\"ticketQuantities\"],\n includePriceBreakdown: boolean,\n): Ticket[] {\n if (!ticketQuantities || ticketQuantities.length === 0) return [];\n return ticketQuantities.map((ticket) => ({\n name: ticket.resourceOptionSnapshot?.name || \"Unknown\",\n quantity: ticket.quantity || 0,\n ticketId: ticket.resourceOptionSnapshot?.id || \"unknown\",\n listPrice: includePriceBreakdown ? mapPrice(ticket.value?.price) : undefined,\n totalValue: includePriceBreakdown ? mapPrice(ticket.value?.total) : undefined,\n }));\n}\n\nfunction durationInMin(startsAt: string | null, endsAt: string | null): number {\n if (!startsAt || !endsAt) return 0;\n const duration = new Date(endsAt).getTime() - new Date(startsAt).getTime();\n return Math.floor(duration / 1000 / 60);\n}\n\nfunction ticketQuantity(ticketQuantities: BookingNode[\"ticketQuantities\"]): number {\n if (!ticketQuantities || ticketQuantities.length === 0) return 0;\n return ticketQuantities.reduce((acc, ticket) => acc + (ticket.quantity || 0), 0);\n}\n\nfunction formatTickets(ticketQuantities: BookingNode[\"ticketQuantities\"]): string {\n if (!ticketQuantities || ticketQuantities.length === 0) return \"\";\n return ticketQuantities\n .map((ticket) => `${ticket.quantity || 0}x ${ticket.resourceOptionSnapshot?.name || \"Unknown\"}`)\n .join(\", \");\n}\n\nfunction mapResourcePoolAssignments(\n poolAssignments: BookingNode[\"resourcePoolAssignments\"],\n): ResourcePoolAssignment[] {\n if (!poolAssignments || poolAssignments.length === 0) return [];\n return poolAssignments.flatMap((pool) =>\n (pool.resourceAssignments ?? []).map((assignment) => ({\n id: assignment.resource?.id || \"\",\n name: assignment.resource?.name || \"\",\n })),\n );\n}\n\nfunction mapPrice(\n priceData: { amount?: string; formatted?: string } | undefined,\n): Price | undefined {\n if (!priceData || (!priceData.amount && !priceData.formatted)) {\n return undefined;\n }\n return {\n amount: priceData.amount || \"0\",\n display: priceData.formatted || \"\",\n };\n}\n","/**\n * Resolves the dedicated guests query into a merged guest list (booking guests\n * plus the primary guest when not already present).\n */\nimport type { Guest } from \"../../../models/peek/booking.js\";\nimport { mapGuestNode } from \"./booking-converter.js\";\nimport type { BookingGuestsResponse } from \"./booking-queries.js\";\n\n/** Maps a booking-guests response into a {@link Guest} list. */\nexport function fromBookingGuestsResponse(\n response: BookingGuestsResponse | undefined,\n): Guest[] {\n const firstEdge = (response?.sales?.edges ?? [])[0];\n if (!firstEdge) {\n return [];\n }\n\n const bookingNode = firstEdge.node;\n const primaryGuestNode = bookingNode.primaryGuest;\n const bookingGuestsNodes = Array.isArray(bookingNode.bookingGuests)\n ? bookingNode.bookingGuests\n : [];\n const primaryId = primaryGuestNode?.id;\n\n const guests: Guest[] = [];\n for (const guestNode of bookingGuestsNodes) {\n guests.push(mapGuestNode(guestNode, primaryId ? guestNode.id === primaryId : false));\n }\n\n const hasPrimaryInGuests = primaryId\n ? bookingGuestsNodes.some((guest) => guest.id === primaryId)\n : false;\n if (!hasPrimaryInGuests && primaryGuestNode) {\n guests.push(mapGuestNode(primaryGuestNode, true));\n }\n\n return guests;\n}\n","/**\n * Aggregates a booking's raw order payments + payment sources into the clean\n * {@link BookingPaymentsOnFile} model, grouping payments under their source.\n */\nimport type {\n BookingPaymentsOnFile,\n Payment,\n PaymentSource,\n} from \"../../../models/peek/booking-payment.js\";\nimport type { BookingPaymentsOnFileResponse } from \"./booking-queries.js\";\n\n/**\n * Maps a payments-on-file response into the aggregated result, or null when the\n * booking is not found.\n */\nexport function fromPaymentsOnFileResponse(\n response: BookingPaymentsOnFileResponse | undefined,\n bookingId: string,\n): BookingPaymentsOnFile | null {\n const firstEdge = (response?.sales?.edges ?? [])[0];\n if (!firstEdge) {\n return null;\n }\n\n const order = firstEdge.node.order;\n const orderId = order?.id ?? \"\";\n const rawPaymentSources = order?.paymentSources ?? [];\n const rawPayments = order?.payments ?? [];\n\n const paymentsBySourceId = new Map<string, Payment[]>();\n for (const payment of rawPayments) {\n const sourceId = payment.paymentSource?.id;\n if (!sourceId) continue;\n const mapped: Payment = {\n id: payment.id,\n paidAt: dateOnly(payment.appliedAt),\n currentAmount: payment.currentAmount,\n refundableAmount: payment.refundableAmount,\n };\n const existing = paymentsBySourceId.get(sourceId);\n if (existing) {\n existing.push(mapped);\n } else {\n paymentsBySourceId.set(sourceId, [mapped]);\n }\n }\n\n const paymentsOnFile: PaymentSource[] = rawPaymentSources.map((source) => {\n const payments = paymentsBySourceId.get(source.id);\n return {\n description: source.description,\n id: source.id,\n type: source.type,\n ...(payments ? { payments } : {}),\n };\n });\n\n return { bookingId, orderId, paymentsOnFile };\n}\n\nfunction dateOnly(iso: string): string {\n /* v8 ignore next -- split always yields at least one element */\n return iso.split(\"T\")[0] ?? iso;\n}\n","/**\n * Raw Peek GraphQL query, variables, and response shapes for listing the\n * add-ons (items + item options) attached to a single booking. Internal.\n *\n * The `SALES_ADDONS_QUERY` runs the `sales` query filtered by a booking's\n * display id (`filter.searchString`) and returns every item on the booking\n * together with its item options, refids, and reservation statuses — the\n * detail needed both to surface add-ons and to build add/cancel mutations.\n */\n\n/** Reservation status for a live (confirmed) item or option. */\nexport const RESERVATION_STATUS_CONFIRMED = \"CONFIRMED\";\n/** Reservation status marking an item or option as canceled. */\nexport const ADDON_OPTION_STATUS_CANCELED = \"CANCELED\";\n\n/** Page size for the sales add-ons query (a single booking, so one page). */\nconst SALES_ADDONS_PAGE_SIZE = 100;\n\n/**\n * GraphQL query fetching the items and item options for a single booking\n * matched by `filter.searchString` (the booking display id).\n */\nexport const SALES_ADDONS_QUERY = `\n query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {\n sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {\n pageInfo { endCursor hasNextPage }\n edges {\n node {\n order { id displayId }\n ... on Booking {\n displayId\n id\n refid\n reservationStatus\n items {\n id\n refid\n value { total { amount currency formatted } }\n reservationStatus\n options {\n refid\n reservationStatus\n price { amount currency formatted }\n itemOptionSnapshot { id name }\n itemSnapshot { id name }\n }\n }\n }\n }\n }\n }\n }\n`;\n\n/** Variables for {@link SALES_ADDONS_QUERY}. */\nexport interface SalesAddonsVariables {\n first: number;\n after: string | null;\n orderBy: { direction: string; field: string };\n filter: { searchString: string };\n}\n\n/** Builds the variables for the sales add-ons query from a booking display id. */\nexport function buildSalesAddonsVariables(searchString: string): SalesAddonsVariables {\n return {\n first: SALES_ADDONS_PAGE_SIZE,\n after: null,\n orderBy: { direction: \"DESC\", field: \"STARTS_AT\" },\n filter: { searchString },\n };\n}\n\n/** Raw money shape returned by the `sales` add-ons query. */\nexport interface AddonGqlPrice {\n amount: string;\n currency: string;\n formatted: string;\n}\n\nexport interface SalesAddonItemOptionNode {\n refid: string;\n reservationStatus: string;\n price: AddonGqlPrice | null;\n itemOptionSnapshot: { id: string; name: string } | null;\n itemSnapshot: { id: string; name: string } | null;\n}\n\nexport interface SalesAddonItemNode {\n id: string;\n refid: string;\n value: { total: AddonGqlPrice | null } | null;\n reservationStatus: string;\n options: SalesAddonItemOptionNode[] | null;\n}\n\nexport interface SalesAddonBookingNode {\n id: string;\n displayId: string;\n refid: string;\n reservationStatus: string;\n order: { id: string; displayId: string } | null;\n items: SalesAddonItemNode[] | null;\n}\n\nexport interface SalesAddonsResponse {\n sales: {\n pageInfo: { endCursor: string | null; hasNextPage: boolean };\n edges: Array<{ node: SalesAddonBookingNode }>;\n };\n}\n","/**\n * Pure mappers between the raw `sales` add-ons response and the add-on models.\n *\n * `parseSaleNode` produces the internal, detail-rich {@link AddonItem} model\n * (refids + reservation statuses) that the service uses to build add/cancel\n * mutations. `toBookingAddon` collapses one internal item into the clean,\n * public {@link BookingAddon}. The internal model is intentionally not exported\n * from the package's public entry point.\n */\nimport type { BookingAddon, BookingAddonOption } from \"../../../models/peek/booking-addon.js\";\nimport {\n ADDON_OPTION_STATUS_CANCELED,\n type AddonGqlPrice,\n type SalesAddonBookingNode,\n} from \"./addon-queries.js\";\n\nconst ERROR_INCONSISTENT_ADDON_ITEM_ID =\n \"Add-on group contains options with mismatched item IDs\";\n\n/** One add-on option on a booking, with the refids/statuses needed to mutate it. */\nexport interface AddonItemOption {\n itemId: string;\n optionId: string;\n itemName: string;\n optionName: string;\n optionRefid: string;\n optionReservationStatus: string;\n itemReservationStatus: string;\n itemRefid: string;\n}\n\n/** One add-on item on a booking (internal; grouped by add-on item). */\nexport interface AddonItem {\n bookingId: string;\n displayId: string;\n orderId: string;\n total: AddonGqlPrice | null;\n bookingQuoteRefid: string;\n bookingQuoteReservationStatus: string;\n addonItemOptions: AddonItemOption[];\n}\n\n/**\n * Converts a single booking node into the internal {@link AddonItem}[] model.\n * Booking-level identifiers (bookingId, displayId, orderId) are repeated on\n * each item for convenience.\n */\nexport function parseSaleNode(node: SalesAddonBookingNode): AddonItem[] {\n const bookingId = node.id || \"\";\n const displayId = node.displayId || \"\";\n const orderId = node.order?.id || \"\";\n const bookingQuoteRefid = node.refid || \"\";\n const bookingQuoteReservationStatus = node.reservationStatus || \"\";\n const items = Array.isArray(node.items) ? node.items : [];\n\n return items.map((item) => {\n const options = Array.isArray(item.options) ? item.options : [];\n const addonItemOptions: AddonItemOption[] = options.map((opt) => ({\n itemId: opt.itemSnapshot?.id || \"\",\n optionId: opt.itemOptionSnapshot?.id || \"\",\n itemName: opt.itemSnapshot?.name || \"\",\n optionName: opt.itemOptionSnapshot?.name || \"\",\n optionRefid: opt.refid || \"\",\n optionReservationStatus: opt.reservationStatus || \"\",\n itemReservationStatus: item.reservationStatus || \"\",\n itemRefid: item.refid || \"\",\n }));\n\n return {\n bookingId,\n displayId,\n orderId,\n total: item.value?.total ?? null,\n bookingQuoteRefid,\n bookingQuoteReservationStatus,\n addonItemOptions,\n };\n });\n}\n\n/**\n * Collapses one internal {@link AddonItem} (already grouped by add-on item id)\n * into a clean public {@link BookingAddon}. All of the item's options must\n * share the same item id (a data-integrity invariant); a mismatch throws.\n * Canceled options are dropped and the rest are combined by option id with a\n * quantity count. Returns `null` when no live options remain, so the caller\n * can omit the add-on entirely.\n */\nexport function toBookingAddon(item: AddonItem): BookingAddon | null {\n const options = item.addonItemOptions || [];\n if (options.length === 0) {\n return null;\n }\n\n const addonId = options[0]!.itemId;\n const addonName = options[0]!.itemName;\n\n if (options.some((opt) => opt.itemId !== addonId)) {\n throw new Error(ERROR_INCONSISTENT_ADDON_ITEM_ID);\n }\n\n const grouped = new Map<string, BookingAddonOption>();\n options\n .filter((opt) => opt.optionReservationStatus !== ADDON_OPTION_STATUS_CANCELED)\n .forEach((opt) => {\n const existing = grouped.get(opt.optionId);\n if (existing) {\n existing.quantity += 1;\n } else {\n grouped.set(opt.optionId, {\n addonOptionId: opt.optionId,\n addonOptionName: opt.optionName,\n quantity: 1,\n });\n }\n });\n\n const addonOptions = Array.from(grouped.values());\n if (addonOptions.length === 0) {\n return null;\n }\n\n return { addonId, addonName, total: item.total, addonOptions };\n}\n","/**\n * Pure resolution of caller-supplied custom-question answers against an\n * activity's actual custom questions. No I/O — the questions are fetched by the\n * service and passed in, so this whole module is unit-testable without a client\n * (and, deliberately, without minting the answer `refid`s, which the service\n * adds afterward).\n *\n * Each {@link CustomQuestionAnswerInput} is matched to exactly one question and\n * its `value` validated/resolved by question type into the shape the quote\n * mutation expects. Any ambiguity or mismatch throws before the booking is made.\n */\nimport type {\n CustomQuestion,\n CustomQuestionOption,\n} from \"../../../models/peek/custom-question.js\";\nimport type { CustomQuestionAnswerInput } from \"../../../models/peek/booking.js\";\n\n/** Peek question-type values this resolver knows how to answer. */\nexport const QUESTION_TYPE_CHECK_BOX = \"CHECK_BOX\";\nexport const QUESTION_TYPE_TEXT = \"TEXT\";\nexport const QUESTION_TYPE_SELECT_ONE = \"SELECT_ONE\";\nexport const QUESTION_TYPE_LOCATION = \"LOCATION\";\n\n/** A `cq_…` question id vs. free-text; a `cqao_…` option id vs. an option label. */\nconst QUESTION_ID_REGEX = /^cq_[a-z0-9]+$/;\nconst OPTION_ID_REGEX = /^cqao_[a-z0-9]+$/;\n\n/**\n * Whether `idOrText` is a custom-question id (`cq_…`) rather than free-text.\n * The service uses this to decide whether it must fetch the activity's questions:\n * a by-name answer always needs the list to resolve, a by-id answer does not when\n * unknown ids are being accepted (see `acceptAllIds`).\n */\nexport function isCustomQuestionId(idOrText: string): boolean {\n return QUESTION_ID_REGEX.test(idOrText);\n}\n\n/** Checkbox truthiness — `value` (lowercased) must be one of the valid set. */\nconst CHECKBOX_TRUE = new Set([\"yes\", \"true\"]);\nconst CHECKBOX_VALID = new Set([\"yes\", \"no\", \"true\", \"false\"]);\n\n/** Display text the gateway expects in `questionAnswerText` for a checkbox. */\nconst CHECKBOX_TEXT_TRUE = \"Yes\";\nconst CHECKBOX_TEXT_FALSE = \"No\";\n\n// ─── Error messages ──────────────────────────────────────────────────────────\nconst errUnknownQuestionId = (v: string): string =>\n `No custom question matches id \"${v}\" for this activity`;\nconst errNoTextMatch = (v: string): string =>\n `No custom question matches text \"${v}\" for this activity`;\nconst errAmbiguousText = (v: string): string =>\n `Custom question text \"${v}\" matches more than one question`;\nconst errPerGuestUnsupported = (id: string): string =>\n `Per-guest custom question \"${id}\" is not yet supported`;\nconst errUnsupportedType = (type: string, id: string): string =>\n `Custom question \"${id}\" has unsupported type \"${type}\"`;\nconst errInvalidCheckbox = (v: string, id: string): string =>\n `Checkbox answer for question \"${id}\" must be yes/no/true/false, got \"${v}\"`;\nconst errUnknownOptionId = (v: string, id: string): string =>\n `No option matches id \"${v}\" for question \"${id}\"`;\nconst errNoOptionMatch = (v: string, id: string): string =>\n `No option matches \"${v}\" for question \"${id}\"`;\nconst errAmbiguousOption = (v: string, id: string): string =>\n `Option \"${v}\" matches more than one option for question \"${id}\"`;\nconst errMissingRequired = (text: string, id: string): string =>\n `Custom question \"${text}\" (${id}) is required but was not answered`;\n\n/**\n * A resolved answer, minus the `refid` the service mints. `questionAnswerText`\n * is always set (the gateway requires it): the raw value for text, the exact\n * option label for select-one/location, and `\"Yes\"`/`\"No\"` for a checkbox. The\n * type-specific field (`questionAnswerOptionId` / `isChecked`) is set in\n * addition, per the question's type.\n */\nexport interface ResolvedCustomAnswer {\n questionId: string;\n questionAnswerText: string;\n questionAnswerOptionId?: string;\n isChecked?: boolean;\n}\n\n/** Lowercases and strips non-alphanumerics for lenient matching. */\nfunction normalize(value: string): string {\n return value.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n}\n\n/**\n * Finds the one question an input targets, by id or by lenient text match.\n * Returns `null` (rather than throwing) for an unknown `cq_…` id when\n * `acceptAllIds` is set — the caller then accepts the id blindly as a text\n * answer. A by-name input is always resolved against the list (there is no id to\n * accept), so `acceptAllIds` never relaxes an unmatched/ambiguous text match.\n */\nfunction resolveQuestion(\n idOrText: string,\n questions: CustomQuestion[],\n acceptAllIds: boolean,\n): CustomQuestion | null {\n if (QUESTION_ID_REGEX.test(idOrText)) {\n const byId = questions.find((question) => question.id === idOrText);\n if (!byId) {\n if (acceptAllIds) return null;\n throw new Error(errUnknownQuestionId(idOrText));\n }\n return byId;\n }\n const target = normalize(idOrText);\n const matches = questions.filter(\n (question) => normalize(question.questionText) === target,\n );\n if (matches.length === 0) throw new Error(errNoTextMatch(idOrText));\n if (matches.length > 1) throw new Error(errAmbiguousText(idOrText));\n return matches[0]!;\n}\n\n/** Finds the one option a value targets, by id or by lenient label match. */\nfunction resolveOption(\n value: string,\n question: CustomQuestion,\n): CustomQuestionOption {\n if (OPTION_ID_REGEX.test(value)) {\n const byId = question.options.find((option) => option.id === value);\n if (!byId) throw new Error(errUnknownOptionId(value, question.id));\n return byId;\n }\n const target = normalize(value);\n const matches = question.options.filter(\n (option) => normalize(option.value) === target,\n );\n if (matches.length === 0) throw new Error(errNoOptionMatch(value, question.id));\n if (matches.length > 1) throw new Error(errAmbiguousOption(value, question.id));\n return matches[0]!;\n}\n\n/** Resolves a single answer input against the matched question's type. */\nfunction resolveOne(\n answer: CustomQuestionAnswerInput,\n questions: CustomQuestion[],\n acceptAllIds: boolean,\n): ResolvedCustomAnswer {\n const question = resolveQuestion(answer.questionIdOrText, questions, acceptAllIds);\n // An unknown id accepted blindly (acceptAllIds): there is no question\n // definition to type-check against, so pass the id and value through as a\n // plain text answer.\n if (!question) {\n return { questionId: answer.questionIdOrText, questionAnswerText: answer.value };\n }\n // Per-guest answers require per-guest wiring the quote payload does not carry\n // yet — reject rather than silently drop the distinction.\n if (question.perGuest) {\n throw new Error(errPerGuestUnsupported(question.id));\n }\n switch (question.questionType) {\n case QUESTION_TYPE_CHECK_BOX: {\n const normalized = answer.value.trim().toLowerCase();\n if (!CHECKBOX_VALID.has(normalized)) {\n throw new Error(errInvalidCheckbox(answer.value, question.id));\n }\n const isChecked = CHECKBOX_TRUE.has(normalized);\n // The gateway requires questionAnswerText even for a checkbox.\n return {\n questionId: question.id,\n isChecked,\n questionAnswerText: isChecked ? CHECKBOX_TEXT_TRUE : CHECKBOX_TEXT_FALSE,\n };\n }\n case QUESTION_TYPE_TEXT:\n return { questionId: question.id, questionAnswerText: answer.value };\n case QUESTION_TYPE_SELECT_ONE:\n case QUESTION_TYPE_LOCATION: {\n // Select the option only — Peek applies each location option's configured\n // lat/long. questionAnswerText must be the option's exact current label.\n const option = resolveOption(answer.value, question);\n return {\n questionId: question.id,\n questionAnswerOptionId: option.id,\n questionAnswerText: option.value,\n };\n }\n default:\n throw new Error(errUnsupportedType(question.questionType, question.id));\n }\n}\n\n/** Options controlling how the answer set as a whole is validated. */\nexport interface ResolveCustomQuestionOptions {\n /**\n * When `true`, every question the activity marks `isRequired` must have an\n * answer — resolution throws for the first required question left unanswered.\n * Per-guest questions are excluded (they cannot be answered here anyway).\n */\n requireRequired?: boolean;\n /**\n * When `true`, an answer identified by a `cq_…` id that is **not** in the\n * activity's question list is accepted as-is (passed through as a text answer)\n * instead of throwing. By-name answers are unaffected — they still must match a\n * question, since there is no id to accept. Default: `false`.\n */\n acceptAllIds?: boolean;\n}\n\n/**\n * Resolves every caller-supplied answer against the activity's custom questions,\n * throwing on the first unmatched question, ambiguous match, or invalid value.\n * The returned objects carry no `refid` — the service adds one per answer.\n *\n * With `requireRequired`, the resolved set is additionally checked for coverage:\n * any required, non-per-guest question with no answer throws. This check runs\n * even when `answers` is empty, so an activity with unanswered required\n * questions fails rather than booking without them.\n *\n * With `acceptAllIds`, an answer whose `cq_…` id is not in `questions` is\n * accepted as a plain text answer instead of throwing.\n */\nexport function resolveCustomQuestionAnswers(\n answers: CustomQuestionAnswerInput[],\n questions: CustomQuestion[],\n options?: ResolveCustomQuestionOptions,\n): ResolvedCustomAnswer[] {\n const acceptAllIds = options?.acceptAllIds ?? false;\n const resolved = answers.map((answer) => resolveOne(answer, questions, acceptAllIds));\n if (options?.requireRequired) {\n assertRequiredAnswered(resolved, questions);\n }\n return resolved;\n}\n\n/** Throws for the first required, non-per-guest question left unanswered. */\nfunction assertRequiredAnswered(\n resolved: ResolvedCustomAnswer[],\n questions: CustomQuestion[],\n): void {\n const answered = new Set(resolved.map((answer) => answer.questionId));\n for (const question of questions) {\n if (question.isRequired && !question.perGuest && !answered.has(question.id)) {\n throw new Error(errMissingRequired(question.questionText, question.id));\n }\n }\n}\n","/**\n * Booking operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getBookingService}.\n */\nimport { randomUUID } from \"node:crypto\";\n\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type { ProductService } from \"../products/product-service.js\";\nimport {\n resolveAccessOptions,\n type AccessOptions,\n} from \"../../../access-options.js\";\nimport { PiiAccessDisabledError } from \"../../../errors.js\";\nimport type {\n Booking,\n BookingReadOptions,\n BookingTimeRangeSearch,\n CreateBookingInput,\n CreatedBooking,\n Guest,\n NoteMode,\n} from \"../../../models/peek/booking.js\";\nimport { ADD_ON_PRODUCT_TYPE } from \"../../../models/peek/product.js\";\nimport type {\n BookingPaymentsOnFile,\n InvoiceLinkResult,\n MakePaymentInput,\n MakePaymentResult,\n RefundInput,\n RefundResult,\n} from \"../../../models/peek/booking-payment.js\";\nimport type {\n BookingAddons,\n BookingAddonsMutationResult,\n} from \"../../../models/peek/booking-addon.js\";\nimport { fromBookingNode } from \"./booking-converter.js\";\nimport { fromBookingGuestsResponse } from \"./booking-guest-converter.js\";\nimport { fromPaymentsOnFileResponse } from \"./payments-on-file-converter.js\";\nimport {\n type AddonItem,\n parseSaleNode,\n toBookingAddon,\n} from \"./addon-converter.js\";\nimport {\n isCustomQuestionId,\n resolveCustomQuestionAnswers,\n} from \"./custom-question-answer.js\";\nimport {\n ADDON_OPTION_STATUS_CANCELED,\n RESERVATION_STATUS_CONFIRMED,\n SALES_ADDONS_QUERY,\n buildSalesAddonsVariables,\n type SalesAddonsResponse,\n} from \"./addon-queries.js\";\nimport {\n AMEND_ORDER_MUTATION,\n APPLY_PAYMENT_TO_ORDER_MUTATION,\n APPLY_REFUND_TO_ORDER_MUTATION,\n BOOKING_PAYMENTS_ON_FILE_QUERY,\n CANCEL_BOOKING_MUTATION,\n CREATE_INVOICE_LINK_MUTATION,\n CREATE_ORDER_FROM_QUOTE_MUTATION,\n CREATE_QUOTE_FROM_ORDER_MUTATION,\n CREATE_QUOTE_V2_MUTATION,\n SEARCH_BY_PURCHASE_DATE,\n UPDATE_BOOKING_CHECKIN_MUTATION,\n UPDATE_OPERATOR_NOTES_MUTATION,\n UPDATE_QUOTE_V2_MUTATION,\n buildBookingGuestsQuery,\n buildBookingsListingQuery,\n buildBookingsVariables,\n normalizeBookingId,\n type AmendOrderResponse,\n type ApplyPaymentToOrderResponse,\n type ApplyRefundToOrderResponse,\n type BookingGuestsResponse,\n type BookingPaymentsOnFileResponse,\n type BookingsResponse,\n type CreateInvoiceLinkResponse,\n type CreateOrderFromQuoteResponse,\n type CreateQuoteFromOrderResponse,\n type CreateQuoteV2Response,\n type UpdateQuoteV2Response,\n} from \"./booking-queries.js\";\n\n/** Default page size for cursor-paginated bookings. */\nconst DEFAULT_PAGE_SIZE = 50;\n/** Default note used when cancelling without an explicit reason. */\nconst DEFAULT_CANCEL_NOTE = \"Canceled\";\n/** Default customer message attached to a charge. */\nconst DEFAULT_CUSTOMER_MESSAGE = \"Charge initiated via API\";\n\n// Booking/order ids come in two forms: a lowercase db id with `_`\n// (`b_abc123` / `o_abc123`) and an uppercase display id with `-`\n// (`B-ABC123` / `O-ABC123`). Bookings are prefixed `b`, orders `o`.\nconst BOOKING_DB_ID_REGEX = /^b_[a-z0-9]+$/;\nconst BOOKING_DISPLAY_ID_REGEX = /^B-[A-Z0-9]+$/;\nconst ORDER_DB_ID_REGEX = /^o_[a-z0-9]+$/;\nconst ORDER_DISPLAY_ID_REGEX = /^O-[A-Z0-9]+$/;\nconst PAYMENT_SOURCE_PREFIX = \"ps_\";\nconst PAYMENT_ID_PREFIX = \"pmt_\";\nconst ALLOWED_PAYMENT_SOURCE_IDS = [\"cash/cash\", \"custom/other\", \"custom/voucher\"];\nconst CURRENCY_CODE_REGEX = /^[A-Z]{3}$/;\n\n/** Result of cancelling a booking. */\nexport interface CancelBookingResult {\n id: string;\n displayId: string;\n reservationStatus: string;\n}\n\ninterface CancelBookingResponse {\n cancelBooking?: { booking?: CancelBookingResult | null } | null;\n}\n\n/** Tuning options for a {@link BookingService}. */\nexport interface BookingServiceOptions {\n /** Page size for cursor pagination. Default: 50. */\n pageSize?: number;\n /** Cross-cutting access options (PII exposure). Default: PII off. */\n accessOptions?: AccessOptions;\n}\n\n/** Dependencies the {@link BookingService} composes for add-on resolution. */\nexport interface BookingServiceDeps {\n productService: ProductService;\n}\n\n/** Input for adding or removing an add-on on a booking. */\nexport interface AddAddonInput {\n /** The add-on (item option) id. */\n addonOptionId?: string;\n /**\n * @deprecated Use `addonOptionId`. Still accepted for backwards\n * compatibility; treated as `addonOptionId` when `addonOptionId` is absent.\n */\n addonId?: string;\n /** Quantity as a positive integer string. */\n quantity: string;\n}\n\nconst ERROR_ADDON_OPTION_ID_REQUIRED = \"addonOptionId is required\";\nconst ERROR_QUANTITY_INVALID = \"quantity must be a positive integer string\";\nconst ERROR_INVALID_BOOKING_ID =\n \"bookingId is required and must be a valid booking id, e.g. 'b_abc123' or 'B-ABC123'\";\nconst ERROR_INVALID_ORDER_ID =\n \"orderId is required and must be a valid order id, e.g. 'o_abc123' or 'O-ABC123'\";\nconst ERROR_BOOKING_NOT_FOUND = \"Booking not found\";\nconst ERROR_MULTIPLE_BOOKINGS_FOUND =\n \"Expected exactly one booking for the provided bookingId\";\nconst ERROR_NO_ADDON_OPTION_TO_REMOVE =\n \"No confirmed add-on option matching addonOptionId was found on the booking\";\nconst ERROR_CREATE_QUOTE_FAILED = \"Failed to create quote from order\";\nconst ERROR_UPDATE_QUOTE_FAILED = \"Failed to update quote with add-on\";\nconst ERROR_AMEND_ORDER_FAILED = \"Failed to amend order with add-on\";\n\nexport class BookingService {\n private readonly pageSize: number;\n /** Whether customer PII is requested and payment operations are allowed. */\n private readonly fullCustomerAccess: boolean;\n\n constructor(\n private readonly client: GraphQLClient,\n private readonly deps: BookingServiceDeps,\n options: BookingServiceOptions = {},\n ) {\n this.pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;\n this.fullCustomerAccess = resolveAccessOptions(options.accessOptions).fullCustomerAccess;\n }\n\n /**\n * Throws a {@link PiiAccessDisabledError} for `operation` when this service was\n * created without `fullCustomerAccess` — used to gate payment and booking-modification\n * operations that touch customer financial data.\n */\n private assertPiiEnabled(operation: string): void {\n if (!this.fullCustomerAccess) {\n throw new PiiAccessDisabledError(operation);\n }\n }\n\n /**\n * Returns a single booking by id, or null when not found. The `bookingId` is\n * normalized internally (lowercased, `-` → `_`), so `B-ABC123` and `b_abc123`\n * resolve to the same booking.\n *\n * @example\n * ```ts\n * const bookings = peek.getBookingService();\n * const booking = await bookings.getById(\"b_abc123\", {\n * includeGuests: true,\n * includePriceBreakdown: true,\n * });\n * if (booking) console.log(booking.displayId, booking.outstandingBalanceAmount);\n * ```\n */\n async getById(\n bookingId: string,\n options: BookingReadOptions = {},\n ): Promise<Booking | null> {\n assertBookingId(bookingId);\n const includeGuests = options.includeGuests ?? false;\n const includePriceBreakdown = options.includePriceBreakdown ?? false;\n\n const body: GraphQLBody<BookingsResponse> =\n await this.client.request<BookingsResponse>(\n SALES_ENDPOINT,\n buildBookingsListingQuery(includeGuests, includePriceBreakdown, this.fullCustomerAccess),\n buildBookingsVariables({\n pageSize: this.pageSize,\n after: null,\n bookingId: normalizeBookingId(bookingId),\n }),\n );\n\n const firstEdge = (body.data?.sales?.edges ?? [])[0];\n if (!firstEdge) {\n return null;\n }\n return fromBookingNode(firstEdge.node, includeGuests, includePriceBreakdown);\n }\n\n /** Returns all bookings matching a time range (paginated). */\n async searchByTimeRange(input: BookingTimeRangeSearch): Promise<Booking[]> {\n const includeGuests = input.includeGuests ?? false;\n const includePriceBreakdown = input.includePriceBreakdown ?? false;\n\n return this.fetchPaginated(\n buildBookingsListingQuery(includeGuests, includePriceBreakdown, this.fullCustomerAccess),\n {\n startDateTime: input.start,\n endDateTime: input.end,\n searchBy: input.searchBy ?? SEARCH_BY_PURCHASE_DATE,\n productId: input.productId,\n email: input.email,\n searchString: input.searchString,\n },\n includeGuests,\n includePriceBreakdown,\n );\n }\n\n /** Returns all bookings on a timeslot (paginated). */\n async searchByTimeslot(\n timeslotId: string,\n options: BookingReadOptions = {},\n ): Promise<Booking[]> {\n const includeGuests = options.includeGuests ?? false;\n const includePriceBreakdown = options.includePriceBreakdown ?? false;\n\n return this.fetchPaginated(\n buildBookingsListingQuery(includeGuests, includePriceBreakdown, this.fullCustomerAccess),\n { timeslotId },\n includeGuests,\n includePriceBreakdown,\n );\n }\n\n /** Returns the guests on a booking (primary guest included). */\n async getGuests(bookingId: string): Promise<Guest[]> {\n assertBookingId(bookingId);\n const body: GraphQLBody<BookingGuestsResponse> =\n await this.client.request<BookingGuestsResponse>(\n SALES_ENDPOINT,\n buildBookingGuestsQuery(this.fullCustomerAccess),\n buildBookingsVariables({\n pageSize: this.pageSize,\n after: null,\n bookingId: normalizeBookingId(bookingId),\n }),\n );\n return fromBookingGuestsResponse(body.data);\n }\n\n /** Returns the payments on file for a booking, or null when not found. */\n async getPaymentsOnFile(bookingId: string): Promise<BookingPaymentsOnFile | null> {\n this.assertPiiEnabled(\"getPaymentsOnFile\");\n assertBookingId(bookingId);\n const normalized = normalizeBookingId(bookingId);\n const body: GraphQLBody<BookingPaymentsOnFileResponse> =\n await this.client.request<BookingPaymentsOnFileResponse>(\n SALES_ENDPOINT,\n BOOKING_PAYMENTS_ON_FILE_QUERY,\n buildBookingsVariables({ pageSize: this.pageSize, after: null, bookingId: normalized }),\n );\n return fromPaymentsOnFileResponse(body.data, normalized);\n }\n\n /**\n * Appends to (or overwrites) a booking's operator notes. Returns the updated\n * booking, or null when the booking is not found.\n */\n async appendNote(\n bookingId: string,\n note: string,\n mode: NoteMode = \"append\",\n ): Promise<Booking | null> {\n assertBookingId(bookingId);\n const normalized = normalizeBookingId(bookingId);\n const booking = await this.getById(normalized);\n if (!booking) {\n return null;\n }\n\n const newNote =\n mode === \"overwrite\" || !booking.notes ? note : `${booking.notes}\\n${note}`;\n\n await this.client.request(SALES_ENDPOINT, UPDATE_OPERATOR_NOTES_MUTATION, {\n input: { id: normalized, operatorNotes: newNote },\n });\n\n booking.notes = newNote;\n return booking;\n }\n\n /**\n * Sets a booking's check-in status. Returns the refreshed booking, or null\n * when not found.\n */\n async setCheckinStatus(\n bookingId: string,\n checkedIn: boolean,\n ): Promise<Booking | null> {\n assertBookingId(bookingId);\n const normalized = normalizeBookingId(bookingId);\n const checkedInAt = checkedIn ? new Date().toISOString() : null;\n\n await this.client.request(SALES_ENDPOINT, UPDATE_BOOKING_CHECKIN_MUTATION, {\n input: { id: normalized, checkedInAt },\n });\n\n return this.getById(normalized);\n }\n\n /** Cancels a booking and returns its id/displayId/status. */\n async cancel(\n bookingId: string,\n notes: string = DEFAULT_CANCEL_NOTE,\n ): Promise<CancelBookingResult> {\n assertBookingId(bookingId);\n const body: GraphQLBody<CancelBookingResponse> =\n await this.client.request<CancelBookingResponse>(\n SALES_ENDPOINT,\n CANCEL_BOOKING_MUTATION,\n { input: { bookingId: normalizeBookingId(bookingId), notes } },\n );\n\n const booking = body.data?.cancelBooking?.booking;\n if (!booking) {\n throw new Error(\"No booking data returned from cancelBooking\");\n }\n return {\n id: booking.id,\n displayId: booking.displayId,\n reservationStatus: booking.reservationStatus,\n };\n }\n\n /**\n * Charges a booking. Validates input, resolves the order + payment source via\n * payments-on-file, then applies the payment. The `idempotencyKey` is passed\n * through to Peek.\n *\n * @example\n * ```ts\n * const result = await peek.getBookingService().makePayment({\n * bookingId: \"b_abc123\",\n * paymentSourceId: \"custom/other\", // or a \"ps_…\" source on file\n * amount: \"25.00\",\n * currency: \"USD\",\n * idempotencyKey: crypto.randomUUID(),\n * });\n * console.log(result.transactionId);\n * ```\n *\n * @throws {Error} when `paymentSourceId` is missing or not a `ps_…` id / one\n * of `cash/cash`, `custom/other`, `custom/voucher`; when `amount` is not a\n * valid number; when `currency` is not a 3-letter uppercase code; when\n * `idempotencyKey` is empty; when `bookingId` is not a valid booking id\n * (`b_…`/`B-…`); when the booking or payment source is not found; or when the\n * charge fails.\n */\n async makePayment(input: MakePaymentInput): Promise<MakePaymentResult> {\n this.assertPiiEnabled(\"makePayment\");\n this.validatePaymentInput(input);\n const normalized = normalizeBookingId(input.bookingId);\n\n const onFile = await this.getPaymentsOnFile(normalized);\n if (!onFile) {\n throw new Error(\"Booking not found\");\n }\n if (!onFile.paymentsOnFile.some((source) => source.id === input.paymentSourceId)) {\n throw new Error(\"paymentSourceId not found for this booking\");\n }\n\n const customerMessage = input.customerMessage\n ? `${DEFAULT_CUSTOMER_MESSAGE} (${input.customerMessage})`\n : DEFAULT_CUSTOMER_MESSAGE;\n\n const body: GraphQLBody<ApplyPaymentToOrderResponse> =\n await this.client.request<ApplyPaymentToOrderResponse>(\n SALES_ENDPOINT,\n APPLY_PAYMENT_TO_ORDER_MUTATION,\n {\n input: {\n amount: { amount: input.amount, currency: input.currency },\n orderId: onFile.orderId,\n paymentSourceId: input.paymentSourceId,\n idempotencyKey: input.idempotencyKey,\n customerMessage,\n scopedTo: [normalized],\n },\n },\n );\n\n const result = body.data?.applyPaymentToOrder;\n if (result?.errors && result.errors.length > 0) {\n throw new Error(`Payment failed: ${result.errors[0]!.detail}`);\n }\n\n return {\n transactionId: result?.transactionId ?? \"\",\n bookingId: normalized,\n orderId: onFile.orderId,\n amount: input.amount,\n currency: input.currency,\n paymentSourceId: input.paymentSourceId,\n };\n }\n\n /**\n * Refunds a booking payment. Validates input, resolves the order + payment via\n * payments-on-file, then applies the refund.\n */\n async refund(input: RefundInput): Promise<RefundResult> {\n this.assertPiiEnabled(\"refund\");\n this.validateRefundInput(input);\n const normalized = normalizeBookingId(input.bookingId);\n\n const onFile = await this.getPaymentsOnFile(normalized);\n if (!onFile) {\n throw new Error(\"Booking not found\");\n }\n const paymentExists = onFile.paymentsOnFile.some((source) =>\n (source.payments ?? []).some((payment) => payment.id === input.paymentId),\n );\n if (!paymentExists) {\n throw new Error(\"paymentId not found for this booking\");\n }\n\n const body: GraphQLBody<ApplyRefundToOrderResponse> =\n await this.client.request<ApplyRefundToOrderResponse>(\n SALES_ENDPOINT,\n APPLY_REFUND_TO_ORDER_MUTATION,\n {\n input: {\n amount: { amount: input.amount, currency: input.currency },\n orderId: onFile.orderId,\n paymentId: input.paymentId,\n idempotencyKey: input.idempotencyKey,\n scopedTo: [normalized],\n },\n },\n );\n\n const result = body.data?.applyRefundToOrder;\n if (result?.errors && result.errors.length > 0) {\n throw new Error(`Refund failed: ${result.errors[0]!.detail}`);\n }\n\n return {\n transactionId: result?.transactionId ?? \"\",\n bookingId: normalized,\n orderId: onFile.orderId,\n amount: input.amount,\n currency: input.currency,\n paymentId: input.paymentId,\n };\n }\n\n /** Creates an invoice link for a booking's order. */\n async createInvoiceLink(bookingId: string): Promise<InvoiceLinkResult> {\n this.assertPiiEnabled(\"createInvoiceLink\");\n assertBookingId(bookingId);\n const normalized = normalizeBookingId(bookingId);\n\n const booking = await this.getById(normalized);\n if (!booking || !booking.orderId) {\n throw new Error(\"Booking not found\");\n }\n const orderId = normalizeBookingId(booking.orderId);\n\n const body: GraphQLBody<CreateInvoiceLinkResponse> =\n await this.client.request<CreateInvoiceLinkResponse>(\n SALES_ENDPOINT,\n CREATE_INVOICE_LINK_MUTATION,\n { input: { orderId } },\n );\n\n const url = body.data?.createInvoiceLink?.invoiceLink?.url;\n if (!url) {\n throw new Error(\"Failed to create invoice link\");\n }\n return { bookingId: normalized, orderId, invoiceLink: url };\n }\n\n /** Returns the add-ons on a booking, grouped by add-on item (clean model). */\n async listAddons(bookingId: string): Promise<BookingAddons> {\n assertBookingId(bookingId);\n const { items, displayId, orderId, normalizedBookingId } =\n await this.fetchBookingSale(bookingId);\n\n const addons = items\n .map((item) => toBookingAddon(item))\n .filter((addon): addon is NonNullable<typeof addon> => addon !== null);\n\n return {\n bookingId: items[0]?.bookingId || normalizedBookingId,\n displayId: items[0]?.displayId || displayId,\n orderId: items[0]?.orderId || orderId,\n addons,\n };\n }\n\n /**\n * Adds an add-on to a booking via createQuoteFromOrder → updateQuoteV2 →\n * amendOrder. Lists the booking's add-ons first to derive the order id and\n * reuse an existing add-on refid; resolves the add-on's parent item via the\n * product service. Returns the booking's add-ons after the change.\n *\n * `quantity` is a **positive-integer string** (\"1\", \"2\", …); one add-on\n * itemOption is created per unit. `addonOptionId` is the add-on's item-option\n * id (a ticket id on an `ADD_ON_PRODUCT_TYPE` product from\n * {@link ProductService.getAllProducts}).\n *\n * @example\n * ```ts\n * const result = await peek.getBookingService().addAddon(\"b_abc123\", {\n * addonOptionId: \"io_helmet\",\n * quantity: \"2\",\n * });\n * console.log(result.updatedBookingAddons.addons);\n * ```\n *\n * @throws {Error} when `addonOptionId` is missing, `quantity` is not a\n * positive-integer string, the add-on is not found on any product, or any of\n * the underlying quote/order mutations fail.\n */\n async addAddon(\n bookingId: string,\n input: AddAddonInput,\n ): Promise<BookingAddonsMutationResult> {\n this.assertPiiEnabled(\"addAddon\");\n assertBookingId(bookingId);\n const addonOptionId = (input?.addonOptionId || input?.addonId || \"\").trim();\n if (!addonOptionId) {\n throw new Error(ERROR_ADDON_OPTION_ID_REQUIRED);\n }\n const quantity = parseQuantity(input?.quantity);\n if (quantity === null) {\n throw new Error(ERROR_QUANTITY_INVALID);\n }\n\n // List the booking's existing add-ons first — this yields the order id (no\n // separate lookup) and lets us reuse an existing add-on refid instead of\n // minting a new one. Resolve the add-on's parent item in parallel.\n const [sale, parentItemId] = await Promise.all([\n this.fetchBookingSale(bookingId),\n this.resolveParentItemId(addonOptionId),\n ]);\n\n const normalizedOrderId = normalizeBookingId(sale.orderId);\n\n // Reuse the bookingQuote item refid when this parent item is already on the\n // booking under a non-canceled add-on; otherwise mint a fresh refid.\n const existingItemRefid = sale.items\n .filter(\n (item) => item.bookingQuoteReservationStatus !== ADDON_OPTION_STATUS_CANCELED,\n )\n .flatMap((item) => item.addonItemOptions)\n .find((opt) => opt.itemId === parentItemId)?.itemRefid;\n const addonRefid = existingItemRefid || randomUUID();\n\n // Step 1 — create a quote from the order.\n const { quoteId, saleQuoteRefid } =\n await this.createQuoteFromOrderOrThrow(normalizedOrderId);\n if (!saleQuoteRefid) {\n throw new Error(ERROR_CREATE_QUOTE_FAILED);\n }\n\n // Step 2 — add the add-on to the quote (one new itemOption per unit).\n const itemOptions = Array.from({ length: quantity }, () => ({\n itemOptionId: addonOptionId,\n reservationStatus: RESERVATION_STATUS_CONFIRMED,\n refid: randomUUID(),\n }));\n await this.updateQuoteOrThrow(quoteId, {\n bookingQuotes: [\n {\n refid: saleQuoteRefid,\n addons: [\n {\n itemOptions,\n itemId: parentItemId,\n reservationStatus: RESERVATION_STATUS_CONFIRMED,\n refid: addonRefid,\n },\n ],\n reservationStatus: RESERVATION_STATUS_CONFIRMED,\n },\n ],\n });\n\n // Step 3 — amend the order with the updated quote.\n await this.amendOrderOrThrow(quoteId, normalizedOrderId);\n\n return { updatedBookingAddons: await this.listAddons(bookingId) };\n }\n\n /**\n * Removes (cancels) add-on options from a booking. Lists the booking's\n * add-ons first to get the order id and the existing item/option refids, then\n * issues the same three mutations as {@link addAddon} but with cancellation\n * variables. Returns the booking's add-ons after the change.\n */\n async removeAddon(\n bookingId: string,\n input: AddAddonInput,\n ): Promise<BookingAddonsMutationResult> {\n this.assertPiiEnabled(\"removeAddon\");\n assertBookingId(bookingId);\n const addonOptionId = (input?.addonOptionId || input?.addonId || \"\").trim();\n if (!addonOptionId) {\n throw new Error(ERROR_ADDON_OPTION_ID_REQUIRED);\n }\n const quantity = parseQuantity(input?.quantity);\n if (quantity === null) {\n throw new Error(ERROR_QUANTITY_INVALID);\n }\n\n const sale = await this.fetchBookingSale(bookingId);\n const normalizedOrderId = normalizeBookingId(sale.orderId);\n\n const { bookingQuotes, canceledCount } = buildCancellation(\n sale.items,\n addonOptionId,\n quantity,\n );\n if (canceledCount === 0) {\n throw new Error(ERROR_NO_ADDON_OPTION_TO_REMOVE);\n }\n\n // Step 1 — create a quote from the order (only the quote id is needed; the\n // refids come from the existing booking, not the quote).\n const { quoteId } = await this.createQuoteFromOrderOrThrow(normalizedOrderId);\n\n // Step 2 — update the quote, canceling the selected options.\n await this.updateQuoteOrThrow(quoteId, { bookingQuotes });\n\n // Step 3 — amend the order.\n await this.amendOrderOrThrow(quoteId, normalizedOrderId);\n\n return { updatedBookingAddons: await this.listAddons(bookingId) };\n }\n\n /**\n * Runs the sales add-ons query for a booking, validates that exactly one\n * booking matched, and parses the node into the internal model.\n */\n private async fetchBookingSale(bookingId: string): Promise<{\n items: AddonItem[];\n displayId: string;\n orderId: string;\n normalizedBookingId: string;\n }> {\n const body: GraphQLBody<SalesAddonsResponse> =\n await this.client.request<SalesAddonsResponse>(\n SALES_ENDPOINT,\n SALES_ADDONS_QUERY,\n buildSalesAddonsVariables(bookingId),\n );\n\n const edges = body.data?.sales?.edges ?? [];\n if (edges.length === 0) {\n throw new Error(ERROR_BOOKING_NOT_FOUND);\n }\n if (edges.length > 1) {\n throw new Error(ERROR_MULTIPLE_BOOKINGS_FOUND);\n }\n\n const node = edges[0]!.node;\n return {\n items: parseSaleNode(node),\n displayId: node.displayId || \"\",\n orderId: node.order?.id || \"\",\n normalizedBookingId: node.id || \"\",\n };\n }\n\n /**\n * Runs `createQuoteFromOrder` and validates the response, returning the new\n * quote id and the first sale quote refid (empty string when absent).\n */\n private async createQuoteFromOrderOrThrow(\n normalizedOrderId: string,\n ): Promise<{ quoteId: string; saleQuoteRefid: string }> {\n const body: GraphQLBody<CreateQuoteFromOrderResponse> =\n await this.client.request<CreateQuoteFromOrderResponse>(\n SALES_ENDPOINT,\n CREATE_QUOTE_FROM_ORDER_MUTATION,\n { input: { orderId: normalizedOrderId, quoteInput: {} } },\n );\n\n const created = body.data?.createQuoteFromOrder;\n const quote = created?.quote;\n if ((created?.errors && created.errors.length > 0) || !quote?.id) {\n throw new Error(ERROR_CREATE_QUOTE_FAILED);\n }\n return { quoteId: quote.id, saleQuoteRefid: quote.saleQuotes?.[0]?.refid || \"\" };\n }\n\n /** Runs `updateQuoteV2` with the given quoteInput and validates the response. */\n private async updateQuoteOrThrow(\n quoteId: string,\n quoteInput: Record<string, unknown>,\n ): Promise<void> {\n const body: GraphQLBody<UpdateQuoteV2Response> =\n await this.client.request<UpdateQuoteV2Response>(\n SALES_ENDPOINT,\n UPDATE_QUOTE_V2_MUTATION,\n { input: { quoteId, quoteInput } },\n );\n const updated = body.data?.updateQuoteV2;\n if ((updated?.errors && updated.errors.length > 0) || !updated?.quote) {\n throw new Error(ERROR_UPDATE_QUOTE_FAILED);\n }\n }\n\n /** Runs `amendOrder` and validates the response. */\n private async amendOrderOrThrow(\n quoteId: string,\n normalizedOrderId: string,\n ): Promise<void> {\n const body: GraphQLBody<AmendOrderResponse> =\n await this.client.request<AmendOrderResponse>(\n SALES_ENDPOINT,\n AMEND_ORDER_MUTATION,\n { input: { quoteId, orderId: normalizedOrderId } },\n );\n const amended = body.data?.amendOrder;\n if ((amended?.errors && amended.errors.length > 0) || !amended?.order) {\n throw new Error(ERROR_AMEND_ORDER_FAILED);\n }\n }\n\n /**\n * Creates a booking via createQuoteV2 → createOrderFromQuote, optionally\n * marking it paid. IDs must be pre-resolved (no free-text matching) — resolve\n * `activityId` + ticket `resourceOptionId`s from {@link ProductService} and\n * `availabilityTimeId` from {@link AvailabilityService.getAvailabilityTimes}.\n *\n * @example\n * ```ts\n * const created = await peek.getBookingService().create({\n * activityId: \"a_kayak_tour\",\n * availabilityTimeId: \"at_2026_06_20_0900\",\n * tickets: [{ resourceOptionId: \"ro_adult\", quantity: 2 }],\n * guest: { name: \"Sam Rivera\", email: \"sam@example.com\" },\n * markAsPaid: true,\n * idempotencyKey: crypto.randomUUID(),\n * });\n * console.log(created.bookingId, created.displayId, created.balanceFormatted);\n * ```\n *\n * @throws {Error} when `activityId`, `availabilityTimeId`, a ticket\n * `resourceOptionId`/positive `quantity`, or the guest `name` is missing; when\n * `markAsPaid` is set without an `idempotencyKey`; when\n * `requireRequiredQuestions` is set and a required custom question is left\n * unanswered; or when the quote/order mutations fail.\n */\n async create(input: CreateBookingInput): Promise<CreatedBooking> {\n validateCreateInput(input);\n\n // Resolve custom-question answers before anything is created: fetch the\n // activity's questions and validate/map each answer, so a bad answer fails\n // here rather than after a quote exists.\n const questionAnswers = await this.buildQuestionAnswers(input);\n\n const tickets = input.tickets.flatMap((ticket) =>\n Array.from({ length: ticket.quantity }, () => ({\n resourceOptionId: ticket.resourceOptionId,\n reservationStatus: \"CONFIRMED\",\n refid: randomUUID(),\n })),\n );\n\n const bookingQuote: Record<string, unknown> = {\n tickets,\n activityId: input.activityId,\n availabilityTimeId: input.availabilityTimeId,\n refid: randomUUID(),\n skipCustomerEmail: input.skipCustomerEmail ?? false,\n guest: {\n name: input.guest.name,\n email: input.guest.email ?? null,\n phone: input.guest.phone ?? null,\n optinMarketing: input.guest.optinMarketing ?? false,\n optinSms: input.guest.optinSms ?? false,\n postalCode: input.guest.postalCode ?? null,\n country: input.guest.country ?? null,\n },\n };\n if (input.operatorNotes) {\n bookingQuote.operatorNotes = input.operatorNotes;\n }\n if (questionAnswers) {\n bookingQuote.questionAnswers = questionAnswers;\n }\n\n const quoteInput: Record<string, unknown> = { bookingQuotes: [bookingQuote] };\n if (input.parentOrderId) {\n quoteInput.source = { clonedFromId: input.parentOrderId };\n }\n\n // Step 1 — create the quote.\n const quoteBody: GraphQLBody<CreateQuoteV2Response> =\n await this.client.request<CreateQuoteV2Response>(SALES_ENDPOINT, CREATE_QUOTE_V2_MUTATION, {\n input: { quoteInput },\n });\n const quoteResult = quoteBody.data?.createQuoteV2;\n if ((quoteResult?.errors && quoteResult.errors.length > 0) || !quoteResult?.quote?.id) {\n throw new Error(\"Failed to create quote\");\n }\n const quoteId = quoteResult.quote.id;\n\n // Step 2 — create the order from the quote.\n const orderBody: GraphQLBody<CreateOrderFromQuoteResponse> =\n await this.client.request<CreateOrderFromQuoteResponse>(\n SALES_ENDPOINT,\n CREATE_ORDER_FROM_QUOTE_MUTATION,\n { input: { quoteId } },\n );\n const orderResult = orderBody.data?.createOrderFromQuote;\n if (orderResult?.errors && orderResult.errors.length > 0) {\n throw new Error(\"Failed to create order from quote\");\n }\n const order = orderResult?.order;\n const sale = order?.sales?.[0];\n if (!order || !sale) {\n throw new Error(\"Order created but no sales found\");\n }\n\n const created: CreatedBooking = {\n orderId: order.id,\n bookingId: sale.id,\n displayId: sale.displayId,\n balanceAmount: sale.balance?.total?.amount ?? \"0.00\",\n balanceCurrency: sale.balance?.total?.currency ?? \"USD\",\n balanceFormatted: sale.balance?.total?.formatted ?? \"$0.00\",\n };\n\n // Step 3 — optionally mark the booking paid.\n if (input.markAsPaid) {\n created.transactionId = await this.markCreatedBookingPaid(created, input);\n }\n\n return created;\n }\n\n /**\n * Resolves the input's custom-question answers into the quote's\n * `questionAnswers` payload (each tagged with a fresh `refid`), or `null` when\n * none were supplied. Fetches the activity's custom questions to validate\n * against; throws on the first unmatched/ambiguous/invalid answer. When\n * `acceptAllCustomQuestionIds` is set the fetch is skipped if every answer is\n * given by id (a by-name answer still needs the list to resolve).\n */\n private async buildQuestionAnswers(\n input: CreateBookingInput,\n ): Promise<Array<Record<string, unknown>> | null> {\n const answers = input.customQuestionAnswers ?? [];\n const requireRequired = input.requireRequiredQuestions ?? false;\n const acceptAllIds = input.acceptAllCustomQuestionIds ?? false;\n // Nothing to resolve and no required-coverage check to enforce — skip the\n // questions fetch entirely.\n if (answers.length === 0 && !requireRequired) {\n return null;\n }\n // When accepting all ids and not enforcing required-question coverage, the\n // activity's questions are only needed to resolve by-name answers — every\n // by-id answer is accepted as-is. Skip the fetch when no answer needs it.\n const needsQuestions =\n !acceptAllIds ||\n requireRequired ||\n answers.some((answer) => !isCustomQuestionId(answer.questionIdOrText));\n const questions = needsQuestions\n ? await this.deps.productService.getCustomQuestions(input.activityId)\n : [];\n const resolved = resolveCustomQuestionAnswers(answers, questions, {\n requireRequired,\n acceptAllIds,\n });\n if (resolved.length === 0) {\n return null;\n }\n return resolved.map((answer) => ({\n ...answer,\n refid: randomUUID(),\n }));\n }\n\n private async markCreatedBookingPaid(\n booking: CreatedBooking,\n input: CreateBookingInput,\n ): Promise<string> {\n const parsedPartial = input.markAsPaidAmount ? parseFloat(input.markAsPaidAmount) : NaN;\n const amount =\n !Number.isNaN(parsedPartial) && parsedPartial > 0\n ? parsedPartial.toFixed(2)\n : booking.balanceAmount;\n\n const body: GraphQLBody<ApplyPaymentToOrderResponse> =\n await this.client.request<ApplyPaymentToOrderResponse>(\n SALES_ENDPOINT,\n APPLY_PAYMENT_TO_ORDER_MUTATION,\n {\n input: {\n amount: { amount, currency: booking.balanceCurrency },\n orderId: booking.orderId,\n paymentSourceId: \"custom/other\",\n idempotencyKey: input.idempotencyKey,\n customerMessage: \"Marked as paid\",\n scopedTo: [booking.bookingId],\n },\n },\n );\n\n const result = body.data?.applyPaymentToOrder;\n if ((result?.errors && result.errors.length > 0) || !result?.transactionId) {\n throw new Error(\"Failed to mark booking as paid\");\n }\n return result.transactionId;\n }\n\n /** Finds the parent item id of an add-on by matching its option id. */\n private async resolveParentItemId(addonOptionId: string): Promise<string> {\n const products = await this.deps.productService.getAllProducts();\n const matched = products.find(\n (product) =>\n product.type === ADD_ON_PRODUCT_TYPE &&\n product.tickets.some((ticket) => ticket.id === addonOptionId),\n );\n if (!matched) {\n throw new Error(\"Add-on not found for the provided addonOptionId\");\n }\n return matched.productId;\n }\n\n private validatePaymentInput(input: MakePaymentInput): void {\n if (\n !input.paymentSourceId ||\n (!input.paymentSourceId.startsWith(PAYMENT_SOURCE_PREFIX) &&\n !ALLOWED_PAYMENT_SOURCE_IDS.includes(input.paymentSourceId))\n ) {\n throw new Error(\n \"paymentSourceId is required and must start with 'ps_' or be one of \" +\n \"'cash/cash', 'custom/other', 'custom/voucher'\",\n );\n }\n assertAmount(input.amount);\n assertCurrency(input.currency);\n assertIdempotencyKey(input.idempotencyKey);\n assertBookingId(input.bookingId);\n }\n\n private validateRefundInput(input: RefundInput): void {\n if (!input.paymentId || !input.paymentId.startsWith(PAYMENT_ID_PREFIX)) {\n throw new Error(\"paymentId is required and must start with 'pmt_'\");\n }\n assertAmount(input.amount);\n assertCurrency(input.currency);\n assertIdempotencyKey(input.idempotencyKey);\n assertBookingId(input.bookingId);\n }\n\n private async fetchPaginated(\n query: string,\n baseParams: {\n startDateTime?: string;\n endDateTime?: string;\n timeslotId?: string;\n searchBy?: BookingTimeRangeSearch[\"searchBy\"];\n productId?: string;\n email?: string;\n searchString?: string;\n },\n includeGuests: boolean,\n includePriceBreakdown: boolean,\n ): Promise<Booking[]> {\n const bookings: Booking[] = [];\n let after: string | null = null;\n\n for (;;) {\n const body: GraphQLBody<BookingsResponse> =\n await this.client.request<BookingsResponse>(\n SALES_ENDPOINT,\n query,\n buildBookingsVariables({ ...baseParams, pageSize: this.pageSize, after }),\n );\n\n const sales = body.data?.sales;\n for (const edge of sales?.edges ?? []) {\n bookings.push(fromBookingNode(edge.node, includeGuests, includePriceBreakdown));\n }\n\n const pageInfo = sales?.pageInfo;\n if (pageInfo?.hasNextPage && pageInfo.endCursor) {\n after = pageInfo.endCursor;\n } else {\n break;\n }\n }\n\n return bookings;\n }\n}\n\nfunction assertAmount(amount: string): void {\n if (!amount || Number.isNaN(Number(amount))) {\n throw new Error(\"amount is required and must be a valid number\");\n }\n}\n\nfunction assertCurrency(currency: string): void {\n if (!currency || !CURRENCY_CODE_REGEX.test(currency)) {\n throw new Error(\"currency is required and must be a 3-letter uppercase code\");\n }\n}\n\nfunction assertIdempotencyKey(idempotencyKey: string): void {\n if (!idempotencyKey) {\n throw new Error(\"idempotencyKey is required\");\n }\n}\n\n/** Throws unless `bookingId` is a valid booking db id (`b_…`) or display id (`B-…`). */\nfunction assertBookingId(bookingId: string): void {\n if (!(BOOKING_DB_ID_REGEX.test(bookingId) || BOOKING_DISPLAY_ID_REGEX.test(bookingId))) {\n throw new Error(ERROR_INVALID_BOOKING_ID);\n }\n}\n\n/** Throws unless `orderId` is a valid order db id (`o_…`) or display id (`O-…`). */\nfunction assertOrderId(orderId: string): void {\n if (!(ORDER_DB_ID_REGEX.test(orderId) || ORDER_DISPLAY_ID_REGEX.test(orderId))) {\n throw new Error(ERROR_INVALID_ORDER_ID);\n }\n}\n\nfunction validateCreateInput(input: CreateBookingInput): void {\n if (!input.activityId) throw new Error(\"activityId is required\");\n if (!input.availabilityTimeId) throw new Error(\"availabilityTimeId is required\");\n if (!input.tickets || input.tickets.length === 0) {\n throw new Error(\"at least one ticket is required\");\n }\n if (input.tickets.some((ticket) => !ticket.resourceOptionId || !(ticket.quantity > 0))) {\n throw new Error(\"each ticket requires a resourceOptionId and a positive quantity\");\n }\n if (!input.guest || !input.guest.name) {\n throw new Error(\"guest name is required\");\n }\n if (input.markAsPaid && !input.idempotencyKey) {\n throw new Error(\"idempotencyKey is required when markAsPaid is set\");\n }\n if (input.parentOrderId) {\n assertOrderId(input.parentOrderId);\n }\n}\n\nfunction parseQuantity(value: unknown): number | null {\n if (typeof value !== \"string\" && typeof value !== \"number\") {\n return null;\n }\n const str = String(value).trim();\n if (!/^\\d+$/.test(str)) {\n return null;\n }\n const num = parseInt(str, 10);\n if (!Number.isFinite(num) || num <= 0) {\n return null;\n }\n return num;\n}\n\n/**\n * Builds the `bookingQuotes` cancellation payload for `updateQuoteV2`. Selects\n * up to `quantity` options across the booking where the item and the option are\n * both still `CONFIRMED` and `optionId === addonOptionId`, grouped by booking\n * item. Each selected option becomes a CANCELED itemOptions entry (by its\n * `optionRefid`); the parent add-on is marked CANCELED only when every one of\n * its options ends up canceled.\n */\nfunction buildCancellation(\n items: AddonItem[],\n addonOptionId: string,\n quantity: number,\n): { bookingQuotes: Array<Record<string, unknown>>; canceledCount: number } {\n let budget = quantity;\n // bookingQuoteRefid -> (itemRefid -> { item, canceledOptionRefids })\n const byBookingQuote = new Map<\n string,\n Map<string, { item: AddonItem; canceledOptionRefids: string[] }>\n >();\n\n for (const item of items) {\n if (budget <= 0) break;\n for (const opt of item.addonItemOptions) {\n if (budget <= 0) break;\n // Only cancel options that are themselves still confirmed — an item can\n // hold a mix of already-canceled and confirmed options for the same\n // optionId, and we must skip the canceled ones.\n if (\n opt.itemReservationStatus !== RESERVATION_STATUS_CONFIRMED ||\n opt.optionReservationStatus !== RESERVATION_STATUS_CONFIRMED ||\n opt.optionId !== addonOptionId\n ) {\n continue;\n }\n\n let itemMap = byBookingQuote.get(item.bookingQuoteRefid);\n if (!itemMap) {\n itemMap = new Map();\n byBookingQuote.set(item.bookingQuoteRefid, itemMap);\n }\n let entry = itemMap.get(opt.itemRefid);\n if (!entry) {\n entry = { item, canceledOptionRefids: [] };\n itemMap.set(opt.itemRefid, entry);\n }\n entry.canceledOptionRefids.push(opt.optionRefid);\n budget -= 1;\n }\n }\n\n const canceledCount = quantity - budget;\n\n const bookingQuotes = Array.from(byBookingQuote.entries()).map(\n ([bookingQuoteRefid, itemMap]) => ({\n refid: bookingQuoteRefid,\n addons: Array.from(itemMap.entries()).map(\n ([itemRefid, { item, canceledOptionRefids }]) => {\n const canceledSet = new Set(canceledOptionRefids);\n const itemOptions = canceledOptionRefids.map((refid) => ({\n reservationStatus: ADDON_OPTION_STATUS_CANCELED,\n refid,\n }));\n\n // Mark the add-on canceled only if every option ends up canceled.\n const allCanceled = item.addonItemOptions.every(\n (o) =>\n o.optionReservationStatus === ADDON_OPTION_STATUS_CANCELED ||\n canceledSet.has(o.optionRefid),\n );\n\n const addon: Record<string, unknown> = { itemOptions, refid: itemRefid };\n if (allCanceled) {\n addon.reservationStatus = ADDON_OPTION_STATUS_CANCELED;\n }\n return addon;\n },\n ),\n }),\n );\n\n return { bookingQuotes, canceledCount };\n}\n","/**\n * Pure functions resolving the daily-note GraphQL unions into the clean\n * {@link DailyNote} model. A not-found / missing note maps to `null`.\n */\nimport type { DailyNote } from \"../../../models/peek/daily-note.js\";\nimport type {\n DailyNoteResponse,\n UpsertDailyNoteResponse,\n} from \"./daily-note-queries.js\";\n\n/** Resolves a daily-note query response into a {@link DailyNote}, or null. */\nexport function toDailyNote(\n response: DailyNoteResponse | undefined,\n): DailyNote | null {\n const union = response?.dailyNote;\n if (!union) {\n return null;\n }\n // Success branch carries a nested `dailyNote`; the not-found branch carries `message`.\n if (\"dailyNote\" in union) {\n return cleanNote(union.dailyNote);\n }\n return null;\n}\n\n/** Resolves an upsert response into the saved {@link DailyNote}, or null. */\nexport function fromUpsertResponse(\n response: UpsertDailyNoteResponse | undefined,\n): DailyNote | null {\n return cleanNote(response?.upsertDailyNote?.dailyNote);\n}\n\nfunction cleanNote(note: DailyNote | null | undefined): DailyNote | null {\n if (!note || typeof note.note !== \"string\") {\n return null;\n }\n return { note: note.note };\n}\n","/**\n * Raw Peek GraphQL query/mutation and response shapes for the daily note.\n * Internal.\n */\nimport type { DailyNote } from \"../../../models/peek/daily-note.js\";\n\n/** The global-note type for the dashboard daily note. */\nexport const GLOBAL_NOTE_TYPE = \"DASHBOARD\";\n\n/** Fetches today's daily note. */\nexport const DAILY_NOTE_TODAY_QUERY = `\n query dailyNote($type: GlobalNoteType!) {\n dailyNote(type: $type) {\n ... on DailyNoteSuccess {\n dailyNote {\n note\n }\n }\n ... on NotFoundError {\n message\n }\n }\n }\n`;\n\n/** Upserts the daily note. */\nexport const UPSERT_DAILY_NOTE_MUTATION = `\n mutation Account($input: UpsertDailyNoteInput!) {\n upsertDailyNote(input: $input) {\n ... on UpsertDailyNoteSuccess {\n dailyNote {\n note\n }\n }\n }\n }\n`;\n\n/** `data` payload of {@link DAILY_NOTE_TODAY_QUERY} (a success/not-found union). */\nexport interface DailyNoteResponse {\n dailyNote: { dailyNote: DailyNote | null } | { message: string };\n}\n\n/** `data` payload of {@link UPSERT_DAILY_NOTE_MUTATION}. */\nexport interface UpsertDailyNoteResponse {\n upsertDailyNote: { dailyNote: DailyNote | null };\n}\n\n/** Builds the variables for {@link UPSERT_DAILY_NOTE_MUTATION}. */\nexport function buildUpsertDailyNoteVariables(note: string): {\n input: { type: string; note: string };\n} {\n return { input: { type: GLOBAL_NOTE_TYPE, note } };\n}\n","/**\n * Daily-note operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getDailyNoteService}.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type { DailyNote } from \"../../../models/peek/daily-note.js\";\nimport { fromUpsertResponse, toDailyNote } from \"./daily-note-converter.js\";\nimport {\n DAILY_NOTE_TODAY_QUERY,\n GLOBAL_NOTE_TYPE,\n UPSERT_DAILY_NOTE_MUTATION,\n buildUpsertDailyNoteVariables,\n type DailyNoteResponse,\n type UpsertDailyNoteResponse,\n} from \"./daily-note-queries.js\";\n\nexport class DailyNoteService {\n constructor(private readonly client: GraphQLClient) {}\n\n /** Returns today's daily note, or null when none is set. */\n async getToday(): Promise<DailyNote | null> {\n const body: GraphQLBody<DailyNoteResponse> =\n await this.client.request<DailyNoteResponse>(SALES_ENDPOINT, DAILY_NOTE_TODAY_QUERY, {\n type: GLOBAL_NOTE_TYPE,\n });\n return toDailyNote(body.data);\n }\n\n /** Upserts the daily note and returns the saved note, or null. */\n async update(note: string): Promise<DailyNote | null> {\n const body: GraphQLBody<UpsertDailyNoteResponse> =\n await this.client.request<UpsertDailyNoteResponse>(\n SALES_ENDPOINT,\n UPSERT_DAILY_NOTE_MUTATION,\n buildUpsertDailyNoteVariables(note),\n );\n return fromUpsertResponse(body.data);\n }\n}\n","/**\n * Mints and caches the short-lived JWT used to authenticate with the Peek\n * gateway. The token is signed on demand and reused until it nears expiry.\n */\nimport * as jwt from \"jsonwebtoken\";\n\nexport interface TokenManagerOptions {\n /** HMAC secret used to sign the JWT. */\n secret: string;\n /** JWT issuer (the app name). */\n issuer: string;\n /** JWT subject (the install ID). */\n installId: string;\n /** Token lifetime in seconds. */\n ttlSeconds: number;\n /** Re-mint the cached token this many seconds before its expiry. */\n leewaySeconds: number;\n}\n\nexport class TokenManager {\n private cached?: { token: string; expiresAtMs: number };\n\n constructor(private readonly options: TokenManagerOptions) {}\n\n /**\n * Returns a valid bearer token, reusing the cached one until it is within\n * `leewaySeconds` of expiring, at which point a fresh token is minted.\n */\n getToken(): string {\n const now = Date.now();\n if (this.cached && now < this.cached.expiresAtMs) {\n return this.cached.token;\n }\n\n const { secret, issuer, installId, ttlSeconds, leewaySeconds } = this.options;\n const token = jwt.sign({}, secret, {\n expiresIn: ttlSeconds,\n issuer,\n subject: installId,\n });\n\n this.cached = {\n token,\n expiresAtMs: now + (ttlSeconds - leewaySeconds) * 1000,\n };\n return token;\n }\n}\n","/**\n * Config shared by every access service in this package (Peek, CNG, …).\n *\n * Each gateway's access service extends {@link BaseAccessServiceConfig} with its\n * own extras (e.g. Peek adds `gatewayKey`/`mode`), so the only real difference\n * between accessors is the transport they build and the services they expose.\n * The shared defaults and the token-manager builder live here too, so that\n * plumbing is written once.\n */\nimport { TokenManager } from \"./internal/token-manager.js\";\nimport type { AccessOptions } from \"./access-options.js\";\nimport type { Logger } from \"./logger.js\";\n\n/** Fields common to every access service's config. */\nexport interface BaseAccessServiceConfig {\n /** Install ID. Becomes the JWT subject. */\n installId: string;\n /** HMAC secret used to sign the JWT. */\n jwtSecret: string;\n /** JWT issuer — the app name / app ID. */\n issuer: string;\n /**\n * The install's **base API URL** — persist the install webhook's `apiUrl` and\n * pass it here. It is the app endpoint with no per-platform routing slug; each\n * service class appends its own slug (e.g. `peek_backoffice_api-v1`, via that\n * platform's endpoint lookup) when it makes a call, so different services can\n * route through different slugs. If the URL you pass still carries this\n * platform's slug it is stripped back off to recover the base; a URL carrying a\n * *different* platform's slug makes the constructor throw. No app-id/gateway\n * segment is inserted, so `appId` is not required. This is the forward-looking\n * way to target an install — prefer it over `baseUrl`/`appId`, which are\n * deprecated (the hardcoded base-URL fallbacks will be removed and a URL will\n * become required in a future release).\n */\n apiUrl?: string;\n /**\n * App ID, inserted into the gateway endpoint path.\n *\n * @deprecated Required only in the legacy `baseUrl` mode. Prefer `apiUrl` (the\n * install's app endpoint), which needs no app-id segment.\n */\n appId?: string;\n\n /**\n * Override the gateway base URL. Default: per-service.\n *\n * @deprecated Prefer `apiUrl` (the install's app endpoint, used as given). The\n * hardcoded per-service default will be removed and a URL will become required.\n */\n baseUrl?: string;\n /** JWT lifetime in seconds. Default: 3600. */\n tokenTtlSeconds?: number;\n /** Re-mint the cached token this many seconds before expiry. Default: 60. */\n tokenRefreshLeewaySeconds?: number;\n /** Backoff delays (ms) for HTTP 429 retries. Default: [1000, 2000, 4000]. */\n retryDelaysMs?: number[];\n /** Optional logger. Default: no-op (silent). */\n logger?: Logger;\n /** Custom `fetch` implementation. Default: the global `fetch`. */\n fetch?: typeof fetch;\n\n /**\n * Cross-cutting access options (PII exposure, …). When omitted, defaults are\n * used ({@link AccessOptions.fullCustomerAccess} `false`). Threaded down to the\n * resource services that read customer data.\n */\n accessOptions?: AccessOptions;\n}\n\n/** Default JWT lifetime (1 hour). */\nexport const DEFAULT_TOKEN_TTL_SECONDS = 3600;\n/** Default leeway before expiry at which a cached token is re-minted. */\nexport const DEFAULT_TOKEN_REFRESH_LEEWAY_SECONDS = 60;\n/** Default HTTP 429 retry backoff. */\nexport const DEFAULT_RETRY_DELAYS_MS = [1000, 2000, 4000];\n\n/**\n * Throws when a required config field is empty, prefixing the message with the\n * concrete service name (e.g. `PeekAccessService: \"installId\" is required`).\n */\nexport function requireNonEmpty(\n value: string,\n name: string,\n serviceName: string,\n): void {\n if (!value) {\n throw new Error(`${serviceName}: \"${name}\" is required`);\n }\n}\n\n/**\n * Matches a backoffice-API extendable slug and captures the platform prefix —\n * e.g. `peek` from `peek_backoffice_api-v1` or `peek-backoffice-api-v1`. Dashes\n * and underscores are interchangeable as separators, so both spellings the app\n * registry emits are recognised. Anchored to the whole segment so an ordinary\n * install-path segment (e.g. `google-things-to-do-integration`) never matches.\n */\nconst EXTENDABLE_SLUG_RE = /^([a-z0-9]+)[-_]backoffice[-_]api[-_]v1$/i;\n\n/**\n * Recovers the **base API URL** from the install's app endpoint (`apiUrl`).\n *\n * The base is the install's app endpoint with no per-platform routing slug — the\n * service classes append their own slug (via their endpoint lookup) when they\n * make calls. Callers may pass the raw base, or a URL that still carries this\n * platform's slug; either way this returns the base:\n *\n * - **No slug present** → the URL is already the base; return it (trailing slash\n * trimmed).\n * - **This platform's slug present** → strip it off (dashes/underscores either\n * way) and return the base.\n * - **A different platform's slug present** → throw, since the URL targets the\n * wrong gateway and silently stripping it would mask a wiring mistake.\n */\nexport function resolveBaseApiUrl(\n apiUrl: string,\n platformSlug: string,\n serviceName: string,\n): string {\n const trimmed = apiUrl.replace(/\\/+$/, \"\");\n const lastSegment = trimmed.slice(trimmed.lastIndexOf(\"/\") + 1);\n const found = EXTENDABLE_SLUG_RE.exec(lastSegment);\n if (!found) return trimmed;\n\n const foundPlatform = found[1]!.toLowerCase();\n const expectedPlatform = EXTENDABLE_SLUG_RE.exec(platformSlug)![1]!.toLowerCase();\n if (foundPlatform !== expectedPlatform) {\n throw new Error(\n `${serviceName}: \"apiUrl\" carries a \"${foundPlatform}\" backoffice ` +\n `slug but this service targets \"${expectedPlatform}\" — pass the ` +\n `install's ${expectedPlatform} app endpoint`,\n );\n }\n // Strip this platform's slug back off to recover the base API URL.\n return trimmed.slice(0, trimmed.lastIndexOf(\"/\"));\n}\n\n/**\n * Builds the shared {@link TokenManager} from the common config fields, applying\n * the shared TTL/leeway defaults. Used by every access service.\n */\nexport function createTokenManager(config: BaseAccessServiceConfig): TokenManager {\n return new TokenManager({\n secret: config.jwtSecret,\n issuer: config.issuer,\n installId: config.installId,\n ttlSeconds: config.tokenTtlSeconds ?? DEFAULT_TOKEN_TTL_SECONDS,\n leewaySeconds:\n config.tokenRefreshLeewaySeconds ?? DEFAULT_TOKEN_REFRESH_LEEWAY_SECONDS,\n });\n}\n","/**\n * Shared HTTP transport core for both gateway clients (Peek GraphQL + CNG REST).\n *\n * The retry/backoff loop and the 418/429 status mapping are identical across\n * both gateways — only URL construction, request method/body, and success-body\n * handling differ. Those differences are supplied by the caller: it builds the\n * `url`/`init`, and its `onResponse` callback runs for every non-418/429 status\n * to produce the final value (or throw a transport-specific error).\n */\nimport { AdminAccountRequiredError, RateLimitError } from \"../errors.js\";\nimport type { Logger } from \"../logger.js\";\n\nexport const RATE_LIMIT_STATUS = 429;\nexport const ADMIN_ACCOUNT_REQUIRED_STATUS = 418;\n\n/** The subset of client options the shared retry loop needs. */\nexport interface HttpRetryOptions {\n /** Backoff delays (ms) applied on successive HTTP 429 responses. */\n retryDelaysMs: number[];\n /** Diagnostics sink. */\n logger: Logger;\n /** `fetch` implementation to use. */\n fetchFn: typeof fetch;\n}\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Reads a response body as JSON, falling back to the raw text when it is not\n * valid JSON. Never throws — a non-JSON error page (e.g. a gateway `404` with a\n * plain-text body) is returned verbatim as a string rather than blowing up the\n * caller with a `SyntaxError` that hides the real HTTP status.\n *\n * Shared by all three transports (Peek GraphQL, CNG REST, ACME REST) so their\n * error paths can carry the raw body regardless of its content type.\n */\nexport async function parseBody(response: Response): Promise<unknown> {\n const text = await response.text();\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\n/**\n * Runs a request through the shared retry loop. Maps HTTP 418 →\n * {@link AdminAccountRequiredError} and HTTP 429 → retry then\n * {@link RateLimitError}; delegates every other response to `onResponse`.\n *\n * @param label a short identifier for the request (endpoint name / REST path),\n * used only in the warn/error log messages.\n */\nexport async function requestWithRetry<T>(\n http: HttpRetryOptions,\n url: string,\n init: RequestInit,\n label: string,\n onResponse: (response: Response) => Promise<T>,\n): Promise<T> {\n const { retryDelaysMs, logger, fetchFn } = http;\n\n for (let attempt = 0; attempt <= retryDelaysMs.length; attempt++) {\n const response = await fetchFn(url, init);\n\n if (response.status === ADMIN_ACCOUNT_REQUIRED_STATUS) {\n logger.warn(`Admin account required for ${label} (HTTP 418)`, { url });\n throw new AdminAccountRequiredError();\n }\n\n if (response.status === RATE_LIMIT_STATUS) {\n const delay = retryDelaysMs[attempt];\n if (delay !== undefined) {\n logger.warn(\n `Rate limited on ${label}, retrying in ${delay}ms ` +\n `(attempt ${attempt + 1}/${retryDelaysMs.length})`,\n );\n await sleep(delay);\n continue;\n }\n logger.error(`Rate limit exceeded for ${label}`, { url });\n throw new RateLimitError();\n }\n\n return onResponse(response);\n }\n\n /* istanbul ignore next -- unreachable: the 429 branch always returns/throws */\n throw new RateLimitError();\n}\n","/**\n * The SDK identification header sent on every outbound gateway request (Peek\n * GraphQL, CNG REST, ACME REST) so the downstream platforms can attribute\n * traffic to this package and its version.\n *\n * The version is a literal rather than a `package.json` read: the dual ESM+CJS\n * build has no portable way to resolve its own `package.json` at runtime\n * (`import.meta.url` is ESM-only, `__dirname` is CJS-only), and a static const\n * keeps the package dependency-light and tree-shakeable. `sdk-headers.test.ts`\n * pins it to `package.json` so the two can never drift.\n */\n\n/** Header name carrying the SDK identifier. */\nexport const SDK_HEADER_NAME = \"x-peek-sdk\";\n\n/** Platform prefix in the header value (`<platform>-<version>`). */\nconst SDK_PLATFORM = \"js\";\n\n/** Must equal the `version` field in `package.json`. */\nexport const SDK_VERSION = \"0.9.2\";\n\n/** The `x-peek-sdk` header value, e.g. `js-0.9.0`. */\nexport const SDK_HEADER_VALUE = `${SDK_PLATFORM}-${SDK_VERSION}`;\n","/**\n * Thin GraphQL-over-HTTP transport built on the global `fetch`. Handles\n * endpoint construction, auth headers, query whitespace collapsing, and\n * GraphQL-specific response handling. The shared retry/backoff loop and 418/429\n * mapping live in `./http-transport.ts` (used by the CNG REST transport too).\n */\nimport { PeekGraphQLError, PeekHttpError } from \"../../errors.js\";\nimport { ApiEndpoints, joinUrl } from \"../api-endpoints.js\";\nimport { parseBody, requestWithRetry } from \"../http-transport.js\";\nimport { SDK_HEADER_NAME, SDK_HEADER_VALUE } from \"../sdk-headers.js\";\nimport type { Logger } from \"../../logger.js\";\n\n/** The raw body of a GraphQL HTTP response. */\nexport interface GraphQLBody<T> {\n data?: T;\n errors?: unknown[];\n}\n\n/** Narrows an unknown parsed body to an inspectable object (not a string/null). */\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\n\nexport interface GraphQLClientOptions {\n /**\n * The install's **base API URL** (no trailing slash, no routing slug). Every\n * GraphQL call POSTs to `baseApiUrl/<slug>`, where the slug comes from\n * {@link endpoints} for the request's endpoint name.\n */\n baseApiUrl: string;\n /** Maps an endpoint name to the relative slug appended to {@link baseApiUrl}. */\n endpoints: ApiEndpoints;\n /** API gateway key sent as the `pk-api-key` header. Omitted from headers when absent (v2 mode). */\n gatewayKey?: string;\n /** Supplies a valid bearer token for each request. */\n getToken: () => string;\n /** Backoff delays (ms) applied on successive HTTP 429 responses. */\n retryDelaysMs: number[];\n /** Diagnostics sink. */\n logger: Logger;\n /** `fetch` implementation to use. */\n fetchFn: typeof fetch;\n}\n\nexport class GraphQLClient {\n constructor(private readonly options: GraphQLClientOptions) {}\n\n /**\n * Executes a GraphQL query against the named endpoint and returns the raw\n * response body. Retries on HTTP 429 per the configured backoff (via the\n * shared {@link requestWithRetry} loop).\n */\n async request<T>(\n endpointName: string,\n query: string,\n variables: object,\n ): Promise<GraphQLBody<T>> {\n const { logger } = this.options;\n const url = this.endpoint(endpointName);\n const collapsedQuery = query.replace(/\\s+/g, \" \").trim();\n\n logger.info(\"Making GraphQL request\", { url, endpointName });\n\n return requestWithRetry(\n this.options,\n url,\n {\n method: \"POST\",\n headers: this.buildHeaders(),\n body: JSON.stringify({ query: collapsedQuery, variables }),\n },\n endpointName,\n async (response) => {\n // Parse the body defensively *before* branching on status: a non-JSON\n // error page (e.g. a `404` with a \"Not Found\" text body) must surface\n // as a typed HTTP error, not a `SyntaxError` that hides the real status.\n const raw = await parseBody(response);\n const body = (isObject(raw) ? raw : {}) as GraphQLBody<T>;\n\n if (body.errors) {\n logger.error(`GraphQL errors for ${endpointName}`, {\n url,\n graphqlErrors: JSON.stringify(body.errors),\n });\n throw new PeekGraphQLError(body.errors);\n }\n\n if (!response.ok) {\n logger.error(`GraphQL request failed with HTTP ${response.status}`, { url });\n throw new PeekHttpError(response.status, url, raw);\n }\n\n return body;\n },\n );\n }\n\n private endpoint(endpointName: string): string {\n const { baseApiUrl, endpoints } = this.options;\n return joinUrl(baseApiUrl, endpoints.pathFor(endpointName));\n }\n\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"X-Peek-Auth\": `Bearer ${this.options.getToken()}`,\n \"Content-Type\": \"application/json\",\n [SDK_HEADER_NAME]: SDK_HEADER_VALUE,\n };\n if (this.options.gatewayKey) {\n headers[\"pk-api-key\"] = this.options.gatewayKey;\n }\n return headers;\n }\n}\n","/**\n * Every platform this package knows about. Exported as a value (not just a\n * union) so runtime code can recognise a reported platform without restating\n * the list. New platforms extend this array.\n */\nexport const PEEK_PLATFORMS = [\"peek\", \"cng\", \"acme\"] as const;\n\n/**\n * Platform that embedded the app for this session. Verification is\n * brand-agnostic — one peek-auth JWT is minted for every platform — so this\n * claim is the single thing that identifies which platform a request came from.\n */\nexport type PeekPlatform = (typeof PEEK_PLATFORMS)[number];\n\n/**\n * User context embedded in a Peek auth token.\n *\n * Every field is nullable: the token is untrusted even after its signature\n * verifies, so a claim may be absent, `null`, or a sentinel (`\"\"`, `\"null\"`)\n * that this package normalizes to `null`. Never assume a field is populated —\n * always null-check.\n */\nexport interface PeekAuthTokenUser {\n /** User's email address, or `null` if the token omits it. */\n email: string | null;\n /**\n * The user's own Peek user ID — it identifies the signed-in person, **not**\n * the account or partner they belong to. Use it only to key the user; never\n * treat it as an account/partner id. `null` when the token omits it.\n */\n id: string | null;\n /** Whether the user has admin privileges, or `null` if the token omits it. */\n isAdmin: boolean | null;\n /** User's locale (e.g. `\"en\"`), or `null` if the token omits it. */\n locale: string | null;\n /** User's display name, or `null` if the token omits it. */\n name: string | null;\n /**\n * Which platform embedded the app for this session, or `null` when the token\n * omits it or reports one this version of the package doesn't recognize.\n */\n platform: PeekPlatform | null;\n}\n\n/** Claims returned by {@link PeekAccessService.verifyPeekAuthToken}. */\nexport interface PeekAuthTokenClaims {\n /** Install ID — the JWT subject (`sub`). Peek-assigned UUID. */\n installId: string;\n /** App display version at time of issuance. */\n displayVersion: string;\n /**\n * Authenticated user context, or `null` when the token carries no `user`\n * block. Do not assume a session token always names a user.\n */\n user: PeekAuthTokenUser | null;\n}\n\n/** The Peek account an install belongs to, as reported on an install webhook. */\nexport interface InstallWebhookAccount {\n /** Peek account ID that owns the install. */\n id: string;\n}\n\n/**\n * Claims returned by `verifyInstallWebhook` — the decoded, signature-verified\n * install-status webhook token.\n *\n * Shares the `app_registry_v2` token family with {@link PeekAuthTokenClaims},\n * but is emitted by the app registry itself for install lifecycle events\n * (installed / uninstalled / status changed) rather than for a user session —\n * so {@link InstallWebhookClaims.user} is `null` for system-initiated events\n * that no user triggered.\n */\nexport interface InstallWebhookClaims {\n /** Install ID — the JWT subject (`sub`). Peek-assigned UUID. */\n installId: string;\n /** The account the install belongs to. */\n account: InstallWebhookAccount;\n /** Install lifecycle status (e.g. `\"installed\"`, `\"uninstalled\"`). */\n status: string;\n /** App display version at time of issuance. Empty string when absent. */\n displayVersion: string;\n /**\n * The user that triggered the event, or `null` for system-initiated events\n * (the whole point of a distinct type from {@link PeekAuthTokenClaims}).\n */\n user: PeekAuthTokenUser | null;\n}\n","/**\n * Shared verification core for the `app_registry_v2` JWT family.\n *\n * Every token Peek's app registry mints — the per-session **peek-auth token**\n * (see {@link PeekAccessService.verifyPeekAuthToken}) and the **install-status\n * webhook token** (see {@link verifyInstallWebhook}) — is signed with the app's\n * HMAC secret and carries the same `issuer`/`audience` and the same snake_case\n * `user` block. This module owns those shared constants and the signature check\n * so the two entry points can't drift apart.\n *\n * Internal only — never re-exported from `src/index.ts`.\n */\nimport * as jwt from \"jsonwebtoken\";\nimport { PEEK_PLATFORMS } from \"../../models/peek/auth-token.js\";\nimport type { PeekAuthTokenUser, PeekPlatform } from \"../../models/peek/auth-token.js\";\n\n/** JWT issuer set by the Peek app registry on all tokens it issues. */\nexport const PEEK_TOKEN_ISSUER = \"app_registry_v2\";\n/** JWT audience set by the Peek app registry on all tokens it issues. */\nexport const PEEK_TOKEN_AUDIENCE = \"Joken\";\n/** Case-insensitive `Bearer ` scheme prefix on an `x-peek-auth` header value. */\nconst BEARER_PREFIX = \"bearer \";\n\n/**\n * Strips a leading `Bearer ` prefix (case-insensitive) so every caller can pass\n * the raw `x-peek-auth` request header value straight through — with or without\n * the scheme — without unwrapping it first. A real `app_registry_v2` JWT is\n * base64url and never starts with `\"bearer \"`, so this is a no-op on well-formed\n * tokens.\n */\nfunction stripBearer(token: string): string {\n const trimmed = token.trim();\n return trimmed.toLowerCase().startsWith(BEARER_PREFIX)\n ? trimmed.slice(BEARER_PREFIX.length).trim()\n : trimmed;\n}\n\n/**\n * The raw, snake_case user block embedded in an `app_registry_v2` token. Every\n * field is optional/nullable: the block is untrusted attacker- **or** registry-\n * shaped input, so a field may be missing, `null`, or a sentinel string. The\n * clean {@link PeekAuthTokenUser} is produced by {@link mapPeekTokenUser}.\n */\nexport interface RawPeekTokenUser {\n email?: string | null;\n id?: string | null;\n is_admin?: boolean | null;\n locale?: string | null;\n name?: string | null;\n platform?: string | null;\n}\n\n/** Strings Peek is known to emit in place of an absent value. */\nconst NULLISH_STRINGS = new Set([\"\", \"null\"]);\n\n/**\n * Normalizes an untrusted string claim: trims it, then collapses an empty string\n * or the literal `\"null\"` (case-insensitive) — both of which Peek has been seen\n * to send for an absent value — to `null`. A non-string (a real `null`,\n * `undefined`, or wrong-typed claim) also becomes `null`.\n */\nexport function cleanTokenString(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n const trimmed = value.trim();\n return NULLISH_STRINGS.has(trimmed.toLowerCase()) ? null : trimmed;\n}\n\n/** Narrows an untrusted platform claim to a known {@link PeekPlatform}, else `null`. */\nfunction cleanTokenPlatform(value: unknown): PeekPlatform | null {\n const cleaned = cleanTokenString(value);\n return cleaned !== null && (PEEK_PLATFORMS as readonly string[]).includes(cleaned)\n ? (cleaned as PeekPlatform)\n : null;\n}\n\n/**\n * Verifies an `app_registry_v2` token's HMAC signature (with `secret`), its\n * expiry, the `\"app_registry_v2\"` issuer, and the `\"Joken\"` audience, then\n * returns the decoded payload cast to `T`. Throws from the `jsonwebtoken`\n * library on any failure (`JsonWebTokenError` / `TokenExpiredError` /\n * `NotBeforeError`).\n *\n * The `token` argument accepts the raw `x-peek-auth` header value: a leading\n * `Bearer ` scheme prefix (case-insensitive) is stripped before verification, so\n * every token entry point in the family tolerates it uniformly.\n */\nexport function verifyPeekJwt<T>(token: string, secret: string): T {\n return jwt.verify(stripBearer(token), secret, {\n issuer: PEEK_TOKEN_ISSUER,\n audience: PEEK_TOKEN_AUDIENCE,\n }) as T;\n}\n\n/**\n * Maps the raw snake_case user block to the clean {@link PeekAuthTokenUser}.\n *\n * The block is untrusted even after the signature verifies: it may be absent\n * entirely (system-initiated events, malformed tokens) and any field inside it\n * may be missing, `null`, or a sentinel like `\"\"`/`\"null\"`. An absent block\n * yields `null`; a present block yields a user whose every field is\n * independently nullable (garbage strings normalized to `null` via\n * {@link cleanTokenString}). No field is required, so this never throws — in\n * particular `id` is the user's own id, not an account/partner id, and its\n * absence is not treated as an error.\n */\nexport function mapPeekTokenUser(\n u: RawPeekTokenUser | null | undefined,\n): PeekAuthTokenUser | null {\n if (!u) return null;\n return {\n email: cleanTokenString(u.email),\n id: cleanTokenString(u.id),\n isAdmin: typeof u.is_admin === \"boolean\" ? u.is_admin : null,\n locale: cleanTokenString(u.locale),\n name: cleanTokenString(u.name),\n platform: cleanTokenPlatform(u.platform),\n };\n}\n","/**\n * Pure function flattening raw membership nodes into the clean\n * {@link Membership} model — one record per variant.\n */\nimport type { Membership } from \"../../../models/peek/membership.js\";\nimport type { MembershipsResponse } from \"./membership-queries.js\";\n\n/** Flattens a memberships response into one {@link Membership} per variant. */\nexport function fromMembershipsResponse(\n response: MembershipsResponse | undefined,\n): Membership[] {\n return (response?.memberships ?? []).flatMap((membership) =>\n (membership.membershipVariants ?? []).map((variant) => ({\n id: membership.id,\n membershipVariantId: variant.id,\n description: variant.description ?? null,\n externalName: variant.externalName,\n imageUrl: variant.imageUrl ?? null,\n internalName: variant.internalName,\n displayName: membership.name,\n })),\n );\n}\n","/**\n * Raw Peek GraphQL query and response shape for memberships. Internal.\n */\n\n/** Fetches all memberships with their variants. */\nexport const MEMBERSHIPS_QUERY = `\n query Sales {\n memberships {\n name\n id\n membershipVariants {\n id\n description\n imageUrl\n externalName\n internalName\n }\n }\n }\n`;\n\n/** A single membership variant node. */\nexport interface MembershipVariantNode {\n id: string;\n description: string | null;\n imageUrl: string | null;\n externalName: string;\n internalName: string;\n}\n\n/** A single membership node as returned by {@link MEMBERSHIPS_QUERY}. */\nexport interface MembershipNode {\n name: string;\n id: string;\n membershipVariants: MembershipVariantNode[];\n}\n\n/** The `data` payload of {@link MEMBERSHIPS_QUERY}. */\nexport interface MembershipsResponse {\n memberships: MembershipNode[];\n}\n\n/** Creates a quote (used here to start a membership purchase). */\nexport const CREATE_QUOTE_V2_MUTATION = `\n mutation CreateQuoteV2($input: CreateQuoteV2Input!) {\n createQuoteV2(input: $input) {\n errors { detail value code }\n quote { id }\n }\n }\n`;\n\n/** Creates a membership order from a quote. */\nexport const CREATE_MEMBERSHIP_ORDER_FROM_QUOTE_MUTATION = `\n mutation CreateOrderFromQuote($input: CreateOrderFromQuoteInput!) {\n createOrderFromQuote(input: $input) {\n errors { code detail value }\n order {\n id\n sales {\n id\n displayId\n ... on SoldMembership {\n id\n displayId\n primaryMember { name id }\n balance { total { amount currency formatted } }\n }\n }\n }\n }\n }\n`;\n\n/** Member details attached to a membership quote. */\nexport interface MembershipMember {\n email: string;\n country?: string;\n formattedAddress?: string;\n membershipCode?: string;\n name?: string;\n phone?: string;\n}\n\ninterface MutationError {\n code: string;\n detail: string;\n value: string | null;\n}\n\n/** `data` payload of {@link CREATE_QUOTE_V2_MUTATION}. */\nexport interface CreateQuoteV2Response {\n createQuoteV2: { errors: MutationError[] | null; quote: { id: string } | null };\n}\n\n/** A sold membership returned by the order mutation. */\nexport interface SoldMembershipSale {\n id: string;\n displayId: string;\n primaryMember?: { id: string; name: string } | null;\n balance?: { total: { amount: string; currency: string; formatted: string } } | null;\n}\n\n/** `data` payload of {@link CREATE_MEMBERSHIP_ORDER_FROM_QUOTE_MUTATION}. */\nexport interface CreateMembershipOrderResponse {\n createOrderFromQuote: {\n errors: MutationError[] | null;\n order: { id: string; sales: SoldMembershipSale[] } | null;\n };\n}\n","/**\n * Membership operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getMembershipService}.\n */\nimport { randomUUID } from \"node:crypto\";\n\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type {\n Membership,\n MembershipPurchaseInput,\n PurchasedMembership,\n} from \"../../../models/peek/membership.js\";\nimport { fromMembershipsResponse } from \"./membership-converter.js\";\nimport {\n CREATE_MEMBERSHIP_ORDER_FROM_QUOTE_MUTATION,\n CREATE_QUOTE_V2_MUTATION,\n MEMBERSHIPS_QUERY,\n type CreateMembershipOrderResponse,\n type CreateQuoteV2Response,\n type MembershipMember,\n type MembershipsResponse,\n} from \"./membership-queries.js\";\n\nconst QUOTE_STATUS_CONFIRMED = \"CONFIRMED\";\nconst DEFAULT_BALANCE_AMOUNT = \"0.00\";\nconst DEFAULT_BALANCE_CURRENCY = \"USD\";\nconst DEFAULT_BALANCE_FORMATTED = \"$0.00\";\nconst EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst COUNTRY_REGEX = /^[A-Z]{2}$/i;\nconst PHONE_REGEX = /^[0-9+\\s()\\-.]+$/;\n\nexport class MembershipService {\n constructor(private readonly client: GraphQLClient) {}\n\n /** Returns all membership variants, flattened into {@link Membership} records. */\n async getAll(): Promise<Membership[]> {\n const body: GraphQLBody<MembershipsResponse> =\n await this.client.request<MembershipsResponse>(SALES_ENDPOINT, MEMBERSHIPS_QUERY, {});\n return fromMembershipsResponse(body.data);\n }\n\n /**\n * Purchases a membership via the two-step quote → order flow. Throws on\n * invalid input or when Peek returns errors.\n */\n async purchase(input: MembershipPurchaseInput): Promise<PurchasedMembership> {\n validatePurchaseInput(input);\n\n const quoteBody: GraphQLBody<CreateQuoteV2Response> =\n await this.client.request<CreateQuoteV2Response>(\n SALES_ENDPOINT,\n CREATE_QUOTE_V2_MUTATION,\n {\n input: {\n quoteInput: {\n membershipQuotes: [\n {\n member: buildMember(input),\n membershipVariantId: input.membershipVariantId,\n refid: randomUUID(),\n status: QUOTE_STATUS_CONFIRMED,\n },\n ],\n },\n },\n },\n );\n\n const quoteResult = quoteBody.data?.createQuoteV2;\n if (quoteResult?.errors && quoteResult.errors.length > 0) {\n throw new Error(`Failed to create membership quote: ${quoteResult.errors[0]!.detail}`);\n }\n const quoteId = quoteResult?.quote?.id;\n if (!quoteId) {\n throw new Error(\"Membership quote created but missing quote id\");\n }\n\n const orderBody: GraphQLBody<CreateMembershipOrderResponse> =\n await this.client.request<CreateMembershipOrderResponse>(\n SALES_ENDPOINT,\n CREATE_MEMBERSHIP_ORDER_FROM_QUOTE_MUTATION,\n { input: { quoteId } },\n );\n\n const orderResult = orderBody.data?.createOrderFromQuote;\n if (orderResult?.errors && orderResult.errors.length > 0) {\n throw new Error(`Failed to create membership order: ${orderResult.errors[0]!.detail}`);\n }\n\n const order = orderResult?.order;\n const sale = order?.sales?.[0];\n if (!order || !sale) {\n throw new Error(\"Membership order created but no sales found\");\n }\n\n return {\n orderId: order.id,\n membershipId: sale.id,\n displayId: sale.displayId,\n primaryMemberId: sale.primaryMember?.id ?? null,\n primaryMemberName: sale.primaryMember?.name ?? null,\n balanceAmount: sale.balance?.total?.amount ?? DEFAULT_BALANCE_AMOUNT,\n balanceCurrency: sale.balance?.total?.currency ?? DEFAULT_BALANCE_CURRENCY,\n balanceFormatted: sale.balance?.total?.formatted ?? DEFAULT_BALANCE_FORMATTED,\n };\n }\n}\n\n/** Builds the GraphQL member, including only non-empty optional fields. */\nfunction buildMember(input: MembershipPurchaseInput): MembershipMember {\n const member: MembershipMember = { email: input.email };\n if (input.country?.trim()) member.country = input.country;\n if (input.formattedAddress?.trim()) member.formattedAddress = input.formattedAddress;\n if (input.membershipCode?.trim()) member.membershipCode = input.membershipCode;\n if (input.name?.trim()) member.name = input.name;\n if (input.phone?.trim()) member.phone = input.phone;\n return member;\n}\n\nfunction validatePurchaseInput(input: MembershipPurchaseInput): void {\n const errors: string[] = [];\n\n if (!input.membershipVariantId || input.membershipVariantId.trim().length === 0) {\n errors.push(\"membershipVariantId is required\");\n }\n if (!input.email || input.email.trim().length === 0) {\n errors.push(\"email is required\");\n } else if (!EMAIL_REGEX.test(input.email)) {\n errors.push(\"email is invalid\");\n }\n if (input.country && !COUNTRY_REGEX.test(input.country)) {\n errors.push(\"country is invalid\");\n }\n if (input.phone && !PHONE_REGEX.test(input.phone)) {\n errors.push(\"phone is invalid\");\n }\n\n if (errors.length > 0) {\n throw new Error(errors.join(\", \"));\n }\n}\n","/**\n * Pure functions mapping raw channel nodes into the clean {@link Channel}\n * model, flattening the agents edge/node structure.\n */\nimport type { Channel } from \"../../../models/peek/channel.js\";\nimport type { ChannelNode, ChannelsResponse } from \"./channel-queries.js\";\n\n/** Converts a channels response into {@link Channel}s. */\nexport function fromChannelsResponse(\n response: ChannelsResponse | undefined,\n): Channel[] {\n return (response?.channels ?? []).map(fromChannelNode);\n}\n\nfunction fromChannelNode(node: ChannelNode): Channel {\n return {\n id: node.id,\n name: node.name,\n notes: node.notes,\n pricingModel: node.pricingModel,\n state: node.state,\n type: node.type,\n agents: (node.agents?.edges ?? []).map((edge) => ({\n email: edge.node.email,\n name: edge.node.name,\n internalNotes: edge.node.internalNotes,\n phone: edge.node.phone,\n })),\n };\n}\n","/**\n * Raw Peek GraphQL query and response shape for reseller channels. Internal.\n *\n * Channels themselves are returned in full; `$first` limits the number of\n * agents fetched per channel.\n */\n\n/** Fetches reseller channels with up to `$first` agents each. */\nexport const CHANNELS_QUERY = `\n query Sales($first: Int) {\n channels {\n id\n agents(first: $first) {\n edges {\n node {\n email\n name\n internalNotes\n phone\n }\n }\n }\n name\n notes\n state\n type\n pricingModel\n }\n }\n`;\n\n/** A single agent node. */\nexport interface AgentNode {\n email: string | null;\n name: string;\n internalNotes: string | null;\n phone: string | null;\n}\n\n/** A single channel node as returned by {@link CHANNELS_QUERY}. */\nexport interface ChannelNode {\n id: string;\n name: string;\n notes: string | null;\n pricingModel: string;\n state: string;\n type: string;\n agents: { edges: Array<{ node: AgentNode }> } | null;\n}\n\n/** The `data` payload of {@link CHANNELS_QUERY}. */\nexport interface ChannelsResponse {\n channels: ChannelNode[];\n}\n","/**\n * Reseller-channel operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getResellerService}.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type { Channel } from \"../../../models/peek/channel.js\";\nimport { fromChannelsResponse } from \"./channel-converter.js\";\nimport { CHANNELS_QUERY, type ChannelsResponse } from \"./channel-queries.js\";\n\n/** Default number of agents fetched per channel. */\nconst DEFAULT_AGENTS_PER_CHANNEL = 10;\n\nexport class ResellerService {\n constructor(private readonly client: GraphQLClient) {}\n\n /**\n * Returns all reseller channels, each with up to `agentsPerChannel` agents\n * (default 10).\n */\n async getAllChannels(\n agentsPerChannel: number = DEFAULT_AGENTS_PER_CHANNEL,\n ): Promise<Channel[]> {\n const body: GraphQLBody<ChannelsResponse> =\n await this.client.request<ChannelsResponse>(SALES_ENDPOINT, CHANNELS_QUERY, {\n first: agentsPerChannel,\n });\n return fromChannelsResponse(body.data);\n }\n}\n","/**\n * Pure functions mapping raw resource-pool nodes into the clean\n * {@link ResourcePool} model.\n */\nimport type {\n ResourcePool,\n ResourcePoolAccountUser,\n} from \"../../../models/peek/resource-pool.js\";\nimport type {\n ResourcePoolNode,\n ResourcePoolsResponse,\n} from \"./resource-pool-queries.js\";\n\n/** Converts a resource-pools response into {@link ResourcePool}s. */\nexport function fromResourcePoolsResponse(\n response: ResourcePoolsResponse | undefined,\n): ResourcePool[] {\n return (response?.resourcePools ?? []).map(fromResourcePoolNode);\n}\n\nfunction fromResourcePoolNode(pool: ResourcePoolNode): ResourcePool {\n return {\n id: pool.id || \"\",\n name: pool.name || \"\",\n imageUrl: pool.imageUrl ?? null,\n mode: pool.mode || \"\",\n colorHex: pool.colorHex ?? null,\n quantity: pool.quantity ?? null,\n category: pool.category || \"\",\n capacity: pool.capacity ?? null,\n resourceTrackingMode: pool.resourceTrackingMode ?? null,\n accountUser: fromAccountUser(pool.accountUser),\n };\n}\n\nfunction fromAccountUser(\n accountUser: { id: string; name: string } | null | undefined,\n): ResourcePoolAccountUser | null {\n if (!accountUser) {\n return null;\n }\n return {\n id: accountUser.id || \"\",\n name: accountUser.name || \"\",\n };\n}\n","/**\n * Raw Peek GraphQL query and response shape for resource pools. Internal.\n */\n\n/** Fetches resource pools matching a mode filter. */\nexport const RESOURCE_POOLS_QUERY = `\n query Sales($filter: ResourcePoolsFilter) {\n resourcePools(filter: $filter) {\n id\n name\n imageUrl\n mode\n colorHex\n quantity\n category\n capacity\n resourceTrackingMode\n accountUser {\n id\n name\n }\n }\n }\n`;\n\n/** A single resource-pool node as returned by {@link RESOURCE_POOLS_QUERY}. */\nexport interface ResourcePoolNode {\n id: string;\n name: string;\n imageUrl: string | null;\n mode: string;\n colorHex: string | null;\n quantity: number | null;\n category: string;\n capacity: number | null;\n resourceTrackingMode: string | null;\n accountUser: { id: string; name: string } | null;\n}\n\n/** The `data` payload of {@link RESOURCE_POOLS_QUERY}. */\nexport interface ResourcePoolsResponse {\n resourcePools: ResourcePoolNode[];\n}\n","/**\n * Resource-pool operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getResourcePoolService}.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type {\n ResourcePool,\n ResourcePoolMode,\n} from \"../../../models/peek/resource-pool.js\";\nimport { fromResourcePoolsResponse } from \"./resource-pool-converter.js\";\nimport {\n RESOURCE_POOLS_QUERY,\n type ResourcePoolsResponse,\n} from \"./resource-pool-queries.js\";\n\n/** Default mode filter (matches the connector). */\nconst DEFAULT_MODE: ResourcePoolMode = \"ALL\";\n\nexport class ResourcePoolService {\n constructor(private readonly client: GraphQLClient) {}\n\n /**\n * Returns all resource pools for the given mode filter (defaults to `\"ALL\"`).\n */\n async getAll(mode: ResourcePoolMode = DEFAULT_MODE): Promise<ResourcePool[]> {\n const body: GraphQLBody<ResourcePoolsResponse> =\n await this.client.request<ResourcePoolsResponse>(\n SALES_ENDPOINT,\n RESOURCE_POOLS_QUERY,\n { filter: { mode } },\n );\n return fromResourcePoolsResponse(body.data);\n }\n}\n","/**\n * Pure, I/O-free mapping from raw review nodes to the clean {@link Review}\n * model. No network, no logging, no clock access.\n */\nimport type {\n Guide,\n ProductReviewSummary,\n Review,\n} from \"../../../models/peek/review.js\";\nimport type {\n ActivityReviewSummaryNode,\n ReviewNode,\n} from \"./review-queries.js\";\n\n/** Length of an ISO `YYYY-MM-DD` date prefix. */\nconst ISO_DATE_LENGTH = 10;\n\n/** Extracts the `YYYY-MM-DD` date prefix from an ISO date-time string. */\nexport function toDateOnly(isoDateTime: string): string {\n return isoDateTime.slice(0, ISO_DATE_LENGTH);\n}\n\n/** Maps a raw review node to the clean {@link Review} model. */\nexport function fromReviewNode(node: ReviewNode): Review {\n const guides: Guide[] = (node.guides ?? []).map((guide) => ({\n id: guide.id,\n name: guide.name,\n }));\n\n return {\n id: node.id,\n productId: node.activity?.id ?? \"\",\n productName: node.activity?.name ?? \"\",\n guides,\n customerName: node.name ?? null,\n customerEmail: node.email ?? null,\n activityDate: toDateOnly(node.purchasedFor),\n reviewDate: toDateOnly(node.reviewedAt),\n rating: node.rating,\n comment: node.comment ?? null,\n };\n}\n\n/**\n * Maps a raw activity node to a clean {@link ProductReviewSummary}. A missing\n * `reviewMeta` (an activity with no reviews) collapses to a null average and\n * zero counts.\n */\nexport function fromActivityReviewSummaryNode(\n node: ActivityReviewSummaryNode,\n): ProductReviewSummary {\n const meta = node.reviewMeta;\n return {\n productId: node.id,\n productName: node.name,\n avgRating: meta?.avgRating ?? null,\n countTotal: meta?.count ?? 0,\n countOneStar: meta?.oneStar ?? 0,\n countTwoStar: meta?.twoStar ?? 0,\n countThreeStar: meta?.threeStar ?? 0,\n countFourStar: meta?.fourStar ?? 0,\n countFiveStar: meta?.fiveStar ?? 0,\n };\n}\n\n/** Maps every activity node to a {@link ProductReviewSummary}. */\nexport function fromActivityReviewSummaryNodes(\n nodes: ActivityReviewSummaryNode[],\n): ProductReviewSummary[] {\n return nodes.map(fromActivityReviewSummaryNode);\n}\n","/**\n * Encode/decode for the Peek reviews connection cursor. Internal.\n *\n * A cursor is the base64 of `range:<start>..<end>,<offset>` where `<offset>` is\n * the **absolute index** of the object in the current result set. {@link\n * encodeCursor} mints the `after` cursor used to skip a fixed number of the\n * newest reviews.\n */\nconst CURSOR_REGEX = /^range:(\\d+)\\.\\.(\\d+),(\\d+)$/;\n\n/** The parsed parts of a reviews cursor. */\nexport interface DecodedCursor {\n /** Inclusive start index of the page window the object belonged to. */\n start: number;\n /** Inclusive end index of the page window the object belonged to. */\n end: number;\n /** Absolute index of the object in the result set. */\n offset: number;\n}\n\n/** Decodes a base64 reviews cursor into its parts. */\nexport function decodeCursor(cursor: string): DecodedCursor {\n const text = Buffer.from(cursor, \"base64\").toString(\"utf8\");\n const match = CURSOR_REGEX.exec(text);\n if (!match) {\n throw new Error(`Unrecognized review cursor: ${cursor}`);\n }\n const [, start, end, offset] = match;\n return { start: Number(start), end: Number(end), offset: Number(offset) };\n}\n\n/** Returns just the absolute offset encoded in a cursor. */\nexport function decodeOffset(cursor: string): number {\n return decodeCursor(cursor).offset;\n}\n\n/**\n * Rebuilds a cursor that points at a given absolute `offset`, mimicking the\n * last edge of a `pageSize` page that ends at `offset`. Used to resume (`after`)\n * pagination from a cached, re-anchored offset. The gateway resolves the next\n * window from the trailing offset.\n */\nexport function encodeCursor(offset: number, pageSize: number): string {\n const start = Math.max(0, offset - pageSize + 1);\n return Buffer.from(`range:${start}..${offset},${offset}`).toString(\"base64\");\n}\n","/**\n * Raw Peek GraphQL query and response shapes for activity reviews. Internal —\n * never re-exported from the public barrel.\n */\n\n/**\n * Fetches a page of reviews, newest-first, optionally filtered by activity and\n * resumed from a cursor. The gateway returns up to `first` reviews per page in\n * descending `reviewedAt` order; pagination walks backwards in time via the\n * last edge's `cursor` as the next `after`.\n */\n/**\n * Builds the reviews query. Without `fullCustomerAccess`, the reviewer's `name` and\n * `email` are not requested (they come back absent → `null` in the converter);\n * the review `comment`, rating, dates, and credited guides are always selected.\n */\nexport function buildReviewsQuery(fullCustomerAccess: boolean): string {\n return `\n query Reviews($first: Int, $filter: ReviewFilter, $after: String) {\n reviews(first: $first, filter: $filter, after: $after) {\n edges {\n node {\n activity {\n id\n name\n }\n guides {\n id\n name\n }\n id\n ${fullCustomerAccess ? \"name\\n email\" : \"\"}\n rating\n comment\n reviewedAt\n purchasedFor\n }\n cursor\n }\n }\n }\n`;\n}\n\n/** A guide node as returned by the gateway. */\nexport interface ReviewGuideNode {\n id: string;\n name: string;\n}\n\n/** A single review node as returned by the gateway. */\nexport interface ReviewNode {\n activity: { id: string; name: string } | null;\n guides: ReviewGuideNode[] | null;\n id: string;\n name: string | null;\n email: string | null;\n rating: number;\n comment: string | null;\n reviewedAt: string;\n purchasedFor: string;\n}\n\n/** A single edge in the reviews connection. */\nexport interface ReviewEdge {\n node: ReviewNode;\n cursor: string;\n}\n\n/** `data` payload of {@link buildReviewsQuery}. */\nexport interface ReviewsResponse {\n reviews: { edges: ReviewEdge[] } | null;\n}\n\n/**\n * Fetches every activity with its aggregate review statistics. The `activities`\n * connection is the same list `getAllProducts` reads; here only the id, name,\n * and `reviewMeta` rating distribution are selected. Carries no PII, so it is\n * unaffected by `fullCustomerAccess`.\n */\nexport const REVIEW_SUMMARIES_QUERY = `\n query ReviewSummaries {\n activities {\n id\n name\n reviewMeta {\n avgRating\n count\n fiveStar\n fourStar\n threeStar\n twoStar\n oneStar\n }\n }\n }\n`;\n\n/** An activity's aggregate review statistics as returned by the gateway. */\nexport interface ReviewMetaNode {\n avgRating: number | null;\n count: number;\n fiveStar: number;\n fourStar: number;\n threeStar: number;\n twoStar: number;\n oneStar: number;\n}\n\n/** A single activity node as returned by {@link REVIEW_SUMMARIES_QUERY}. */\nexport interface ActivityReviewSummaryNode {\n id: string;\n name: string;\n reviewMeta: ReviewMetaNode | null;\n}\n\n/** The `data` payload of {@link REVIEW_SUMMARIES_QUERY}. */\nexport interface ReviewSummariesResponse {\n activities: ActivityReviewSummaryNode[];\n}\n\n/** Variables for {@link buildReviewsQuery}. */\nexport interface ReviewsVariables {\n first: number;\n filter: { activityIds: string[] };\n after: string | null;\n}\n\n/** Builds the variables for {@link buildReviewsQuery}. */\nexport function buildReviewsVariables(params: {\n activityId: string;\n first: number;\n after: string | null;\n}): ReviewsVariables {\n return {\n first: params.first,\n filter: { activityIds: [params.activityId] },\n after: params.after,\n };\n}\n","/**\n * Review operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getReviewService}.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type {\n ProductReviewSummary,\n Review,\n} from \"../../../models/peek/review.js\";\nimport {\n resolveAccessOptions,\n type AccessOptions,\n} from \"../../../access-options.js\";\nimport {\n fromActivityReviewSummaryNodes,\n fromReviewNode,\n} from \"./review-converter.js\";\nimport { encodeCursor } from \"./review-cursor.js\";\nimport {\n buildReviewsQuery,\n buildReviewsVariables,\n REVIEW_SUMMARIES_QUERY,\n type ReviewsResponse,\n type ReviewSummariesResponse,\n} from \"./review-queries.js\";\n\n/** Number of reviews returned when `reviewCount` is omitted. */\nconst DEFAULT_REVIEW_COUNT = 50;\n/** Smallest allowed `reviewCount`. */\nconst MIN_REVIEW_COUNT = 1;\n/** Largest allowed `reviewCount` (a single gateway page). */\nconst MAX_REVIEW_COUNT = 50;\n\nconst ERROR_PRODUCT_ID_REQUIRED = \"productId is required\";\nconst ERROR_INVALID_REVIEW_COUNT = `reviewCount must be an integer between ${MIN_REVIEW_COUNT} and ${MAX_REVIEW_COUNT}`;\nconst ERROR_INVALID_REVIEW_OFFSET = \"reviewOffset must be a non-negative integer\";\n\n/**\n * Reads activity reviews from the gateway, which returns them newest-first\n * (descending `reviewedAt`). {@link ReviewService.getReviews} fetches a single\n * page of up to `reviewCount` reviews, skipping the first `reviewOffset` of\n * them via the connection cursor.\n *\n * Obtain an instance via {@link PeekAccessService.getReviewService}.\n */\nexport class ReviewService {\n /** Whether reviewer PII (name/email) is requested. */\n private readonly fullCustomerAccess: boolean;\n\n constructor(\n private readonly client: GraphQLClient,\n accessOptions?: AccessOptions,\n ) {\n this.fullCustomerAccess = resolveAccessOptions(accessOptions).fullCustomerAccess;\n }\n\n /**\n * Returns up to `reviewCount` reviews for an activity in **descending order\n * by review date (newest first)**, skipping the `reviewOffset` newest reviews\n * before collecting.\n *\n * The gateway cursor resumes *after* a given absolute offset, so to skip the\n * first `reviewOffset` reviews the request is anchored on the review just\n * before the window. A `reviewOffset` of 0 needs no cursor and is sent\n * without one.\n *\n * @param productId - The activity (product) id to fetch reviews for.\n * @param reviewCount - How many reviews to return (1–50). Default: 50.\n * @param reviewOffset - How many of the newest reviews to skip first\n * (0-based). Default: 0 (start at the newest review).\n *\n * @throws {Error} when `productId` is empty, `reviewCount` is not an integer\n * in 1–50, or `reviewOffset` is not a non-negative integer.\n *\n * @example\n * ```ts\n * const reviews = await peek\n * .getReviewService()\n * .getReviews(\"87cdf37f-1872-42cb-b0bd-518312624fc1\", 25, 50);\n * ```\n */\n async getReviews(\n productId: string,\n reviewCount: number = DEFAULT_REVIEW_COUNT,\n reviewOffset = 0,\n ): Promise<Review[]> {\n this.validate(productId, reviewCount, reviewOffset);\n\n const after =\n reviewOffset > 0 ? encodeCursor(reviewOffset - 1, reviewCount) : null;\n\n const body: GraphQLBody<ReviewsResponse> =\n await this.client.request<ReviewsResponse>(\n SALES_ENDPOINT,\n buildReviewsQuery(this.fullCustomerAccess),\n buildReviewsVariables({ activityId: productId, first: reviewCount, after }),\n );\n\n const edges = body.data?.reviews?.edges ?? [];\n return edges.map((edge) => fromReviewNode(edge.node));\n }\n\n /**\n * Returns an aggregate review summary for **every** activity — its average\n * rating and the count of reviews at each star level. This reads the same\n * activity list as `getAllProducts`; it carries no per-review detail or PII, so\n * it is unaffected by `fullCustomerAccess`. An activity with no reviews comes\n * back with a `null` `avgRating` and zero counts.\n *\n * @example\n * ```ts\n * const summaries = await peek.getReviewService().getAllReviewSummaries();\n * for (const s of summaries) {\n * console.log(s.productName, s.avgRating, s.countTotal);\n * }\n * ```\n */\n async getAllReviewSummaries(): Promise<ProductReviewSummary[]> {\n const body: GraphQLBody<ReviewSummariesResponse> =\n await this.client.request<ReviewSummariesResponse>(\n SALES_ENDPOINT,\n REVIEW_SUMMARIES_QUERY,\n {},\n );\n\n return fromActivityReviewSummaryNodes(body.data?.activities ?? []);\n }\n\n private validate(\n productId: string,\n reviewCount: number,\n reviewOffset: number,\n ): void {\n if (!productId) {\n throw new Error(ERROR_PRODUCT_ID_REQUIRED);\n }\n if (\n !Number.isInteger(reviewCount) ||\n reviewCount < MIN_REVIEW_COUNT ||\n reviewCount > MAX_REVIEW_COUNT\n ) {\n throw new Error(ERROR_INVALID_REVIEW_COUNT);\n }\n if (!Number.isInteger(reviewOffset) || reviewOffset < 0) {\n throw new Error(ERROR_INVALID_REVIEW_OFFSET);\n }\n }\n}\n","/**\n * Pure functions mapping raw timeslot nodes into the clean {@link Timeslot}\n * model.\n */\nimport type { AssignedResource, Timeslot } from \"../../../models/peek/timeslot.js\";\nimport type {\n TimeslotNode,\n TimeslotResourceAllocationNode,\n} from \"./timeslot-queries.js\";\n\n/** Converts a list of timeslot nodes for the given activity into {@link Timeslot}s. */\nexport function fromTimeslotNodes(\n nodes: Array<TimeslotNode | null>,\n productId: string,\n): Timeslot[] {\n if (!Array.isArray(nodes) || nodes.length === 0) {\n return [];\n }\n return nodes.map((node) => fromTimeslotNode(node, productId));\n}\n\n/** Converts a single timeslot node into a {@link Timeslot}. A missing node yields a zeroed timeslot. */\nexport function fromTimeslotNode(\n node: TimeslotNode | null | undefined,\n productId: string,\n): Timeslot {\n if (!node) {\n return {\n id: \"\",\n productId,\n totalCapacity: 0,\n availableCapacity: 0,\n maxPartySize: 0,\n bookingCount: 0,\n checkedInCount: 0,\n status: \"\",\n notes: null,\n durationMin: 0,\n date: \"\",\n startTime: null,\n assignedResources: [],\n };\n }\n\n return {\n id: node.id || \"\",\n productId,\n totalCapacity: node.totalCapacity ?? 0,\n availableCapacity: node.availableSpots ?? 0,\n maxPartySize: node.maxPartySize ?? 0,\n bookingCount: node.bookingCount ?? 0,\n checkedInCount: node.checkedInCount ?? 0,\n status: node.status || \"\",\n notes: node.manifestNotes ?? null,\n durationMin: node.minuteLength ?? 0,\n date: node.date || \"\",\n startTime: node.start ?? null,\n assignedResources: mapAssignedResources(selectResourceAllocations(node)),\n };\n}\n\n/** Only allocations with this status are considered assigned. */\nconst ACTIVE_ALLOCATION_STATUS = \"ACTIVE\";\n\n/**\n * Timeslots may carry both inherited (schedule-level) and directly-assigned\n * resource allocations. Prefer inherited; fall back to the regular allocations\n * only when the inherited field is absent or empty.\n */\nfunction selectResourceAllocations(\n node: TimeslotNode,\n): TimeslotResourceAllocationNode[] | null | undefined {\n const inherited = node.inheritedResourceAllocations;\n if (Array.isArray(inherited) && inherited.length > 0) {\n return inherited;\n }\n return node.resourceAllocations;\n}\n\nfunction mapAssignedResources(\n allocations: TimeslotResourceAllocationNode[] | null | undefined,\n): AssignedResource[] {\n if (!Array.isArray(allocations) || allocations.length === 0) {\n return [];\n }\n\n return allocations\n .filter((allocation) => allocation.status === ACTIVE_ALLOCATION_STATUS)\n .map((allocation) => {\n const pool = allocation.resourcePool;\n return {\n name: pool?.name || \"\",\n capacity: pool?.capacity ?? 0,\n category: pool?.category || \"\",\n quantity: allocation.quantity ?? 0,\n accountUserId: pool?.accountUser?.id ?? null,\n };\n });\n}\n","/**\n * Pure guide-matching logic: resolves a caller-supplied guide identifier to a\n * resource-pool id. A guide may be referenced by resource-pool id, by backing\n * account-user id, or by name (directly or via an account user).\n */\nimport type { ResourcePool } from \"../../../models/peek/resource-pool.js\";\n\n/**\n * Resolves a `guideId` to a resource-pool id using `guideResourcePools`\n * (resource pools already filtered to the guide category) and `accountUsers`.\n * Returns the matched pool id, or `null` when nothing matches.\n */\nexport function matchGuideToResourcePool(\n guideId: string,\n guideResourcePools: ResourcePool[],\n accountUsers: Array<{ id: string; name: string }>,\n): string | null {\n // Direct resource-pool id match.\n const directIdMatch = guideResourcePools.find((pool) => pool.id === guideId);\n if (directIdMatch) {\n return directIdMatch.id;\n }\n\n // Match by backing account-user id.\n const accountUserMatch = guideResourcePools.find(\n (pool) => pool.accountUser?.id === guideId,\n );\n if (accountUserMatch) {\n return accountUserMatch.id;\n }\n\n // Match by pool name.\n const nameMatch = guideResourcePools.find((pool) => pool.name === guideId);\n if (nameMatch) {\n return nameMatch.id;\n }\n\n // Resolve via an account user, then match its pool by id or name.\n const matchedUser = accountUsers.find((user) => user.id === guideId);\n if (matchedUser) {\n const userIdMatch = guideResourcePools.find(\n (pool) => pool.accountUser?.id === matchedUser.id,\n );\n /* v8 ignore next 3 -- unreachable: the earlier account-user id match already\n returns when a pool's accountUser.id equals the guideId; kept for source parity. */\n if (userIdMatch) {\n return userIdMatch.id;\n }\n\n const userNameMatch = guideResourcePools.find(\n (pool) => pool.name === matchedUser.name,\n );\n if (userNameMatch) {\n return userNameMatch.id;\n }\n }\n\n return null;\n}\n","/**\n * Raw Peek GraphQL mutation and shapes for bulk resource-allocation requests\n * (used by guide assignment). Internal.\n */\n\n/** Bulk-(un)assigns resources (e.g. guides) to timeslots. */\nexport const RESOURCE_ALLOCATION_BULK_REQUEST_MUTATION = `\n mutation ResourceAllocationBulkRequest($input: ResourceAllocationBulkRequestInput!) {\n resourceAllocationBulkRequest(input: $input) {\n __typename\n ... on ResourceAllocationRequest {\n id\n }\n ... on GenericError {\n __typename\n message\n }\n }\n }\n`;\n\n/** Allocation status: assigning (`ACTIVE`) or unassigning (`REMOVAL`). */\nexport type ResourceAllocationStatus = \"ACTIVE\" | \"REMOVAL\";\n\n/** `data` payload of {@link RESOURCE_ALLOCATION_BULK_REQUEST_MUTATION}. */\nexport interface ResourceAllocationBulkRequestResponse {\n resourceAllocationBulkRequest:\n | { __typename: \"ResourceAllocationRequest\"; id: string }\n | { __typename: \"GenericError\"; message: string };\n}\n\n/** Builds the variables for {@link RESOURCE_ALLOCATION_BULK_REQUEST_MUTATION}. */\nexport function buildResourceAllocationVariables(\n timeslotIds: string[],\n resourcePoolIds: string[],\n status: ResourceAllocationStatus,\n): { input: { timeslotIds: string[]; resourcePoolIds: string[]; status: ResourceAllocationStatus } } {\n return { input: { timeslotIds, resourcePoolIds, status } };\n}\n","/**\n * Raw Peek GraphQL queries/mutations and response shapes for timeslots.\n * Internal.\n */\nimport type { TimeslotFilter } from \"../../../models/peek/timeslot.js\";\n\n/** Fetches timeslots for an activity/date via a filter. */\nexport const TIMESLOTS_QUERY = `\n query Sales($params: TimeslotsFilter!) {\n timeslots(filter: $params) {\n ... on TimeslotsSuccess {\n timeslots {\n id\n bookingCount\n availableSpots\n maxPartySize\n totalCapacity\n checkedInCount\n manifestNotes\n minuteLength\n status\n date\n inheritedResourceAllocations {\n id\n status\n quantity\n resourcePool {\n id\n name\n category\n capacity\n accountUser {\n id\n }\n }\n }\n resourceAllocations {\n quantity\n status\n resourcePool {\n id\n name\n category\n capacity\n accountUser {\n id\n }\n }\n }\n ... on VariableTimeslot {\n start\n }\n ... on FixedTimeslot {\n start\n }\n }\n }\n }\n }\n`;\n\n/** Fetches a single timeslot by id. */\nexport const TIMESLOT_BY_ID_QUERY = `\n query Sales($id: ID!) {\n timeslot(id: $id) {\n ... on ActivityTimeslotSuccess {\n timeslot {\n id\n bookingCount\n availableSpots\n maxPartySize\n totalCapacity\n checkedInCount\n manifestNotes\n minuteLength\n status\n date\n inheritedResourceAllocations {\n id\n status\n quantity\n resourcePool {\n id\n name\n category\n capacity\n accountUser {\n id\n }\n }\n }\n resourceAllocations {\n quantity\n status\n resourcePool {\n id\n name\n category\n capacity\n accountUser {\n id\n }\n }\n }\n ... on VariableTimeslot {\n start\n }\n ... on FixedTimeslot {\n start\n }\n }\n }\n }\n }\n`;\n\n/** Updates a timeslot's manifest notes and/or status. */\nexport const UPDATE_TIMESLOT_MUTATION = `\n mutation Account($input: UpdateTimeslotInput!) {\n updateTimeslot(input: $input) {\n ... on UpdateTimeslotSuccess {\n timeslot {\n id\n manifestNotes\n status\n }\n }\n }\n }\n`;\n\n/**\n * A single resource allocation on a timeslot node. Shared by both the\n * `inheritedResourceAllocations` and `resourceAllocations` selections; the\n * allocation-level `id` is only present on the inherited variant.\n */\nexport interface TimeslotResourceAllocationNode {\n id?: string | null;\n quantity: number | null;\n status: string | null;\n resourcePool: {\n id: string;\n name: string;\n category: string;\n capacity: number | null;\n accountUser: { id: string } | null;\n } | null;\n}\n\n/** A single timeslot node as returned by the timeslot queries. */\nexport interface TimeslotNode {\n id: string;\n bookingCount: number | null;\n availableSpots: number | null;\n maxPartySize: number | null;\n totalCapacity: number | null;\n checkedInCount: number | null;\n manifestNotes: string | null;\n minuteLength: number | null;\n status: string | null;\n date: string | null;\n start?: string | null;\n inheritedResourceAllocations: TimeslotResourceAllocationNode[] | null;\n resourceAllocations: TimeslotResourceAllocationNode[] | null;\n}\n\n/** `data` payload of {@link TIMESLOTS_QUERY}. */\nexport interface TimeslotsResponse {\n timeslots: { timeslots: TimeslotNode[] };\n}\n\n/** `data` payload of {@link TIMESLOT_BY_ID_QUERY}. */\nexport interface SingleTimeslotResponse {\n timeslot: { timeslot: TimeslotNode | null } | null;\n}\n\n/** `data` payload of {@link UPDATE_TIMESLOT_MUTATION}. */\nexport interface UpdateTimeslotResponse {\n updateTimeslot: {\n timeslot: { id: string; manifestNotes: string | null; status: string | null };\n };\n}\n\n/** Input for {@link UPDATE_TIMESLOT_MUTATION}. */\nexport interface UpdateTimeslotInput {\n id: string;\n manifestNotes?: string;\n status?: string;\n}\n\n/** Builds the variables for {@link TIMESLOTS_QUERY}. */\nexport function buildTimeslotVariables(\n productId: string,\n date: string,\n filter: TimeslotFilter,\n): { params: { activityIds: string[]; dateRange: string; hasBookings?: boolean } } {\n const params: {\n activityIds: string[];\n dateRange: string;\n hasBookings?: boolean;\n } = {\n activityIds: [productId],\n dateRange: `[${date},${date}]`,\n };\n\n if (filter === \"withBookings\") {\n params.hasBookings = true;\n } else if (filter === \"withoutBookings\") {\n params.hasBookings = false;\n }\n\n return { params };\n}\n","/**\n * Timeslot operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getTimeslotService}. The\n * `assignGuide` operation composes the resource-pool and account-user services\n * to resolve guides before issuing the allocation request.\n */\nimport type { AccountUserService } from \"../account-users/account-user-service.js\";\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type { ResourcePoolService } from \"../resource-pools/resource-pool-service.js\";\nimport type {\n AssignGuideResult,\n GuideAssignment,\n Timeslot,\n TimeslotFilter,\n UpdateTimeslotResult,\n} from \"../../../models/peek/timeslot.js\";\nimport { fromTimeslotNode, fromTimeslotNodes } from \"./timeslot-converter.js\";\nimport { matchGuideToResourcePool } from \"./guide-matcher.js\";\nimport {\n RESOURCE_ALLOCATION_BULK_REQUEST_MUTATION,\n buildResourceAllocationVariables,\n type ResourceAllocationBulkRequestResponse,\n type ResourceAllocationStatus,\n} from \"./resource-allocation-queries.js\";\nimport {\n TIMESLOTS_QUERY,\n TIMESLOT_BY_ID_QUERY,\n UPDATE_TIMESLOT_MUTATION,\n buildTimeslotVariables,\n type SingleTimeslotResponse,\n type TimeslotsResponse,\n type UpdateTimeslotInput,\n type UpdateTimeslotResponse,\n} from \"./timeslot-queries.js\";\n\nconst GUIDE_CATEGORY = \"guide\";\nconst ERROR_MISSING_TIMESLOTS_OR_GUIDES =\n \"At least one timeslot and one guide are required\";\nconst ERROR_INVALID_ACTION = \"Invalid action. Must be either assign or unassign\";\nconst ERROR_GUIDE_NOT_FOUND = \"Guide not found\";\n\n/** Dependencies the {@link TimeslotService} composes for guide assignment. */\nexport interface TimeslotServiceDeps {\n resourcePoolService: ResourcePoolService;\n accountUserService: AccountUserService;\n}\n\nexport class TimeslotService {\n constructor(\n private readonly client: GraphQLClient,\n private readonly deps: TimeslotServiceDeps,\n ) {}\n\n /** Returns the timeslots for an activity on a given date. */\n async getForDay(\n productId: string,\n date: string,\n filter: TimeslotFilter = \"all\",\n ): Promise<Timeslot[]> {\n const normalizedDate = normalizeDate(date);\n const body: GraphQLBody<TimeslotsResponse> =\n await this.client.request<TimeslotsResponse>(\n SALES_ENDPOINT,\n TIMESLOTS_QUERY,\n buildTimeslotVariables(productId, normalizedDate, filter),\n );\n\n return fromTimeslotNodes(body.data?.timeslots?.timeslots ?? [], productId);\n }\n\n /** Returns a single timeslot by id, or null when not found. */\n async getById(timeslotId: string): Promise<Timeslot | null> {\n const body: GraphQLBody<SingleTimeslotResponse> =\n await this.client.request<SingleTimeslotResponse>(\n SALES_ENDPOINT,\n TIMESLOT_BY_ID_QUERY,\n { id: timeslotId },\n );\n\n const node = body.data?.timeslot?.timeslot;\n if (!node) {\n return null;\n }\n return fromTimeslotNode(node, extractProductId(timeslotId));\n }\n\n /** Sets the timeslot's status (e.g. open/closed). */\n async setAvailability(\n timeslotId: string,\n status: string,\n ): Promise<UpdateTimeslotResult> {\n return this.updateTimeslot({ id: timeslotId, status });\n }\n\n /** Sets the timeslot's manifest notes. */\n async setNotes(\n timeslotId: string,\n manifestNotes: string,\n ): Promise<UpdateTimeslotResult> {\n return this.updateTimeslot({ id: timeslotId, manifestNotes });\n }\n\n /**\n * Assigns or unassigns guides across timeslots. Guides are resolved to\n * resource pools (by pool id, account-user id, or name) before the bulk\n * allocation request is issued.\n *\n * @example\n * ```ts\n * await peek.getTimeslotService().assignGuide({\n * timeslotIds: [\"ts_2026_06_20_0900\"],\n * guideIds: [\"Alex Guide\"], // pool id, account-user id, or name\n * action: \"assign\",\n * });\n * ```\n */\n async assignGuide(assignment: GuideAssignment): Promise<AssignGuideResult> {\n const { timeslotIds, guideIds, action } = assignment;\n\n if (!timeslotIds?.length || !guideIds?.length) {\n throw new Error(ERROR_MISSING_TIMESLOTS_OR_GUIDES);\n }\n if (action !== \"assign\" && action !== \"unassign\") {\n throw new Error(ERROR_INVALID_ACTION);\n }\n\n const [allPools, accountUsers] = await Promise.all([\n this.deps.resourcePoolService.getAll(),\n this.deps.accountUserService.getAll(),\n ]);\n const guidePools = allPools.filter((pool) => pool.category === GUIDE_CATEGORY);\n\n const resourcePoolIds = guideIds.map((guideId) => {\n const matched = matchGuideToResourcePool(guideId, guidePools, accountUsers);\n if (!matched) {\n throw new Error(`${ERROR_GUIDE_NOT_FOUND}: ${guideId}`);\n }\n return matched;\n });\n\n const status: ResourceAllocationStatus =\n action === \"assign\" ? \"ACTIVE\" : \"REMOVAL\";\n\n const body: GraphQLBody<ResourceAllocationBulkRequestResponse> =\n await this.client.request<ResourceAllocationBulkRequestResponse>(\n SALES_ENDPOINT,\n RESOURCE_ALLOCATION_BULK_REQUEST_MUTATION,\n buildResourceAllocationVariables(timeslotIds, resourcePoolIds, status),\n );\n\n const result = body.data?.resourceAllocationBulkRequest;\n if (result?.__typename === \"ResourceAllocationRequest\") {\n return {\n status: \"success\",\n resourceAllocationRequestId: result.id,\n errors: null,\n };\n }\n\n return {\n status: \"error\",\n resourceAllocationRequestId: null,\n errors: [{ message: result?.message ?? \"Unknown error\" }],\n };\n }\n\n private async updateTimeslot(\n input: UpdateTimeslotInput,\n ): Promise<UpdateTimeslotResult> {\n const body: GraphQLBody<UpdateTimeslotResponse> =\n await this.client.request<UpdateTimeslotResponse>(\n SALES_ENDPOINT,\n UPDATE_TIMESLOT_MUTATION,\n { input },\n );\n\n const timeslot = body.data?.updateTimeslot?.timeslot;\n return {\n manifestNotes: timeslot?.manifestNotes ?? null,\n status: timeslot?.status ?? null,\n };\n }\n}\n\n/** Activity timeslot ids are `\"<activityId>|...\"`; the activity id is the product id. */\nfunction extractProductId(timeslotId: string): string {\n /* v8 ignore next -- split always yields at least one element */\n return timeslotId.split(\"|\")[0] ?? \"\";\n}\n\n/** Timeslot day queries expect a `YYYY-MM-DD` date; drop any time component. */\nfunction normalizeDate(date: string): string {\n /* v8 ignore next -- split always yields at least one element */\n return date.split(\"T\")[0] ?? date;\n}\n","/**\n * Shared, pure helper for mapping a raw gateway money node\n * (`{ amount, currency, formatted }`) into the clean {@link PricingMoney} model.\n *\n * Internal only — never re-exported from `src/index.ts`. Converters across\n * resources (products, pricing overrides) reuse this so the `formatted →\n * displayPrice` mapping lives in exactly one place.\n */\nimport type { PricingMoney } from \"../../models/peek/pricing.js\";\n\n/** A raw money node as returned by the gateway. */\nexport interface RawMoney {\n amount: string;\n currency: string;\n /** Human-formatted display string (e.g. `\"$50.00\"`). */\n formatted?: string | null;\n}\n\n/**\n * Maps a raw money node into a {@link PricingMoney}, carrying the gateway's\n * `formatted` string across as `displayPrice`. Returns `null` for an\n * absent/`null` input so callers can pass an optional wire field straight\n * through.\n */\nexport function toPricingMoney(raw?: RawMoney | null): PricingMoney | null {\n if (!raw) return null;\n const money: PricingMoney = { amount: raw.amount, currency: raw.currency };\n if (raw.formatted != null) money.displayPrice = raw.formatted;\n return money;\n}\n","/**\n * Pure functions that map raw Peek GraphQL nodes into the clean {@link Product}\n * model. No I/O — straightforward, testable transformations.\n */\nimport {\n ADD_ON_PRODUCT_TYPE,\n type Product,\n type ProductMeetingLocation,\n} from \"../../../models/peek/product.js\";\nimport { toPricingMoney } from \"../money.js\";\nimport type { ActivityNode, ItemOptionNode } from \"./product-queries.js\";\n\n/** Default display color applied to add-on products. */\nconst ADD_ON_COLOR = \"#FFFFFF\";\n\n/**\n * Builds a {@link ProductMeetingLocation} from the flat activity fields,\n * collapsing to `null` when Peek reports no location detail at all. Each field\n * is independently nullable.\n */\nfunction toMeetingLocation(activity: ActivityNode): ProductMeetingLocation | null {\n const summary = activity.infoMeetingLocation ?? null;\n const address = activity.meetingLocationFormattedAddress ?? null;\n const url = activity.meetingLocationUrl ?? null;\n if (summary === null && address === null && url === null) return null;\n return { summary, address, url };\n}\n\n/** Converts the activities from a products response into {@link Product}s. */\nexport function fromActivities(activities: ActivityNode[]): Product[] {\n return activities.map(fromActivity);\n}\n\n/** Converts a single activity node into a {@link Product}. */\nfunction fromActivity(activity: ActivityNode): Product {\n return {\n // Prefer the primary GraphQL ID for stable product identity.\n productId: activity.id || activity.legacyId || \"\",\n name: activity.name,\n type: activity.type,\n color: activity.colorHex || \"\",\n currency: activity.currency || \"\",\n imageUrl: activity.imageUrl ?? null,\n description: activity.description ?? null,\n meetingLocation: toMeetingLocation(activity),\n tickets: (activity.resourceOptions ?? []).map((option) => ({\n id: option.id,\n name: option.name,\n minPrice: toPricingMoney(option.priceRange?.min),\n maxPrice: toPricingMoney(option.priceRange?.max),\n })),\n };\n}\n\n/**\n * Converts a flat list of item option nodes into add-on {@link Product}s by\n * grouping each option under its parent item. The parent item id becomes the\n * `productId` and its name becomes the product `name`; each option becomes a\n * ticket.\n */\nexport function fromItemOptionNodes(nodes: ItemOptionNode[]): Product[] {\n const grouped = new Map<string, Product>();\n\n for (const node of nodes) {\n const itemId = node.item?.id;\n if (!itemId) continue;\n\n let product = grouped.get(itemId);\n if (!product) {\n product = {\n productId: itemId,\n name: node.item.name,\n type: ADD_ON_PRODUCT_TYPE,\n color: ADD_ON_COLOR,\n currency: \"\",\n imageUrl: null,\n description: null,\n meetingLocation: null,\n tickets: [],\n };\n grouped.set(itemId, product);\n }\n product.tickets.push({\n id: node.id,\n name: node.name,\n minPrice: null,\n maxPrice: null,\n });\n }\n\n return Array.from(grouped.values());\n}\n","/**\n * Pure functions that map raw Peek question configuration nodes into the clean\n * {@link CustomQuestion} model. No I/O — straightforward, testable transforms.\n */\nimport type {\n CustomQuestion,\n CustomQuestionOption,\n} from \"../../../models/peek/custom-question.js\";\nimport type {\n QuestionConfigurationNode,\n RawQuestionOptionNode,\n} from \"./custom-question-queries.js\";\n\n/** Converts an activity's question configurations into {@link CustomQuestion}s. */\nexport function fromQuestionConfigurations(\n configs: QuestionConfigurationNode[],\n): CustomQuestion[] {\n return configs.map(fromQuestionConfiguration);\n}\n\n/** Converts a single question configuration node into a {@link CustomQuestion}. */\nfunction fromQuestionConfiguration(\n config: QuestionConfigurationNode,\n): CustomQuestion {\n const question = config.question;\n return {\n id: question.id,\n order: config.order ?? 0,\n isRequired: config.isRequired ?? false,\n questionText: question.text,\n hintText: question.hint ?? null,\n questionType: question.questionType,\n internalLabel: question.internalLabel ?? null,\n perGuest: question.perGuest ?? false,\n defaultValue: question.answerDefaultValue ?? null,\n options: (question.options ?? []).map(fromQuestionOption),\n };\n}\n\n/** Converts a raw choice-question option node into a {@link CustomQuestionOption}. */\nfunction fromQuestionOption(\n option: RawQuestionOptionNode,\n): CustomQuestionOption {\n return {\n id: option.id,\n order: option.order,\n value: option.text,\n };\n}\n","/**\n * Raw Peek GraphQL queries and response shapes for products. These are an\n * internal implementation detail of the package and are deliberately not\n * re-exported from the public entry point.\n */\n\n/** Fetches all activities (primary bookable products). */\nexport const PRODUCTS_QUERY = `\n query Sales {\n activities {\n name\n legacyId\n id\n deletedAt\n type\n colorHex\n currency\n imageUrl\n description\n meetingLocationFormattedAddress\n meetingLocationUrl\n infoMeetingLocation\n resourceOptions {\n id\n name\n priceRange {\n min {\n currency\n amount\n formatted\n }\n max {\n currency\n amount\n formatted\n }\n }\n }\n }\n }\n`;\n\n/** A raw monetary value on the wire (a `PricingMoney` before conversion). */\nexport interface RawMoneyNode {\n currency: string;\n amount: string;\n formatted?: string;\n}\n\n/** A single activity node as returned by {@link PRODUCTS_QUERY}. */\nexport interface ActivityNode {\n name: string;\n legacyId?: string;\n id: string;\n deletedAt?: string | null;\n type: string;\n colorHex: string;\n currency?: string;\n imageUrl?: string | null;\n description?: string | null;\n meetingLocationFormattedAddress?: string | null;\n meetingLocationUrl?: string | null;\n infoMeetingLocation?: string | null;\n resourceOptions: Array<{\n id: string;\n name: string;\n priceRange?: { min?: RawMoneyNode | null; max?: RawMoneyNode | null } | null;\n }>;\n}\n\n/** The `data` payload of {@link PRODUCTS_QUERY}. */\nexport interface ProductsResponse {\n activities: ActivityNode[];\n}\n\n/** Fetches a single cursor-paginated page of item options (add-ons). */\nexport const ITEM_OPTIONS_QUERY = `\n query GetItemOptions($first: Int, $after: String) {\n itemOptions(first: $first, after: $after) {\n edges {\n cursor\n node {\n id\n name\n description\n item {\n id\n name\n }\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n`;\n\n/** A single item option node as returned by {@link ITEM_OPTIONS_QUERY}. */\nexport interface ItemOptionNode {\n id: string;\n name: string;\n description: string | null;\n item: {\n id: string;\n name: string;\n };\n}\n\n/** The `data` payload of {@link ITEM_OPTIONS_QUERY}. */\nexport interface ItemOptionsData {\n itemOptions: {\n edges: Array<{ cursor: string; node: ItemOptionNode }>;\n pageInfo: {\n hasNextPage: boolean;\n endCursor: string | null;\n };\n };\n}\n","/**\n * Raw Peek GraphQL query and response shapes for an activity's custom\n * questions. These are an internal implementation detail of the package and are\n * deliberately not re-exported from the public entry point.\n */\n\n/** Fetches every custom question configured on a single activity. */\nexport const CUSTOM_QUESTIONS_QUERY = `\n query Sales($id: ID!) {\n activity(id: $id) {\n id\n name\n questionActivityConfigurations {\n isRequired\n order\n question {\n id\n questionType\n text\n answerDefaultValue\n hint\n internalLabel\n perGuest\n ... on ChoiceQuestion {\n options {\n id\n text\n order\n }\n }\n }\n }\n }\n }\n`;\n\n/** A single selectable option on a raw `ChoiceQuestion` node. */\nexport interface RawQuestionOptionNode {\n id: string;\n text: string;\n order: number;\n}\n\n/** A raw question node as returned inside a question configuration. */\nexport interface RawQuestionNode {\n id: string;\n questionType: string;\n text: string;\n answerDefaultValue?: string | null;\n hint?: string | null;\n internalLabel?: string | null;\n perGuest?: boolean | null;\n /** Present only on `ChoiceQuestion` nodes (via the inline fragment). */\n options?: RawQuestionOptionNode[] | null;\n}\n\n/** A single `questionActivityConfigurations` entry pairing config + question. */\nexport interface QuestionConfigurationNode {\n isRequired?: boolean | null;\n order?: number | null;\n question: RawQuestionNode;\n}\n\n/** The `data` payload of {@link CUSTOM_QUESTIONS_QUERY}. */\nexport interface CustomQuestionsResponse {\n activity: {\n id: string;\n name: string;\n questionActivityConfigurations?: QuestionConfigurationNode[] | null;\n } | null;\n}\n","/**\n * Product-related operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getProductService} rather than\n * constructing it directly — the access service wires in the authenticated,\n * shared transport. This class is where product-specific business logic lives.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport {\n ACTIVITY_PRODUCT_TYPE,\n RENTAL_PRODUCT_TYPE,\n type Product,\n} from \"../../../models/peek/product.js\";\nimport type { CustomQuestion } from \"../../../models/peek/custom-question.js\";\nimport { fromActivities, fromItemOptionNodes } from \"./product-converter.js\";\nimport { fromQuestionConfigurations } from \"./custom-question-converter.js\";\nimport {\n ITEM_OPTIONS_QUERY,\n PRODUCTS_QUERY,\n type ItemOptionNode,\n type ItemOptionsData,\n type ProductsResponse,\n} from \"./product-queries.js\";\nimport {\n CUSTOM_QUESTIONS_QUERY,\n type CustomQuestionsResponse,\n} from \"./custom-question-queries.js\";\n\n/** Thrown-error message when a product id is missing or blank. */\nconst ERROR_PRODUCT_ID_REQUIRED = \"A non-empty product id is required.\";\n\n/** Default page size for cursor-paginated item options. */\nconst DEFAULT_ITEM_OPTIONS_PAGE_SIZE = 50;\n\n/** Tuning options for a {@link ProductService}. */\nexport interface ProductServiceOptions {\n /** Page size for cursor-paginated item options. Default: 50. */\n itemOptionsPageSize?: number;\n}\n\nexport class ProductService {\n private readonly itemOptionsPageSize: number;\n\n constructor(\n private readonly client: GraphQLClient,\n options: ProductServiceOptions = {},\n ) {\n this.itemOptionsPageSize =\n options.itemOptionsPageSize ?? DEFAULT_ITEM_OPTIONS_PAGE_SIZE;\n }\n\n /**\n * Returns every product as a single flat list: activities plus add-ons (the\n * latter tagged with the add-on type). Add-ons are gathered across all\n * cursor-paginated pages.\n *\n * @example Split activities from add-ons\n * ```ts\n * import { ADD_ON_PRODUCT_TYPE } from \"@peektravel/app-utilities\";\n *\n * const products = await peek.getProductService().getAllProducts();\n * const activities = products.filter((p) => p.type !== ADD_ON_PRODUCT_TYPE);\n * const addons = products.filter((p) => p.type === ADD_ON_PRODUCT_TYPE);\n * ```\n */\n async getAllProducts(): Promise<Product[]> {\n const [activities, itemOptionNodes] = await Promise.all([\n this.fetchActivities(),\n this.fetchAllItemOptionNodes(),\n ]);\n\n return [...fromActivities(activities), ...fromItemOptionNodes(itemOptionNodes)];\n }\n\n /** Returns products with type {@link ACTIVITY_PRODUCT_TYPE}. */\n async getAllActivities(): Promise<Product[]> {\n const activities = await this.fetchActivities();\n return fromActivities(activities).filter((p) => p.type === ACTIVITY_PRODUCT_TYPE);\n }\n\n /** Returns products with type {@link RENTAL_PRODUCT_TYPE}. */\n async getAllRentals(): Promise<Product[]> {\n const activities = await this.fetchActivities();\n return fromActivities(activities).filter((p) => p.type === RENTAL_PRODUCT_TYPE);\n }\n\n /** Returns only add-on products. */\n async getAllAddons(): Promise<Product[]> {\n const nodes = await this.fetchAllItemOptionNodes();\n return fromItemOptionNodes(nodes);\n }\n\n /**\n * Returns every custom question configured on a single activity, in the order\n * Peek reports them. Choice-style questions (`SELECT_ONE`, `LOCATION`, …)\n * carry their selectable {@link CustomQuestion.options}; free-text/checkbox\n * questions return an empty option list.\n *\n * These are question **definitions**, not customer answers — no PII is\n * involved, so the result is unaffected by `fullCustomerAccess`.\n *\n * @param productId The activity's id.\n * @returns The activity's custom questions, or an empty list when the activity\n * has none or is not found.\n * @throws Error when `productId` is missing or blank.\n */\n async getCustomQuestions(productId: string): Promise<CustomQuestion[]> {\n if (!productId?.trim()) {\n throw new Error(ERROR_PRODUCT_ID_REQUIRED);\n }\n\n const body: GraphQLBody<CustomQuestionsResponse> =\n await this.client.request<CustomQuestionsResponse>(\n SALES_ENDPOINT,\n CUSTOM_QUESTIONS_QUERY,\n { id: productId },\n );\n\n const configs = body.data?.activity?.questionActivityConfigurations ?? [];\n return fromQuestionConfigurations(configs);\n }\n\n private async fetchActivities(): Promise<ProductsResponse[\"activities\"]> {\n const body: GraphQLBody<ProductsResponse> =\n await this.client.request<ProductsResponse>(\n SALES_ENDPOINT,\n PRODUCTS_QUERY,\n {},\n );\n return body.data?.activities ?? [];\n }\n\n private async fetchAllItemOptionNodes(): Promise<ItemOptionNode[]> {\n const all: ItemOptionNode[] = [];\n let after: string | null = null;\n\n for (;;) {\n const body: GraphQLBody<ItemOptionsData> =\n await this.client.request<ItemOptionsData>(\n SALES_ENDPOINT,\n ITEM_OPTIONS_QUERY,\n { first: this.itemOptionsPageSize, after },\n );\n\n const connection = body.data?.itemOptions;\n for (const edge of connection?.edges ?? []) {\n all.push(edge.node);\n }\n\n const pageInfo = connection?.pageInfo;\n if (pageInfo?.hasNextPage && pageInfo.endCursor) {\n after = pageInfo.endCursor;\n } else {\n break;\n }\n }\n\n return all;\n }\n}\n","/**\n * Raw Peek GraphQL query/mutation and response shapes for promo codes.\n * Internal. The promo-code node matches the public {@link PromoCode} model\n * one-to-one, so no converter is needed.\n */\nimport type { PromoCode } from \"../../../models/peek/promo-code.js\";\n\n/** Fetches a cursor-paginated page of promo codes. */\nexport const PROMO_CODES_QUERY = `\n query Sales($first: Int, $after: String) {\n promoCodes(first: $first, after: $after) {\n edges {\n node {\n id\n name\n percentAmount\n perTicketDiscount\n redemptionCode\n fixedAmount {\n amount\n currency\n formatted\n }\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n`;\n\n/** Creates a promo code. Returns the new code's id/name or an InvalidDataError. */\nexport const CREATE_PROMO_CODE_MUTATION = `\n mutation Sales($input: CreatePromoCodeInput!) {\n createPromoCode(input: $input) {\n ... on InvalidDataError {\n message\n }\n ... on PromoCode {\n id\n name\n }\n }\n }\n`;\n\n/** `data` payload of {@link PROMO_CODES_QUERY}. */\nexport interface PromoCodesResponse {\n promoCodes: {\n edges: Array<{ node: PromoCode }>;\n pageInfo: { hasNextPage: boolean; endCursor: string | null };\n };\n}\n\n/** `data` payload of {@link CREATE_PROMO_CODE_MUTATION}. */\nexport interface CreatePromoCodeResponse {\n createPromoCode: { message: string } | { id: string; name: string };\n}\n\n/** Variables for {@link CREATE_PROMO_CODE_MUTATION}. */\nexport interface CreatePromoCodeVariables {\n input: {\n code: string;\n name: string;\n maxRedeemCount?: number;\n fixedAmount?: { amount: string; currency: string };\n percentAmount?: string;\n };\n}\n","/**\n * Promo-code operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getPromoCodeService}.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type {\n CreatePromoCodeInput,\n CreatedPromoCode,\n PromoCode,\n} from \"../../../models/peek/promo-code.js\";\nimport {\n CREATE_PROMO_CODE_MUTATION,\n PROMO_CODES_QUERY,\n type CreatePromoCodeResponse,\n type CreatePromoCodeVariables,\n type PromoCodesResponse,\n} from \"./promo-code-queries.js\";\n\n/** Default page size for cursor-paginated promo codes. */\nconst DEFAULT_PAGE_SIZE = 50;\n/** Default currency for fixed-amount discounts. */\nconst DEFAULT_CURRENCY = \"USD\";\n/** ISO currency codes are three uppercase letters. */\nconst CURRENCY_PATTERN = /^[A-Z]{3}$/;\n\n/** Tuning options for a {@link PromoCodeService}. */\nexport interface PromoCodeServiceOptions {\n /** Page size for cursor pagination. Default: 50. */\n pageSize?: number;\n}\n\nexport class PromoCodeService {\n private readonly pageSize: number;\n\n constructor(\n private readonly client: GraphQLClient,\n options: PromoCodeServiceOptions = {},\n ) {\n this.pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;\n }\n\n /** Returns all promo codes, walking the cursor pagination to the end. */\n async getAll(): Promise<PromoCode[]> {\n const all: PromoCode[] = [];\n let after: string | null = null;\n\n for (;;) {\n const body: GraphQLBody<PromoCodesResponse> =\n await this.client.request<PromoCodesResponse>(SALES_ENDPOINT, PROMO_CODES_QUERY, {\n first: this.pageSize,\n after,\n });\n\n const connection = body.data?.promoCodes;\n for (const edge of connection?.edges ?? []) {\n all.push(edge.node);\n }\n\n const pageInfo = connection?.pageInfo;\n if (pageInfo?.hasNextPage && pageInfo.endCursor) {\n after = pageInfo.endCursor;\n } else {\n break;\n }\n }\n\n return all;\n }\n\n /**\n * Creates a promo code. Throws on invalid input or when Peek returns an\n * InvalidDataError.\n */\n async create(input: CreatePromoCodeInput): Promise<CreatedPromoCode> {\n if (!input.name) throw new Error(\"name is required\");\n if (!input.code) throw new Error(\"code is required\");\n if (!input.amount) throw new Error(\"amount is required\");\n if (!input.discountType) throw new Error(\"discountType is required\");\n if (input.discountType !== \"percent\" && input.discountType !== \"fixed\") {\n throw new Error(\"discountType must be either 'percent' or 'fixed'\");\n }\n if (Number.isNaN(parseFloat(input.amount))) {\n throw new Error(\"amount must be a valid number\");\n }\n const currency = input.currency || DEFAULT_CURRENCY;\n if (!CURRENCY_PATTERN.test(currency)) {\n throw new Error(\"currency must be 3 uppercase letters\");\n }\n\n const variables: CreatePromoCodeVariables = {\n input: {\n code: input.code,\n name: input.name,\n maxRedeemCount: input.maxRedemptions\n ? parseInt(String(input.maxRedemptions), 10)\n : undefined,\n },\n };\n if (input.discountType === \"fixed\") {\n variables.input.fixedAmount = { amount: input.amount, currency };\n } else {\n variables.input.percentAmount = input.amount;\n }\n\n const body: GraphQLBody<CreatePromoCodeResponse> =\n await this.client.request<CreatePromoCodeResponse>(\n SALES_ENDPOINT,\n CREATE_PROMO_CODE_MUTATION,\n variables,\n );\n\n const result = body.data?.createPromoCode;\n if (result && \"message\" in result) {\n throw new Error(result.message);\n }\n if (!result) {\n throw new Error(\"createPromoCode returned no data\");\n }\n return { id: result.id, name: result.name };\n }\n}\n","/**\n * Raw Peek GraphQL mutations, response shapes, and clean→raw variable builders\n * for pricing engines and pricing overrides. Internal — never re-exported.\n *\n * The public {@link UpsertOverridesInput} mirrors the wire input almost exactly;\n * the only transform the builders apply is stripping the `mode` discriminant off\n * each resource-option override down to the bare `price` / `percentageAdjustment`\n * key the API expects. Filters already match the wire shape and pass through.\n */\nimport type {\n ClearOverridesInput,\n CreateEngineInput,\n PricingOverrideFilter,\n UpdateEngineInput,\n UpsertOverridesInput,\n} from \"../../../models/peek/pricing.js\";\n\n// ─── Mutations ───────────────────────────────────────────────────────────────\n\n/** Creates a pricing engine, optionally scoped to a set of activity ids. */\nexport const CREATE_PRICING_ENGINE_MUTATION = `\n mutation CreatePricingEngine($input: CreatePricingEngineInput!) {\n createPricingEngine(input: $input) {\n __typename\n ... on CreatePricingEngineSuccess {\n engine {\n id\n }\n }\n ... on InvalidDataError {\n message\n }\n }\n }\n`;\n\n/** Updates a pricing engine's name and/or activity-id scope. */\nexport const UPDATE_PRICING_ENGINE_MUTATION = `\n mutation UpdatePricingEngine($input: UpdatePricingEngineInput!) {\n updatePricingEngine(input: $input) {\n __typename\n ... on UpdatePricingEngineSuccess {\n engine {\n id\n name\n }\n }\n ... on InvalidDataError {\n message\n }\n ... on NotFoundError {\n id\n message\n }\n }\n }\n`;\n\n/** Deletes a pricing engine. Idempotent — a NotFoundError is treated as success. */\nexport const DELETE_PRICING_ENGINE_MUTATION = `\n mutation DeletePricingEngine($id: ID!) {\n deletePricingEngine(id: $id) {\n __typename\n ... on DeletePricingEngineSuccess {\n engine {\n id\n name\n }\n }\n ... on NotFoundError {\n id\n message\n }\n }\n }\n`;\n\n/** Upserts (or clears, via empty overrides) pricing overrides for a date range. */\nexport const UPSERT_PRICING_OVERRIDES_MUTATION = `\n mutation UpsertPricingOverridesActivityContexts($input: UpsertPricingOverridesActivityContextsInput!) {\n upsertPricingOverridesActivityContexts(input: $input) {\n __typename\n ... on UpsertPricingOverridesActivityContextsSuccess {\n activityContexts {\n date\n activity {\n id\n name\n }\n engine {\n id\n name\n }\n overrides {\n order\n resourceOptions {\n resourceOption {\n id\n name\n }\n override {\n ... on PricingOverridesActivityContextResourceOptionPriceOverride {\n price {\n amount\n currency\n formatted\n }\n }\n ... on PricingOverridesActivityContextResourceOptionPercentageAdjustmentOverride {\n percentageAdjustment\n }\n }\n }\n filters {\n __typename\n ... on PricingOverridesActivityContextStartTimeRangeFilter {\n startTimeRange\n }\n ... on PricingOverridesActivityContextSpotsTakenFilter {\n minSpots\n maxSpots\n }\n }\n }\n }\n }\n ... on InvalidDataError {\n message\n }\n }\n }\n`;\n\n// ─── Filter typenames (used by the converter to tag response filters) ─────────\n\n/** `__typename` of the start-time-range filter in a pricing-override response. */\nexport const START_TIME_RANGE_FILTER_TYPENAME =\n \"PricingOverridesActivityContextStartTimeRangeFilter\";\n/** `__typename` of the spots-taken filter in a pricing-override response. */\nexport const SPOTS_TAKEN_FILTER_TYPENAME =\n \"PricingOverridesActivityContextSpotsTakenFilter\";\n\n// ─── Raw wire shapes: engine mutations ────────────────────────────────────────\n\n/** Raw variables for {@link CREATE_PRICING_ENGINE_MUTATION}. */\nexport interface CreateEngineVariables {\n input: { name: string; filters?: Array<{ activityIds: string[] }> };\n}\n\n/** `data` payload of {@link CREATE_PRICING_ENGINE_MUTATION}. */\nexport interface CreateEngineResponse {\n createPricingEngine:\n | { __typename: \"CreatePricingEngineSuccess\"; engine: { id: string } }\n | { __typename: \"InvalidDataError\"; message: string };\n}\n\n/** Raw variables for {@link UPDATE_PRICING_ENGINE_MUTATION}. */\nexport interface UpdateEngineVariables {\n input: { id: string; name: string; filters: Array<{ activityIds: string[] }> };\n}\n\n/** `data` payload of {@link UPDATE_PRICING_ENGINE_MUTATION}. */\nexport interface UpdateEngineResponse {\n updatePricingEngine:\n | { __typename: \"UpdatePricingEngineSuccess\"; engine: { id: string; name: string } }\n | { __typename: \"InvalidDataError\"; message: string }\n | { __typename: \"NotFoundError\"; id: string; message: string };\n}\n\n/** Raw variables for {@link DELETE_PRICING_ENGINE_MUTATION}. */\nexport interface DeleteEngineVariables {\n id: string;\n}\n\n/** `data` payload of {@link DELETE_PRICING_ENGINE_MUTATION}. */\nexport interface DeleteEngineResponse {\n deletePricingEngine:\n | { __typename: \"DeletePricingEngineSuccess\"; engine: { id: string; name: string } }\n | { __typename: \"NotFoundError\"; id: string; message: string };\n}\n\n// ─── Raw wire shapes: upsert mutation ─────────────────────────────────────────\n\n/** A raw resource-option override on the wire (the `mode` tag stripped). */\nexport type RawResourceOptionOverride =\n | { id: string; price: { amount: string; currency: string } }\n | { id: string; percentageAdjustment: string };\n\n/** A raw override entry on the wire. */\nexport interface RawOverride {\n order: number;\n resourceOptions: RawResourceOptionOverride[];\n filters: PricingOverrideFilter[];\n}\n\n/** The raw upsert input on the wire. */\nexport interface RawUpsertInput {\n engineId: string;\n dateRange: string;\n activities: Array<{ activityId: string; overrides: RawOverride[] }>;\n}\n\n/** Raw variables for {@link UPSERT_PRICING_OVERRIDES_MUTATION}. */\nexport interface UpsertOverridesVariables {\n input: RawUpsertInput;\n}\n\n/** A single resolved resource-option override as returned by the API. */\nexport type RawResolvedOverride =\n | { price: { amount: string; currency: string; formatted?: string } }\n | { percentageAdjustment: string };\n\n/** A single resolved filter as returned by the API (tagged by `__typename`). */\nexport type RawResolvedFilter =\n | { __typename: typeof START_TIME_RANGE_FILTER_TYPENAME; startTimeRange: string }\n | {\n __typename: typeof SPOTS_TAKEN_FILTER_TYPENAME;\n minSpots: number | null;\n maxSpots: number | null;\n };\n\n/** A single resolved activity context as returned by the API. */\nexport interface RawActivityContext {\n date: string;\n activity: { id: string; name: string };\n engine: { id: string; name: string };\n overrides: Array<{\n order: number;\n resourceOptions: Array<{\n resourceOption: { id: string; name: string };\n override: RawResolvedOverride;\n }>;\n filters: RawResolvedFilter[];\n }>;\n}\n\n/** `data` payload of {@link UPSERT_PRICING_OVERRIDES_MUTATION}. */\nexport interface UpsertOverridesResponse {\n upsertPricingOverridesActivityContexts:\n | {\n __typename: \"UpsertPricingOverridesActivityContextsSuccess\";\n activityContexts: RawActivityContext[];\n }\n | { __typename: \"InvalidDataError\"; message: string };\n}\n\n// ─── Clean → raw variable builders ────────────────────────────────────────────\n\n/** Builds the raw create-engine input, attaching an activity-ids filter when scoped. */\nexport function buildCreateEngineInput(\n input: CreateEngineInput,\n): CreateEngineVariables[\"input\"] {\n const activityIds = input.activityIds ?? [];\n return activityIds.length > 0\n ? { name: input.name, filters: [{ activityIds }] }\n : { name: input.name };\n}\n\n/** Builds the raw update-engine input. An empty/omitted scope clears the filter. */\nexport function buildUpdateEngineInput(\n input: UpdateEngineInput,\n): UpdateEngineVariables[\"input\"] {\n const activityIds = input.activityIds ?? [];\n return {\n id: input.engineId,\n name: input.name,\n filters: activityIds.length > 0 ? [{ activityIds }] : [],\n };\n}\n\n/** Maps a clean {@link UpsertOverridesInput} to the raw wire input. */\nexport function buildUpsertInput(input: UpsertOverridesInput): RawUpsertInput {\n return {\n engineId: input.engineId,\n dateRange: input.dateRange,\n activities: input.activities.map((activity) => ({\n activityId: activity.activityId,\n overrides: activity.overrides.map((override) => ({\n order: override.order,\n resourceOptions: override.resourceOptions.map((option) =>\n option.mode === \"fixed\"\n ? {\n id: option.id,\n // Send only the wire fields — `displayPrice` is read-only.\n price: { amount: option.price.amount, currency: option.price.currency },\n }\n : { id: option.id, percentageAdjustment: option.percentageAdjustment },\n ),\n filters: override.filters,\n })),\n })),\n };\n}\n\n/** Builds the raw upsert input that clears all overrides for the given activities. */\nexport function buildClearInput(input: ClearOverridesInput): RawUpsertInput {\n return {\n engineId: input.engineId,\n dateRange: input.dateRange,\n activities: input.activityIds.map((activityId) => ({\n activityId,\n overrides: [],\n })),\n };\n}\n","/**\n * Pure functions mapping raw pricing-override GraphQL nodes into the clean\n * {@link PricingActivityContext} model. No I/O — easy to unit-test.\n *\n * Two normalizations happen here, both erasing quirks of the wire format:\n * - Each resource-option override arrives as either a `price` object or a bare\n * `percentageAdjustment`; we tag it with a `mode` discriminant.\n * - Each filter arrives `__typename`-tagged with `null`-able bounds; we map it\n * back to the same compact {@link PricingOverrideFilter} union used on input,\n * dropping absent (`null`) spots bounds.\n */\nimport type {\n PricingActivityContext,\n PricingOverrideFilter,\n ResolvedOverride,\n ResolvedPricingOverride,\n ResolvedResourceOption,\n} from \"../../../models/peek/pricing.js\";\nimport { toPricingMoney } from \"../money.js\";\nimport {\n SPOTS_TAKEN_FILTER_TYPENAME,\n type RawActivityContext,\n type RawResolvedFilter,\n type RawResolvedOverride,\n} from \"./pricing-queries.js\";\n\n/** Converts the raw activity contexts from an upsert response into clean models. */\nexport function fromActivityContexts(\n contexts: RawActivityContext[],\n): PricingActivityContext[] {\n return contexts.map(fromActivityContext);\n}\n\nfunction fromActivityContext(context: RawActivityContext): PricingActivityContext {\n return {\n date: context.date,\n activity: { id: context.activity.id, name: context.activity.name },\n engine: { id: context.engine.id, name: context.engine.name },\n overrides: context.overrides.map(fromOverride),\n };\n}\n\nfunction fromOverride(\n override: RawActivityContext[\"overrides\"][number],\n): ResolvedPricingOverride {\n return {\n order: override.order,\n resourceOptions: override.resourceOptions.map(fromResourceOption),\n filters: override.filters.map(fromFilter),\n };\n}\n\nfunction fromResourceOption(\n option: RawActivityContext[\"overrides\"][number][\"resourceOptions\"][number],\n): ResolvedResourceOption {\n return {\n resourceOption: {\n id: option.resourceOption.id,\n name: option.resourceOption.name,\n },\n override: fromResolvedOverride(option.override),\n };\n}\n\nfunction fromResolvedOverride(override: RawResolvedOverride): ResolvedOverride {\n return \"price\" in override\n ? { mode: \"fixed\", price: toPricingMoney(override.price)! }\n : { mode: \"percentage\", percentageAdjustment: override.percentageAdjustment };\n}\n\nfunction fromFilter(filter: RawResolvedFilter): PricingOverrideFilter {\n if (filter.__typename === SPOTS_TAKEN_FILTER_TYPENAME) {\n const spotsTaken: { minSpots?: number; maxSpots?: number } = {};\n if (filter.minSpots !== null) spotsTaken.minSpots = filter.minSpots;\n if (filter.maxSpots !== null) spotsTaken.maxSpots = filter.maxSpots;\n return { spotsTaken };\n }\n return { startTimeRange: filter.startTimeRange };\n}\n","/**\n * Pricing-engine and pricing-override operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getPricingService} rather than\n * constructing it directly.\n *\n * Scope: this service is a thin, faithful wrapper over the Peek pricing\n * primitives. It creates/updates/deletes engines and upserts/clears overrides,\n * validating inputs and mapping the typed-error unions to thrown `Error`s. It\n * does **not** own the domain logic that decides what the overrides should be —\n * segmenting activities across time windows, ordering override tiers, or\n * computing `spotsTaken` bounds. Callers build the {@link UpsertOverridesInput}\n * (see the model docs) and this service sends it as-is.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type {\n ClearOverridesInput,\n CreateEngineInput,\n CreatedPricingEngine,\n PricingEngine,\n ResourceOptionOverride,\n UpdateEngineInput,\n UpsertOverridesInput,\n UpsertOverridesResult,\n} from \"../../../models/peek/pricing.js\";\nimport { fromActivityContexts } from \"./pricing-converter.js\";\nimport {\n buildClearInput,\n buildCreateEngineInput,\n buildUpdateEngineInput,\n buildUpsertInput,\n CREATE_PRICING_ENGINE_MUTATION,\n DELETE_PRICING_ENGINE_MUTATION,\n UPDATE_PRICING_ENGINE_MUTATION,\n UPSERT_PRICING_OVERRIDES_MUTATION,\n type CreateEngineResponse,\n type DeleteEngineResponse,\n type UpdateEngineResponse,\n type UpsertOverridesResponse,\n} from \"./pricing-queries.js\";\n\n/** ISO 4217 currency codes are three uppercase letters. */\nconst CURRENCY_PATTERN = /^[A-Z]{3}$/;\n/** A percentage adjustment must be strictly greater than this floor. */\nconst PERCENTAGE_FLOOR = -100;\n\nconst ERROR_NAME_REQUIRED = \"name is required\";\nconst ERROR_ENGINE_ID_REQUIRED = \"engineId is required\";\nconst ERROR_DATE_RANGE_REQUIRED = \"dateRange is required\";\nconst ERROR_ACTIVITIES_REQUIRED = \"activities is required\";\nconst ERROR_ACTIVITY_ID_REQUIRED = \"activityId is required\";\nconst ERROR_TICKET_ID_REQUIRED = \"resource-option id is required\";\nconst ERROR_CURRENCY_FORMAT = \"currency must be 3 uppercase letters\";\nconst ERROR_AMOUNT_NUMBER = \"price amount must be a valid number\";\nconst ERROR_PERCENTAGE_NUMBER = \"percentageAdjustment must be a valid number\";\nconst ERROR_PERCENTAGE_FLOOR = \"percentageAdjustment must be greater than -100\";\nconst ERROR_NO_DATA = \"pricing mutation returned no data\";\n\nexport class PricingService {\n constructor(private readonly client: GraphQLClient) {}\n\n /**\n * Creates a pricing engine. Store the returned id and reuse it on every\n * subsequent override upsert. Throws on an InvalidDataError from Peek.\n */\n async createEngine(input: CreateEngineInput): Promise<CreatedPricingEngine> {\n if (!input.name) throw new Error(ERROR_NAME_REQUIRED);\n\n const body: GraphQLBody<CreateEngineResponse> =\n await this.client.request<CreateEngineResponse>(\n SALES_ENDPOINT,\n CREATE_PRICING_ENGINE_MUTATION,\n { input: buildCreateEngineInput(input) },\n );\n\n const result = body.data?.createPricingEngine;\n if (!result) throw new Error(ERROR_NO_DATA);\n if (result.__typename !== \"CreatePricingEngineSuccess\") {\n throw new Error(result.message);\n }\n return { id: result.engine.id };\n }\n\n /**\n * Updates a pricing engine's name and/or activity scope. Throws on an\n * InvalidDataError or NotFoundError from Peek.\n */\n async updateEngine(input: UpdateEngineInput): Promise<PricingEngine> {\n if (!input.engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);\n if (!input.name) throw new Error(ERROR_NAME_REQUIRED);\n\n const body: GraphQLBody<UpdateEngineResponse> =\n await this.client.request<UpdateEngineResponse>(\n SALES_ENDPOINT,\n UPDATE_PRICING_ENGINE_MUTATION,\n { input: buildUpdateEngineInput(input) },\n );\n\n const result = body.data?.updatePricingEngine;\n if (!result) throw new Error(ERROR_NO_DATA);\n if (result.__typename !== \"UpdatePricingEngineSuccess\") {\n throw new Error(result.message);\n }\n return { id: result.engine.id, name: result.engine.name };\n }\n\n /**\n * Deletes a pricing engine. Idempotent — resolves whether the engine existed\n * or was already gone (Peek's NotFoundError is treated as success).\n */\n async deleteEngine(engineId: string): Promise<void> {\n if (!engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);\n\n await this.client.request<DeleteEngineResponse>(\n SALES_ENDPOINT,\n DELETE_PRICING_ENGINE_MUTATION,\n { id: engineId },\n );\n }\n\n /**\n * Upserts pricing overrides for the engine and date range in `input`. Returns\n * the resolved contexts Peek stored. Throws on an InvalidDataError from Peek.\n */\n async upsertOverrides(input: UpsertOverridesInput): Promise<UpsertOverridesResult> {\n this.validateUpsertInput(input);\n return this.sendUpsert(buildUpsertInput(input));\n }\n\n /**\n * Clears all overrides for the given activities across a date range. This is\n * an upsert with empty overrides — never clear by omitting an activity.\n */\n async clearOverrides(input: ClearOverridesInput): Promise<UpsertOverridesResult> {\n if (!input.engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);\n if (!input.dateRange) throw new Error(ERROR_DATE_RANGE_REQUIRED);\n if (!Array.isArray(input.activityIds)) throw new Error(ERROR_ACTIVITIES_REQUIRED);\n for (const activityId of input.activityIds) {\n if (!activityId) throw new Error(ERROR_ACTIVITY_ID_REQUIRED);\n }\n return this.sendUpsert(buildClearInput(input));\n }\n\n private async sendUpsert(\n rawInput: ReturnType<typeof buildUpsertInput>,\n ): Promise<UpsertOverridesResult> {\n const body: GraphQLBody<UpsertOverridesResponse> =\n await this.client.request<UpsertOverridesResponse>(\n SALES_ENDPOINT,\n UPSERT_PRICING_OVERRIDES_MUTATION,\n { input: rawInput },\n );\n\n const result = body.data?.upsertPricingOverridesActivityContexts;\n if (!result) throw new Error(ERROR_NO_DATA);\n if (result.__typename !== \"UpsertPricingOverridesActivityContextsSuccess\") {\n throw new Error(result.message);\n }\n return { activityContexts: fromActivityContexts(result.activityContexts) };\n }\n\n private validateUpsertInput(input: UpsertOverridesInput): void {\n if (!input.engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);\n if (!input.dateRange) throw new Error(ERROR_DATE_RANGE_REQUIRED);\n if (!Array.isArray(input.activities)) throw new Error(ERROR_ACTIVITIES_REQUIRED);\n\n for (const activity of input.activities) {\n if (!activity.activityId) throw new Error(ERROR_ACTIVITY_ID_REQUIRED);\n for (const override of activity.overrides) {\n for (const option of override.resourceOptions) {\n this.validateResourceOption(option);\n }\n }\n }\n }\n\n private validateResourceOption(option: ResourceOptionOverride): void {\n if (!option.id) throw new Error(ERROR_TICKET_ID_REQUIRED);\n\n if (option.mode === \"fixed\") {\n if (!CURRENCY_PATTERN.test(option.price.currency)) {\n throw new Error(ERROR_CURRENCY_FORMAT);\n }\n if (Number.isNaN(Number.parseFloat(option.price.amount))) {\n throw new Error(ERROR_AMOUNT_NUMBER);\n }\n return;\n }\n\n const percentage = Number.parseFloat(option.percentageAdjustment);\n if (Number.isNaN(percentage)) throw new Error(ERROR_PERCENTAGE_NUMBER);\n if (percentage <= PERCENTAGE_FLOOR) throw new Error(ERROR_PERCENTAGE_FLOOR);\n }\n}\n","/**\n * Minimal structured logger interface the package can write diagnostics to.\n *\n * Consumers may supply their own implementation (e.g. wrapping an existing\n * application logger). When none is provided the package stays completely\n * silent via {@link noopLogger}.\n */\nexport interface Logger {\n info(message: string, context?: Record<string, unknown>): void;\n warn(message: string, context?: Record<string, unknown>): void;\n error(message: string, context?: Record<string, unknown>): void;\n}\n\n/** A {@link Logger} that discards everything. Used as the default. */\nexport const noopLogger: Logger = {\n info() {},\n warn() {},\n error() {},\n};\n","/**\n * Authenticated root entry point to the Peek backoffice GraphQL gateway.\n *\n * Configure one instance per install with everything needed to authenticate and\n * reach the gateway. The access service owns the shared, authenticated\n * transport (it mints and caches tokens on demand) and hands out per-resource\n * service objects — e.g. {@link PeekAccessService.getProductService} — that\n * carry the resource-specific business logic.\n */\nimport { AccountUserService } from \"./internal/peek/account-users/account-user-service.js\";\nimport { AvailabilityService } from \"./internal/peek/availability/availability-service.js\";\nimport { BookingService } from \"./internal/peek/bookings/booking-service.js\";\nimport { DailyNoteService } from \"./internal/peek/daily-notes/daily-note-service.js\";\nimport {\n createTokenManager,\n requireNonEmpty,\n resolveBaseApiUrl,\n DEFAULT_RETRY_DELAYS_MS,\n type BaseAccessServiceConfig,\n} from \"./access-service-config.js\";\nimport {\n resolveAccessOptions,\n type ResolvedAccessOptions,\n} from \"./access-options.js\";\nimport { GraphQLClient } from \"./internal/peek/graphql-client.js\";\nimport {\n mapPeekTokenUser,\n verifyPeekJwt,\n type RawPeekTokenUser,\n} from \"./internal/peek/peek-auth-token.js\";\nimport { MembershipService } from \"./internal/peek/memberships/membership-service.js\";\nimport { ResellerService } from \"./internal/peek/resellers/reseller-service.js\";\nimport { ResourcePoolService } from \"./internal/peek/resource-pools/resource-pool-service.js\";\nimport { ReviewService } from \"./internal/peek/reviews/review-service.js\";\nimport { TimeslotService } from \"./internal/peek/timeslots/timeslot-service.js\";\nimport {\n ProductService,\n type ProductServiceOptions,\n} from \"./internal/peek/products/product-service.js\";\nimport { PromoCodeService } from \"./internal/peek/promo-codes/promo-code-service.js\";\nimport { PricingService } from \"./internal/peek/pricing/pricing-service.js\";\nimport {\n V2_EXTENDABLE_SLUG,\n peekApiEndpoints,\n} from \"./internal/peek/gateway-endpoints.js\";\nimport { noopLogger } from \"./logger.js\";\nimport type { PeekAuthTokenClaims } from \"./models/peek/auth-token.js\";\nimport type { AvailabilityTimesQuery } from \"./models/peek/availability-time.js\";\nimport type {\n BookingReadOptions,\n BookingTimeRangeSearch,\n CreateBookingInput,\n NoteMode,\n} from \"./models/peek/booking.js\";\nimport type { MakePaymentInput, RefundInput } from \"./models/peek/booking-payment.js\";\nimport type { MembershipPurchaseInput } from \"./models/peek/membership.js\";\nimport type { CreatePromoCodeInput } from \"./models/peek/promo-code.js\";\nimport type {\n ClearOverridesInput,\n CreateEngineInput,\n UpdateEngineInput,\n UpsertOverridesInput,\n} from \"./models/peek/pricing.js\";\nimport type { ResourcePoolMode } from \"./models/peek/resource-pool.js\";\nimport type { GuideAssignment, TimeslotFilter } from \"./models/peek/timeslot.js\";\nimport type { AddAddonInput } from \"./internal/peek/bookings/booking-service.js\";\n\n/** Default backoffice GraphQL gateway base URL (v1). */\nconst DEFAULT_BASE_URL = \"https://apps.peekapis.com/backoffice-gql\";\n/** Default gateway base URL when operating in v2 mode. */\nconst DEFAULT_V2_BASE_URL =\n \"https://app-registry.peeklabs.com/installations-api\";\ninterface RawPeekTokenPayload {\n sub: string;\n display_version: string;\n user?: RawPeekTokenUser | null;\n}\n\n/**\n * Configuration for a {@link PeekAccessService} instance. Extends the shared\n * {@link BaseAccessServiceConfig} (install/auth/transport fields) with the\n * Peek-specific extras below.\n */\nexport interface PeekAccessServiceConfig extends BaseAccessServiceConfig {\n /** API gateway key, sent as the `pk-api-key` header. Required in v1 mode; not used in v2. */\n gatewayKey?: string;\n\n /**\n * Gateway mode. `\"v2\"` routes through the app-registry installations API\n * (`baseUrl/appId/peek_backoffice_api-v1/endpointName`) and defaults to the\n * app-registry sandbox base URL. `\"v1\"` (default) uses the standard backoffice\n * GraphQL gateway.\n */\n mode?: \"v2\";\n /** Page size for cursor-paginated item options. Default: 50. */\n itemOptionsPageSize?: number;\n}\n\n/**\n * Authenticated root entry point to the Peek backoffice GraphQL gateway.\n *\n * Construct one instance per install, then call the `get<Resource>Service()`\n * accessors to reach the resource-specific operations. Each accessor returns a\n * memoized service bound to the shared, authenticated transport — the access\n * service mints and caches a short-lived JWT on demand.\n *\n * @example Configure once, then call resource services\n * ```ts\n * import { PeekAccessService, type Product } from \"@peektravel/app-utilities\";\n *\n * const peek = new PeekAccessService({\n * installId: \"install-123\", // JWT subject\n * jwtSecret: process.env.PEEK_INTERNAL_SECRET!, // signs the JWT\n * issuer: process.env.APP_NAME!, // JWT issuer\n * appId: process.env.PEEK_APP_ID!, // gateway path segment\n * gatewayKey: process.env.PEEK_GATEWAY_KEY!, // pk-api-key header\n * });\n *\n * const products: Product[] = await peek.getProductService().getAllProducts();\n * const booking = await peek.getBookingService().getById(\"b_abc123\");\n * ```\n *\n * @throws {Error} from the constructor when any required config field\n * (`installId`, `jwtSecret`, `issuer`, `appId`, `gatewayKey`) is empty.\n */\nexport class PeekAccessService {\n private readonly client: GraphQLClient;\n private readonly productServiceOptions: ProductServiceOptions;\n private readonly accessOptions: ResolvedAccessOptions;\n private readonly jwtSecret: string;\n private productService?: ProductService;\n private accountUserService?: AccountUserService;\n private resourcePoolService?: ResourcePoolService;\n private timeslotService?: TimeslotService;\n private resellerService?: ResellerService;\n private promoCodeService?: PromoCodeService;\n private pricingService?: PricingService;\n private dailyNoteService?: DailyNoteService;\n private availabilityService?: AvailabilityService;\n private membershipService?: MembershipService;\n private bookingService?: BookingService;\n private reviewService?: ReviewService;\n\n constructor(config: PeekAccessServiceConfig) {\n const hasApiUrl = !!config.apiUrl;\n const isV2 = config.mode === \"v2\";\n requireNonEmpty(config.installId, \"installId\", \"PeekAccessService\");\n requireNonEmpty(config.jwtSecret, \"jwtSecret\", \"PeekAccessService\");\n requireNonEmpty(config.issuer, \"issuer\", \"PeekAccessService\");\n // `appId` is only a URL path segment for the legacy `baseUrl` mode; the\n // registry's `apiUrl` already includes whatever the registry routes on.\n if (!hasApiUrl) requireNonEmpty(config.appId ?? \"\", \"appId\", \"PeekAccessService\");\n // The registry app endpoint authenticates on the JWT alone (like v2), so the\n // `pk-api-key` gateway key is only required in the legacy v1 `baseUrl` mode.\n if (!hasApiUrl && !isV2) requireNonEmpty(config.gatewayKey ?? \"\", \"gatewayKey\", \"PeekAccessService\");\n\n this.jwtSecret = config.jwtSecret;\n\n const logger = config.logger ?? noopLogger;\n const tokens = createTokenManager(config);\n\n // Registry modes (an app-endpoint `apiUrl`, or legacy v2) route the `sales`\n // endpoint through the `peek_backoffice_api-v1` slug; the legacy v1 gateway\n // has no slug. `apiUrl` is the base directly (its own slug stripped back off);\n // otherwise the base is `baseUrl/appId`.\n const useRegistrySlug = hasApiUrl || isV2;\n const defaultBaseUrl = isV2 ? DEFAULT_V2_BASE_URL : DEFAULT_BASE_URL;\n const baseApiUrl = hasApiUrl\n ? resolveBaseApiUrl(config.apiUrl!, V2_EXTENDABLE_SLUG, \"PeekAccessService\")\n : `${config.baseUrl ?? defaultBaseUrl}/${config.appId}`;\n this.client = new GraphQLClient({\n baseApiUrl,\n endpoints: peekApiEndpoints(useRegistrySlug),\n gatewayKey: config.gatewayKey,\n getToken: () => tokens.getToken(),\n retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,\n logger,\n fetchFn: config.fetch ?? globalThis.fetch,\n });\n\n this.productServiceOptions = {\n itemOptionsPageSize: config.itemOptionsPageSize,\n };\n this.accessOptions = resolveAccessOptions(config.accessOptions);\n }\n\n /**\n * Verifies a Peek auth token issued by the app registry and returns the\n * decoded claims.\n *\n * Validates the HMAC signature (using this service's `jwtSecret`), the token\n * expiry, the `\"app_registry_v2\"` issuer, and the `\"Joken\"` audience. Pass the\n * raw `x-peek-auth` request header value — a leading `Bearer ` prefix, if\n * present, is stripped for you. Throws from the `jsonwebtoken` library on any\n * failure — callers should catch to distinguish error kinds:\n *\n * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or token\n * malformed\n * - `TokenExpiredError` — past `exp`\n * - `NotBeforeError` — before `nbf`\n *\n * Claim *extraction* is defensive: once the signature verifies, a token with\n * no `user` block yields `claims.user === null`, and any individual user field\n * that is absent or a sentinel (`\"\"`, `\"null\"`) is normalized to `null`. This\n * method never throws on a shape problem — only on a verification failure.\n *\n * @throws {JsonWebTokenError} signature invalid or token malformed\n * @throws {TokenExpiredError} token has expired\n * @throws {NotBeforeError} token not yet valid\n */\n verifyPeekAuthToken(token: string): PeekAuthTokenClaims {\n const payload = verifyPeekJwt<RawPeekTokenPayload>(token, this.jwtSecret);\n return {\n installId: payload.sub,\n displayVersion: payload.display_version,\n user: mapPeekTokenUser(payload.user),\n };\n }\n\n /**\n * Returns the {@link ProductService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getProductService(): ProductService {\n if (!this.productService) {\n this.productService = new ProductService(\n this.client,\n this.productServiceOptions,\n );\n }\n return this.productService;\n }\n\n /**\n * Returns the {@link AccountUserService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getAccountUserService(): AccountUserService {\n if (!this.accountUserService) {\n this.accountUserService = new AccountUserService(this.client);\n }\n return this.accountUserService;\n }\n\n /**\n * Returns the {@link ResourcePoolService} for this install, bound to the\n * shared authenticated transport. The instance is created lazily and reused.\n */\n getResourcePoolService(): ResourcePoolService {\n if (!this.resourcePoolService) {\n this.resourcePoolService = new ResourcePoolService(this.client);\n }\n return this.resourcePoolService;\n }\n\n /**\n * Returns the {@link TimeslotService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused; its\n * guide assignment composes the resource-pool and account-user services.\n */\n getTimeslotService(): TimeslotService {\n if (!this.timeslotService) {\n this.timeslotService = new TimeslotService(this.client, {\n resourcePoolService: this.getResourcePoolService(),\n accountUserService: this.getAccountUserService(),\n });\n }\n return this.timeslotService;\n }\n\n /**\n * Returns the {@link ResellerService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getResellerService(): ResellerService {\n if (!this.resellerService) {\n this.resellerService = new ResellerService(this.client);\n }\n return this.resellerService;\n }\n\n /**\n * Returns the {@link PromoCodeService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getPromoCodeService(): PromoCodeService {\n if (!this.promoCodeService) {\n this.promoCodeService = new PromoCodeService(this.client);\n }\n return this.promoCodeService;\n }\n\n /**\n * Returns the {@link PricingService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getPricingService(): PricingService {\n if (!this.pricingService) {\n this.pricingService = new PricingService(this.client);\n }\n return this.pricingService;\n }\n\n /**\n * Returns the {@link DailyNoteService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getDailyNoteService(): DailyNoteService {\n if (!this.dailyNoteService) {\n this.dailyNoteService = new DailyNoteService(this.client);\n }\n return this.dailyNoteService;\n }\n\n /**\n * Returns the {@link AvailabilityService} for this install, bound to the\n * shared authenticated transport. The instance is created lazily and reused.\n */\n getAvailabilityService(): AvailabilityService {\n if (!this.availabilityService) {\n this.availabilityService = new AvailabilityService(this.client);\n }\n return this.availabilityService;\n }\n\n /**\n * Returns the {@link MembershipService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getMembershipService(): MembershipService {\n if (!this.membershipService) {\n this.membershipService = new MembershipService(this.client);\n }\n return this.membershipService;\n }\n\n /**\n * Returns the {@link BookingService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getBookingService(): BookingService {\n if (!this.bookingService) {\n this.bookingService = new BookingService(\n this.client,\n { productService: this.getProductService() },\n { accessOptions: this.accessOptions },\n );\n }\n return this.bookingService;\n }\n\n /**\n * Returns the {@link ReviewService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getReviewService(): ReviewService {\n if (!this.reviewService) {\n this.reviewService = new ReviewService(this.client, this.accessOptions);\n }\n return this.reviewService;\n }\n\n // ─── Product short-forms ─────────────────────────────────────────────────\n\n /** All products (activities + add-ons). @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ProductService.getAllProducts}. */\n getAllProducts() { return this.getProductService().getAllProducts(); }\n\n /** All activity products (excludes add-ons). @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ProductService.getAllActivities}. */\n getAllActivities() { return this.getProductService().getAllActivities(); }\n\n /** All rental products. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ProductService.getAllRentals}. */\n getAllRentals() { return this.getProductService().getAllRentals(); }\n\n /** All add-on products. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ProductService.getAllAddons}. */\n getAllAddons() { return this.getProductService().getAllAddons(); }\n\n /** An activity's custom questions. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ProductService.getCustomQuestions}. */\n getCustomQuestions(productId: string) { return this.getProductService().getCustomQuestions(productId); }\n\n // ─── Account-user short-forms ─────────────────────────────────────────────\n\n /** All active account users. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link AccountUserService.getAll}. */\n getAllAccountUsers() { return this.getAccountUserService().getAll(); }\n\n /** Account user by id, or null. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link AccountUserService.getById}. */\n getAccountUserById(userId: string) { return this.getAccountUserService().getById(userId); }\n\n // ─── Resource-pool short-forms ────────────────────────────────────────────\n\n /** All resource pools. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ResourcePoolService.getAll}. */\n getAllResourcePools(mode?: ResourcePoolMode) { return this.getResourcePoolService().getAll(mode); }\n\n // ─── Timeslot short-forms ─────────────────────────────────────────────────\n\n /** Timeslots for an activity on a given date. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link TimeslotService.getForDay}. */\n getTimeslotsForDay(productId: string, date: string, filter?: TimeslotFilter) {\n return this.getTimeslotService().getForDay(productId, date, filter);\n }\n\n /** Single timeslot by id. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link TimeslotService.getById}. */\n getTimeslotById(timeslotId: string) { return this.getTimeslotService().getById(timeslotId); }\n\n /** Set timeslot status. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link TimeslotService.setAvailability}. */\n setTimeslotAvailability(timeslotId: string, status: string) {\n return this.getTimeslotService().setAvailability(timeslotId, status);\n }\n\n /** Set timeslot manifest notes. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link TimeslotService.setNotes}. */\n setTimeslotNotes(timeslotId: string, manifestNotes: string) {\n return this.getTimeslotService().setNotes(timeslotId, manifestNotes);\n }\n\n /** Assign or unassign guides on timeslots. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link TimeslotService.assignGuide}. */\n assignTimeslotGuide(assignment: GuideAssignment) {\n return this.getTimeslotService().assignGuide(assignment);\n }\n\n // ─── Reseller short-forms ─────────────────────────────────────────────────\n\n /** All reseller channels. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ResellerService.getAllChannels}. */\n getAllChannels(agentsPerChannel?: number) {\n return this.getResellerService().getAllChannels(agentsPerChannel);\n }\n\n // ─── Promo-code short-forms ───────────────────────────────────────────────\n\n /** All promo codes. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PromoCodeService.getAll}. */\n getAllPromoCodes() { return this.getPromoCodeService().getAll(); }\n\n /** Create a promo code. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PromoCodeService.create}. */\n createPromoCode(input: CreatePromoCodeInput) { return this.getPromoCodeService().create(input); }\n\n // ─── Pricing short-forms ──────────────────────────────────────────────────\n\n /** Create a pricing engine. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PricingService.createEngine}. */\n createPricingEngine(input: CreateEngineInput) { return this.getPricingService().createEngine(input); }\n\n /** Update a pricing engine. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PricingService.updateEngine}. */\n updatePricingEngine(input: UpdateEngineInput) { return this.getPricingService().updateEngine(input); }\n\n /** Delete a pricing engine (idempotent). @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PricingService.deleteEngine}. */\n deletePricingEngine(engineId: string) { return this.getPricingService().deleteEngine(engineId); }\n\n /** Upsert pricing overrides. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PricingService.upsertOverrides}. */\n upsertPricingOverrides(input: UpsertOverridesInput) { return this.getPricingService().upsertOverrides(input); }\n\n /** Clear pricing overrides for a set of activities. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PricingService.clearOverrides}. */\n clearPricingOverrides(input: ClearOverridesInput) { return this.getPricingService().clearOverrides(input); }\n\n // ─── Daily-note short-forms ───────────────────────────────────────────────\n\n /** Today's daily note. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link DailyNoteService.getToday}. */\n getDailyNoteToday() { return this.getDailyNoteService().getToday(); }\n\n /** Update today's daily note. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link DailyNoteService.update}. */\n updateDailyNote(note: string) { return this.getDailyNoteService().update(note); }\n\n // ─── Availability short-forms ─────────────────────────────────────────────\n\n /** Availability times for an activity. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link AvailabilityService.getAvailabilityTimes}. */\n getAvailabilityTimes(query: AvailabilityTimesQuery) {\n return this.getAvailabilityService().getAvailabilityTimes(query);\n }\n\n // ─── Membership short-forms ───────────────────────────────────────────────\n\n /** All memberships. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link MembershipService.getAll}. */\n getAllMemberships() { return this.getMembershipService().getAll(); }\n\n /** Purchase a membership. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link MembershipService.purchase}. */\n purchaseMembership(input: MembershipPurchaseInput) {\n return this.getMembershipService().purchase(input);\n }\n\n // ─── Booking short-forms ──────────────────────────────────────────────────\n\n /** Booking by id. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.getById}. */\n getBookingById(bookingId: string, options?: BookingReadOptions) {\n return this.getBookingService().getById(bookingId, options);\n }\n\n /** Bookings by time range. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.searchByTimeRange}. */\n searchBookingsByTimeRange(input: BookingTimeRangeSearch) {\n return this.getBookingService().searchByTimeRange(input);\n }\n\n /** Bookings on a timeslot. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.searchByTimeslot}. */\n searchBookingsByTimeslot(timeslotId: string, options?: BookingReadOptions) {\n return this.getBookingService().searchByTimeslot(timeslotId, options);\n }\n\n /** Guests on a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.getGuests}. */\n getBookingGuests(bookingId: string) { return this.getBookingService().getGuests(bookingId); }\n\n /** Payments on file for a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.getPaymentsOnFile}. */\n getBookingPaymentsOnFile(bookingId: string) {\n return this.getBookingService().getPaymentsOnFile(bookingId);\n }\n\n /** Append or overwrite operator notes. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.appendNote}. */\n appendBookingNote(bookingId: string, note: string, mode?: NoteMode) {\n return this.getBookingService().appendNote(bookingId, note, mode);\n }\n\n /** Set booking check-in status. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.setCheckinStatus}. */\n setBookingCheckinStatus(bookingId: string, checkedIn: boolean) {\n return this.getBookingService().setCheckinStatus(bookingId, checkedIn);\n }\n\n /** Cancel a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.cancel}. */\n cancelBooking(bookingId: string, notes?: string) {\n return this.getBookingService().cancel(bookingId, notes);\n }\n\n /** Charge a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.makePayment}. */\n makeBookingPayment(input: MakePaymentInput) { return this.getBookingService().makePayment(input); }\n\n /** Refund a booking payment. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.refund}. */\n refundBooking(input: RefundInput) { return this.getBookingService().refund(input); }\n\n /** Create an invoice link. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.createInvoiceLink}. */\n createBookingInvoiceLink(bookingId: string) {\n return this.getBookingService().createInvoiceLink(bookingId);\n }\n\n /** List add-ons on a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.listAddons}. */\n listBookingAddons(bookingId: string) { return this.getBookingService().listAddons(bookingId); }\n\n /** Add an add-on to a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.addAddon}. */\n addBookingAddon(bookingId: string, input: AddAddonInput) {\n return this.getBookingService().addAddon(bookingId, input);\n }\n\n /** Remove an add-on from a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.removeAddon}. */\n removeBookingAddon(bookingId: string, input: AddAddonInput) {\n return this.getBookingService().removeAddon(bookingId, input);\n }\n\n /** Create a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.create}. */\n createBooking(input: CreateBookingInput) { return this.getBookingService().create(input); }\n\n // ─── Review short-forms ───────────────────────────────────────────────────\n\n /** Reviews for an activity. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ReviewService.getReviews}. */\n getReviews(productId: string, reviewCount?: number, reviewOffset?: number) {\n return this.getReviewService().getReviews(productId, reviewCount, reviewOffset);\n }\n}\n","/**\n * Endpoint routing for the CNG backoffice REST gateway. Shared across the CNG\n * resources so each value lives in exactly one place, with {@link CNG_API_ENDPOINTS}\n * as the simple lookup a new CNG API extends. (The Peek gateway routing lives\n * separately in `../gateway-endpoints.ts`.)\n */\nimport { ApiEndpoints } from \"../api-endpoints.js\";\n\n/**\n * Routing slug inserted between the base API URL and the REST path. This is the\n * only routing difference from the Peek gateway (`peek_backoffice_api-v1`).\n */\nexport const CNG_EXTENDABLE_SLUG = \"cng_backoffice_api-v1\";\n\n/** Endpoint key for the app-registry products list. */\nexport const CNG_PRODUCTS_ENDPOINT = \"products\";\n\n/**\n * REST path (relative to the slug) for the app-registry products list.\n * `active=1` keeps the gateway from returning inactive/archived products, so\n * only bookable activities come back.\n */\nexport const PRODUCTS_PATH = \"api/v2/app-registry/products?active=1\";\n\n/** The endpoint keys the CNG REST transport knows how to route. */\nexport type CngEndpointKey = typeof CNG_PRODUCTS_ENDPOINT;\n\n/**\n * The CNG endpoint lookup — maps each endpoint key to the routing slug appended\n * to the base API URL. Add a new CNG API by adding one entry (with its own slug\n * when it needs a different one).\n */\nexport const CNG_API_ENDPOINTS: ApiEndpoints<CngEndpointKey> = new ApiEndpoints({\n [CNG_PRODUCTS_ENDPOINT]: CNG_EXTENDABLE_SLUG,\n});\n","/**\n * The clean, transport-agnostic data model for a CNG product.\n *\n * The CNG sibling of `../peek/product.ts`. Kept as a separate model because the\n * CNG gateway is a distinct backoffice, but the shape deliberately mirrors the\n * Peek `Product` so consumers can treat both brands uniformly. The raw CNG REST\n * response types and the conversion logic live inside the package and are never\n * exposed here.\n */\n\n/**\n * A bookable activity in a CNG account.\n *\n * `CngAccessService.getAllActivities()` returns these as a flat list.\n *\n * Mapped from the `app-registry/products` REST payload — see\n * `internal/cng/products/product-queries.ts`. That payload carries no\n * product-type discriminator and no sub-options, so `type` is always\n * {@link ACTIVITY_PRODUCT_TYPE} and `tickets` is always empty.\n */\nexport interface Activity {\n /** Stable unique identifier for the activity. */\n productId: string;\n\n /** Human-readable display name. */\n name: string;\n\n /**\n * Product type. Always {@link ACTIVITY_PRODUCT_TYPE} — the CNG products\n * payload has no type discriminator. Kept for parity with the Peek `Product`.\n */\n type: string;\n\n /**\n * Display color as a hex string (e.g. `\"#1A2B3C\"`), from the product's\n * access-control color. Empty string when no color is set.\n */\n color: string;\n\n /**\n * The bookable sub-options (tickets) of this activity. Always empty — CNG\n * exposes no tickets on the products endpoint today.\n */\n tickets: ActivityTicket[];\n}\n\n/** A single bookable sub-option (ticket) of an {@link Activity}. */\nexport interface ActivityTicket {\n /** Unique identifier of the ticket. */\n id: string;\n /** Human-readable name of the ticket. */\n name: string;\n}\n\n/** {@link Activity.type} for standard bookable activities. */\nexport const ACTIVITY_PRODUCT_TYPE = \"ACTIVITY\";\n","/**\n * Pure functions that map raw CNG product nodes into the clean {@link Activity}\n * model. No I/O — straightforward, testable transformations.\n *\n * The CNG products payload carries no product-type discriminator and no\n * sub-options, so every activity reports the {@link ACTIVITY_PRODUCT_TYPE} type\n * and an empty `tickets` list (same as ACME). Only `productId`, `name`, and\n * `color` come from the payload.\n */\nimport { ACTIVITY_PRODUCT_TYPE, type Activity } from \"../../../models/cng/product.js\";\nimport type { ProductNode } from \"./product-queries.js\";\n\n/** Converts a list of raw product nodes into {@link Activity}s. */\nexport function fromProductNodes(nodes: ProductNode[]): Activity[] {\n return nodes.map(fromProductNode);\n}\n\n/** Converts a single raw product node into an {@link Activity}. */\nfunction fromProductNode(node: ProductNode): Activity {\n return {\n productId: node.id == null ? \"\" : String(node.id),\n name: node.name || \"\",\n type: ACTIVITY_PRODUCT_TYPE,\n color: node.access_control_color_hex || \"\",\n tickets: [],\n };\n}\n","/**\n * Product-related operations against the CNG gateway.\n *\n * Obtain an instance via {@link CngAccessService.getProductService} rather than\n * constructing it directly — the access service wires in the authenticated,\n * shared transport. This class is where CNG product-specific business logic\n * lives. Named `CngProductService` to disambiguate from the Peek\n * `ProductService` in the same package.\n */\nimport { CNG_PRODUCTS_ENDPOINT, PRODUCTS_PATH } from \"../endpoints.js\";\nimport type { RestClient } from \"../rest-client.js\";\nimport type { Activity } from \"../../../models/cng/product.js\";\nimport { fromProductNodes } from \"./product-converter.js\";\nimport type { ProductsResponse } from \"./product-queries.js\";\n\nexport class CngProductService {\n constructor(private readonly client: RestClient) {}\n\n /**\n * Returns every activity as a single flat list.\n *\n * @example\n * ```ts\n * const activities = await cng.getProductService().getAllActivities();\n * ```\n */\n async getAllActivities(): Promise<Activity[]> {\n const body = await this.client.get<ProductsResponse>(\n CNG_PRODUCTS_ENDPOINT,\n PRODUCTS_PATH,\n );\n return fromProductNodes(body?.data ?? []);\n }\n}\n","/**\n * Thin REST-over-HTTP transport for the CNG gateway, built on the global\n * `fetch`. Handles endpoint construction, auth headers, and REST-specific\n * response handling. The shared retry/backoff loop and 418/429 mapping live in\n * `../http-transport.ts` (used by the Peek GraphQL transport too).\n *\n * The REST sibling of `../graphql-client.ts`, minus the GraphQL specifics:\n * requests are plain GETs (no `{query, variables}` envelope, no GraphQL `errors`\n * array), and there is no `pk-api-key` header — the CNG gateway authenticates on\n * the app JWT (`X-Peek-Auth`) alone. Both transports share the same\n * `TokenManager`, `Logger`, base error types, and retry loop.\n *\n * HTTP 403 is special-cased: the gateway uses it for \"this app is missing\n * permission X\", which is an expected misconfiguration rather than a fault, so\n * it is logged at `warn` (no stack, no body dump) and raised as the typed\n * {@link CngPermissionError} carrying the named permissions.\n */\nimport { CngApiError, CngPermissionError, FORBIDDEN_STATUS } from \"../../errors.js\";\nimport { ApiEndpoints, joinUrl } from \"../api-endpoints.js\";\nimport { parseBody, requestWithRetry } from \"../http-transport.js\";\nimport { SDK_HEADER_NAME, SDK_HEADER_VALUE } from \"../sdk-headers.js\";\nimport type { Logger } from \"../../logger.js\";\n\n/** Separator between the gateway's prose and the permission name it names. */\nconst PERMISSION_SEPARATOR = \": \";\n\nexport interface RestClientOptions {\n /**\n * The install's **base API URL** (no trailing slash, no routing slug). Each\n * request builds `baseApiUrl/<slug>/<path>`, where the slug comes from\n * {@link endpoints} for the request's endpoint key.\n */\n baseApiUrl: string;\n /** Maps an endpoint key to the relative slug appended to {@link baseApiUrl}. */\n endpoints: ApiEndpoints;\n /** Supplies a valid bearer token for each request. */\n getToken: () => string;\n /** Backoff delays (ms) applied on successive HTTP 429 responses. */\n retryDelaysMs: number[];\n /** Diagnostics sink. */\n logger: Logger;\n /** `fetch` implementation to use. */\n fetchFn: typeof fetch;\n}\n\nexport class RestClient {\n constructor(private readonly options: RestClientOptions) {}\n\n /**\n * Issues a GET against the named REST path and returns the parsed JSON body.\n * Retries on HTTP 429 per the configured backoff (via the shared\n * {@link requestWithRetry} loop).\n *\n * @throws {AdminAccountRequiredError} on HTTP 418\n * @throws {RateLimitError} on HTTP 429 after retries are exhausted\n * @throws {CngPermissionError} on HTTP 403 (app missing a permission)\n * @throws {CngApiError} on any other non-2xx response\n */\n async get<T>(endpoint: string, path: string): Promise<T> {\n const { logger } = this.options;\n const url = this.endpoint(endpoint, path);\n\n logger.info(\"Making CNG request\", { url, path });\n\n return requestWithRetry(\n this.options,\n url,\n { method: \"GET\", headers: this.buildHeaders() },\n path,\n async (response) => {\n const body = await parseBody(response);\n\n if (response.status === FORBIDDEN_STATUS) {\n const permissions = extractMissingPermissions(body);\n // Expected for a misconfigured install — warn, don't error.\n logger.warn(`Missing permission for ${path} (HTTP 403)`, { url, permissions });\n throw new CngPermissionError(permissions, body);\n }\n\n if (!response.ok) {\n logger.error(`CNG request failed with HTTP ${response.status}`, { url });\n throw new CngApiError(response.status, body);\n }\n\n return body as T;\n },\n );\n }\n\n private endpoint(endpoint: string, path: string): string {\n const { baseApiUrl, endpoints } = this.options;\n return joinUrl(baseApiUrl, endpoints.pathFor(endpoint), path);\n }\n\n private buildHeaders(): Record<string, string> {\n return {\n \"X-Peek-Auth\": `Bearer ${this.options.getToken()}`,\n \"Content-Type\": \"application/json\",\n [SDK_HEADER_NAME]: SDK_HEADER_VALUE,\n };\n }\n}\n\n/** Shape of the gateway's 403 body: `{ errors: { permission: [...] }, message }`. */\ninterface ForbiddenBody {\n errors?: { permission?: unknown } | null;\n}\n\n/**\n * Pulls the permission names out of a 403 body. The gateway reports them as\n * sentences (`\"The app does not have the required permission: products:read\"`),\n * so the trailing token after the last `\": \"` is the permission itself; a\n * sentence without one is kept verbatim. Returns an empty list for any body\n * that does not carry `errors.permission` strings.\n */\nfunction extractMissingPermissions(body: unknown): string[] {\n if (typeof body !== \"object\" || body === null) return [];\n const raw = (body as ForbiddenBody).errors?.permission;\n if (!Array.isArray(raw)) return [];\n return raw\n .filter((entry): entry is string => typeof entry === \"string\")\n .map((entry) => entry.split(PERMISSION_SEPARATOR).pop()!.trim())\n .filter((permission) => permission.length > 0);\n}\n","/**\n * Authenticated root entry point to the CNG backoffice REST gateway.\n *\n * The CNG sibling of {@link PeekAccessService}. Configure one instance per\n * install; it owns the shared, authenticated transport (minting/caching tokens\n * on demand) and hands out the {@link CngProductService}.\n *\n * Auth and transport mirror the Peek access service: the same app JWT\n * (`X-Peek-Auth: Bearer`) minted from the Peek app credentials via the shared\n * {@link TokenManager}, routed through the app-registry installations API. The\n * only differences are the extendable slug (`cng_backoffice_api-v1`), REST\n * rather than GraphQL, and no `pk-api-key` header.\n */\nimport {\n createTokenManager,\n requireNonEmpty,\n resolveBaseApiUrl,\n DEFAULT_RETRY_DELAYS_MS,\n type BaseAccessServiceConfig,\n} from \"./access-service-config.js\";\nimport { CNG_API_ENDPOINTS, CNG_EXTENDABLE_SLUG } from \"./internal/cng/endpoints.js\";\nimport { CngProductService } from \"./internal/cng/products/product-service.js\";\nimport { RestClient } from \"./internal/cng/rest-client.js\";\nimport { noopLogger } from \"./logger.js\";\n\n/** Default gateway base URL — the app-registry installations API. */\nconst DEFAULT_BASE_URL = \"https://app-registry.peeklabs.com/installations-api\";\n\n/**\n * Configuration for a {@link CngAccessService} instance. CNG adds no fields\n * beyond {@link BaseAccessServiceConfig} — it authenticates on the app JWT\n * alone (no `pk-api-key`, so no `gatewayKey`).\n */\nexport type CngAccessServiceConfig = BaseAccessServiceConfig;\n\n/**\n * Authenticated root entry point to the CNG backoffice REST gateway.\n *\n * @example\n * ```ts\n * import { CngAccessService, type Activity } from \"@peektravel/app-utilities\";\n *\n * const cng = new CngAccessService({\n * installId: \"install-123\",\n * jwtSecret: process.env.PEEK_APP_SECRET!,\n * issuer: process.env.PEEK_APP_ID!,\n * appId: process.env.PEEK_APP_ID!,\n * });\n *\n * const activities: Activity[] = await cng.getProductService().getAllActivities();\n * ```\n *\n * @throws {Error} from the constructor when any required config field\n * (`installId`, `jwtSecret`, `issuer`, `appId`) is empty.\n */\nexport class CngAccessService {\n private readonly client: RestClient;\n private productService?: CngProductService;\n\n constructor(config: CngAccessServiceConfig) {\n const hasApiUrl = !!config.apiUrl;\n requireNonEmpty(config.installId, \"installId\", \"CngAccessService\");\n requireNonEmpty(config.jwtSecret, \"jwtSecret\", \"CngAccessService\");\n requireNonEmpty(config.issuer, \"issuer\", \"CngAccessService\");\n if (!hasApiUrl) requireNonEmpty(config.appId ?? \"\", \"appId\", \"CngAccessService\");\n\n const logger = config.logger ?? noopLogger;\n const tokens = createTokenManager(config);\n\n const baseApiUrl = hasApiUrl\n ? resolveBaseApiUrl(config.apiUrl!, CNG_EXTENDABLE_SLUG, \"CngAccessService\")\n : `${config.baseUrl ?? DEFAULT_BASE_URL}/${config.appId}`;\n this.client = new RestClient({\n baseApiUrl,\n endpoints: CNG_API_ENDPOINTS,\n getToken: () => tokens.getToken(),\n retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,\n logger,\n fetchFn: config.fetch ?? globalThis.fetch,\n });\n }\n\n /**\n * Returns the {@link CngProductService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getProductService(): CngProductService {\n if (!this.productService) {\n this.productService = new CngProductService(this.client);\n }\n return this.productService;\n }\n\n /** All activities. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link CngProductService.getAllActivities}. */\n getAllActivities() {\n return this.getProductService().getAllActivities();\n }\n}\n","/**\n * Endpoint routing for the ACME backoffice REST gateway. Shared across the ACME\n * resources so each value lives in exactly one place, with {@link ACME_API_ENDPOINTS}\n * as the simple lookup a new ACME API extends. (The CNG gateway routing lives\n * separately in `../cng/endpoints.ts`.)\n */\nimport { ApiEndpoints } from \"../api-endpoints.js\";\n\n/**\n * Routing slug inserted between the base API URL and the REST path. This is the\n * only routing difference from the other gateways (CNG uses\n * `cng_backoffice_api-v1`; Peek uses `peek_backoffice_api-v1`).\n */\nexport const ACME_EXTENDABLE_SLUG = \"acme_backoffice_api-v1\";\n\n/** Endpoint key for the event-template names list. */\nexport const ACME_TEMPLATES_ENDPOINT = \"templates\";\n\n/** REST path (relative to the slug) for the event-template names list. */\nexport const TEMPLATES_PATH = \"v2/b2b/event/templates/names?pageSize=-1&page=1\";\n\n/** The endpoint keys the ACME REST transport knows how to route. */\nexport type AcmeEndpointKey = typeof ACME_TEMPLATES_ENDPOINT;\n\n/**\n * The ACME endpoint lookup — maps each endpoint key to the routing slug appended\n * to the base API URL. Add a new ACME API by adding one entry (with its own slug\n * when it needs a different one).\n */\nexport const ACME_API_ENDPOINTS: ApiEndpoints<AcmeEndpointKey> = new ApiEndpoints({\n [ACME_TEMPLATES_ENDPOINT]: ACME_EXTENDABLE_SLUG,\n});\n","/**\n * The clean, transport-agnostic data model for an ACME event template.\n *\n * The ACME sibling of `../cng/product.ts`. Kept as a separate model because the\n * ACME gateway is a distinct backoffice, but the shape deliberately mirrors the\n * CNG `Activity` so consumers can treat every brand uniformly. The raw ACME\n * REST response types and the conversion logic live inside the package and are\n * never exposed here.\n */\n\n/**\n * A bookable activity in an ACME account (an event template).\n *\n * `AcmeAccessService.getAllActivities()` returns these as a flat list, filtered\n * to published templates only. ACME does not expose tickets today, so\n * {@link AcmeActivity.tickets} is always an empty list.\n */\nexport interface AcmeActivity {\n /** Stable unique identifier for the activity. */\n productId: string;\n\n /** Human-readable display name. */\n name: string;\n\n /** Product type reported by ACME (e.g. `\"standard\"`). */\n type: string;\n\n /**\n * Display color as a hex string (e.g. `\"#00695c\"`). Falls back to a neutral\n * gray (`\"#d1d1d1\"`) when no color is set.\n */\n color: string;\n\n /** The bookable sub-options (tickets) of this activity. Always empty today. */\n tickets: AcmeActivityTicket[];\n}\n\n/** A single bookable sub-option (ticket) of an {@link AcmeActivity}. */\nexport interface AcmeActivityTicket {\n /** Unique identifier of the ticket. */\n id: string;\n /** Human-readable name of the ticket. */\n name: string;\n}\n\n/** {@link AcmeActivity.type} fallback for templates missing a type. */\nexport const ACME_ACTIVITY_TYPE = \"standard\";\n","/**\n * Raw ACME REST response shapes for event templates. Internal implementation\n * detail of the package — deliberately not re-exported from the public entry\n * point.\n *\n * The `v2/b2b/event/templates/names` endpoint returns a `{ list: [...] }`\n * envelope. Each node carries a `reviewState`; only `\"published\"` templates are\n * surfaced as activities (see the converter).\n */\n\n/** The published review state — the only templates surfaced as activities. */\nexport const PUBLISHED_REVIEW_STATE = \"published\";\n\n/** A single template node as returned by the templates/names endpoint. */\nexport interface TemplateNode {\n /** Stable template id. */\n id: string;\n /** Display name. */\n name: string;\n /** Template type (e.g. `\"standard\"`). */\n type?: string;\n /** Admission type (e.g. `\"standard\"`). */\n admissionType?: string;\n /** Publication state; only `\"published\"` templates are surfaced. */\n reviewState?: string;\n /** Display color pair, if set. */\n colorCategory?: {\n backgroundColor?: string | null;\n textColor?: string | null;\n } | null;\n}\n\n/**\n * The templates list payload. Tolerates either a top-level `list` array or a\n * bare array response.\n */\nexport interface TemplatesResponse {\n list?: TemplateNode[];\n}\n","/**\n * Pure functions that map raw ACME template nodes into the clean\n * {@link AcmeActivity} model. No I/O — straightforward, testable\n * transformations.\n *\n * Only `\"published\"` templates are surfaced; ACME does not expose tickets, so\n * every activity carries an empty `tickets` list.\n */\nimport { ACME_ACTIVITY_TYPE, type AcmeActivity } from \"../../../models/acme/product.js\";\nimport { PUBLISHED_REVIEW_STATE, type TemplateNode } from \"./product-queries.js\";\n\n/**\n * Converts a list of raw template nodes into {@link AcmeActivity}s, keeping only\n * published templates.\n */\nexport function fromTemplateNodes(nodes: TemplateNode[]): AcmeActivity[] {\n return nodes\n .filter((node) => node.reviewState === PUBLISHED_REVIEW_STATE)\n .map(fromTemplateNode);\n}\n\n/** Converts a single raw template node into an {@link AcmeActivity}. */\nfunction fromTemplateNode(node: TemplateNode): AcmeActivity {\n return {\n productId: node.id || \"\",\n name: node.name || \"\",\n type: node.type || ACME_ACTIVITY_TYPE,\n color: node.colorCategory?.backgroundColor || \"#d1d1d1\",\n tickets: [],\n };\n}\n","/**\n * Product-related operations against the ACME gateway.\n *\n * Obtain an instance via {@link AcmeAccessService.getProductService} rather than\n * constructing it directly — the access service wires in the authenticated,\n * shared transport. This class is where ACME product-specific business logic\n * lives. Named `AcmeProductService` to disambiguate from the Peek\n * `ProductService` and the CNG `CngProductService` in the same package.\n */\nimport { ACME_TEMPLATES_ENDPOINT, TEMPLATES_PATH } from \"../endpoints.js\";\nimport type { RestClient } from \"../rest-client.js\";\nimport type { AcmeActivity } from \"../../../models/acme/product.js\";\nimport { fromTemplateNodes } from \"./product-converter.js\";\nimport type { TemplatesResponse } from \"./product-queries.js\";\n\nexport class AcmeProductService {\n constructor(private readonly client: RestClient) {}\n\n /**\n * Returns every published event template as a single flat list of activities.\n *\n * @example\n * ```ts\n * const activities = await acme.getProductService().getAllActivities();\n * ```\n */\n async getAllActivities(): Promise<AcmeActivity[]> {\n const body = await this.client.get<TemplatesResponse | TemplatesResponse[\"list\"]>(\n ACME_TEMPLATES_ENDPOINT,\n TEMPLATES_PATH,\n );\n // Tolerate either a { list: [...] } envelope or a bare array.\n const nodes = Array.isArray(body) ? body : (body?.list ?? []);\n return fromTemplateNodes(nodes ?? []);\n }\n}\n","/**\n * Thin REST-over-HTTP transport for the ACME gateway, built on the global\n * `fetch`. Handles endpoint construction, auth headers, and REST-specific\n * response handling. The shared retry/backoff loop and 418/429 mapping live in\n * `../http-transport.ts` (used by the Peek GraphQL and CNG REST transports too).\n *\n * The REST sibling of `../cng/rest-client.ts`: requests are plain GETs (no\n * `{query, variables}` envelope, no GraphQL `errors` array), and there is no\n * `pk-api-key` header — the ACME gateway authenticates on the app JWT\n * (`X-Peek-Auth`) alone. Both transports share the same `TokenManager`,\n * `Logger`, base error types, and retry loop.\n */\nimport { AcmeApiError } from \"../../errors.js\";\nimport { ApiEndpoints, joinUrl } from \"../api-endpoints.js\";\nimport { parseBody, requestWithRetry } from \"../http-transport.js\";\nimport { SDK_HEADER_NAME, SDK_HEADER_VALUE } from \"../sdk-headers.js\";\nimport type { Logger } from \"../../logger.js\";\n\nexport interface RestClientOptions {\n /**\n * The install's **base API URL** (no trailing slash, no routing slug). Each\n * request builds `baseApiUrl/<slug>/<path>`, where the slug comes from\n * {@link endpoints} for the request's endpoint key.\n */\n baseApiUrl: string;\n /** Maps an endpoint key to the relative slug appended to {@link baseApiUrl}. */\n endpoints: ApiEndpoints;\n /** Supplies a valid bearer token for each request. */\n getToken: () => string;\n /** Backoff delays (ms) applied on successive HTTP 429 responses. */\n retryDelaysMs: number[];\n /** Diagnostics sink. */\n logger: Logger;\n /** `fetch` implementation to use. */\n fetchFn: typeof fetch;\n}\n\nexport class RestClient {\n constructor(private readonly options: RestClientOptions) {}\n\n /**\n * Issues a GET against the named REST path and returns the parsed JSON body.\n * Retries on HTTP 429 per the configured backoff (via the shared\n * {@link requestWithRetry} loop).\n *\n * @throws {AdminAccountRequiredError} on HTTP 418\n * @throws {RateLimitError} on HTTP 429 after retries are exhausted\n * @throws {AcmeApiError} on any other non-2xx response\n */\n async get<T>(endpoint: string, path: string): Promise<T> {\n const { logger } = this.options;\n const url = this.endpoint(endpoint, path);\n\n logger.info(\"Making ACME request\", { url, path });\n\n return requestWithRetry(\n this.options,\n url,\n { method: \"GET\", headers: this.buildHeaders() },\n path,\n async (response) => {\n const body = await parseBody(response);\n\n if (!response.ok) {\n logger.error(`ACME request failed with HTTP ${response.status}`, { url });\n throw new AcmeApiError(response.status, body);\n }\n\n return body as T;\n },\n );\n }\n\n private endpoint(endpoint: string, path: string): string {\n const { baseApiUrl, endpoints } = this.options;\n return joinUrl(baseApiUrl, endpoints.pathFor(endpoint), path);\n }\n\n private buildHeaders(): Record<string, string> {\n return {\n \"X-Peek-Auth\": `Bearer ${this.options.getToken()}`,\n \"Content-Type\": \"application/json\",\n [SDK_HEADER_NAME]: SDK_HEADER_VALUE,\n };\n }\n}\n","/**\n * Authenticated root entry point to the ACME backoffice REST gateway.\n *\n * The ACME sibling of {@link PeekAccessService} / {@link CngAccessService}.\n * Configure one instance per install; it owns the shared, authenticated\n * transport (minting/caching tokens on demand) and hands out the\n * {@link AcmeProductService}.\n *\n * Auth and transport mirror the CNG access service: the same app JWT\n * (`X-Peek-Auth: Bearer`) minted from the Peek app credentials via the shared\n * {@link TokenManager}, routed through the app-registry installations API. The\n * only differences are the extendable slug (`acme_backoffice_api-v1`), REST\n * rather than GraphQL, and no `pk-api-key` header.\n */\nimport {\n createTokenManager,\n requireNonEmpty,\n resolveBaseApiUrl,\n DEFAULT_RETRY_DELAYS_MS,\n type BaseAccessServiceConfig,\n} from \"./access-service-config.js\";\nimport { ACME_API_ENDPOINTS, ACME_EXTENDABLE_SLUG } from \"./internal/acme/endpoints.js\";\nimport { AcmeProductService } from \"./internal/acme/products/product-service.js\";\nimport { RestClient } from \"./internal/acme/rest-client.js\";\nimport { noopLogger } from \"./logger.js\";\n\n/** Default gateway base URL — the app-registry installations API. */\nconst DEFAULT_BASE_URL = \"https://app-registry.peeklabs.com/installations-api\";\n\n/**\n * Configuration for an {@link AcmeAccessService} instance. ACME adds no fields\n * beyond {@link BaseAccessServiceConfig} — it authenticates on the app JWT\n * alone (no `pk-api-key`, so no `gatewayKey`).\n */\nexport type AcmeAccessServiceConfig = BaseAccessServiceConfig;\n\n/**\n * Authenticated root entry point to the ACME backoffice REST gateway.\n *\n * @example\n * ```ts\n * import { AcmeAccessService, type AcmeActivity } from \"@peektravel/app-utilities\";\n *\n * const acme = new AcmeAccessService({\n * installId: \"install-123\",\n * jwtSecret: process.env.PEEK_APP_SECRET!,\n * issuer: process.env.PEEK_APP_ID!,\n * appId: process.env.PEEK_APP_ID!,\n * });\n *\n * const activities: AcmeActivity[] = await acme.getProductService().getAllActivities();\n * ```\n *\n * @throws {Error} from the constructor when any required config field\n * (`installId`, `jwtSecret`, `issuer`, `appId`) is empty.\n */\nexport class AcmeAccessService {\n private readonly client: RestClient;\n private productService?: AcmeProductService;\n\n constructor(config: AcmeAccessServiceConfig) {\n const hasApiUrl = !!config.apiUrl;\n requireNonEmpty(config.installId, \"installId\", \"AcmeAccessService\");\n requireNonEmpty(config.jwtSecret, \"jwtSecret\", \"AcmeAccessService\");\n requireNonEmpty(config.issuer, \"issuer\", \"AcmeAccessService\");\n if (!hasApiUrl) requireNonEmpty(config.appId ?? \"\", \"appId\", \"AcmeAccessService\");\n\n const logger = config.logger ?? noopLogger;\n const tokens = createTokenManager(config);\n\n const baseApiUrl = hasApiUrl\n ? resolveBaseApiUrl(config.apiUrl!, ACME_EXTENDABLE_SLUG, \"AcmeAccessService\")\n : `${config.baseUrl ?? DEFAULT_BASE_URL}/${config.appId}`;\n this.client = new RestClient({\n baseApiUrl,\n endpoints: ACME_API_ENDPOINTS,\n getToken: () => tokens.getToken(),\n retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,\n logger,\n fetchFn: config.fetch ?? globalThis.fetch,\n });\n }\n\n /**\n * Returns the {@link AcmeProductService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getProductService(): AcmeProductService {\n if (!this.productService) {\n this.productService = new AcmeProductService(this.client);\n }\n return this.productService;\n }\n\n /** All activities. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link AcmeProductService.getAllActivities}. */\n getAllActivities() {\n return this.getProductService().getAllActivities();\n }\n}\n","/**\n * Factory that turns a persisted install (or a parsed install webhook) into the\n * right access service for its platform, wired to the install's own app\n * endpoint.\n *\n * The install webhook is the only source of an install's `platform` and `apiUrl`\n * (see `src/models/peek/install.ts`), and those two facts are exactly what's\n * needed to target it: `platform` picks the service class, and `apiUrl` is used\n * **as given** as that service's endpoint. This helper encodes that mapping so a\n * consumer that persisted an install can construct its client in one call\n * instead of switching on the platform and hand-wiring the URL.\n */\nimport {\n PeekAccessService,\n type PeekAccessServiceConfig,\n} from \"./peek-access-service.js\";\nimport { CngAccessService } from \"./cng-access-service.js\";\nimport { AcmeAccessService } from \"./acme-access-service.js\";\nimport type { PeekPlatform } from \"./models/peek/auth-token.js\";\n\n/**\n * The per-install facts needed to build an access service — a structural subset\n * of {@link InstallWebhook}, so a persisted install record (or the webhook event\n * itself) satisfies it directly.\n */\nexport interface InstallAccessTarget {\n /** Which platform serves the install (the install webhook's `platform`). */\n platform: PeekPlatform | null;\n /**\n * The install's base API URL (the install webhook's `apiUrl`). The chosen\n * access service's service classes append their own backoffice slug when they\n * call; a URL already carrying this platform's slug is stripped back to the\n * base, and one carrying a different platform's slug throws.\n */\n apiUrl: string;\n /** The install id (the install webhook's `installId`) — becomes the JWT subject. */\n installId: string;\n}\n\n/**\n * The per-app credentials/options shared by every access service — everything\n * except the per-install `installId`/`apiUrl` (supplied by the target) and the\n * deprecated `appId`/`baseUrl`/`mode` URL controls (superseded by `apiUrl`).\n * `gatewayKey` is accepted for Peek and ignored by CNG/ACME.\n */\nexport type InstallAccessConfig = Omit<\n PeekAccessServiceConfig,\n \"installId\" | \"apiUrl\" | \"appId\" | \"baseUrl\" | \"mode\"\n>;\n\n/** The union of access services this factory can return, narrowed by `platform`. */\nexport type InstallAccessService =\n | PeekAccessService\n | CngAccessService\n | AcmeAccessService;\n\n/**\n * Builds the access service for `install.platform`, using `install.apiUrl` as\n * the service's endpoint. Narrow the return by `install.platform` (or\n * `instanceof`) to reach a platform-specific surface.\n *\n * @throws {Error} when `install.platform` is `null` or unrecognised — an install\n * with an unknown platform has no service to route to, and silently defaulting\n * would point it at the wrong gateway.\n */\nexport function createAccessServiceForInstall(\n install: InstallAccessTarget,\n config: InstallAccessConfig,\n): InstallAccessService {\n const shared = { ...config, installId: install.installId, apiUrl: install.apiUrl };\n switch (install.platform) {\n case \"peek\":\n return new PeekAccessService(shared);\n case \"cng\":\n return new CngAccessService(shared);\n case \"acme\":\n return new AcmeAccessService(shared);\n default:\n throw new Error(\n `createAccessServiceForInstall: unknown or missing platform ` +\n `\"${install.platform}\" for install \"${install.installId}\"`,\n );\n }\n}\n","/**\n * Public webhook surface for bookings.\n *\n * A Peek \"backoffice\" booking webhook's payload shape is defined by a GraphQL\n * field selection registered with the hook. That registration happens once, in\n * an external system (the App Store `broadcast_to_url` config) — not from\n * consumer code — so this package registers nothing at runtime. It owns the two\n * pieces that must agree:\n *\n * - {@link BOOKING_WEBHOOK_GQL_QUERY} — the canonical selection to paste into\n * that external config. A setup-time artifact surfaced through\n * `docs/webhooks.md` and pinned by a drift-guard test; **internal**, not part\n * of the runtime public API.\n * - {@link parseBookingWebhook} — the only runtime export; turns a delivered\n * payload into a clean {@link Booking} using the very same converter as the\n * read path.\n *\n * Parsing an inbound webhook needs no auth, no network, and no client — it is a\n * pure transform — so it is exported as a standalone function rather than a\n * method on `PeekAccessService` (the receiver may not hold gateway credentials).\n */\nimport type { Booking } from \"../../../models/peek/booking.js\";\nimport { fromBookingNode } from \"./booking-converter.js\";\nimport {\n bookingGuestsFields,\n bookingQueryFields,\n PRICE_BREAKDOWN_FIELDS,\n type BookingNode,\n} from \"./booking-queries.js\";\n\n/** The envelope key the webhook delivery wraps the booking node under. */\nconst PAYLOAD_BOOKING_KEY = \"booking\";\n\n/** The `value` sub-field that anchors the price-breakdown injection. */\nconst VALUE_OPEN_TOKEN = \"value {\";\n\n/**\n * Price-breakdown field names that only appear on `value` when the breakdown was\n * requested — their presence is how {@link parseBookingWebhook} auto-detects it.\n */\nconst PRICE_BREAKDOWN_KEYS = [\n \"convenienceFee\",\n \"deposit\",\n \"discount\",\n \"discountedPrice\",\n \"fees\",\n \"flatPartnerFee\",\n \"price\",\n \"retailPrice\",\n \"taxes\",\n] as const;\n\n/**\n * The canonical GraphQL selection set to register with the booking webhook — the\n * value that goes in the external `output_fields_gql_query` config.\n *\n * It is the **maximal** selection (guests + full price breakdown included), so a\n * single registration captures everything and {@link parseBookingWebhook}\n * auto-detects whatever the payload actually carries. It is the bare selection\n * set (`{ … }`), not a wrapped `query`, because the webhook system supplies the\n * operation around it; whitespace is collapsed so it drops into a JSON config\n * string.\n *\n * Internal: the webhook is configured in an external system, so this is a\n * setup-time artifact (see `docs/webhooks.md`), not a runtime API. A drift-guard\n * test snapshots it so the documented string can't silently rot.\n */\nexport const BOOKING_WEBHOOK_GQL_QUERY = buildMaximalWebhookQuery();\n\nfunction buildMaximalWebhookQuery(): string {\n const fields = bookingQueryFields.replace(\n VALUE_OPEN_TOKEN,\n `${VALUE_OPEN_TOKEN} ${PRICE_BREAKDOWN_FIELDS}`,\n );\n return `{ ${fields} ${bookingGuestsFields} }`.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Parses a delivered booking webhook payload into a clean {@link Booking}.\n *\n * Accepts the raw request body — either the `{ booking: … }` envelope or a bare\n * booking node, and a JSON string is parsed first. Which optional field groups\n * are present is auto-detected from the payload, so there is nothing to keep in\n * sync with the registered query.\n */\nexport function parseBookingWebhook(payload: unknown): Booking {\n const node = extractBookingNode(payload);\n return fromBookingNode(node, hasGuests(node), hasPriceBreakdown(node));\n}\n\n/** Narrows the raw request body down to the booking node, tolerating both shapes. */\nfunction extractBookingNode(payload: unknown): BookingNode {\n let body: unknown = payload;\n if (typeof body === \"string\") {\n try {\n body = JSON.parse(body);\n } catch {\n return {};\n }\n }\n if (!body || typeof body !== \"object\") return {};\n const record = body as Record<string, unknown>;\n const inner = record[PAYLOAD_BOOKING_KEY];\n if (inner && typeof inner === \"object\") return inner as BookingNode;\n return record as BookingNode;\n}\n\nfunction hasGuests(node: BookingNode): boolean {\n return Array.isArray(node.bookingGuests);\n}\n\nfunction hasPriceBreakdown(node: BookingNode): boolean {\n const value = node.value;\n if (!value) return false;\n return PRICE_BREAKDOWN_KEYS.some((key) => key in value);\n}\n","/**\n * Public webhook surface for waivers.\n *\n * Unlike bookings, a waiver webhook needs **no GraphQL registration query** —\n * Peek delivers a fixed payload (the App Store `waiver_webhook_data` output\n * format, with `output_fields_gql_query` left null), so there is nothing to\n * register beyond subscribing to the `agreement_signature_created` event. The\n * package's only job is to parse the delivered payload into a clean\n * {@link Waiver}.\n *\n * Like the booking parser, this is a pure transform — no auth, no network, no\n * client — so it is a standalone function rather than a method on\n * `PeekAccessService` (the receiver may not hold gateway credentials).\n */\nimport type { Waiver } from \"../../../models/peek/waiver.js\";\nimport {\n resolveAccessOptions,\n type AccessOptions,\n} from \"../../../access-options.js\";\n\n/** The envelope key the webhook delivery wraps the waiver node under. */\nconst PAYLOAD_WAIVER_KEY = \"waiver\";\n\n/** Raw, snake_case waiver payload as delivered by the webhook. Internal. */\ninterface WaiverNode {\n agreement_template_id?: string;\n booking_id?: string;\n file_url?: string;\n signed_at?: string;\n signed_by_guardian?: boolean;\n waiver_data?: {\n participant_name?: string | null;\n participant_optin_marketing?: boolean;\n participant_optin_sms?: boolean;\n } | null;\n}\n\n/**\n * Parses a delivered waiver webhook payload into a clean {@link Waiver}.\n *\n * Accepts the raw request body — either the `{ waiver: … }` envelope or a bare\n * waiver node, and a JSON string is parsed first. Never throws on malformed\n * input: a missing/garbled body yields a {@link Waiver} with empty fields.\n *\n * Because a waiver webhook has no GraphQL selection to trim (Peek delivers a\n * fixed payload), the PII fields — the participant `guestName` and the signed\n * document `fileUrl` — are instead redacted here at parse time when `options`\n * does not enable PII. Pass `{ fullCustomerAccess: true }` to keep them.\n */\nexport function parseWaiverWebhook(\n payload: unknown,\n options?: AccessOptions,\n): Waiver {\n const waiver = fromWaiverNode(extractWaiverNode(payload));\n if (!resolveAccessOptions(options).fullCustomerAccess) {\n waiver.guestName = null;\n waiver.fileUrl = \"\";\n }\n return waiver;\n}\n\n/** Pure mapping of a raw waiver node into the clean {@link Waiver} model. */\nexport function fromWaiverNode(node: WaiverNode | null | undefined): Waiver {\n const data = node ?? {};\n const waiverData = data.waiver_data ?? {};\n return {\n templateId: data.agreement_template_id || \"\",\n bookingId: data.booking_id || \"\",\n fileUrl: data.file_url || \"\",\n signedAt: data.signed_at || \"\",\n isSignedByGuardian: Boolean(data.signed_by_guardian),\n guestName: waiverData.participant_name || null,\n isOptinMarketing: Boolean(waiverData.participant_optin_marketing),\n isOptinSms: Boolean(waiverData.participant_optin_sms),\n };\n}\n\n/** Narrows the raw request body down to the waiver node, tolerating both shapes. */\nfunction extractWaiverNode(payload: unknown): WaiverNode {\n let body: unknown = payload;\n if (typeof body === \"string\") {\n try {\n body = JSON.parse(body);\n } catch {\n return {};\n }\n }\n if (!body || typeof body !== \"object\") return {};\n const record = body as Record<string, unknown>;\n const inner = record[PAYLOAD_WAIVER_KEY];\n if (inner && typeof inner === \"object\") return inner as WaiverNode;\n return record as WaiverNode;\n}\n","/**\n * The clean data model for an app-store **install lifecycle event** — the single\n * flat object `parseInstallWebhook` returns for the webhook Peek's app registry\n * POSTs when an app is installed, uninstalled, or updated.\n *\n * That delivery carries two things at once: a **signed `app_registry_v2` JWT**\n * (the security boundary) and a plain **JSON body** (the event payload).\n * `parseInstallWebhook` verifies the JWT and merges both into this shape, so a\n * consumer sees one clean, flat, JSON-safe record instead of two differently\n * shaped payloads. The **JSON body is the source of the event data** — it\n * carries every field below; the verified JWT authenticates the delivery and\n * acts as the **fallback** for the fields it also happens to carry (`installId`,\n * `accountId`, `status`, `displayVersion`, `user`) when the body omits them.\n *\n * It is also the single origin of the account id (and the `apiUrl`/`timezone`)\n * in the whole system: no GraphQL read returns them, so whatever a consumer\n * persists from this event is all it will ever have.\n *\n * **Every install event is a full snapshot — upsert by `installId`.** An\n * `update_installed` event carries the *same complete record* as the original\n * `installed` event, so treat each delivery as an upsert keyed by `installId`\n * and overwrite the stored fields with the incoming ones. This is how the\n * registry pushes changes — e.g. a new `apiUrl` — so a consumer that only reads\n * the first `installed` event and ignores later updates will keep stale data.\n */\nimport type { PeekAuthTokenUser, PeekPlatform } from \"./auth-token.js\";\n\n/**\n * Every install lifecycle status Peek's app registry sends today. Exported so\n * consumers can validate or enumerate without restating the vocabulary.\n */\nexport const INSTALL_STATUSES = [\n \"installed\",\n \"uninstalled\",\n \"update_installed\",\n] as const;\n\n/** Install lifecycle status. */\nexport type InstallStatus = (typeof INSTALL_STATUSES)[number];\n\n/**\n * A verified install lifecycle event — what happened, to which install, and who\n * (if anyone) triggered it — as one flat, JSON-safe record.\n *\n * This is the shape `parseInstallWebhook` returns. It is flat by design: it\n * round-trips through a datastore unchanged, so the same shape the parser\n * returns is the shape a consumer persists and later rehydrates. There is\n * deliberately no nested identity object and no second representation.\n *\n * Every field is read from the **JSON body** first, falling back to the\n * **verified JWT** for the fields it also carries (`installId`, `accountId`,\n * `status`, `displayVersion`, `user`). The delivery is authenticated as a whole\n * by the JWT signature, so the body is trusted within a verified request.\n */\nexport interface InstallWebhook {\n /** Install ID — Peek-assigned UUID. Also the JWT subject (`sub`). */\n installId: string;\n /**\n * Stable Peek account id — the same value Peek calls the **partner ID**.\n * This event is its only source; it cannot be re-fetched later.\n */\n accountId: string;\n /** Partner display name. `\"\"` when the JSON body omits it. */\n accountName: string;\n /**\n * Which Peek platform owns the install, or `null` when the registry reported\n * a platform this version of the package does not know. `null` means \"newer\n * than this package\", **not** \"absent\" — do not coerce it to a default.\n *\n * **Persist and track this per install.** It is not cosmetic: the platform\n * determines which APIs the install is served by, and therefore which access\n * service a consumer must construct for it — `PeekAccessService` for `\"peek\"`,\n * `CngAccessService` for `\"cng\"`, `AcmeAccessService` for `\"acme\"`, each\n * routed at a different gateway. Two installs of the same app can sit on\n * different platforms, so this cannot be inferred from app-level config and\n * has no source other than this event.\n */\n platform: PeekPlatform | null;\n /** Whether this is a test account. Defaults to `false` when not reported. */\n isTest: boolean;\n /**\n * The account's IANA timezone (e.g. `\"America/New_York\"`), or `\"\"` when the\n * body omits it.\n *\n * **Persist this per install.** It has no source other than this event, and\n * downstream date/time handling for the install (scheduling, day boundaries,\n * display) needs the account's own timezone rather than the server's.\n */\n timezone: string;\n /**\n * The **app endpoint URL** the registry serves this install from (the body's\n * `api.url`), or `\"\"` when the body omits it.\n *\n * Use it **as given** as the base URL for this install's API calls — do not\n * decompose it or append your own app id. The registry may tag traffic with an\n * app id in the path; that is the registry's concern and opaque to callers, so\n * hit the URL unmodified.\n *\n * **Persist this per install, and refresh it on every install event.** It is\n * install-specific, has no source other than this webhook, and the registry\n * can change it: an `update_installed` event redelivers the full record with a\n * (possibly new) `apiUrl`, so re-key by `installId` and overwrite the stored\n * URL whenever an event arrives.\n */\n apiUrl: string;\n /**\n * The lifecycle status, or `null` when the registry sent a status this\n * version of the package does not know. Handle `null` explicitly — treating\n * it as a no-op silently drops a lifecycle transition.\n */\n status: InstallStatus | null;\n /** The status exactly as delivered, for logging and for the `null` case. */\n rawStatus: string;\n /** App display version at the time of the event. */\n displayVersion: string;\n /**\n * The user that triggered the event, or `null` for system-initiated events\n * (install lifecycle changes are often system-initiated). Read from the body's\n * `modified_by`, falling back to the JWT's `user`.\n */\n user: PeekAuthTokenUser | null;\n}\n","/**\n * Pure, I/O-free helpers for the install webhook: narrowing an unknown request\n * body to the raw JSON node, and narrowing a delivered `status`/`platform`\n * string to its known union. No network, no logging, no clock.\n *\n * Internal only — never re-exported from `src/index.ts`.\n */\nimport {\n PEEK_PLATFORMS,\n type PeekPlatform,\n} from \"../../../models/peek/auth-token.js\";\nimport {\n INSTALL_STATUSES,\n type InstallStatus,\n} from \"../../../models/peek/install.js\";\nimport type { RawPeekTokenUser } from \"../peek-auth-token.js\";\n\n/** The raw, snake_case account block of an install webhook's JSON body. */\nexport interface InstallWebhookBodyAccount {\n id?: string;\n name?: string;\n platform?: string;\n timezone?: string;\n is_test?: boolean;\n}\n\n/**\n * The raw, snake_case JSON body delivered alongside the install webhook token.\n * This is the **primary source of the event data**: it carries the full\n * `account` block, the per-install `api.url`, the `modified_by` actor, and the\n * `install_id`/`status`/`display_version` the token also carries (the token is\n * the fallback for those). Extraction is defensive — any field may be absent.\n */\nexport interface InstallWebhookBody {\n status?: string;\n install_id?: string;\n display_version?: string;\n account?: InstallWebhookBodyAccount | null;\n /** The per-install backoffice API endpoint block. */\n api?: { url?: string } | null;\n /** The user that triggered the event (same shape as the token's `user`). */\n modified_by?: RawPeekTokenUser | null;\n}\n\n/**\n * Narrows an unknown request body to an {@link InstallWebhookBody}, tolerating a\n * JSON string (parsed first) and returning `{}` for anything non-object or\n * unparseable, so the caller never has to guard.\n */\nexport function extractInstallWebhookBody(payload: unknown): InstallWebhookBody {\n let body: unknown = payload;\n if (typeof body === \"string\") {\n try {\n body = JSON.parse(body);\n } catch {\n return {};\n }\n }\n if (!body || typeof body !== \"object\") return {};\n return body as InstallWebhookBody;\n}\n\n/**\n * Narrows a delivered status to the {@link InstallStatus} union, or `null` when\n * the registry sent one this version of the package does not know.\n */\nexport function toInstallStatus(raw: string): InstallStatus | null {\n return (INSTALL_STATUSES as readonly string[]).includes(raw)\n ? (raw as InstallStatus)\n : null;\n}\n\n/**\n * Narrows a reported platform to the {@link PeekPlatform} union, or `null` when\n * the registry sent one this version of the package does not know.\n */\nexport function toPeekPlatform(raw: string): PeekPlatform | null {\n return (PEEK_PLATFORMS as readonly string[]).includes(raw)\n ? (raw as PeekPlatform)\n : null;\n}\n","/**\n * Public webhook surface for install-status events.\n *\n * Peek's app registry notifies your app of install lifecycle changes (installed,\n * uninstalled, status changed) with a single POST that carries **two** things at\n * once: a **signed `app_registry_v2` JWT** (delivered in the `x-peek-auth`\n * request header) and a plain **JSON body**. The JWT is the security boundary —\n * verifying its\n * signature is what authenticates that the notification really came from Peek\n * before your app acts on it (e.g. de-provisioning an uninstall). The JSON body\n * is the **event payload**: it carries the full account block (name, platform,\n * timezone, test flag), the per-install `api.url`, the acting user, and the\n * install id / status / version.\n *\n * `parseInstallWebhook` verifies the token and reads the event from the body,\n * falling back to the token for the fields it also carries, returning one flat\n * {@link InstallWebhook} so a consumer makes a single call instead of stitching\n * two differently shaped payloads together.\n *\n * This is exported as a standalone function rather than a method on\n * `PeekAccessService` because the receiver has no per-install service to inherit\n * a secret from yet — an install webhook can arrive before the first session, or\n * describe an install that is being torn down. The caller passes the app's\n * signing secret directly (the same secret used to mint peek-auth tokens).\n *\n * The signature/issuer/audience/expiry checks are strict (they are the security\n * boundary); the claim *extraction* is defensive so an unexpected-but-valid\n * payload yields empty fields rather than throwing.\n */\nimport {\n extractInstallWebhookBody,\n toInstallStatus,\n toPeekPlatform,\n} from \"./install-converter.js\";\nimport {\n cleanTokenString,\n mapPeekTokenUser,\n verifyPeekJwt,\n type RawPeekTokenUser,\n} from \"../peek-auth-token.js\";\nimport type { InstallWebhook } from \"../../../models/peek/install.js\";\nimport type { InstallWebhookClaims } from \"../../../models/peek/auth-token.js\";\n\n/** Raw, snake_case payload of an `app_registry_v2` install-webhook token. */\ninterface RawInstallWebhookPayload {\n /** Install ID — the JWT subject. */\n sub?: string;\n /** App display version at time of issuance. */\n display_version?: string;\n /** Install lifecycle status. */\n status?: string;\n /** The account the install belongs to. */\n account?: { id?: string } | null;\n /** The triggering user, or `null` for system-initiated events. */\n user?: RawPeekTokenUser | null;\n}\n\n/**\n * Verifies an install-status webhook token and merges it with the delivered\n * JSON body into one flat {@link InstallWebhook}.\n *\n * The **JSON body** is the source of the event data — `installId`, `accountId`,\n * `accountName`, `platform`, `isTest`, `timezone`, `apiUrl`, `status`,\n * `displayVersion`, and `user`. The **verified token** authenticates the whole\n * delivery and is the **fallback** for the fields it also carries (`installId`,\n * `accountId`, `status`, `displayVersion`, `user`) when the body omits them. A\n * missing or malformed body degrades the body-only fields (`accountName`,\n * `platform`, `isTest`, `timezone`, `apiUrl`) to `\"\"`/`null`/`false` and leans\n * on the token for the rest; it never throws.\n *\n * Signature verification is strict: the HMAC signature (with `secret`), the\n * token expiry, the `\"app_registry_v2\"` issuer, and the `\"Joken\"` audience are\n * all checked — the same checks as {@link PeekAccessService.verifyPeekAuthToken}.\n * Any failure throws from the `jsonwebtoken` library, so callers can branch on\n * the error kind:\n *\n * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed\n * - `TokenExpiredError` — past `exp`\n * - `NotBeforeError` — before `nbf`\n *\n * An unrecognised `status` or `platform` maps to `null` (with the wire status\n * preserved on {@link InstallWebhook.rawStatus}) rather than being coerced —\n * Peek treats any 2xx as delivered and does not redeliver, so handle a `null`\n * `status` explicitly:\n *\n * ```ts\n * const event = parseInstallWebhook(token, req.body, secret);\n * switch (event.status) {\n * case \"installed\": return provision(event);\n * case \"uninstalled\": return deprovision(event);\n * case \"update_installed\": return recordVersion(event);\n * default: throw new Error(`unknown install status: ${event.rawStatus}`);\n * }\n * ```\n *\n * @param token the JWT delivered by the install webhook. Pass the raw\n * `x-peek-auth` header value directly — a leading `Bearer ` prefix, if\n * present, is stripped for you.\n * @param body the delivered JSON body (raw object or a JSON string)\n * @param secret the app's HMAC signing secret (the `jwtSecret` you construct\n * `PeekAccessService` with)\n * @throws {JsonWebTokenError} signature invalid or token malformed\n * @throws {TokenExpiredError} token has expired\n * @throws {NotBeforeError} token not yet valid\n */\nexport function parseInstallWebhook(\n token: string,\n body: unknown,\n secret: string,\n): InstallWebhook {\n const payload = verifyPeekJwt<RawInstallWebhookPayload>(token, secret);\n const parsed = extractInstallWebhookBody(body);\n const account = parsed.account ?? {};\n // The JSON body is the source of the event data; the verified token is the\n // fallback for the fields it also carries. `||` so an empty body value falls\n // through to the token rather than masking it.\n const rawStatus = parsed.status || payload.status || \"\";\n return {\n installId: parsed.install_id || payload.sub || \"\",\n accountId: account.id || payload.account?.id || \"\",\n accountName: account.name || \"\",\n platform: toPeekPlatform(account.platform || \"\"),\n isTest: Boolean(account.is_test),\n timezone: account.timezone || \"\",\n apiUrl: parsed.api?.url || \"\",\n status: toInstallStatus(rawStatus),\n rawStatus,\n displayVersion: parsed.display_version || payload.display_version || \"\",\n user: resolveInstallUser(parsed.modified_by, payload.user),\n };\n}\n\n/**\n * Resolves the acting user, preferring the body's `modified_by` and falling back\n * to the token's `user`; system-initiated events carry neither and yield `null`.\n * The body is preferred only when its `modified_by` carries a *real* id — an\n * absent, empty, or `\"null\"` id (see {@link cleanTokenString}) is treated as no\n * user and defers to the token. {@link mapPeekTokenUser} then maps whichever\n * block wins, tolerating any missing/nullable field.\n */\nfunction resolveInstallUser(\n bodyUser: RawPeekTokenUser | null | undefined,\n tokenUser: RawPeekTokenUser | null | undefined,\n): InstallWebhook[\"user\"] {\n if (cleanTokenString(bodyUser?.id) !== null) return mapPeekTokenUser(bodyUser);\n return mapPeekTokenUser(tokenUser);\n}\n\n/**\n * Verifies an install-status webhook token and returns its clean claims.\n *\n * @deprecated Use {@link parseInstallWebhook} instead. This verifier reads only\n * the signed token, so it cannot report the account **name**, **platform**, or\n * **test** flag that the webhook's JSON body also carries — the caller was left\n * to parse that body separately and stitch the two shapes together.\n * `parseInstallWebhook(token, body, secret)` verifies the same token and returns\n * one flat {@link InstallWebhook} with every field. This function remains only\n * for backwards compatibility.\n *\n * Validates the HMAC signature (with `secret`), the token expiry, the\n * `\"app_registry_v2\"` issuer, and the `\"Joken\"` audience — the same checks as\n * {@link PeekAccessService.verifyPeekAuthToken} — then maps the payload to\n * {@link InstallWebhookClaims}, tolerating a `null` `user` (system events).\n * Throws from the `jsonwebtoken` library on any verification failure:\n *\n * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed\n * - `TokenExpiredError` — past `exp`\n * - `NotBeforeError` — before `nbf`\n *\n * @param token the JWT delivered by the install webhook. Pass the raw\n * `x-peek-auth` header value directly — a leading `Bearer ` prefix, if\n * present, is stripped for you.\n * @param secret the app's HMAC signing secret (the `jwtSecret` you construct\n * `PeekAccessService` with)\n * @throws {JsonWebTokenError} signature invalid or token malformed\n * @throws {TokenExpiredError} token has expired\n * @throws {NotBeforeError} token not yet valid\n */\nexport function verifyInstallWebhook(\n token: string,\n secret: string,\n): InstallWebhookClaims {\n const payload = verifyPeekJwt<RawInstallWebhookPayload>(token, secret);\n return {\n installId: payload.sub ?? \"\",\n account: { id: payload.account?.id ?? \"\" },\n status: payload.status ?? \"\",\n displayVersion: payload.display_version ?? \"\",\n user: mapPeekTokenUser(payload.user),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/api-endpoints.ts","../src/internal/peek/gateway-endpoints.ts","../src/internal/peek/account-users/account-user-converter.ts","../src/internal/peek/account-users/account-user-queries.ts","../src/internal/peek/account-users/account-user-service.ts","../src/internal/peek/availability/availability-queries.ts","../src/internal/peek/availability/availability-service.ts","../src/access-options.ts","../src/errors.ts","../src/models/peek/product.ts","../src/internal/peek/bookings/booking-queries.ts","../src/internal/peek/bookings/booking-converter.ts","../src/internal/peek/bookings/booking-guest-converter.ts","../src/internal/peek/bookings/metadata-converter.ts","../src/internal/peek/bookings/metadata-queries.ts","../src/internal/peek/bookings/payments-on-file-converter.ts","../src/internal/peek/bookings/addon-queries.ts","../src/internal/peek/bookings/addon-converter.ts","../src/internal/peek/bookings/custom-question-answer.ts","../src/internal/peek/bookings/list-price.ts","../src/internal/peek/bookings/booking-service.ts","../src/internal/peek/daily-notes/daily-note-converter.ts","../src/internal/peek/daily-notes/daily-note-queries.ts","../src/internal/peek/daily-notes/daily-note-service.ts","../src/internal/token-manager.ts","../src/access-service-config.ts","../src/internal/http-transport.ts","../src/internal/sdk-headers.ts","../src/internal/peek/graphql-client.ts","../src/models/peek/auth-token.ts","../src/internal/peek/peek-auth-token.ts","../src/internal/peek/memberships/membership-converter.ts","../src/internal/peek/memberships/membership-queries.ts","../src/internal/peek/memberships/membership-service.ts","../src/internal/peek/resellers/channel-converter.ts","../src/internal/peek/resellers/channel-queries.ts","../src/internal/peek/resellers/reseller-service.ts","../src/internal/peek/resource-pools/resource-pool-converter.ts","../src/internal/peek/resource-pools/resource-pool-queries.ts","../src/internal/peek/resource-pools/resource-pool-service.ts","../src/internal/peek/reviews/review-converter.ts","../src/internal/peek/reviews/review-cursor.ts","../src/internal/peek/reviews/review-queries.ts","../src/internal/peek/reviews/review-service.ts","../src/internal/peek/timeslots/timeslot-converter.ts","../src/internal/peek/timeslots/guide-matcher.ts","../src/internal/peek/timeslots/resource-allocation-queries.ts","../src/internal/peek/timeslots/timeslot-queries.ts","../src/internal/peek/timeslots/timeslot-service.ts","../src/internal/peek/money.ts","../src/internal/peek/products/product-converter.ts","../src/internal/peek/products/custom-question-converter.ts","../src/internal/peek/products/product-queries.ts","../src/internal/peek/products/custom-question-queries.ts","../src/internal/peek/products/product-service.ts","../src/internal/peek/promo-codes/promo-code-queries.ts","../src/internal/peek/promo-codes/promo-code-service.ts","../src/internal/peek/pricing/pricing-queries.ts","../src/internal/peek/pricing/pricing-converter.ts","../src/internal/peek/pricing/pricing-service.ts","../src/logger.ts","../src/peek-access-service.ts","../src/internal/cng/endpoints.ts","../src/models/cng/product.ts","../src/internal/cng/products/product-converter.ts","../src/internal/cng/products/product-service.ts","../src/internal/cng/rest-client.ts","../src/cng-access-service.ts","../src/internal/acme/endpoints.ts","../src/models/acme/product.ts","../src/internal/acme/products/product-queries.ts","../src/internal/acme/products/product-converter.ts","../src/internal/acme/products/product-service.ts","../src/internal/acme/rest-client.ts","../src/acme-access-service.ts","../src/access-service-factory.ts","../src/internal/peek/bookings/booking-webhook.ts","../src/internal/peek/waivers/waiver-webhook.ts","../src/models/peek/install.ts","../src/internal/peek/installs/install-converter.ts","../src/internal/peek/installs/install-webhook.ts"],"names":["DEFAULT_PAGE_SIZE","randomUUID","jwt","jwt2","CREATE_QUOTE_V2_MUTATION","ERROR_PRODUCT_ID_REQUIRED","DEFAULT_CURRENCY","CURRENCY_PATTERN","ACTIVITY_PRODUCT_TYPE","DEFAULT_BASE_URL","RestClient"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * A platform's tiny map of **API endpoint key → relative path** (the \"slug\"\n * inserted between the install's base API URL and the endpoint's own path).\n *\n * The base API URL is the install's app endpoint with no routing segment — the\n * install webhook's `apiUrl` (with any slug stripped back off), or\n * `baseUrl/appId` when built from the deprecated defaults. Each service class\n * resolves *its own* slug through this lookup, so two services on the same\n * platform can route through different slugs. Adding a new API — even one on a\n * different slug than its siblings — is a single entry here.\n *\n * An empty-string path means the endpoint sits directly on the base with no\n * slug (e.g. the legacy Peek v1 GraphQL gateway, which has no extendable slug).\n */\nexport class ApiEndpoints<Key extends string = string> {\n constructor(private readonly paths: Readonly<Record<Key, string>>) {}\n\n /** The relative path (slug) for `endpoint`, appended to the base API URL. */\n pathFor(endpoint: Key): string {\n return this.paths[endpoint];\n }\n}\n\n/**\n * Joins URL path parts with single slashes, dropping empty parts so an absent\n * slug never produces a `//`. The base keeps its scheme's `//` intact because\n * it is passed as one already-joined part.\n */\nexport function joinUrl(...parts: string[]): string {\n return parts.filter((part) => part.length > 0).join(\"/\");\n}\n","/**\n * Endpoint routing for the backoffice GraphQL gateway. Every current operation\n * routes through the `sales` endpoint; the endpoint key and slugs live here so\n * they sit in exactly one place, and {@link peekApiEndpoints} is the simple\n * lookup a new Peek API extends.\n */\nimport { ApiEndpoints } from \"../api-endpoints.js\";\n\n/** The GraphQL endpoint key every current Peek operation routes through. */\nexport const SALES_ENDPOINT = \"sales\";\n\n/** Registry routing slug for the `sales` endpoint (v2 / app-endpoint mode). */\nexport const V2_EXTENDABLE_SLUG = \"peek_backoffice_api-v1\";\n\n/** The endpoint keys the Peek GraphQL transport knows how to route. */\nexport type PeekEndpointKey = typeof SALES_ENDPOINT;\n\n/**\n * Builds the Peek endpoint lookup for a transport generation.\n *\n * - **Registry mode** (`useRegistrySlug` — v2 or an app-endpoint `apiUrl`): the\n * `sales` endpoint routes through the `peek_backoffice_api-v1` slug appended\n * to the base API URL, and the GraphQL POST hits that slug directly.\n * - **Legacy v1 mode**: the backoffice-GraphQL gateway has no extendable slug,\n * so `sales` sits directly under the base (`base/sales`).\n *\n * Add a new Peek API by adding one entry — with its own slug when it needs one.\n */\nexport function peekApiEndpoints(\n useRegistrySlug: boolean,\n): ApiEndpoints<PeekEndpointKey> {\n return new ApiEndpoints({\n [SALES_ENDPOINT]: useRegistrySlug ? V2_EXTENDABLE_SLUG : SALES_ENDPOINT,\n });\n}\n","/**\n * Pure functions mapping raw account-user nodes into the clean\n * {@link AccountUser} model. Inactive users are dropped (mapped to `null`).\n */\nimport type { AccountUser } from \"../../../models/peek/account-user.js\";\nimport type { AccountUserNode } from \"./account-user-queries.js\";\n\n/** Only users in this status are surfaced. */\nconst ACTIVE_STATUS = \"ACTIVE\";\n\n/**\n * Converts a single node into an {@link AccountUser}, or `null` when the node is\n * missing or the user is not active.\n */\nexport function fromAccountUserNode(\n node: AccountUserNode | null | undefined,\n): AccountUser | null {\n if (!node || node.status !== ACTIVE_STATUS) {\n return null;\n }\n\n return {\n id: node.id,\n name: node.name,\n email: node.email,\n phone: node.phone,\n assignedActivities: (node.assignedActivities ?? []).map((activity) => ({\n id: activity.id,\n name: activity.name,\n })),\n };\n}\n\n/** Converts a list of nodes into active {@link AccountUser}s, dropping the rest. */\nexport function fromAccountUserNodes(\n nodes: Array<AccountUserNode | null | undefined>,\n): AccountUser[] {\n const users: AccountUser[] = [];\n for (const node of nodes) {\n const user = fromAccountUserNode(node);\n if (user) {\n users.push(user);\n }\n }\n return users;\n}\n","/**\n * Raw Peek GraphQL queries and response shapes for account users. Internal —\n * not re-exported from the public entry point.\n */\n\n/** Fetches a cursor-paginated page of account users. */\nexport const USER_QUERY = `\n query Sales($first: Int, $after: String) {\n accountUsers(first: $first, after: $after) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n id\n name\n email\n phone\n status\n assignedActivities {\n id\n name\n }\n }\n }\n }\n }\n`;\n\n/** Fetches account users matching a filter (e.g. by id). */\nexport const USER_BY_FILTER_QUERY = `\n query Sales($first: Int, $filter: AccountUsersFilter) {\n accountUsers(first: $first, filter: $filter) {\n edges {\n cursor\n node {\n id\n name\n email\n phone\n status\n assignedActivities {\n id\n name\n }\n }\n }\n }\n }\n`;\n\n/** A single account-user node as returned by the account-user queries. */\nexport interface AccountUserNode {\n id: string;\n name: string;\n email: string;\n phone: string;\n status: string;\n assignedActivities: Array<{ id: string; name: string }>;\n}\n\n/** The `data` payload of the account-user queries. */\nexport interface AccountUsersResponse {\n accountUsers: {\n pageInfo?: { endCursor: string | null; hasNextPage: boolean };\n edges: Array<{ cursor: string; node: AccountUserNode }>;\n };\n}\n","/**\n * Account-user operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getAccountUserService}. Only\n * active users are returned.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type { AccountUser } from \"../../../models/peek/account-user.js\";\nimport {\n fromAccountUserNode,\n fromAccountUserNodes,\n} from \"./account-user-converter.js\";\nimport {\n USER_BY_FILTER_QUERY,\n USER_QUERY,\n type AccountUsersResponse,\n} from \"./account-user-queries.js\";\n\n/** Default page size for cursor-paginated account users. */\nconst DEFAULT_PAGE_SIZE = 50;\n\n/** Tuning options for an {@link AccountUserService}. */\nexport interface AccountUserServiceOptions {\n /** Page size for cursor pagination. Default: 50. */\n pageSize?: number;\n}\n\nexport class AccountUserService {\n private readonly pageSize: number;\n\n constructor(\n private readonly client: GraphQLClient,\n options: AccountUserServiceOptions = {},\n ) {\n this.pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;\n }\n\n /**\n * Returns all active account users, walking the cursor pagination to the end.\n * Inactive users are omitted.\n */\n async getAll(): Promise<AccountUser[]> {\n const users: AccountUser[] = [];\n let after: string | null = null;\n\n for (;;) {\n const body: GraphQLBody<AccountUsersResponse> =\n await this.client.request<AccountUsersResponse>(SALES_ENDPOINT, USER_QUERY, {\n first: this.pageSize,\n after,\n });\n\n const connection = body.data?.accountUsers;\n const edges = connection?.edges ?? [];\n if (edges.length === 0) {\n break;\n }\n\n users.push(...fromAccountUserNodes(edges.map((edge) => edge.node)));\n\n const pageInfo = connection?.pageInfo;\n if (pageInfo?.hasNextPage && pageInfo.endCursor) {\n after = pageInfo.endCursor;\n } else {\n break;\n }\n }\n\n return users;\n }\n\n /**\n * Returns a single active account user by id, or `null` when no active user\n * matches.\n */\n async getById(userId: string): Promise<AccountUser | null> {\n const body: GraphQLBody<AccountUsersResponse> =\n await this.client.request<AccountUsersResponse>(\n SALES_ENDPOINT,\n USER_BY_FILTER_QUERY,\n { first: this.pageSize, filter: { ids: [userId] } },\n );\n\n const firstEdge = (body.data?.accountUsers?.edges ?? [])[0];\n if (!firstEdge) {\n return null;\n }\n return fromAccountUserNode(firstEdge.node);\n }\n}\n","/**\n * Raw Peek GraphQL query and response shape for availability times. Internal.\n * The node matches the public {@link AvailabilityTime} model one-to-one.\n */\nimport type { AvailabilityTime } from \"../../../models/peek/availability-time.js\";\n\n/** Fetches availability times for an activity/date and resource-option quantities. */\nexport const AVAILABILITY_TIMES_QUERY = `\n query Sales($activityId: ID!, $resourceOptionQuantities: [ResourceOptionQuantityData!]!, $date: Date!) {\n availabilityTimes(activityId: $activityId, resourceOptionQuantities: $resourceOptionQuantities, date: $date) {\n id\n time\n from\n end\n duration {\n name\n length {\n amount\n unit\n }\n }\n status\n availability {\n qty\n taken\n resourceOptionId\n }\n }\n }\n`;\n\n/** The `data` payload of {@link AVAILABILITY_TIMES_QUERY}. */\nexport interface AvailabilityTimesResponse {\n availabilityTimes: AvailabilityTime[];\n}\n","/**\n * Availability-times operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getAvailabilityService}.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type {\n AvailabilityTime,\n AvailabilityTimesQuery,\n} from \"../../../models/peek/availability-time.js\";\nimport {\n AVAILABILITY_TIMES_QUERY,\n type AvailabilityTimesResponse,\n} from \"./availability-queries.js\";\n\nexport class AvailabilityService {\n constructor(private readonly client: GraphQLClient) {}\n\n /** Returns the availability times for an activity/date and requested quantities. */\n async getAvailabilityTimes(\n query: AvailabilityTimesQuery,\n ): Promise<AvailabilityTime[]> {\n const body: GraphQLBody<AvailabilityTimesResponse> =\n await this.client.request<AvailabilityTimesResponse>(\n SALES_ENDPOINT,\n AVAILABILITY_TIMES_QUERY,\n {\n activityId: query.activityId,\n resourceOptionQuantities: query.resourceOptionQuantities,\n date: query.date,\n },\n );\n return body.data?.availabilityTimes ?? [];\n }\n}\n","/**\n * Cross-cutting options that govern what data an access service will read and\n * expose. Passed once when constructing an access service and threaded down to\n * the resource services (and the webhook parsers) so a single object controls\n * behaviour everywhere, rather than a boolean being passed hand-to-hand.\n *\n * Kept deliberately small — today it carries a single PII toggle, but new\n * cross-cutting flags slot in here without changing any downstream signatures.\n */\n\n/** Options controlling PII exposure across an access service's reads. */\nexport interface AccessOptions {\n /**\n * When `true`, customer PII (guest names/emails/phones, custom question\n * answers, the customer booking-portal URL, waiver participant details, …) is\n * requested and returned, and payment/booking-modification operations are\n * available.\n *\n * When `false` (the default), those PII fields are never requested from the\n * gateway and come back `null`/empty, and the payment/booking-modification\n * operations that touch customer financial data are disabled (they throw a\n * {@link PiiAccessDisabledError}).\n */\n fullCustomerAccess?: boolean;\n}\n\n/** A fully-resolved {@link AccessOptions} with every flag defaulted. */\nexport type ResolvedAccessOptions = Required<AccessOptions>;\n\n/**\n * Resolves a possibly-absent {@link AccessOptions} into a concrete object with\n * every flag defaulted. `fullCustomerAccess` defaults to `false` (PII off).\n */\nexport function resolveAccessOptions(options?: AccessOptions): ResolvedAccessOptions {\n return { fullCustomerAccess: options?.fullCustomerAccess ?? false };\n}\n","/**\n * Typed errors thrown by the package. Each mirrors a failure mode of the Peek\n * GraphQL gateway (or the CNG REST gateway) so callers can branch on the error\n * type rather than parsing messages.\n *\n * `AdminAccountRequiredError` and `RateLimitError` are shared by all gateways.\n * `PeekGraphQLError` is Peek-only; `CngApiError` and `CngPermissionError` are\n * CNG-only; `AcmeApiError` is ACME-only.\n */\n\n/** The HTTP status the CNG gateway uses for a missing-permission rejection. */\nexport const FORBIDDEN_STATUS = 403;\n\nconst PERMISSION_MESSAGE_PREFIX = \"CNG request forbidden: the app is missing the required permission\";\nconst PERMISSION_MESSAGE_UNKNOWN = \"CNG request forbidden: the app is missing a required permission\";\n\n/** Builds the {@link CngPermissionError} message from the named permissions. */\nfunction buildPermissionMessage(permissions: string[]): string {\n if (permissions.length === 0) return PERMISSION_MESSAGE_UNKNOWN;\n return `${PERMISSION_MESSAGE_PREFIX}${permissions.length > 1 ? \"s\" : \"\"}: ${permissions.join(\", \")}`;\n}\n\n/**\n * Thrown when the gateway responds with HTTP 418, indicating the install is not\n * permitted to perform the request because an admin account is required.\n */\nexport class AdminAccountRequiredError extends Error {\n /** The HTTP status that triggered this error. */\n public readonly statusCode = 418;\n\n constructor(message = \"Admin account required\") {\n super(message);\n this.name = \"AdminAccountRequiredError\";\n }\n}\n\n/**\n * Thrown when the gateway responds with HTTP 429 and all configured retries\n * have been exhausted.\n */\nexport class RateLimitError extends Error {\n /** The HTTP status that triggered this error. */\n public readonly statusCode = 429;\n\n constructor(message = \"Rate limit exceeded\") {\n super(message);\n this.name = \"RateLimitError\";\n }\n}\n\n/**\n * Thrown when a GraphQL response contains an `errors` array. The raw errors are\n * preserved on {@link PeekGraphQLError.graphqlErrors} for inspection.\n */\nexport class PeekGraphQLError extends Error {\n /** The raw `errors` array returned by the GraphQL endpoint. */\n public readonly graphqlErrors: unknown[];\n\n constructor(graphqlErrors: unknown[], message = \"GraphQL request failed\") {\n super(message);\n this.name = \"PeekGraphQLError\";\n this.graphqlErrors = graphqlErrors;\n }\n}\n\n/**\n * Thrown when the Peek GraphQL gateway returns a non-2xx HTTP response that is\n * not one of the specifically-handled statuses (418/429) and does not carry a\n * GraphQL `errors` array. This is the transport-level failure — a `401`\n * (auth/secret wrong), `404` (wrong app id / not provisioned), `5xx`, etc. —\n * as opposed to {@link PeekGraphQLError}, which is a resolver-level failure\n * reported inside an otherwise-successful HTTP response.\n *\n * The offending status is preserved on {@link PeekHttpError.statusCode}, the\n * request URL on {@link PeekHttpError.url}, and the raw response body (parsed\n * JSON when possible, otherwise the raw text) on {@link PeekHttpError.body} — so\n * callers can tell \"which config is wrong\" without disassembling the bundle.\n */\nexport class PeekHttpError extends Error {\n /** The HTTP status that triggered this error. */\n public readonly statusCode: number;\n /** The request URL that produced the failing response. */\n public readonly url: string;\n /** The raw response body (parsed JSON when possible, otherwise text). */\n public readonly body: unknown;\n\n constructor(statusCode: number, url: string, body: unknown, message?: string) {\n super(message ?? `Peek request failed with HTTP ${statusCode}`);\n this.name = \"PeekHttpError\";\n this.statusCode = statusCode;\n this.url = url;\n this.body = body;\n }\n}\n\n/**\n * Thrown when a payment or booking-modification operation is called on an\n * access service that was constructed without `fullCustomerAccess` (PII access\n * disabled). These operations — pulling payment sources, charging/refunding,\n * creating invoice links, and adding/removing add-ons — touch customer\n * financial data, so they are gated behind the same flag as customer PII.\n */\nexport class PiiAccessDisabledError extends Error {\n /** The name of the operation that was blocked (e.g. `\"makePayment\"`). */\n public readonly operation: string;\n\n constructor(operation: string) {\n super(\n `\"${operation}\" is disabled because this access service was created ` +\n `without \"fullCustomerAccess\"; enable it to allow payment and booking-modification operations`,\n );\n this.name = \"PiiAccessDisabledError\";\n this.operation = operation;\n }\n}\n\n/**\n * Thrown when the CNG REST gateway returns a non-2xx response that is not one\n * of the specifically-handled statuses (418/429). The offending status is\n * preserved on {@link CngApiError.statusCode}, and the raw response body (parsed\n * JSON when possible, otherwise the raw text) on {@link CngApiError.body}.\n */\nexport class CngApiError extends Error {\n /** The HTTP status that triggered this error. */\n public readonly statusCode: number;\n /** The raw response body (parsed JSON when possible, otherwise text). */\n public readonly body: unknown;\n\n constructor(statusCode: number, body: unknown, message?: string) {\n super(message ?? `CNG request failed with HTTP ${statusCode}`);\n this.name = \"CngApiError\";\n this.statusCode = statusCode;\n this.body = body;\n }\n}\n\n/**\n * Thrown when the CNG REST gateway responds with HTTP 403 because the app lacks\n * a permission the endpoint requires (e.g. `products:read`). This is an\n * **expected** failure for a misconfigured install — not a bug — so the\n * transport logs it at `warn` rather than `error` and leaves presentation to the\n * caller, which can branch on the type and surface the missing permission\n * however its UI prefers.\n *\n * The permission names the gateway named are on\n * {@link CngPermissionError.permissions} (empty when the body does not name\n * any), so a caller can render them without re-parsing the raw body. Thrown in\n * place of {@link CngApiError} for 403s only; every other non-2xx status still\n * throws `CngApiError`.\n */\nexport class CngPermissionError extends Error {\n /** The HTTP status that triggered this error. */\n public readonly statusCode = FORBIDDEN_STATUS;\n /**\n * The permissions the gateway reported as missing, e.g. `[\"products:read\"]`.\n * Empty when the response body did not name any.\n */\n public readonly permissions: string[];\n /** The raw response body (parsed JSON when possible, otherwise text). */\n public readonly body: unknown;\n\n constructor(permissions: string[], body: unknown, message?: string) {\n super(message ?? buildPermissionMessage(permissions));\n this.name = \"CngPermissionError\";\n this.permissions = permissions;\n this.body = body;\n }\n}\n\n/**\n * Thrown when the ACME REST gateway returns a non-2xx response that is not one\n * of the specifically-handled statuses (418/429). The offending status is\n * preserved on {@link AcmeApiError.statusCode}, and the raw response body\n * (parsed JSON when possible, otherwise the raw text) on\n * {@link AcmeApiError.body}.\n */\nexport class AcmeApiError extends Error {\n /** The HTTP status that triggered this error. */\n public readonly statusCode: number;\n /** The raw response body (parsed JSON when possible, otherwise text). */\n public readonly body: unknown;\n\n constructor(statusCode: number, body: unknown, message?: string) {\n super(message ?? `ACME request failed with HTTP ${statusCode}`);\n this.name = \"AcmeApiError\";\n this.statusCode = statusCode;\n this.body = body;\n }\n}\n","/**\n * The clean, transport-agnostic data model for a Peek Pro product.\n *\n * This is the shape consumers of the package work with. It is intentionally\n * decoupled from the underlying Peek GraphQL schema — the raw GraphQL types and\n * the conversion logic live inside the package and are never exposed here.\n */\nimport type { PricingMoney } from \"./pricing.js\";\n\n/**\n * A bookable product in a Peek Pro account.\n *\n * `PeekAccessService.getAllProducts()` returns a single flat list that combines\n * two distinct Peek concepts into one uniform shape:\n *\n * - **Activities** — the primary bookable experiences (tours, rentals, classes,\n * etc.). Their {@link Product.type} is whatever Peek reports for the activity.\n * - **Add-ons** — optional item options offered alongside activities. They are\n * grouped under their parent item and always carry the\n * {@link ADD_ON_PRODUCT_TYPE} (`\"ADD-ON\"`) type, so callers can tell the two\n * apart with a single field check.\n */\nexport interface Product {\n /**\n * Stable unique identifier for the product.\n *\n * - Activities: the primary GraphQL `id` (falls back to the `legacyId`).\n * - Add-ons: the id of the parent item the options belong to.\n */\n productId: string;\n\n /** Human-readable display name. */\n name: string;\n\n /**\n * Product type.\n *\n * For activities this is the type reported by Peek; for add-ons it is always\n * {@link ADD_ON_PRODUCT_TYPE}.\n */\n type: string;\n\n /**\n * Display color as a hex string (e.g. `\"#1A2B3C\"`).\n *\n * Add-ons default to white (`\"#FFFFFF\"`). Empty string when no color is set.\n */\n color: string;\n\n /**\n * ISO 4217 currency code the activity prices in (e.g. `\"USD\"`).\n *\n * Populated for activities and rentals; empty string for add-ons (which carry\n * no currency of their own) and when Peek reports none. Consumers building\n * pricing overrides use this to set the currency on fixed-price adjustments.\n */\n currency: string;\n\n /**\n * URL of the product's primary display image, or `null` when Peek reports\n * none. Populated for activities/rentals; always `null` for add-ons.\n */\n imageUrl: string | null;\n\n /**\n * Long-form product description (may contain HTML), or `null` when Peek\n * reports none. Populated for activities/rentals; always `null` for add-ons.\n */\n description: string | null;\n\n /**\n * Where the experience meets, or `null` when Peek reports no location detail.\n * Populated for activities/rentals; always `null` for add-ons. Each field\n * inside is independently nullable.\n */\n meetingLocation: ProductMeetingLocation | null;\n\n /**\n * The bookable sub-options of this product.\n *\n * - Activities: the activity's resource options.\n * - Add-ons: each individual item option grouped under the parent item.\n */\n tickets: ProductTicket[];\n}\n\n/** The meeting point for a bookable experience. Every field is nullable. */\nexport interface ProductMeetingLocation {\n /** Free-text summary / instructions for the meeting point. */\n summary: string | null;\n /** Formatted postal address of the meeting point. */\n address: string | null;\n /** Map/link URL for the meeting point. */\n url: string | null;\n}\n\n/** A single bookable sub-option (resource option or add-on item option). */\nexport interface ProductTicket {\n /** Unique identifier of the ticket / option. */\n id: string;\n /** Human-readable name of the ticket / option. */\n name: string;\n /**\n * Lowest price this ticket can be sold at, across its price range.\n *\n * Populated for activity/rental resource options that expose a price range;\n * `null` for add-on options (which carry no range) and when Peek reports none.\n */\n minPrice: PricingMoney | null;\n /**\n * Highest price this ticket can be sold at, across its price range.\n *\n * Populated for activity/rental resource options that expose a price range;\n * `null` for add-on options (which carry no range) and when Peek reports none.\n */\n maxPrice: PricingMoney | null;\n}\n\n/** {@link Product.type} for standard bookable activities. */\nexport const ACTIVITY_PRODUCT_TYPE = \"ACTIVITY\";\n\n/** {@link Product.type} for rental products. */\nexport const RENTAL_PRODUCT_TYPE = \"RENTAL\";\n\n/**\n * The {@link Product.type} value assigned to add-on products.\n *\n * Exposed so callers can filter add-ons out of (or in to) the combined list\n * returned by {@link Product} queries without hard-coding the string.\n */\nexport const ADD_ON_PRODUCT_TYPE = \"ADD-ON\";\n","/**\n * Raw Peek GraphQL fields, queries, mutations, variables, and response shapes\n * for bookings. Internal.\n */\nimport type { BookingSearchBy } from \"../../../models/peek/booking.js\";\n\nexport const SEARCH_BY_PURCHASE_DATE: BookingSearchBy = \"purchaseDate\";\nexport const SEARCH_BY_ACTIVITY_DATE: BookingSearchBy = \"activityDate\";\n\n/** Normalizes a booking id to the gateway's expected form. */\nexport function normalizeBookingId(bookingId: string): string {\n return bookingId.toLowerCase().replace(/-/g, \"_\");\n}\n\n/**\n * Wraps a `sales` edge-node selection in the shared paginated `sales(...)` query\n * envelope (the `query Sales(...)`/`pageInfo`/`edges { node { … } }` boilerplate\n * every booking read uses). `nodeBody` is the raw selection placed inside\n * `node { … }` (e.g. `... on Booking { … }`, optionally preceded by\n * `Sale`-level fields like `order { … }`). All readers share it so the envelope\n * lives in one place.\n */\nexport function buildSalesQuery(nodeBody: string): string {\n return `\n query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {\n sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {\n pageInfo { endCursor hasNextPage }\n edges {\n node {\n ${nodeBody}\n }\n }\n }\n }\n `;\n}\n\n/**\n * The customer-identity guest fields (name, contact, DOB, postal code, and the\n * free-text custom field responses). These are PII and are only selected when\n * `fullCustomerAccess` is set; the trailing group sits after the non-PII flags to keep\n * the maximal selection order stable for the webhook drift-guard.\n */\nconst GUEST_IDENTITY_PII_FIELDS = \"name country dateOfBirth email isGdpr\";\nconst GUEST_CONTACT_PII_FIELDS = `phone\n postalCode\n fieldResponses {\n id\n text\n fieldLocation {\n field {\n name\n }\n }\n }`;\n\n/**\n * Builds the guest selection. Without `fullCustomerAccess`, only the structural id and\n * the participation/opt-in flags are requested — the identity fields come back\n * absent (→ `null` in the converter).\n */\nexport function buildGuestFields(fullCustomerAccess: boolean): string {\n return `\n id\n ${fullCustomerAccess ? GUEST_IDENTITY_PII_FIELDS : \"\"}\n isParticipant\n optinSms\n optinMarketing\n ${fullCustomerAccess ? GUEST_CONTACT_PII_FIELDS : \"\"}\n`;\n}\n\n/** Builds the `bookingGuests` + `primaryGuest` guest sections. */\nexport function buildBookingGuestsFields(fullCustomerAccess: boolean): string {\n const guestFields = buildGuestFields(fullCustomerAccess);\n return `\n bookingGuests {\n ${guestFields}\n }\n primaryGuest {\n ${guestFields}\n }\n`;\n}\n\n/** The maximal (PII-included) guest sections — used by the webhook selection. */\nexport const bookingGuestsFields = buildBookingGuestsFields(true);\n\n/**\n * The primary-guest PII block on a booking — drives `customerName`/`email`/\n * `phone`. Selected only when `fullCustomerAccess` is set.\n */\nconst BOOKING_PRIMARY_GUEST_PII_FIELDS = `primaryGuest {\n name\n email\n phone\n optinMarketing\n optinSms\n isGdpr\n postalCode\n }`;\n\n/**\n * Custom question answers captured on the booking and per guest/ticket. These\n * routinely carry PII (address, DOB, captured location), so they are selected\n * only when `fullCustomerAccess` is set.\n */\nconst BOOKING_QUESTION_ANSWERS_PII_FIELDS = `questionAnswers {\n answer\n questionText\n questionLocationSnapshot {\n latitude\n longitude\n }\n }\n tickets {\n questionAnswers {\n answer\n questionText\n }\n }`;\n\n/**\n * Builds the booking selection. Without `fullCustomerAccess` the primary-guest block,\n * the customer booking-portal URL, and the custom question answers are omitted\n * entirely (they come back absent → `null`/empty in the converter). The\n * operator-facing deep link, notes, money, and structural fields always stay.\n */\nexport function buildBookingQueryFields(fullCustomerAccess: boolean): string {\n return `\n displayId\n id\n ${fullCustomerAccess ? BOOKING_PRIMARY_GUEST_PII_FIELDS : \"\"}\n activitySnapshot {\n type\n name\n id\n }\n ticketQuantities {\n quantity\n resourceOptionSnapshot {\n name\n id\n }\n }\n reservationStatus\n checkinStatus\n returnStatus\n fulfillmentStatusOverride {\n status\n }\n timeSnapshot {\n id\n legacyId\n }\n purchasedAt\n purchasedAtUtc\n startsAt\n startsAtUtc\n endsAt\n endsAtUtc\n availabilityTimeId\n ${fullCustomerAccess ? \"bookingPortalUrl\" : \"\"}\n operatorNotes\n operatorStatus\n value {\n total {\n formatted\n amount\n }\n }\n balance {\n total {\n amount\n formatted\n }\n }\n tips {\n price {\n amount\n formatted\n }\n }\n order {\n displayId\n id\n promoCodes {\n code\n }\n channelSnapshot {\n id\n name\n agent {\n name\n }\n }\n initialQuote {\n source {\n actor {\n app\n name\n }\n }\n }\n }\n ${fullCustomerAccess ? BOOKING_QUESTION_ANSWERS_PII_FIELDS : \"\"}\n resourcePoolAssignments {\n quantity\n resourcePool {\n name\n shortName\n resources {\n name\n }\n }\n resourceAssignments {\n resource {\n id\n name\n }\n }\n }\n`;\n}\n\n/** The maximal (PII-included) booking selection — used by the webhook selection. */\nexport const bookingQueryFields = buildBookingQueryFields(true);\n\nexport const PRICE_BREAKDOWN_FIELDS = `\n convenienceFee { amount formatted }\n deposit { amount formatted }\n discount { amount formatted }\n discountedPrice { amount formatted }\n fees { amount formatted }\n flatPartnerFee { amount formatted }\n price { amount formatted }\n retailPrice { amount formatted }\n taxes { amount formatted }\n tips { amount formatted }\n`;\n\n/**\n * Per-ticket price selection (list price + line total) injected into\n * `ticketQuantities` when the price breakdown is requested.\n */\nexport const TICKET_VALUE_FIELDS = `\n value {\n price { amount formatted }\n total { amount formatted }\n }\n`;\n\n/**\n * Builds the bookings listing query, optionally including guests and price\n * breakdown. When `fullCustomerAccess` is false (default `true` for the raw builder;\n * the service passes the resolved access option), customer PII fields are not\n * requested at all — see {@link buildBookingQueryFields}.\n */\nexport function buildBookingsListingQuery(\n includeGuests: boolean,\n includePriceBreakdown: boolean,\n fullCustomerAccess = true,\n): string {\n const guestsSection = includeGuests ? buildBookingGuestsFields(fullCustomerAccess) : \"\";\n // Inject the booking-level breakdown first: it anchors on the first `value {`,\n // which is the booking node's. The ticket-level `value` (added by the second\n // replace) must go in afterwards, or it would capture that anchor instead.\n const baseFields = buildBookingQueryFields(fullCustomerAccess);\n const fields = includePriceBreakdown\n ? baseFields\n .replace(\"value {\", `value { ${PRICE_BREAKDOWN_FIELDS}`)\n .replace(\"ticketQuantities {\", `ticketQuantities { ${TICKET_VALUE_FIELDS}`)\n : baseFields;\n\n return buildSalesQuery(`\n ... on Booking {\n ${fields}\n ${guestsSection}\n }\n `);\n}\n\n/**\n * Builds the query fetching the guests for a booking. Without `fullCustomerAccess` the\n * guest identity fields are omitted (only ids + participation/opt-in flags).\n */\nexport function buildBookingGuestsQuery(fullCustomerAccess: boolean): string {\n return buildSalesQuery(`\n ... on Booking {\n displayId\n id\n ${buildBookingGuestsFields(fullCustomerAccess)}\n }\n `);\n}\n\n/** Query fetching a booking's order payments + payment sources. */\nexport const BOOKING_PAYMENTS_ON_FILE_QUERY = buildSalesQuery(`\n order {\n payments {\n id\n paymentSource { id }\n appliedAt\n currentAmount { amount currency }\n refundableAmount { amount currency }\n }\n id\n displayId\n paymentSources { description type id }\n }\n ... on Booking {\n displayId\n id\n }\n`);\n\nexport const UPDATE_OPERATOR_NOTES_MUTATION = `\n mutation Account($input: UpdateOperatorNotesForBookingInput!) {\n updateOperatorNotesForBooking(input: $input) {\n booking { operatorNotes }\n }\n }\n`;\n\nexport const UPDATE_OPERATOR_STATUS_MUTATION = `\n mutation Account($input: UpdateOperatorStatusForBookingInput!) {\n updateOperatorStatusForBooking(input: $input) {\n booking { operatorStatus }\n }\n }\n`;\n\nexport interface UpdateOperatorStatusResponse {\n updateOperatorStatusForBooking?: {\n booking?: { operatorStatus?: string | null } | null;\n } | null;\n}\n\nexport const UPDATE_BOOKING_CHECKIN_MUTATION = `\n mutation Account($input: UpdateBookingCheckInInput!) {\n updateBookingCheckIn(input: $input) {\n booking { checkinStatus }\n }\n }\n`;\n\nexport const CANCEL_BOOKING_MUTATION = `\n mutation Account($input: CancelBookingInput!) {\n cancelBooking(input: $input) {\n booking { id displayId reservationStatus }\n }\n }\n`;\n\nexport const APPLY_PAYMENT_TO_ORDER_MUTATION = `\n mutation ApplyPaymentToOrder($input: ApplyPaymentToOrderInput!) {\n applyPaymentToOrder(input: $input) {\n transactionId\n errors { code detail value }\n }\n }\n`;\n\nexport const APPLY_REFUND_TO_ORDER_MUTATION = `\n mutation ApplyRefundToOrder($input: ApplyRefundToOrderInput!) {\n applyRefundToOrder(input: $input) {\n transactionId\n errors { code detail value }\n }\n }\n`;\n\nexport const CREATE_INVOICE_LINK_MUTATION = `\n mutation CreateInvoiceLink($input: CreateInvoiceLinkInput!) {\n createInvoiceLink(input: $input) {\n invoiceLink { status url }\n errors { code detail value __typename }\n }\n }\n`;\n\n/** A payment/refund/invoice error entry. */\nexport interface PaymentMutationError {\n code: string;\n detail: string;\n value: string | null;\n}\n\nexport interface ApplyPaymentToOrderResponse {\n applyPaymentToOrder: { transactionId: string | null; errors: PaymentMutationError[] | null };\n}\n\nexport interface ApplyRefundToOrderResponse {\n applyRefundToOrder: { transactionId: string | null; errors: PaymentMutationError[] | null };\n}\n\nexport interface CreateInvoiceLinkResponse {\n createInvoiceLink: {\n invoiceLink: { status: string; url: string } | null;\n errors: PaymentMutationError[] | null;\n };\n}\n\nexport const CREATE_QUOTE_FROM_ORDER_MUTATION = `\n mutation CreateQuoteFromOrder($input: CreateQuoteFromOrderInput!) {\n createQuoteFromOrder(input: $input) {\n errors { detail value code }\n quote {\n id\n saleQuotes { refid reservationStatus }\n }\n }\n }\n`;\n\nexport const UPDATE_QUOTE_V2_MUTATION = `\n mutation UpdateQuoteV2($input: UpdateQuoteV2Input!) {\n updateQuoteV2(input: $input) {\n errors { detail value code }\n quote { id }\n }\n }\n`;\n\nexport const AMEND_ORDER_MUTATION = `\n mutation AmendOrder($input: AmendOrderInput!) {\n amendOrder(input: $input) {\n errors { code detail value }\n order { id }\n }\n }\n`;\n\nexport interface CreateQuoteFromOrderResponse {\n createQuoteFromOrder: {\n errors: PaymentMutationError[] | null;\n quote: { id: string; saleQuotes: Array<{ refid: string; reservationStatus: string }> } | null;\n };\n}\n\nexport interface UpdateQuoteV2Response {\n updateQuoteV2: { errors: PaymentMutationError[] | null; quote: { id: string } | null };\n}\n\nexport interface AmendOrderResponse {\n amendOrder: { errors: PaymentMutationError[] | null; order: { id: string } | null };\n}\n\nexport const CREATE_QUOTE_V2_MUTATION = `\n mutation CreateQuoteV2($input: CreateQuoteV2Input!) {\n createQuoteV2(input: $input) {\n errors { detail value code }\n quote { id }\n }\n }\n`;\n\nexport const CREATE_ORDER_FROM_QUOTE_MUTATION = `\n mutation CreateOrderFromQuote($input: CreateOrderFromQuoteInput!) {\n createOrderFromQuote(input: $input) {\n errors { code detail value }\n order {\n id\n sales {\n id\n displayId\n ... on Booking {\n balance { total { amount currency formatted } }\n }\n }\n }\n }\n }\n`;\n\nexport interface CreateQuoteV2Response {\n createQuoteV2: { errors: PaymentMutationError[] | null; quote: { id: string } | null };\n}\n\nexport interface CreateOrderFromQuoteResponse {\n createOrderFromQuote: {\n errors: PaymentMutationError[] | null;\n order: {\n id: string;\n sales: Array<{\n id: string;\n displayId: string;\n balance?: { total: { amount: string; currency: string; formatted: string } } | null;\n }>;\n } | null;\n };\n}\n\n/** Builds the variables for the bookings/guests/payments sales queries. */\nexport function buildBookingsVariables(params: {\n pageSize: number;\n after: string | null;\n startDateTime?: string;\n endDateTime?: string;\n timeslotId?: string;\n searchBy?: BookingSearchBy;\n productId?: string;\n bookingId?: string;\n email?: string;\n searchString?: string;\n}): object {\n const filter: Record<string, unknown> = {};\n const bookingFilter: Record<string, unknown> = {};\n\n if (params.bookingId) {\n bookingFilter.ids = [normalizeBookingId(params.bookingId)];\n } else if (params.timeslotId) {\n bookingFilter.timeslotRefid = params.timeslotId;\n } else {\n if (params.searchBy === SEARCH_BY_ACTIVITY_DATE) {\n bookingFilter.overlapsRange = `[${params.startDateTime},${params.endDateTime}]`;\n } else if (params.searchBy === SEARCH_BY_PURCHASE_DATE) {\n filter.purchasedAtRangeUtc = `[${params.startDateTime},${params.endDateTime}]`;\n }\n if (params.productId) {\n bookingFilter.activityIds = [params.productId];\n }\n }\n\n if (params.email) {\n filter.primaryGuestEmail = params.email;\n }\n if (params.searchString && params.searchString.length > 0) {\n filter.searchString = params.searchString;\n }\n if (Object.keys(bookingFilter).length > 0) {\n filter.bookingFilter = bookingFilter;\n }\n\n return {\n first: params.pageSize,\n after: params.after,\n orderBy: { direction: \"ASC\", field: \"STARTS_AT\" },\n filter,\n };\n}\n\n// ---- Raw response shapes -------------------------------------------------\n\nexport interface BookingNode {\n displayId?: string;\n id?: string;\n // Base bookings query selects name/email/phone; when guests are requested the\n // full guest fields (id, fieldResponses, …) are merged in as well.\n primaryGuest?: BookingGuestNode | null;\n activitySnapshot?: { type?: string; name?: string; id?: string } | null;\n ticketQuantities?: Array<{\n quantity?: number;\n resourceOptionSnapshot?: { name?: string; id?: string } | null;\n // Present only when the price breakdown is requested (see TICKET_VALUE_FIELDS).\n value?: {\n price?: { amount?: string; formatted?: string };\n total?: { amount?: string; formatted?: string };\n };\n }>;\n reservationStatus?: string;\n checkinStatus?: string;\n returnStatus?: string;\n fulfillmentStatusOverride?: { status?: string } | null;\n timeSnapshot?: { id?: string; legacyId?: string | null } | null;\n purchasedAt?: string;\n purchasedAtUtc?: string;\n startsAt?: string;\n startsAtUtc?: string;\n endsAt?: string;\n endsAtUtc?: string;\n availabilityTimeId?: string;\n bookingPortalUrl?: string;\n operatorNotes?: string | null;\n operatorStatus?: string | null;\n value?: Record<string, { amount?: string; formatted?: string } | undefined> & {\n total?: { amount?: string; formatted?: string };\n };\n balance?: { total?: { amount?: string; formatted?: string } } | null;\n tips?: Array<{ price?: { amount?: string; formatted?: string } }>;\n order?: {\n id?: string;\n promoCodes?: Array<{ code: string }>;\n channelSnapshot?: { id?: string; name?: string; agent?: { name?: string } | null } | null;\n initialQuote?: {\n source?: { actor?: { app?: string; name?: string } | null } | null;\n } | null;\n } | null;\n questionAnswers?: Array<{\n answer: string;\n questionText: string;\n questionLocationSnapshot?: { latitude?: string; longitude?: string } | null;\n }>;\n tickets?: Array<{\n questionAnswers?: Array<{ answer: string; questionText: string }> | null;\n }> | null;\n resourcePoolAssignments?: Array<{\n quantity?: number;\n resourcePool?: { name?: string; shortName?: string } | null;\n resourceAssignments?: Array<{ resource?: { id?: string; name?: string } | null }>;\n }>;\n // Present when guests are requested.\n bookingGuests?: BookingGuestNode[];\n}\n\nexport interface BookingsResponse {\n sales: {\n pageInfo: { endCursor: string | null; hasNextPage: boolean };\n edges: Array<{ node: BookingNode }>;\n };\n}\n\nexport interface BookingGuestFieldResponse {\n id: string;\n text: string | null;\n fieldLocation?: { field?: { name?: string } | null } | null;\n}\n\nexport interface BookingGuestNode {\n id: string;\n name?: string | null;\n country?: string | null;\n dateOfBirth?: string | null;\n phone?: string | null;\n email?: string | null;\n isGdpr?: boolean;\n isParticipant?: boolean;\n optinSms?: boolean;\n optinMarketing?: boolean;\n postalCode?: string | null;\n fieldResponses?: BookingGuestFieldResponse[];\n}\n\nexport interface BookingGuestsResponse {\n sales: {\n edges: Array<{\n node: {\n displayId: string;\n id: string;\n bookingGuests?: BookingGuestNode[];\n primaryGuest?: BookingGuestNode | null;\n };\n }>;\n };\n}\n\nexport interface BookingPaymentsOnFileResponse {\n sales: {\n edges: Array<{\n node: {\n order?: {\n id?: string;\n displayId?: string;\n payments?: Array<{\n id: string;\n paymentSource?: { id?: string } | null;\n appliedAt: string;\n currentAmount: { amount: string; currency: string };\n refundableAmount: { amount: string; currency: string };\n }>;\n paymentSources?: Array<{ description: string; id: string; type: string }>;\n } | null;\n };\n }>;\n };\n}\n","/**\n * Pure functions mapping a raw booking node into the clean {@link Booking}\n * model. Ported from the connector's BookingConverter.\n */\nimport type {\n Booking,\n CustomQuestionAnswer,\n Guest,\n GuestMetadata,\n Price,\n ResourcePoolAssignment,\n Ticket,\n} from \"../../../models/peek/booking.js\";\nimport { normalizeBookingId } from \"./booking-queries.js\";\nimport type { BookingGuestNode, BookingNode } from \"./booking-queries.js\";\n\nconst UNKNOWN = \"unknown\";\n\nconst PEEK_PRO_DEEP_LINK_BASE = \"http://pro-app.peek.com/-/order\";\n\nconst SOURCE_SOURCE_MAP: Record<string, string> = {\n APP_REGISTRY: \"app\",\n BOOKING_IMPORTER_FUTURE: \"importer\",\n BOOKING_IMPORTER_HISTORIC: \"importer\",\n EXPEDIA: \"expedia\",\n GROUPON: \"groupon\",\n GYG: \"getyourguide\",\n HOOK: \"internal\",\n INTERNAL_TOOLS: \"internal\",\n IOS_PP: \"ios\",\n OCTO: \"octo\",\n PDC: \"peekcom\",\n PEEK_PLUS: \"peekcom\",\n PP: \"backend\",\n RWG: \"rwg\",\n SELF_SERVE: \"internal\",\n SYSTEM: \"internal\",\n VIATOR: \"viator\",\n WIDGET: \"website\",\n YELP: \"yelp\",\n};\n\nconst SOURCE_DESC_MAP: Record<string, string> = {\n APP_REGISTRY: \"App Store App\",\n BOOKING_IMPORTER_FUTURE: \"Booking Importer\",\n BOOKING_IMPORTER_HISTORIC: \"Booking Importer\",\n EXPEDIA: \"Expedia\",\n GROUPON: \"Groupon\",\n GYG: \"GetYourGuide\",\n HOOK: \"Internal\",\n INTERNAL_TOOLS: \"Internal\",\n IOS_PP: \"Peek Pro: iOS App\",\n OCTO: \"OCTO\",\n PDC: \"Peek.com\",\n PEEK_PLUS: \"Peek.com\",\n PP: \"Peek Pro: Backend\",\n RWG: \"Reserve with Google\",\n SELF_SERVE: \"Internal\",\n SYSTEM: \"Internal\",\n VIATOR: \"Viator\",\n WIDGET: \"Website Booking Flow\",\n YELP: \"Yelp\",\n};\n\n/** Converts a raw booking node into a {@link Booking}. */\nexport function fromBookingNode(\n node: BookingNode | null | undefined,\n includeGuests = false,\n includePriceBreakdown = false,\n): Booking {\n const data = node ?? {};\n const ticketQuantities = data.ticketQuantities ?? [];\n const app = data.order?.initialQuote?.source?.actor?.app ?? null;\n const sourceDetails = data.order?.initialQuote?.source?.actor?.name ?? null;\n\n const customQuestionAnswers: CustomQuestionAnswer[] = (data.questionAnswers ?? []).map(\n (answer) => {\n const base: CustomQuestionAnswer = {\n question: answer.questionText,\n answer: answer.answer,\n };\n const location = answer.questionLocationSnapshot;\n if (location && location.latitude && location.longitude) {\n base.latitude = location.latitude;\n base.longitude = location.longitude;\n }\n return base;\n },\n );\n\n const customGuestQuestionAnswers: CustomQuestionAnswer[] = Array.isArray(data.tickets)\n ? data.tickets.flatMap((ticket) =>\n Array.isArray(ticket?.questionAnswers)\n ? ticket.questionAnswers\n .filter((qa) => qa && qa.answer !== undefined && qa.questionText !== undefined)\n .map((qa) => ({ question: qa.questionText, answer: qa.answer }))\n : [],\n )\n : [];\n\n return {\n bookingId: data.id || \"\",\n displayId: data.displayId || \"\",\n\n source: sourceFromApp(app),\n sourceApp: app || UNKNOWN,\n sourceDescription: sourceDescriptionFromApp(app),\n sourceDetails,\n\n customerName: data.primaryGuest?.name || \"\",\n customerEmail: data.primaryGuest?.email || null,\n customerPhone: data.primaryGuest?.phone || null,\n\n productId: data.activitySnapshot?.id || UNKNOWN,\n productName: data.activitySnapshot?.name || UNKNOWN,\n isRentalProduct: data.activitySnapshot?.type === \"RENTAL\",\n\n timeslotId: data.timeSnapshot?.legacyId || null,\n totalTickets: ticketQuantity(ticketQuantities),\n ticketDescription: formatTickets(ticketQuantities),\n tickets: ticketsToTicketArray(ticketQuantities, includePriceBreakdown),\n\n isCanceled: data.reservationStatus === \"CANCELED\",\n isNoShow: data.fulfillmentStatusOverride?.status === \"NO_SHOW\",\n isCheckedIn: data.checkinStatus !== \"NONE\",\n isReturned: data.returnStatus !== \"NONE\",\n\n purchasedAt: data.purchasedAt || null,\n purchasedAtUtc: data.purchasedAtUtc || null,\n startsAt: data.startsAt || null,\n startsAtUtc: data.startsAtUtc || null,\n endsAt: data.endsAt || null,\n endsAtUtc: data.endsAtUtc || null,\n durationMin: durationInMin(data.startsAt || null, data.endsAt || null),\n availabilityTimeId: data.availabilityTimeId || null,\n\n portalUrl: data.bookingPortalUrl || null,\n notes: data.operatorNotes || \"\",\n customStatus: data.operatorStatus || null,\n\n valueDisplay: data.value?.total?.formatted || \"\",\n valueAmount: data.value?.total?.amount || \"\",\n\n outstandingBalanceAmount: data.balance?.total?.amount || \"\",\n outstandingBalanceDisplay: data.balance?.total?.formatted || \"\",\n promoCodes: data.order?.promoCodes?.map((promo) => promo.code) ?? [],\n tips: (data.tips ?? []).map((tip) => ({\n display: tip.price?.formatted || \"\",\n amount: tip.price?.amount || \"\",\n })),\n\n customQuestionAnswers,\n customGuestQuestionAnswers,\n\n resources: (data.resourcePoolAssignments ?? []).map((resource) => ({\n quantity: resource.quantity || 0,\n name: resource.resourcePool?.name || \"\",\n shortName: resource.resourcePool?.shortName || \"\",\n })),\n\n resourcePoolAssignments: mapResourcePoolAssignments(data.resourcePoolAssignments),\n\n resellerId: data.order?.channelSnapshot?.id || null,\n resellerName: resellerNameFromChannelSnapshot(data.order?.channelSnapshot),\n\n orderId: data.order?.id || \"\",\n peekProBookingDeepLink: buildPeekProBookingDeepLink(data.order?.id, data.id),\n\n convenienceFee: includePriceBreakdown ? mapPrice(data.value?.convenienceFee) : undefined,\n deposit: includePriceBreakdown ? mapPrice(data.value?.deposit) : undefined,\n discount: includePriceBreakdown ? mapPrice(data.value?.discount) : undefined,\n discountedPrice: includePriceBreakdown ? mapPrice(data.value?.discountedPrice) : undefined,\n fees: includePriceBreakdown ? mapPrice(data.value?.fees) : undefined,\n flatPartnerFee: includePriceBreakdown ? mapPrice(data.value?.flatPartnerFee) : undefined,\n price: includePriceBreakdown ? mapPrice(data.value?.price) : undefined,\n retailPrice: includePriceBreakdown ? mapPrice(data.value?.retailPrice) : undefined,\n taxes: includePriceBreakdown ? mapPrice(data.value?.taxes) : undefined,\n tipsBreakdown: includePriceBreakdown ? mapPrice(data.value?.tips) : undefined,\n\n guests: includeGuests ? convertGuests(data) : undefined,\n };\n}\n\n/** Merges a booking node's `bookingGuests` + `primaryGuest` into a guest list. */\nexport function convertGuests(data: BookingNode): Guest[] {\n const bookingGuestsNodes = Array.isArray(data.bookingGuests) ? data.bookingGuests : [];\n const primaryGuestNode = data.primaryGuest;\n const primaryId = primaryGuestNode?.id;\n\n const guests: Guest[] = [];\n for (const guestNode of bookingGuestsNodes) {\n guests.push(mapGuestNode(guestNode, primaryId ? guestNode.id === primaryId : false));\n }\n\n const hasPrimaryInGuests = primaryId\n ? bookingGuestsNodes.some((guest) => guest.id === primaryId)\n : false;\n if (!hasPrimaryInGuests && primaryGuestNode?.id) {\n guests.push(mapGuestNode(primaryGuestNode, true));\n }\n\n return guests;\n}\n\n/** Maps a single raw guest node into a {@link Guest}. */\nexport function mapGuestNode(guestNode: BookingGuestNode, isPrimary: boolean): Guest {\n const fieldResponses = Array.isArray(guestNode.fieldResponses) ? guestNode.fieldResponses : [];\n const metadata: GuestMetadata[] = fieldResponses.map((response) => ({\n id: response.id,\n name: response.fieldLocation?.field?.name ?? \"\",\n value: response.text ?? \"\",\n }));\n\n return {\n id: guestNode.id,\n name: guestNode.name ?? null,\n country: guestNode.country ?? null,\n dateOfBirth: guestNode.dateOfBirth ? new Date(guestNode.dateOfBirth) : null,\n phone: guestNode.phone ?? null,\n email: guestNode.email ?? null,\n isGdpr: Boolean(guestNode.isGdpr),\n isParticipant: Boolean(guestNode.isParticipant),\n isPrimary,\n optinSms: Boolean(guestNode.optinSms),\n optinMarketing: Boolean(guestNode.optinMarketing),\n postalCode: guestNode.postalCode ?? null,\n metadata,\n };\n}\n\n/**\n * Builds the Peek Pro app deep link from an order id and booking id. Both ids\n * are normalized (lowercased, `-` → `_`); returns `\"\"` when either is absent.\n */\nfunction buildPeekProBookingDeepLink(\n orderId: string | null | undefined,\n bookingId: string | null | undefined,\n): string {\n if (!orderId || !bookingId) return \"\";\n return `${PEEK_PRO_DEEP_LINK_BASE}%2F${normalizeBookingId(orderId)}%3FsaleId=${normalizeBookingId(bookingId)}`;\n}\n\nfunction sourceFromApp(app: string | null): string {\n if (!app) return UNKNOWN;\n return SOURCE_SOURCE_MAP[app] ?? UNKNOWN;\n}\n\nfunction sourceDescriptionFromApp(app: string | null): string {\n if (!app) return UNKNOWN;\n return SOURCE_DESC_MAP[app] ?? UNKNOWN;\n}\n\nfunction resellerNameFromChannelSnapshot(\n channelSnapshot: { name?: string; agent?: { name?: string } | null } | null | undefined,\n): string | null {\n if (!channelSnapshot) return null;\n let out = channelSnapshot.name ?? \"\";\n if (channelSnapshot.agent?.name) {\n out += \" - \" + channelSnapshot.agent.name;\n }\n return out;\n}\n\nfunction ticketsToTicketArray(\n ticketQuantities: BookingNode[\"ticketQuantities\"],\n includePriceBreakdown: boolean,\n): Ticket[] {\n if (!ticketQuantities || ticketQuantities.length === 0) return [];\n return ticketQuantities.map((ticket) => ({\n name: ticket.resourceOptionSnapshot?.name || \"Unknown\",\n quantity: ticket.quantity || 0,\n ticketId: ticket.resourceOptionSnapshot?.id || \"unknown\",\n listPrice: includePriceBreakdown ? mapPrice(ticket.value?.price) : undefined,\n totalValue: includePriceBreakdown ? mapPrice(ticket.value?.total) : undefined,\n }));\n}\n\nfunction durationInMin(startsAt: string | null, endsAt: string | null): number {\n if (!startsAt || !endsAt) return 0;\n const duration = new Date(endsAt).getTime() - new Date(startsAt).getTime();\n return Math.floor(duration / 1000 / 60);\n}\n\nfunction ticketQuantity(ticketQuantities: BookingNode[\"ticketQuantities\"]): number {\n if (!ticketQuantities || ticketQuantities.length === 0) return 0;\n return ticketQuantities.reduce((acc, ticket) => acc + (ticket.quantity || 0), 0);\n}\n\nfunction formatTickets(ticketQuantities: BookingNode[\"ticketQuantities\"]): string {\n if (!ticketQuantities || ticketQuantities.length === 0) return \"\";\n return ticketQuantities\n .map((ticket) => `${ticket.quantity || 0}x ${ticket.resourceOptionSnapshot?.name || \"Unknown\"}`)\n .join(\", \");\n}\n\nfunction mapResourcePoolAssignments(\n poolAssignments: BookingNode[\"resourcePoolAssignments\"],\n): ResourcePoolAssignment[] {\n if (!poolAssignments || poolAssignments.length === 0) return [];\n return poolAssignments.flatMap((pool) =>\n (pool.resourceAssignments ?? []).map((assignment) => ({\n id: assignment.resource?.id || \"\",\n name: assignment.resource?.name || \"\",\n })),\n );\n}\n\nfunction mapPrice(\n priceData: { amount?: string; formatted?: string } | undefined,\n): Price | undefined {\n if (!priceData || (!priceData.amount && !priceData.formatted)) {\n return undefined;\n }\n return {\n amount: priceData.amount || \"0\",\n display: priceData.formatted || \"\",\n };\n}\n","/**\n * Resolves the dedicated guests query into a merged guest list (booking guests\n * plus the primary guest when not already present).\n */\nimport type { Guest } from \"../../../models/peek/booking.js\";\nimport { mapGuestNode } from \"./booking-converter.js\";\nimport type { BookingGuestsResponse } from \"./booking-queries.js\";\n\n/** Maps a booking-guests response into a {@link Guest} list. */\nexport function fromBookingGuestsResponse(\n response: BookingGuestsResponse | undefined,\n): Guest[] {\n const firstEdge = (response?.sales?.edges ?? [])[0];\n if (!firstEdge) {\n return [];\n }\n\n const bookingNode = firstEdge.node;\n const primaryGuestNode = bookingNode.primaryGuest;\n const bookingGuestsNodes = Array.isArray(bookingNode.bookingGuests)\n ? bookingNode.bookingGuests\n : [];\n const primaryId = primaryGuestNode?.id;\n\n const guests: Guest[] = [];\n for (const guestNode of bookingGuestsNodes) {\n guests.push(mapGuestNode(guestNode, primaryId ? guestNode.id === primaryId : false));\n }\n\n const hasPrimaryInGuests = primaryId\n ? bookingGuestsNodes.some((guest) => guest.id === primaryId)\n : false;\n if (!hasPrimaryInGuests && primaryGuestNode) {\n guests.push(mapGuestNode(primaryGuestNode, true));\n }\n\n return guests;\n}\n","/**\n * Pure functions mapping a raw booking-metadata node into the clean\n * {@link MetaData} list, plus the integrator filter. I/O-free.\n */\nimport type {\n MetaData,\n MetaDataBarcodeType,\n MetaDataDurationUnit,\n MetaDataValue,\n MetaDataVolumeUnit,\n MetaDataWeightUnit,\n SetMetaDataResult,\n} from \"../../../models/peek/booking-metadata.js\";\nimport type {\n BookingMetaDataNode,\n MetaDataFieldResponseNode,\n MetaDataValueNode,\n UpsertBookingFieldResponsesResponse,\n} from \"./metadata-queries.js\";\n\n/** The `__typename` of the successful upsert result variant. */\nconst UPSERT_SUCCESS_TYPENAME = \"UpsertBookingFieldResponsesSuccess\";\n\n/** Converts a raw booking-metadata node into a list of clean {@link MetaData}. */\nexport function fromBookingMetaDataNode(\n node: BookingMetaDataNode | null | undefined,\n): MetaData[] {\n return (node?.fieldResponses ?? []).map(fromFieldResponseNode);\n}\n\n/** Maps a single raw field-response node into a {@link MetaData}. */\nfunction fromFieldResponseNode(response: MetaDataFieldResponseNode): MetaData {\n const field = response.fieldLocation?.field;\n const prompt = response.fieldLocation?.prompt;\n return {\n id: field?.id || \"\",\n name: field?.name || \"\",\n slug: field?.slug || \"\",\n type: field?.type || \"\",\n prompt: prompt?.label ?? null,\n promptHint: prompt?.hint ?? null,\n isRequired: Boolean(prompt?.isRequired),\n refid: response.refid || \"\",\n value: fromValueNode(response.value),\n };\n}\n\n/**\n * Maps the raw union value node to a typed {@link MetaDataValue}, discriminating\n * on `__typename`. Returns `null` when absent or of an unrecognized (future)\n * variant — unknown types are never coerced.\n */\nfunction fromValueNode(value: MetaDataValueNode | null | undefined): MetaDataValue | null {\n if (!value || !value.__typename) return null;\n switch (value.__typename) {\n case \"AgeFieldResponseValue\": {\n const age = value.age ?? 0;\n return { kind: \"age\", age, displayValue: String(age) };\n }\n case \"AttachmentFieldResponseValue\": {\n const attachmentUrl = value.attachmentUrl ?? \"\";\n const name = value.name ?? null;\n return {\n kind: \"attachment\",\n attachmentUrl,\n mime: value.mime ?? null,\n name,\n size: value.size ?? null,\n displayValue: name || attachmentUrl,\n };\n }\n case \"BarcodeFieldResponseValue\": {\n const barcodeValue = value.barcodeValue ?? \"\";\n return {\n kind: \"barcode\",\n barcodeType: (value.barcodeType as MetaDataBarcodeType | null) ?? null,\n barcodeValue,\n displayValue: barcodeValue,\n };\n }\n case \"BooleanFieldResponseValue\": {\n const bool = Boolean(value.boolean);\n return { kind: \"boolean\", boolean: bool, displayValue: yesNo(bool) };\n }\n case \"CheckboxFieldResponseValue\": {\n const isChecked = Boolean(value.isChecked);\n return { kind: \"checkbox\", isChecked, displayValue: yesNo(isChecked) };\n }\n case \"CurrencyFieldResponseValue\": {\n const currency = value.currency ?? \"\";\n return { kind: \"currency\", currency, displayValue: currency };\n }\n case \"DateFieldResponseValue\": {\n const date = value.date ?? \"\";\n return { kind: \"date\", date, displayValue: date };\n }\n case \"DecimalFieldResponseValue\": {\n const decimal = value.decimal ?? null;\n return { kind: \"decimal\", decimal, displayValue: decimal ?? \"\" };\n }\n case \"DurationFieldResponseValue\": {\n const amount = value.duration?.amount ?? 0;\n const unit = (value.duration?.unit as MetaDataDurationUnit | null) ?? null;\n return { kind: \"duration\", amount, unit, displayValue: amountUnit(amount, unit) };\n }\n case \"EmailFieldResponseValue\": {\n const email = value.email ?? null;\n return { kind: \"email\", email, displayValue: email ?? \"\" };\n }\n case \"GuestFieldResponseValue\": {\n const name = value.name ?? null;\n return {\n kind: \"guest\",\n name,\n email: value.email ?? null,\n dateOfBirth: value.dateOfBirth ?? null,\n notes: value.notes ?? null,\n waiverSigned: value.waiverSigned ?? null,\n displayValue: name ?? \"\",\n };\n }\n case \"HtmlFieldResponseValue\": {\n const html = value.html ?? \"\";\n return { kind: \"html\", html, displayValue: escapeHtml(html) };\n }\n case \"ImageUrlFieldResponseValue\": {\n const imageUrl = value.imageUrl ?? \"\";\n return { kind: \"imageUrl\", imageUrl, displayValue: imageUrl };\n }\n case \"IntegerFieldResponseValue\": {\n const integer = value.integer ?? 0;\n return { kind: \"integer\", integer, displayValue: String(integer) };\n }\n case \"LocationFieldResponseValue\": {\n const streetAddress = value.streetAddress ?? null;\n const locality = value.locality ?? null;\n const region = value.region ?? null;\n const postalCode = value.postalCode ?? null;\n const country = value.country ?? null;\n return {\n kind: \"location\",\n country,\n county: value.county ?? null,\n locality,\n postalCode,\n region,\n streetAddress,\n displayValue: [streetAddress, locality, region, postalCode, country]\n .filter((part) => part)\n .join(\", \"),\n };\n }\n case \"LongTextFieldResponseValue\": {\n const longText = value.longText ?? \"\";\n return { kind: \"longText\", longText, displayValue: longText };\n }\n case \"MetaFieldResponseValue\": {\n const meta = value.meta ?? null;\n return { kind: \"meta\", meta, displayValue: meta == null ? \"\" : JSON.stringify(meta) };\n }\n case \"PercentFieldResponseValue\": {\n const percent = value.percent ?? null;\n return { kind: \"percent\", percent, displayValue: percent == null ? \"\" : `${percent}%` };\n }\n case \"PhoneFieldResponseValue\": {\n const phone = value.phone ?? \"\";\n return { kind: \"phone\", phone, displayValue: phone };\n }\n case \"ShortTextFieldResponseValue\": {\n const shortText = value.shortText ?? \"\";\n return { kind: \"shortText\", shortText, displayValue: shortText };\n }\n case \"TimeFieldResponseValue\": {\n const time = value.time ?? \"\";\n return { kind: \"time\", time, displayValue: time };\n }\n case \"UrlFieldResponseValue\": {\n const url = value.url ?? null;\n return { kind: \"url\", url, displayValue: url ?? \"\" };\n }\n case \"VolumeFieldResponseValue\": {\n const amount = value.volume?.amount ?? \"0\";\n const unit = (value.volume?.unit as MetaDataVolumeUnit | null) ?? null;\n return { kind: \"volume\", amount, unit, displayValue: amountUnit(amount, unit) };\n }\n case \"WeightFieldResponseValue\": {\n const amount = value.weight?.amount ?? \"0\";\n const unit = (value.weight?.unit as MetaDataWeightUnit | null) ?? null;\n return { kind: \"weight\", amount, unit, displayValue: amountUnit(amount, unit) };\n }\n default:\n return null;\n }\n}\n\n/** `\"Yes\"`/`\"No\"` rendering for boolean-like values. */\nfunction yesNo(value: boolean): string {\n return value ? \"Yes\" : \"No\";\n}\n\n/** `\"<amount> <unit>\"` (unit lowercased), or just the amount when no unit. */\nfunction amountUnit(amount: number | string, unit: string | null): string {\n return unit ? `${amount} ${unit.toLowerCase()}` : String(amount);\n}\n\n/** Escapes the five HTML-significant characters so a string is safe to render as text. */\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/**\n * Maps the `upsertBookingFieldResponses` result union into a clean\n * {@link SetMetaDataResult}. `success` is true only for the success variant; the\n * message and (when present) echoed booking id are carried across, falling back\n * to the requested `bookingId`.\n */\nexport function toSetMetaDataResult(\n node: UpsertBookingFieldResponsesResponse[\"upsertBookingFieldResponses\"],\n bookingId: string,\n): SetMetaDataResult {\n return {\n success: node?.__typename === UPSERT_SUCCESS_TYPENAME,\n bookingId: node?.bookingId || bookingId,\n message: node?.message || \"\",\n };\n}\n\n/**\n * Keeps only the metadata whose `slug` starts with `integrator:<integrator>:`\n * (case-sensitive exact prefix), stripping that prefix off the returned `slug`\n * (e.g. with `integrator = \"bob\"`, `integrator:bob:booking_url` → `booking_url`).\n */\nexport function filterMetaDataByIntegrator(\n metaData: MetaData[],\n integrator: string,\n): MetaData[] {\n const prefix = `integrator:${integrator}:`;\n return metaData\n .filter((entry) => entry.slug.startsWith(prefix))\n .map((entry) => ({ ...entry, slug: entry.slug.slice(prefix.length) }));\n}\n","/**\n * Raw Peek GraphQL selection, query builder, and response shapes for a booking's\n * custom-field metadata (`fieldResponses`). Internal.\n *\n * The query is a variant of the single-booking read: it reuses the shared\n * `sales(...)` envelope ({@link buildSalesQuery}) and the shared variable builder\n * ({@link buildBookingsVariables}), selecting only the field-response tree.\n */\nimport { buildSalesQuery } from \"./booking-queries.js\";\n\n/**\n * The `GuestFieldResponseValue` selection. The customer-identity fields\n * (`name`/`email`/`dateOfBirth`) are PII — selected only when\n * `fullCustomerAccess` is set, so without it the gateway never returns them\n * (→ `null` in the converter). `notes`/`waiverSigned` always stay.\n */\nconst GUEST_VALUE_PII_FIELDS = \"dateOfBirth\\n email\\n name\\n \";\n\nfunction buildGuestValueFields(fullCustomerAccess: boolean): string {\n return `... on GuestFieldResponseValue {\n ${fullCustomerAccess ? GUEST_VALUE_PII_FIELDS : \"\"}notes\n waiverSigned\n }`;\n}\n\n/**\n * Builds the `value { __typename … }` union selection. `__typename` is selected\n * so the converter can discriminate the variant cleanly. The only part that\n * varies is the PII-gated guest fragment.\n */\nfunction buildMetaDataValueSelection(fullCustomerAccess: boolean): string {\n return `value {\n __typename\n ... on AgeFieldResponseValue { age }\n ... on AttachmentFieldResponseValue { attachmentUrl mime name size }\n ... on BarcodeFieldResponseValue { barcodeType barcodeValue }\n ... on BooleanFieldResponseValue { boolean }\n ... on CheckboxFieldResponseValue { isChecked }\n ... on CurrencyFieldResponseValue { currency }\n ... on DateFieldResponseValue { date }\n ... on DecimalFieldResponseValue { decimal }\n ... on DurationFieldResponseValue { duration { amount unit } }\n ... on EmailFieldResponseValue { email }\n ${buildGuestValueFields(fullCustomerAccess)}\n ... on HtmlFieldResponseValue { html }\n ... on ImageUrlFieldResponseValue { imageUrl }\n ... on IntegerFieldResponseValue { integer }\n ... on LocationFieldResponseValue { country county locality postalCode region streetAddress }\n ... on LongTextFieldResponseValue { longText }\n ... on MetaFieldResponseValue { meta }\n ... on PercentFieldResponseValue { percent }\n ... on PhoneFieldResponseValue { phone }\n ... on ShortTextFieldResponseValue { shortText }\n ... on TimeFieldResponseValue { time }\n ... on UrlFieldResponseValue { url }\n ... on VolumeFieldResponseValue { volume { amount unit } }\n ... on WeightFieldResponseValue { weight { amount unit } }\n }`;\n}\n\n/**\n * Builds the booking-metadata query. Without `fullCustomerAccess` the guest\n * value's identity fields (name/email/DOB) are not requested at all.\n */\nexport function buildBookingMetaDataQuery(fullCustomerAccess: boolean): string {\n return buildSalesQuery(`\n ... on Booking {\n displayId\n id\n fieldResponses {\n fieldLocation {\n field { id name slug type }\n prompt { label hint isRequired }\n }\n refid\n ${buildMetaDataValueSelection(fullCustomerAccess)}\n }\n }\n `);\n}\n\n/**\n * Upserts a booking's custom-field responses, scoped to an integrator. The\n * result is a union — success or one of two typed errors — discriminated by\n * `__typename`.\n */\nexport const UPSERT_BOOKING_FIELD_RESPONSES_MUTATION = `\n mutation UpsertBookingFieldResponses($input: UpsertBookingFieldResponsesInput!) {\n upsertBookingFieldResponses(input: $input) {\n __typename\n ... on UpsertBookingFieldResponsesSuccess { bookingId message }\n ... on BookingNotFoundError { message bookingId }\n ... on GenericError { message }\n }\n }\n`;\n\nexport interface UpsertBookingFieldResponsesResponse {\n upsertBookingFieldResponses?: {\n __typename?: string;\n bookingId?: string | null;\n message?: string | null;\n } | null;\n}\n\n// ---- Raw response shapes -------------------------------------------------\n\n/** The raw union value node — one branch populated per `__typename`. */\nexport interface MetaDataValueNode {\n __typename?: string;\n age?: number | null;\n attachmentUrl?: string | null;\n mime?: string | null;\n name?: string | null;\n size?: number | null;\n barcodeType?: string | null;\n barcodeValue?: string | null;\n boolean?: boolean | null;\n isChecked?: boolean | null;\n currency?: string | null;\n date?: string | null;\n decimal?: string | null;\n duration?: { amount?: number | null; unit?: string | null } | null;\n email?: string | null;\n dateOfBirth?: string | null;\n notes?: string | null;\n waiverSigned?: boolean | null;\n html?: string | null;\n imageUrl?: string | null;\n integer?: number | null;\n country?: string | null;\n county?: string | null;\n locality?: string | null;\n postalCode?: string | null;\n region?: string | null;\n streetAddress?: string | null;\n longText?: string | null;\n meta?: unknown;\n percent?: string | null;\n phone?: string | null;\n shortText?: string | null;\n time?: string | null;\n url?: string | null;\n volume?: { amount?: string | null; unit?: string | null } | null;\n weight?: { amount?: string | null; unit?: string | null } | null;\n}\n\nexport interface MetaDataFieldResponseNode {\n fieldLocation?: {\n field?: { id?: string; name?: string; slug?: string; type?: string } | null;\n prompt?: { label?: string | null; hint?: string | null; isRequired?: boolean } | null;\n } | null;\n refid?: string;\n value?: MetaDataValueNode | null;\n}\n\nexport interface BookingMetaDataNode {\n displayId?: string;\n id?: string;\n fieldResponses?: MetaDataFieldResponseNode[] | null;\n}\n\nexport interface BookingMetaDataResponse {\n sales: {\n pageInfo?: { endCursor: string | null; hasNextPage: boolean };\n edges: Array<{ node: BookingMetaDataNode }>;\n };\n}\n","/**\n * Aggregates a booking's raw order payments + payment sources into the clean\n * {@link BookingPaymentsOnFile} model, grouping payments under their source.\n */\nimport type {\n BookingPaymentsOnFile,\n Payment,\n PaymentSource,\n} from \"../../../models/peek/booking-payment.js\";\nimport type { BookingPaymentsOnFileResponse } from \"./booking-queries.js\";\n\n/**\n * Maps a payments-on-file response into the aggregated result, or null when the\n * booking is not found.\n */\nexport function fromPaymentsOnFileResponse(\n response: BookingPaymentsOnFileResponse | undefined,\n bookingId: string,\n): BookingPaymentsOnFile | null {\n const firstEdge = (response?.sales?.edges ?? [])[0];\n if (!firstEdge) {\n return null;\n }\n\n const order = firstEdge.node.order;\n const orderId = order?.id ?? \"\";\n const rawPaymentSources = order?.paymentSources ?? [];\n const rawPayments = order?.payments ?? [];\n\n const paymentsBySourceId = new Map<string, Payment[]>();\n for (const payment of rawPayments) {\n const sourceId = payment.paymentSource?.id;\n if (!sourceId) continue;\n const mapped: Payment = {\n id: payment.id,\n paidAt: dateOnly(payment.appliedAt),\n currentAmount: payment.currentAmount,\n refundableAmount: payment.refundableAmount,\n };\n const existing = paymentsBySourceId.get(sourceId);\n if (existing) {\n existing.push(mapped);\n } else {\n paymentsBySourceId.set(sourceId, [mapped]);\n }\n }\n\n const paymentsOnFile: PaymentSource[] = rawPaymentSources.map((source) => {\n const payments = paymentsBySourceId.get(source.id);\n return {\n description: source.description,\n id: source.id,\n type: source.type,\n ...(payments ? { payments } : {}),\n };\n });\n\n return { bookingId, orderId, paymentsOnFile };\n}\n\nfunction dateOnly(iso: string): string {\n /* v8 ignore next -- split always yields at least one element */\n return iso.split(\"T\")[0] ?? iso;\n}\n","/**\n * Raw Peek GraphQL query, variables, and response shapes for listing the\n * add-ons (items + item options) attached to a single booking. Internal.\n *\n * The `SALES_ADDONS_QUERY` runs the `sales` query filtered by a booking's\n * display id (`filter.searchString`) and returns every item on the booking\n * together with its item options, refids, and reservation statuses — the\n * detail needed both to surface add-ons and to build add/cancel mutations.\n */\n\n/** Reservation status for a live (confirmed) item or option. */\nexport const RESERVATION_STATUS_CONFIRMED = \"CONFIRMED\";\n/** Reservation status marking an item or option as canceled. */\nexport const ADDON_OPTION_STATUS_CANCELED = \"CANCELED\";\n\n/** Page size for the sales add-ons query (a single booking, so one page). */\nconst SALES_ADDONS_PAGE_SIZE = 100;\n\n/**\n * GraphQL query fetching the items and item options for a single booking\n * matched by `filter.searchString` (the booking display id).\n */\nexport const SALES_ADDONS_QUERY = `\n query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {\n sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {\n pageInfo { endCursor hasNextPage }\n edges {\n node {\n order { id displayId }\n ... on Booking {\n displayId\n id\n refid\n reservationStatus\n items {\n id\n refid\n value { total { amount currency formatted } }\n reservationStatus\n options {\n refid\n reservationStatus\n price { amount currency formatted }\n itemOptionSnapshot { id name }\n itemSnapshot { id name }\n }\n }\n }\n }\n }\n }\n }\n`;\n\n/** Variables for {@link SALES_ADDONS_QUERY}. */\nexport interface SalesAddonsVariables {\n first: number;\n after: string | null;\n orderBy: { direction: string; field: string };\n filter: { searchString: string };\n}\n\n/** Builds the variables for the sales add-ons query from a booking display id. */\nexport function buildSalesAddonsVariables(searchString: string): SalesAddonsVariables {\n return {\n first: SALES_ADDONS_PAGE_SIZE,\n after: null,\n orderBy: { direction: \"DESC\", field: \"STARTS_AT\" },\n filter: { searchString },\n };\n}\n\n/** Raw money shape returned by the `sales` add-ons query. */\nexport interface AddonGqlPrice {\n amount: string;\n currency: string;\n formatted: string;\n}\n\nexport interface SalesAddonItemOptionNode {\n refid: string;\n reservationStatus: string;\n price: AddonGqlPrice | null;\n itemOptionSnapshot: { id: string; name: string } | null;\n itemSnapshot: { id: string; name: string } | null;\n}\n\nexport interface SalesAddonItemNode {\n id: string;\n refid: string;\n value: { total: AddonGqlPrice | null } | null;\n reservationStatus: string;\n options: SalesAddonItemOptionNode[] | null;\n}\n\nexport interface SalesAddonBookingNode {\n id: string;\n displayId: string;\n refid: string;\n reservationStatus: string;\n order: { id: string; displayId: string } | null;\n items: SalesAddonItemNode[] | null;\n}\n\nexport interface SalesAddonsResponse {\n sales: {\n pageInfo: { endCursor: string | null; hasNextPage: boolean };\n edges: Array<{ node: SalesAddonBookingNode }>;\n };\n}\n","/**\n * Pure mappers between the raw `sales` add-ons response and the add-on models.\n *\n * `parseSaleNode` produces the internal, detail-rich {@link AddonItem} model\n * (refids + reservation statuses) that the service uses to build add/cancel\n * mutations. `toBookingAddon` collapses one internal item into the clean,\n * public {@link BookingAddon}. The internal model is intentionally not exported\n * from the package's public entry point.\n */\nimport type { BookingAddon, BookingAddonOption } from \"../../../models/peek/booking-addon.js\";\nimport {\n ADDON_OPTION_STATUS_CANCELED,\n type AddonGqlPrice,\n type SalesAddonBookingNode,\n} from \"./addon-queries.js\";\n\nconst ERROR_INCONSISTENT_ADDON_ITEM_ID =\n \"Add-on group contains options with mismatched item IDs\";\n\n/** One add-on option on a booking, with the refids/statuses needed to mutate it. */\nexport interface AddonItemOption {\n itemId: string;\n optionId: string;\n itemName: string;\n optionName: string;\n optionRefid: string;\n optionReservationStatus: string;\n itemReservationStatus: string;\n itemRefid: string;\n}\n\n/** One add-on item on a booking (internal; grouped by add-on item). */\nexport interface AddonItem {\n bookingId: string;\n displayId: string;\n orderId: string;\n total: AddonGqlPrice | null;\n bookingQuoteRefid: string;\n bookingQuoteReservationStatus: string;\n addonItemOptions: AddonItemOption[];\n}\n\n/**\n * Converts a single booking node into the internal {@link AddonItem}[] model.\n * Booking-level identifiers (bookingId, displayId, orderId) are repeated on\n * each item for convenience.\n */\nexport function parseSaleNode(node: SalesAddonBookingNode): AddonItem[] {\n const bookingId = node.id || \"\";\n const displayId = node.displayId || \"\";\n const orderId = node.order?.id || \"\";\n const bookingQuoteRefid = node.refid || \"\";\n const bookingQuoteReservationStatus = node.reservationStatus || \"\";\n const items = Array.isArray(node.items) ? node.items : [];\n\n return items.map((item) => {\n const options = Array.isArray(item.options) ? item.options : [];\n const addonItemOptions: AddonItemOption[] = options.map((opt) => ({\n itemId: opt.itemSnapshot?.id || \"\",\n optionId: opt.itemOptionSnapshot?.id || \"\",\n itemName: opt.itemSnapshot?.name || \"\",\n optionName: opt.itemOptionSnapshot?.name || \"\",\n optionRefid: opt.refid || \"\",\n optionReservationStatus: opt.reservationStatus || \"\",\n itemReservationStatus: item.reservationStatus || \"\",\n itemRefid: item.refid || \"\",\n }));\n\n return {\n bookingId,\n displayId,\n orderId,\n total: item.value?.total ?? null,\n bookingQuoteRefid,\n bookingQuoteReservationStatus,\n addonItemOptions,\n };\n });\n}\n\n/**\n * Collapses one internal {@link AddonItem} (already grouped by add-on item id)\n * into a clean public {@link BookingAddon}. All of the item's options must\n * share the same item id (a data-integrity invariant); a mismatch throws.\n * Canceled options are dropped and the rest are combined by option id with a\n * quantity count. Returns `null` when no live options remain, so the caller\n * can omit the add-on entirely.\n */\nexport function toBookingAddon(item: AddonItem): BookingAddon | null {\n const options = item.addonItemOptions || [];\n if (options.length === 0) {\n return null;\n }\n\n const addonId = options[0]!.itemId;\n const addonName = options[0]!.itemName;\n\n if (options.some((opt) => opt.itemId !== addonId)) {\n throw new Error(ERROR_INCONSISTENT_ADDON_ITEM_ID);\n }\n\n const grouped = new Map<string, BookingAddonOption>();\n options\n .filter((opt) => opt.optionReservationStatus !== ADDON_OPTION_STATUS_CANCELED)\n .forEach((opt) => {\n const existing = grouped.get(opt.optionId);\n if (existing) {\n existing.quantity += 1;\n } else {\n grouped.set(opt.optionId, {\n addonOptionId: opt.optionId,\n addonOptionName: opt.optionName,\n quantity: 1,\n });\n }\n });\n\n const addonOptions = Array.from(grouped.values());\n if (addonOptions.length === 0) {\n return null;\n }\n\n return { addonId, addonName, total: item.total, addonOptions };\n}\n","/**\n * Pure resolution of caller-supplied custom-question answers against an\n * activity's actual custom questions. No I/O — the questions are fetched by the\n * service and passed in, so this whole module is unit-testable without a client\n * (and, deliberately, without minting the answer `refid`s, which the service\n * adds afterward).\n *\n * Each {@link CustomQuestionAnswerInput} is matched to exactly one question and\n * its `value` validated/resolved by question type into the shape the quote\n * mutation expects. Any ambiguity or mismatch throws before the booking is made.\n */\nimport type {\n CustomQuestion,\n CustomQuestionOption,\n} from \"../../../models/peek/custom-question.js\";\nimport type { CustomQuestionAnswerInput } from \"../../../models/peek/booking.js\";\n\n/** Peek question-type values this resolver knows how to answer. */\nexport const QUESTION_TYPE_CHECK_BOX = \"CHECK_BOX\";\nexport const QUESTION_TYPE_TEXT = \"TEXT\";\nexport const QUESTION_TYPE_SELECT_ONE = \"SELECT_ONE\";\nexport const QUESTION_TYPE_LOCATION = \"LOCATION\";\n\n/** A `cq_…` question id vs. free-text; a `cqao_…` option id vs. an option label. */\nconst QUESTION_ID_REGEX = /^cq_[a-z0-9]+$/;\nconst OPTION_ID_REGEX = /^cqao_[a-z0-9]+$/;\n\n/**\n * Whether `idOrText` is a custom-question id (`cq_…`) rather than free-text.\n * The service uses this to decide whether it must fetch the activity's questions:\n * a by-name answer always needs the list to resolve, a by-id answer does not when\n * unknown ids are being accepted (see `acceptAllIds`).\n */\nexport function isCustomQuestionId(idOrText: string): boolean {\n return QUESTION_ID_REGEX.test(idOrText);\n}\n\n/** Checkbox truthiness — `value` (lowercased) must be one of the valid set. */\nconst CHECKBOX_TRUE = new Set([\"yes\", \"true\"]);\nconst CHECKBOX_VALID = new Set([\"yes\", \"no\", \"true\", \"false\"]);\n\n/** Display text the gateway expects in `questionAnswerText` for a checkbox. */\nconst CHECKBOX_TEXT_TRUE = \"Yes\";\nconst CHECKBOX_TEXT_FALSE = \"No\";\n\n// ─── Error messages ──────────────────────────────────────────────────────────\nconst errUnknownQuestionId = (v: string): string =>\n `No custom question matches id \"${v}\" for this activity`;\nconst errNoTextMatch = (v: string): string =>\n `No custom question matches text \"${v}\" for this activity`;\nconst errAmbiguousText = (v: string): string =>\n `Custom question text \"${v}\" matches more than one question`;\nconst errPerGuestUnsupported = (id: string): string =>\n `Per-guest custom question \"${id}\" is not yet supported`;\nconst errUnsupportedType = (type: string, id: string): string =>\n `Custom question \"${id}\" has unsupported type \"${type}\"`;\nconst errInvalidCheckbox = (v: string, id: string): string =>\n `Checkbox answer for question \"${id}\" must be yes/no/true/false, got \"${v}\"`;\nconst errUnknownOptionId = (v: string, id: string): string =>\n `No option matches id \"${v}\" for question \"${id}\"`;\nconst errNoOptionMatch = (v: string, id: string): string =>\n `No option matches \"${v}\" for question \"${id}\"`;\nconst errAmbiguousOption = (v: string, id: string): string =>\n `Option \"${v}\" matches more than one option for question \"${id}\"`;\nconst errMissingRequired = (text: string, id: string): string =>\n `Custom question \"${text}\" (${id}) is required but was not answered`;\n\n/**\n * A resolved answer, minus the `refid` the service mints. `questionAnswerText`\n * is always set (the gateway requires it): the raw value for text, the exact\n * option label for select-one/location, and `\"Yes\"`/`\"No\"` for a checkbox. The\n * type-specific field (`questionAnswerOptionId` / `isChecked`) is set in\n * addition, per the question's type.\n */\nexport interface ResolvedCustomAnswer {\n questionId: string;\n questionAnswerText: string;\n questionAnswerOptionId?: string;\n isChecked?: boolean;\n}\n\n/** Lowercases and strips non-alphanumerics for lenient matching. */\nfunction normalize(value: string): string {\n return value.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n}\n\n/**\n * Finds the one question an input targets, by id or by lenient text match.\n * Returns `null` (rather than throwing) for an unknown `cq_…` id when\n * `acceptAllIds` is set — the caller then accepts the id blindly as a text\n * answer. A by-name input is always resolved against the list (there is no id to\n * accept), so `acceptAllIds` never relaxes an unmatched/ambiguous text match.\n */\nfunction resolveQuestion(\n idOrText: string,\n questions: CustomQuestion[],\n acceptAllIds: boolean,\n): CustomQuestion | null {\n if (QUESTION_ID_REGEX.test(idOrText)) {\n const byId = questions.find((question) => question.id === idOrText);\n if (!byId) {\n if (acceptAllIds) return null;\n throw new Error(errUnknownQuestionId(idOrText));\n }\n return byId;\n }\n const target = normalize(idOrText);\n const matches = questions.filter(\n (question) => normalize(question.questionText) === target,\n );\n if (matches.length === 0) throw new Error(errNoTextMatch(idOrText));\n if (matches.length > 1) throw new Error(errAmbiguousText(idOrText));\n return matches[0]!;\n}\n\n/** Finds the one option a value targets, by id or by lenient label match. */\nfunction resolveOption(\n value: string,\n question: CustomQuestion,\n): CustomQuestionOption {\n if (OPTION_ID_REGEX.test(value)) {\n const byId = question.options.find((option) => option.id === value);\n if (!byId) throw new Error(errUnknownOptionId(value, question.id));\n return byId;\n }\n const target = normalize(value);\n const matches = question.options.filter(\n (option) => normalize(option.value) === target,\n );\n if (matches.length === 0) throw new Error(errNoOptionMatch(value, question.id));\n if (matches.length > 1) throw new Error(errAmbiguousOption(value, question.id));\n return matches[0]!;\n}\n\n/** Resolves a single answer input against the matched question's type. */\nfunction resolveOne(\n answer: CustomQuestionAnswerInput,\n questions: CustomQuestion[],\n acceptAllIds: boolean,\n): ResolvedCustomAnswer {\n const question = resolveQuestion(answer.questionIdOrText, questions, acceptAllIds);\n // An unknown id accepted blindly (acceptAllIds): there is no question\n // definition to type-check against, so pass the id and value through as a\n // plain text answer.\n if (!question) {\n return { questionId: answer.questionIdOrText, questionAnswerText: answer.value };\n }\n // Per-guest answers require per-guest wiring the quote payload does not carry\n // yet — reject rather than silently drop the distinction.\n if (question.perGuest) {\n throw new Error(errPerGuestUnsupported(question.id));\n }\n switch (question.questionType) {\n case QUESTION_TYPE_CHECK_BOX: {\n const normalized = answer.value.trim().toLowerCase();\n if (!CHECKBOX_VALID.has(normalized)) {\n throw new Error(errInvalidCheckbox(answer.value, question.id));\n }\n const isChecked = CHECKBOX_TRUE.has(normalized);\n // The gateway requires questionAnswerText even for a checkbox.\n return {\n questionId: question.id,\n isChecked,\n questionAnswerText: isChecked ? CHECKBOX_TEXT_TRUE : CHECKBOX_TEXT_FALSE,\n };\n }\n case QUESTION_TYPE_TEXT:\n return { questionId: question.id, questionAnswerText: answer.value };\n case QUESTION_TYPE_SELECT_ONE:\n case QUESTION_TYPE_LOCATION: {\n // Select the option only — Peek applies each location option's configured\n // lat/long. questionAnswerText must be the option's exact current label.\n const option = resolveOption(answer.value, question);\n return {\n questionId: question.id,\n questionAnswerOptionId: option.id,\n questionAnswerText: option.value,\n };\n }\n default:\n throw new Error(errUnsupportedType(question.questionType, question.id));\n }\n}\n\n/** Options controlling how the answer set as a whole is validated. */\nexport interface ResolveCustomQuestionOptions {\n /**\n * When `true`, every question the activity marks `isRequired` must have an\n * answer — resolution throws for the first required question left unanswered.\n * Per-guest questions are excluded (they cannot be answered here anyway).\n */\n requireRequired?: boolean;\n /**\n * When `true`, an answer identified by a `cq_…` id that is **not** in the\n * activity's question list is accepted as-is (passed through as a text answer)\n * instead of throwing. By-name answers are unaffected — they still must match a\n * question, since there is no id to accept. Default: `false`.\n */\n acceptAllIds?: boolean;\n}\n\n/**\n * Resolves every caller-supplied answer against the activity's custom questions,\n * throwing on the first unmatched question, ambiguous match, or invalid value.\n * The returned objects carry no `refid` — the service adds one per answer.\n *\n * With `requireRequired`, the resolved set is additionally checked for coverage:\n * any required, non-per-guest question with no answer throws. This check runs\n * even when `answers` is empty, so an activity with unanswered required\n * questions fails rather than booking without them.\n *\n * With `acceptAllIds`, an answer whose `cq_…` id is not in `questions` is\n * accepted as a plain text answer instead of throwing.\n */\nexport function resolveCustomQuestionAnswers(\n answers: CustomQuestionAnswerInput[],\n questions: CustomQuestion[],\n options?: ResolveCustomQuestionOptions,\n): ResolvedCustomAnswer[] {\n const acceptAllIds = options?.acceptAllIds ?? false;\n const resolved = answers.map((answer) => resolveOne(answer, questions, acceptAllIds));\n if (options?.requireRequired) {\n assertRequiredAnswered(resolved, questions);\n }\n return resolved;\n}\n\n/** Throws for the first required, non-per-guest question left unanswered. */\nfunction assertRequiredAnswered(\n resolved: ResolvedCustomAnswer[],\n questions: CustomQuestion[],\n): void {\n const answered = new Set(resolved.map((answer) => answer.questionId));\n for (const question of questions) {\n if (question.isRequired && !question.perGuest && !answered.has(question.id)) {\n throw new Error(errMissingRequired(question.questionText, question.id));\n }\n }\n}\n","/**\n * Pure helpers for splitting a booking's total list price across its tickets.\n * I/O-free; validation throws on a malformed amount.\n */\n\nconst ERROR_LIST_PRICE_INVALID =\n \"listPrice must be a positive number string, e.g. '100', '1,000', or '10.00'\";\n\n/**\n * Parses a list-price string into a positive integer number of cents. Commas\n * (thousands separators) are stripped; the value is rounded to the nearest cent.\n * Throws when the input is not a positive number.\n */\nfunction parseListPriceToCents(listPrice: string): number {\n if (typeof listPrice !== \"string\") {\n throw new Error(ERROR_LIST_PRICE_INVALID);\n }\n const cleaned = listPrice.replace(/,/g, \"\").trim();\n if (!/^\\d+(\\.\\d+)?$/.test(cleaned)) {\n throw new Error(ERROR_LIST_PRICE_INVALID);\n }\n const cents = Math.round(Number(cleaned) * 100);\n if (!Number.isFinite(cents) || cents <= 0) {\n throw new Error(ERROR_LIST_PRICE_INVALID);\n }\n return cents;\n}\n\n/** Formats an integer number of cents as a 2-decimal string (e.g. 334 → `\"3.34\"`). */\nfunction centsToAmount(cents: number): string {\n return (cents / 100).toFixed(2);\n}\n\n/**\n * Splits a total list price evenly across `ticketCount` tickets, as 2-decimal\n * amount strings. Each of the first `n-1` tickets gets `floor(total / n)`; the\n * last ticket gets the remainder, so the amounts always sum back to the exact\n * total. For example `\"10.00\"` over 3 tickets → `[\"3.33\", \"3.33\", \"3.34\"]`.\n *\n * `ticketCount` must be a positive integer (the caller guarantees at least one\n * ticket). Throws when `listPrice` is not a positive number string.\n */\nexport function distributeListPrice(listPrice: string, ticketCount: number): string[] {\n const totalCents = parseListPriceToCents(listPrice);\n const perTicketCents = Math.floor(totalCents / ticketCount);\n const amounts: string[] = [];\n for (let i = 0; i < ticketCount - 1; i += 1) {\n amounts.push(centsToAmount(perTicketCents));\n }\n amounts.push(centsToAmount(totalCents - perTicketCents * (ticketCount - 1)));\n return amounts;\n}\n","/**\n * Booking operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getBookingService}.\n */\nimport { randomUUID } from \"node:crypto\";\n\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type { ProductService } from \"../products/product-service.js\";\nimport {\n resolveAccessOptions,\n type AccessOptions,\n} from \"../../../access-options.js\";\nimport { PiiAccessDisabledError } from \"../../../errors.js\";\nimport type {\n Booking,\n BookingReadOptions,\n BookingTimeRangeSearch,\n CreateBookingInput,\n CreatedBooking,\n Guest,\n NoteMode,\n} from \"../../../models/peek/booking.js\";\nimport type {\n MetaData,\n SetMetaDataAttachmentInput,\n SetMetaDataGuestInput,\n SetMetaDataResult,\n} from \"../../../models/peek/booking-metadata.js\";\nimport { ADD_ON_PRODUCT_TYPE } from \"../../../models/peek/product.js\";\nimport type {\n BookingPaymentsOnFile,\n InvoiceLinkResult,\n MakePaymentInput,\n MakePaymentResult,\n RefundInput,\n RefundResult,\n} from \"../../../models/peek/booking-payment.js\";\nimport type {\n BookingAddons,\n BookingAddonsMutationResult,\n} from \"../../../models/peek/booking-addon.js\";\nimport { fromBookingNode } from \"./booking-converter.js\";\nimport { fromBookingGuestsResponse } from \"./booking-guest-converter.js\";\nimport {\n filterMetaDataByIntegrator,\n fromBookingMetaDataNode,\n toSetMetaDataResult,\n} from \"./metadata-converter.js\";\nimport {\n buildBookingMetaDataQuery,\n UPSERT_BOOKING_FIELD_RESPONSES_MUTATION,\n type BookingMetaDataResponse,\n type UpsertBookingFieldResponsesResponse,\n} from \"./metadata-queries.js\";\nimport { fromPaymentsOnFileResponse } from \"./payments-on-file-converter.js\";\nimport {\n type AddonItem,\n parseSaleNode,\n toBookingAddon,\n} from \"./addon-converter.js\";\nimport {\n isCustomQuestionId,\n resolveCustomQuestionAnswers,\n} from \"./custom-question-answer.js\";\nimport { distributeListPrice } from \"./list-price.js\";\nimport {\n ADDON_OPTION_STATUS_CANCELED,\n RESERVATION_STATUS_CONFIRMED,\n SALES_ADDONS_QUERY,\n buildSalesAddonsVariables,\n type SalesAddonsResponse,\n} from \"./addon-queries.js\";\nimport {\n AMEND_ORDER_MUTATION,\n APPLY_PAYMENT_TO_ORDER_MUTATION,\n APPLY_REFUND_TO_ORDER_MUTATION,\n BOOKING_PAYMENTS_ON_FILE_QUERY,\n CANCEL_BOOKING_MUTATION,\n CREATE_INVOICE_LINK_MUTATION,\n CREATE_ORDER_FROM_QUOTE_MUTATION,\n CREATE_QUOTE_FROM_ORDER_MUTATION,\n CREATE_QUOTE_V2_MUTATION,\n SEARCH_BY_PURCHASE_DATE,\n UPDATE_BOOKING_CHECKIN_MUTATION,\n UPDATE_OPERATOR_NOTES_MUTATION,\n UPDATE_OPERATOR_STATUS_MUTATION,\n UPDATE_QUOTE_V2_MUTATION,\n buildBookingGuestsQuery,\n buildBookingsListingQuery,\n buildBookingsVariables,\n normalizeBookingId,\n type AmendOrderResponse,\n type ApplyPaymentToOrderResponse,\n type ApplyRefundToOrderResponse,\n type BookingGuestsResponse,\n type BookingPaymentsOnFileResponse,\n type BookingsResponse,\n type CreateInvoiceLinkResponse,\n type CreateOrderFromQuoteResponse,\n type CreateQuoteFromOrderResponse,\n type CreateQuoteV2Response,\n type UpdateOperatorStatusResponse,\n type UpdateQuoteV2Response,\n} from \"./booking-queries.js\";\n\n/** Default page size for cursor-paginated bookings. */\nconst DEFAULT_PAGE_SIZE = 50;\n/** Default note used when cancelling without an explicit reason. */\nconst DEFAULT_CANCEL_NOTE = \"Canceled\";\n/** Default customer message attached to a charge. */\nconst DEFAULT_CUSTOMER_MESSAGE = \"Charge initiated via API\";\n/** Currency used when the activity's own currency can't be resolved. */\nconst DEFAULT_CURRENCY = \"USD\";\n\n// Booking/order ids come in two forms: a lowercase db id with `_`\n// (`b_abc123` / `o_abc123`) and an uppercase display id with `-`\n// (`B-ABC123` / `O-ABC123`). Bookings are prefixed `b`, orders `o`.\nconst BOOKING_DB_ID_REGEX = /^b_[a-z0-9]+$/;\nconst BOOKING_DISPLAY_ID_REGEX = /^B-[A-Z0-9]+$/;\nconst ORDER_DB_ID_REGEX = /^o_[a-z0-9]+$/;\nconst ORDER_DISPLAY_ID_REGEX = /^O-[A-Z0-9]+$/;\nconst PAYMENT_SOURCE_PREFIX = \"ps_\";\nconst PAYMENT_ID_PREFIX = \"pmt_\";\nconst ALLOWED_PAYMENT_SOURCE_IDS = [\"cash/cash\", \"custom/other\", \"custom/voucher\"];\nconst CURRENCY_CODE_REGEX = /^[A-Z]{3}$/;\n\n/** Result of cancelling a booking. */\nexport interface CancelBookingResult {\n id: string;\n displayId: string;\n reservationStatus: string;\n}\n\ninterface CancelBookingResponse {\n cancelBooking?: { booking?: CancelBookingResult | null } | null;\n}\n\n/** Tuning options for a {@link BookingService}. */\nexport interface BookingServiceOptions {\n /** Page size for cursor pagination. Default: 50. */\n pageSize?: number;\n /** Cross-cutting access options (PII exposure). Default: PII off. */\n accessOptions?: AccessOptions;\n /**\n * Integrator id used to scope `getMetaData` results — only fields whose slug\n * starts with `integrator:<integrator>:` are returned. Defaults to `\"\"` (set\n * by the access service to the install's issuer).\n */\n integrator?: string;\n}\n\n/** Dependencies the {@link BookingService} composes for add-on resolution. */\nexport interface BookingServiceDeps {\n productService: ProductService;\n}\n\n/** Input for adding or removing an add-on on a booking. */\nexport interface AddAddonInput {\n /** The add-on (item option) id. */\n addonOptionId?: string;\n /**\n * @deprecated Use `addonOptionId`. Still accepted for backwards\n * compatibility; treated as `addonOptionId` when `addonOptionId` is absent.\n */\n addonId?: string;\n /** Quantity as a positive integer string. */\n quantity: string;\n}\n\nconst ERROR_ADDON_OPTION_ID_REQUIRED = \"addonOptionId is required\";\nconst ERROR_QUANTITY_INVALID = \"quantity must be a positive integer string\";\nconst ERROR_INVALID_BOOKING_ID =\n \"bookingId is required and must be a valid booking id, e.g. 'b_abc123' or 'B-ABC123'\";\nconst ERROR_INVALID_ORDER_ID =\n \"orderId is required and must be a valid order id, e.g. 'o_abc123' or 'O-ABC123'\";\nconst ERROR_CUSTOM_STATUS_REQUIRED = \"customStatus is required and must be a non-empty string\";\nconst ERROR_GUESTS_REQUIRED = \"at least one guest is required\";\nconst ERROR_ATTACHMENTS_REQUIRED = \"at least one attachment is required\";\n\n// The fixed `fieldName` values the metadata upsert accepts — one per setter.\nconst META_FIELD_GUEST = \"guest\";\nconst META_FIELD_ATTACHMENT = \"attachment\";\nconst META_FIELD_MANIFEST_URL = \"manifest_url\";\nconst META_FIELD_RESERVATION_ID = \"reservation_id\";\nconst META_FIELD_BOOKING_STATUS = \"booking_status\";\nconst META_FIELD_ASSIGNED_PRODUCT = \"assigned_product\";\nconst META_FIELD_ASSIGNED_EMPLOYEE = \"assigned_employee\";\nconst META_FIELD_INSURANCE_PURCHASED = \"insurance_purchased\";\nconst ERROR_BOOKING_NOT_FOUND = \"Booking not found\";\nconst ERROR_MULTIPLE_BOOKINGS_FOUND =\n \"Expected exactly one booking for the provided bookingId\";\nconst ERROR_NO_ADDON_OPTION_TO_REMOVE =\n \"No confirmed add-on option matching addonOptionId was found on the booking\";\nconst ERROR_CREATE_QUOTE_FAILED = \"Failed to create quote from order\";\nconst ERROR_UPDATE_QUOTE_FAILED = \"Failed to update quote with add-on\";\nconst ERROR_AMEND_ORDER_FAILED = \"Failed to amend order with add-on\";\n\nexport class BookingService {\n private readonly pageSize: number;\n /** Whether customer PII is requested and payment operations are allowed. */\n private readonly fullCustomerAccess: boolean;\n /** Integrator id scoping `getMetaData` results. */\n private readonly integrator: string;\n\n constructor(\n private readonly client: GraphQLClient,\n private readonly deps: BookingServiceDeps,\n options: BookingServiceOptions = {},\n ) {\n this.pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;\n this.fullCustomerAccess = resolveAccessOptions(options.accessOptions).fullCustomerAccess;\n this.integrator = options.integrator ?? \"\";\n }\n\n /**\n * Throws a {@link PiiAccessDisabledError} for `operation` when this service was\n * created without `fullCustomerAccess` — used to gate payment and booking-modification\n * operations that touch customer financial data.\n */\n private assertPiiEnabled(operation: string): void {\n if (!this.fullCustomerAccess) {\n throw new PiiAccessDisabledError(operation);\n }\n }\n\n /**\n * Returns a single booking by id, or null when not found. The `bookingId` is\n * normalized internally (lowercased, `-` → `_`), so `B-ABC123` and `b_abc123`\n * resolve to the same booking.\n *\n * @example\n * ```ts\n * const bookings = peek.getBookingService();\n * const booking = await bookings.getById(\"b_abc123\", {\n * includeGuests: true,\n * includePriceBreakdown: true,\n * });\n * if (booking) console.log(booking.displayId, booking.outstandingBalanceAmount);\n * ```\n */\n async getById(\n bookingId: string,\n options: BookingReadOptions = {},\n ): Promise<Booking | null> {\n assertBookingId(bookingId);\n const includeGuests = options.includeGuests ?? false;\n const includePriceBreakdown = options.includePriceBreakdown ?? false;\n\n const body: GraphQLBody<BookingsResponse> =\n await this.client.request<BookingsResponse>(\n SALES_ENDPOINT,\n buildBookingsListingQuery(includeGuests, includePriceBreakdown, this.fullCustomerAccess),\n buildBookingsVariables({\n pageSize: this.pageSize,\n after: null,\n bookingId: normalizeBookingId(bookingId),\n }),\n );\n\n const firstEdge = (body.data?.sales?.edges ?? [])[0];\n if (!firstEdge) {\n return null;\n }\n return fromBookingNode(firstEdge.node, includeGuests, includePriceBreakdown);\n }\n\n /** Returns all bookings matching a time range (paginated). */\n async searchByTimeRange(input: BookingTimeRangeSearch): Promise<Booking[]> {\n const includeGuests = input.includeGuests ?? false;\n const includePriceBreakdown = input.includePriceBreakdown ?? false;\n\n return this.fetchPaginated(\n buildBookingsListingQuery(includeGuests, includePriceBreakdown, this.fullCustomerAccess),\n {\n startDateTime: input.start,\n endDateTime: input.end,\n searchBy: input.searchBy ?? SEARCH_BY_PURCHASE_DATE,\n productId: input.productId,\n email: input.email,\n searchString: input.searchString,\n },\n includeGuests,\n includePriceBreakdown,\n );\n }\n\n /** Returns all bookings on a timeslot (paginated). */\n async searchByTimeslot(\n timeslotId: string,\n options: BookingReadOptions = {},\n ): Promise<Booking[]> {\n const includeGuests = options.includeGuests ?? false;\n const includePriceBreakdown = options.includePriceBreakdown ?? false;\n\n return this.fetchPaginated(\n buildBookingsListingQuery(includeGuests, includePriceBreakdown, this.fullCustomerAccess),\n { timeslotId },\n includeGuests,\n includePriceBreakdown,\n );\n }\n\n /** Returns the guests on a booking (primary guest included). */\n async getGuests(bookingId: string): Promise<Guest[]> {\n assertBookingId(bookingId);\n const body: GraphQLBody<BookingGuestsResponse> =\n await this.client.request<BookingGuestsResponse>(\n SALES_ENDPOINT,\n buildBookingGuestsQuery(this.fullCustomerAccess),\n buildBookingsVariables({\n pageSize: this.pageSize,\n after: null,\n bookingId: normalizeBookingId(bookingId),\n }),\n );\n return fromBookingGuestsResponse(body.data);\n }\n\n /**\n * Returns a booking's custom-field metadata (its `fieldResponses`), scoped to\n * this service's integrator. Only fields whose slug starts with\n * `integrator:<integrator>:` are returned, and that prefix is stripped from\n * each returned `slug`. Returns `[]` when the booking is not found or has no\n * matching fields.\n *\n * @example\n * ```ts\n * const meta = await peek.getBookingService().getMetaData(\"b_abc123\");\n * for (const field of meta) {\n * if (field.value?.kind === \"url\") console.log(field.slug, field.value.url);\n * }\n * ```\n */\n async getMetaData(bookingId: string): Promise<MetaData[]> {\n assertBookingId(bookingId);\n const body: GraphQLBody<BookingMetaDataResponse> =\n await this.client.request<BookingMetaDataResponse>(\n SALES_ENDPOINT,\n buildBookingMetaDataQuery(this.fullCustomerAccess),\n buildBookingsVariables({\n pageSize: this.pageSize,\n after: null,\n bookingId: normalizeBookingId(bookingId),\n }),\n );\n\n const firstEdge = (body.data?.sales?.edges ?? [])[0];\n if (!firstEdge) {\n return [];\n }\n return filterMetaDataByIntegrator(fromBookingMetaDataNode(firstEdge.node), this.integrator);\n }\n\n /**\n * Sets the booking's `guest` metadata field. Each guest requires a `name` and\n * `email`; `dateOfBirth`/`waiverSigned`/`notes` are optional.\n */\n async setMetaDataGuest(\n bookingId: string,\n guests: SetMetaDataGuestInput[],\n ): Promise<SetMetaDataResult> {\n if (!Array.isArray(guests) || guests.length === 0) {\n throw new Error(ERROR_GUESTS_REQUIRED);\n }\n const built = guests.map((guest) => {\n assertNonEmptyString(guest?.name, \"guest name\");\n assertNonEmptyString(guest?.email, \"guest email\");\n const out: Record<string, unknown> = { name: guest.name, email: guest.email };\n if (guest.dateOfBirth !== undefined) out.dateOfBirth = guest.dateOfBirth;\n if (guest.waiverSigned !== undefined) out.waiverSigned = guest.waiverSigned;\n if (guest.notes !== undefined) out.notes = guest.notes;\n return out;\n });\n return this.upsertFieldResponse(bookingId, { fieldName: META_FIELD_GUEST, guests: built });\n }\n\n /**\n * Sets the booking's `attachment` metadata field. Each attachment requires a\n * `name` and `attachmentUrl`.\n */\n async setMetaDataAttachment(\n bookingId: string,\n attachments: SetMetaDataAttachmentInput[],\n ): Promise<SetMetaDataResult> {\n if (!Array.isArray(attachments) || attachments.length === 0) {\n throw new Error(ERROR_ATTACHMENTS_REQUIRED);\n }\n const built = attachments.map((attachment) => {\n assertNonEmptyString(attachment?.name, \"attachment name\");\n assertNonEmptyString(attachment?.attachmentUrl, \"attachment attachmentUrl\");\n return { name: attachment.name, attachmentUrl: attachment.attachmentUrl };\n });\n return this.upsertFieldResponse(bookingId, {\n fieldName: META_FIELD_ATTACHMENT,\n attachments: built,\n });\n }\n\n /** Sets the booking's `manifest_url` metadata field. */\n async setMetaDataManifestUrl(bookingId: string, url: string): Promise<SetMetaDataResult> {\n assertNonEmptyString(url, \"url\");\n return this.upsertFieldResponse(bookingId, { fieldName: META_FIELD_MANIFEST_URL, url });\n }\n\n /** Sets the booking's `reservation_id` metadata field. */\n async setMetaDataReservationId(\n bookingId: string,\n reservationId: string,\n ): Promise<SetMetaDataResult> {\n return this.setShortTextField(bookingId, META_FIELD_RESERVATION_ID, reservationId, \"reservationId\");\n }\n\n /** Sets the booking's `booking_status` metadata field. */\n async setMetaDataBookingStatus(bookingId: string, status: string): Promise<SetMetaDataResult> {\n return this.setShortTextField(bookingId, META_FIELD_BOOKING_STATUS, status, \"status\");\n }\n\n /** Sets the booking's `assigned_product` metadata field. */\n async setMetaDataAssignedProduct(\n bookingId: string,\n productName: string,\n ): Promise<SetMetaDataResult> {\n return this.setShortTextField(bookingId, META_FIELD_ASSIGNED_PRODUCT, productName, \"productName\");\n }\n\n /** Sets the booking's `assigned_employee` metadata field. */\n async setMetaDataAssignedEmployee(\n bookingId: string,\n employeeName: string,\n ): Promise<SetMetaDataResult> {\n return this.setShortTextField(bookingId, META_FIELD_ASSIGNED_EMPLOYEE, employeeName, \"employeeName\");\n }\n\n /** Sets the booking's `insurance_purchased` metadata field. */\n async setMetaDataInsurancePurchased(\n bookingId: string,\n insurancePurchased: boolean,\n ): Promise<SetMetaDataResult> {\n if (typeof insurancePurchased !== \"boolean\") {\n throw new Error(\"insurancePurchased is required and must be a boolean\");\n }\n return this.upsertFieldResponse(bookingId, {\n fieldName: META_FIELD_INSURANCE_PURCHASED,\n boolean: insurancePurchased,\n });\n }\n\n /** Validates a non-empty `shortText` value and upserts it under `fieldName`. */\n private setShortTextField(\n bookingId: string,\n fieldName: string,\n value: string,\n argName: string,\n ): Promise<SetMetaDataResult> {\n assertNonEmptyString(value, argName);\n return this.upsertFieldResponse(bookingId, { fieldName, shortText: value });\n }\n\n /**\n * Validates the booking id and upserts a single field response (scoped to this\n * service's integrator), mapping the result union into a {@link SetMetaDataResult}.\n */\n private async upsertFieldResponse(\n bookingId: string,\n fieldResponse: Record<string, unknown>,\n ): Promise<SetMetaDataResult> {\n assertBookingId(bookingId);\n const normalized = normalizeBookingId(bookingId);\n const body: GraphQLBody<UpsertBookingFieldResponsesResponse> =\n await this.client.request<UpsertBookingFieldResponsesResponse>(\n SALES_ENDPOINT,\n UPSERT_BOOKING_FIELD_RESPONSES_MUTATION,\n {\n input: {\n bookingId: normalized,\n integrator: this.integrator,\n fieldResponses: [fieldResponse],\n },\n },\n );\n return toSetMetaDataResult(body.data?.upsertBookingFieldResponses, normalized);\n }\n\n /** Returns the payments on file for a booking, or null when not found. */\n async getPaymentsOnFile(bookingId: string): Promise<BookingPaymentsOnFile | null> {\n this.assertPiiEnabled(\"getPaymentsOnFile\");\n assertBookingId(bookingId);\n const normalized = normalizeBookingId(bookingId);\n const body: GraphQLBody<BookingPaymentsOnFileResponse> =\n await this.client.request<BookingPaymentsOnFileResponse>(\n SALES_ENDPOINT,\n BOOKING_PAYMENTS_ON_FILE_QUERY,\n buildBookingsVariables({ pageSize: this.pageSize, after: null, bookingId: normalized }),\n );\n return fromPaymentsOnFileResponse(body.data, normalized);\n }\n\n /**\n * Appends to (or overwrites) a booking's operator notes. Returns the updated\n * booking, or null when the booking is not found.\n */\n async appendNote(\n bookingId: string,\n note: string,\n mode: NoteMode = \"append\",\n ): Promise<Booking | null> {\n assertBookingId(bookingId);\n const normalized = normalizeBookingId(bookingId);\n const booking = await this.getById(normalized);\n if (!booking) {\n return null;\n }\n\n const newNote =\n mode === \"overwrite\" || !booking.notes ? note : `${booking.notes}\\n${note}`;\n\n await this.client.request(SALES_ENDPOINT, UPDATE_OPERATOR_NOTES_MUTATION, {\n input: { id: normalized, operatorNotes: newNote },\n });\n\n booking.notes = newNote;\n return booking;\n }\n\n /**\n * Sets a booking's check-in status. Returns the refreshed booking, or null\n * when not found.\n */\n async setCheckinStatus(\n bookingId: string,\n checkedIn: boolean,\n ): Promise<Booking | null> {\n assertBookingId(bookingId);\n const normalized = normalizeBookingId(bookingId);\n const checkedInAt = checkedIn ? new Date().toISOString() : null;\n\n await this.client.request(SALES_ENDPOINT, UPDATE_BOOKING_CHECKIN_MUTATION, {\n input: { id: normalized, checkedInAt },\n });\n\n return this.getById(normalized);\n }\n\n /**\n * Sets a booking's operator-facing custom status. Returns `true` when the\n * gateway confirms the stored `operatorStatus` equals the requested\n * `customStatus`, `false` otherwise.\n *\n * @example\n * ```ts\n * const ok = await peek.getBookingService().updateCustomStatus(\"b_abc123\", \"Awaiting deposit\");\n * ```\n *\n * @throws {Error} when `bookingId` is not a valid booking id (`b_…`/`B-…`) or\n * when `customStatus` is not a non-empty string.\n */\n async updateCustomStatus(bookingId: string, customStatus: string): Promise<boolean> {\n assertBookingId(bookingId);\n assertCustomStatus(customStatus);\n const normalized = normalizeBookingId(bookingId);\n\n const body: GraphQLBody<UpdateOperatorStatusResponse> =\n await this.client.request<UpdateOperatorStatusResponse>(\n SALES_ENDPOINT,\n UPDATE_OPERATOR_STATUS_MUTATION,\n { input: { id: normalized, operatorStatus: customStatus } },\n );\n\n return (\n body.data?.updateOperatorStatusForBooking?.booking?.operatorStatus === customStatus\n );\n }\n\n /** Cancels a booking and returns its id/displayId/status. */\n async cancel(\n bookingId: string,\n notes: string = DEFAULT_CANCEL_NOTE,\n ): Promise<CancelBookingResult> {\n assertBookingId(bookingId);\n const body: GraphQLBody<CancelBookingResponse> =\n await this.client.request<CancelBookingResponse>(\n SALES_ENDPOINT,\n CANCEL_BOOKING_MUTATION,\n { input: { bookingId: normalizeBookingId(bookingId), notes } },\n );\n\n const booking = body.data?.cancelBooking?.booking;\n if (!booking) {\n throw new Error(\"No booking data returned from cancelBooking\");\n }\n return {\n id: booking.id,\n displayId: booking.displayId,\n reservationStatus: booking.reservationStatus,\n };\n }\n\n /**\n * Charges a booking. Validates input, resolves the order + payment source via\n * payments-on-file, then applies the payment. The `idempotencyKey` is passed\n * through to Peek.\n *\n * @example\n * ```ts\n * const result = await peek.getBookingService().makePayment({\n * bookingId: \"b_abc123\",\n * paymentSourceId: \"custom/other\", // or a \"ps_…\" source on file\n * amount: \"25.00\",\n * currency: \"USD\",\n * idempotencyKey: crypto.randomUUID(),\n * });\n * console.log(result.transactionId);\n * ```\n *\n * @throws {Error} when `paymentSourceId` is missing or not a `ps_…` id / one\n * of `cash/cash`, `custom/other`, `custom/voucher`; when `amount` is not a\n * valid number; when `currency` is not a 3-letter uppercase code; when\n * `idempotencyKey` is empty; when `bookingId` is not a valid booking id\n * (`b_…`/`B-…`); when the booking or payment source is not found; or when the\n * charge fails.\n */\n async makePayment(input: MakePaymentInput): Promise<MakePaymentResult> {\n this.assertPiiEnabled(\"makePayment\");\n this.validatePaymentInput(input);\n const normalized = normalizeBookingId(input.bookingId);\n\n const onFile = await this.getPaymentsOnFile(normalized);\n if (!onFile) {\n throw new Error(\"Booking not found\");\n }\n if (!onFile.paymentsOnFile.some((source) => source.id === input.paymentSourceId)) {\n throw new Error(\"paymentSourceId not found for this booking\");\n }\n\n const customerMessage = input.customerMessage\n ? `${DEFAULT_CUSTOMER_MESSAGE} (${input.customerMessage})`\n : DEFAULT_CUSTOMER_MESSAGE;\n\n const body: GraphQLBody<ApplyPaymentToOrderResponse> =\n await this.client.request<ApplyPaymentToOrderResponse>(\n SALES_ENDPOINT,\n APPLY_PAYMENT_TO_ORDER_MUTATION,\n {\n input: {\n amount: { amount: input.amount, currency: input.currency },\n orderId: onFile.orderId,\n paymentSourceId: input.paymentSourceId,\n idempotencyKey: input.idempotencyKey,\n customerMessage,\n scopedTo: [normalized],\n },\n },\n );\n\n const result = body.data?.applyPaymentToOrder;\n if (result?.errors && result.errors.length > 0) {\n throw new Error(`Payment failed: ${result.errors[0]!.detail}`);\n }\n\n return {\n transactionId: result?.transactionId ?? \"\",\n bookingId: normalized,\n orderId: onFile.orderId,\n amount: input.amount,\n currency: input.currency,\n paymentSourceId: input.paymentSourceId,\n };\n }\n\n /**\n * Refunds a booking payment. Validates input, resolves the order + payment via\n * payments-on-file, then applies the refund.\n */\n async refund(input: RefundInput): Promise<RefundResult> {\n this.assertPiiEnabled(\"refund\");\n this.validateRefundInput(input);\n const normalized = normalizeBookingId(input.bookingId);\n\n const onFile = await this.getPaymentsOnFile(normalized);\n if (!onFile) {\n throw new Error(\"Booking not found\");\n }\n const paymentExists = onFile.paymentsOnFile.some((source) =>\n (source.payments ?? []).some((payment) => payment.id === input.paymentId),\n );\n if (!paymentExists) {\n throw new Error(\"paymentId not found for this booking\");\n }\n\n const body: GraphQLBody<ApplyRefundToOrderResponse> =\n await this.client.request<ApplyRefundToOrderResponse>(\n SALES_ENDPOINT,\n APPLY_REFUND_TO_ORDER_MUTATION,\n {\n input: {\n amount: { amount: input.amount, currency: input.currency },\n orderId: onFile.orderId,\n paymentId: input.paymentId,\n idempotencyKey: input.idempotencyKey,\n scopedTo: [normalized],\n },\n },\n );\n\n const result = body.data?.applyRefundToOrder;\n if (result?.errors && result.errors.length > 0) {\n throw new Error(`Refund failed: ${result.errors[0]!.detail}`);\n }\n\n return {\n transactionId: result?.transactionId ?? \"\",\n bookingId: normalized,\n orderId: onFile.orderId,\n amount: input.amount,\n currency: input.currency,\n paymentId: input.paymentId,\n };\n }\n\n /** Creates an invoice link for a booking's order. */\n async createInvoiceLink(bookingId: string): Promise<InvoiceLinkResult> {\n this.assertPiiEnabled(\"createInvoiceLink\");\n assertBookingId(bookingId);\n const normalized = normalizeBookingId(bookingId);\n\n const booking = await this.getById(normalized);\n if (!booking || !booking.orderId) {\n throw new Error(\"Booking not found\");\n }\n const orderId = normalizeBookingId(booking.orderId);\n\n const body: GraphQLBody<CreateInvoiceLinkResponse> =\n await this.client.request<CreateInvoiceLinkResponse>(\n SALES_ENDPOINT,\n CREATE_INVOICE_LINK_MUTATION,\n { input: { orderId } },\n );\n\n const url = body.data?.createInvoiceLink?.invoiceLink?.url;\n if (!url) {\n throw new Error(\"Failed to create invoice link\");\n }\n return { bookingId: normalized, orderId, invoiceLink: url };\n }\n\n /** Returns the add-ons on a booking, grouped by add-on item (clean model). */\n async listAddons(bookingId: string): Promise<BookingAddons> {\n assertBookingId(bookingId);\n const { items, displayId, orderId, normalizedBookingId } =\n await this.fetchBookingSale(bookingId);\n\n const addons = items\n .map((item) => toBookingAddon(item))\n .filter((addon): addon is NonNullable<typeof addon> => addon !== null);\n\n return {\n bookingId: items[0]?.bookingId || normalizedBookingId,\n displayId: items[0]?.displayId || displayId,\n orderId: items[0]?.orderId || orderId,\n addons,\n };\n }\n\n /**\n * Adds an add-on to a booking via createQuoteFromOrder → updateQuoteV2 →\n * amendOrder. Lists the booking's add-ons first to derive the order id and\n * reuse an existing add-on refid; resolves the add-on's parent item via the\n * product service. Returns the booking's add-ons after the change.\n *\n * `quantity` is a **positive-integer string** (\"1\", \"2\", …); one add-on\n * itemOption is created per unit. `addonOptionId` is the add-on's item-option\n * id (a ticket id on an `ADD_ON_PRODUCT_TYPE` product from\n * {@link ProductService.getAllProducts}).\n *\n * @example\n * ```ts\n * const result = await peek.getBookingService().addAddon(\"b_abc123\", {\n * addonOptionId: \"io_helmet\",\n * quantity: \"2\",\n * });\n * console.log(result.updatedBookingAddons.addons);\n * ```\n *\n * @throws {Error} when `addonOptionId` is missing, `quantity` is not a\n * positive-integer string, the add-on is not found on any product, or any of\n * the underlying quote/order mutations fail.\n */\n async addAddon(\n bookingId: string,\n input: AddAddonInput,\n ): Promise<BookingAddonsMutationResult> {\n this.assertPiiEnabled(\"addAddon\");\n assertBookingId(bookingId);\n const addonOptionId = (input?.addonOptionId || input?.addonId || \"\").trim();\n if (!addonOptionId) {\n throw new Error(ERROR_ADDON_OPTION_ID_REQUIRED);\n }\n const quantity = parseQuantity(input?.quantity);\n if (quantity === null) {\n throw new Error(ERROR_QUANTITY_INVALID);\n }\n\n // List the booking's existing add-ons first — this yields the order id (no\n // separate lookup) and lets us reuse an existing add-on refid instead of\n // minting a new one. Resolve the add-on's parent item in parallel.\n const [sale, parentItemId] = await Promise.all([\n this.fetchBookingSale(bookingId),\n this.resolveParentItemId(addonOptionId),\n ]);\n\n const normalizedOrderId = normalizeBookingId(sale.orderId);\n\n // Reuse the bookingQuote item refid when this parent item is already on the\n // booking under a non-canceled add-on; otherwise mint a fresh refid.\n const existingItemRefid = sale.items\n .filter(\n (item) => item.bookingQuoteReservationStatus !== ADDON_OPTION_STATUS_CANCELED,\n )\n .flatMap((item) => item.addonItemOptions)\n .find((opt) => opt.itemId === parentItemId)?.itemRefid;\n const addonRefid = existingItemRefid || randomUUID();\n\n // Step 1 — create a quote from the order.\n const { quoteId, saleQuoteRefid } =\n await this.createQuoteFromOrderOrThrow(normalizedOrderId);\n if (!saleQuoteRefid) {\n throw new Error(ERROR_CREATE_QUOTE_FAILED);\n }\n\n // Step 2 — add the add-on to the quote (one new itemOption per unit).\n const itemOptions = Array.from({ length: quantity }, () => ({\n itemOptionId: addonOptionId,\n reservationStatus: RESERVATION_STATUS_CONFIRMED,\n refid: randomUUID(),\n }));\n await this.updateQuoteOrThrow(quoteId, {\n bookingQuotes: [\n {\n refid: saleQuoteRefid,\n addons: [\n {\n itemOptions,\n itemId: parentItemId,\n reservationStatus: RESERVATION_STATUS_CONFIRMED,\n refid: addonRefid,\n },\n ],\n reservationStatus: RESERVATION_STATUS_CONFIRMED,\n },\n ],\n });\n\n // Step 3 — amend the order with the updated quote.\n await this.amendOrderOrThrow(quoteId, normalizedOrderId);\n\n return { updatedBookingAddons: await this.listAddons(bookingId) };\n }\n\n /**\n * Removes (cancels) add-on options from a booking. Lists the booking's\n * add-ons first to get the order id and the existing item/option refids, then\n * issues the same three mutations as {@link addAddon} but with cancellation\n * variables. Returns the booking's add-ons after the change.\n */\n async removeAddon(\n bookingId: string,\n input: AddAddonInput,\n ): Promise<BookingAddonsMutationResult> {\n this.assertPiiEnabled(\"removeAddon\");\n assertBookingId(bookingId);\n const addonOptionId = (input?.addonOptionId || input?.addonId || \"\").trim();\n if (!addonOptionId) {\n throw new Error(ERROR_ADDON_OPTION_ID_REQUIRED);\n }\n const quantity = parseQuantity(input?.quantity);\n if (quantity === null) {\n throw new Error(ERROR_QUANTITY_INVALID);\n }\n\n const sale = await this.fetchBookingSale(bookingId);\n const normalizedOrderId = normalizeBookingId(sale.orderId);\n\n const { bookingQuotes, canceledCount } = buildCancellation(\n sale.items,\n addonOptionId,\n quantity,\n );\n if (canceledCount === 0) {\n throw new Error(ERROR_NO_ADDON_OPTION_TO_REMOVE);\n }\n\n // Step 1 — create a quote from the order (only the quote id is needed; the\n // refids come from the existing booking, not the quote).\n const { quoteId } = await this.createQuoteFromOrderOrThrow(normalizedOrderId);\n\n // Step 2 — update the quote, canceling the selected options.\n await this.updateQuoteOrThrow(quoteId, { bookingQuotes });\n\n // Step 3 — amend the order.\n await this.amendOrderOrThrow(quoteId, normalizedOrderId);\n\n return { updatedBookingAddons: await this.listAddons(bookingId) };\n }\n\n /**\n * Runs the sales add-ons query for a booking, validates that exactly one\n * booking matched, and parses the node into the internal model.\n */\n private async fetchBookingSale(bookingId: string): Promise<{\n items: AddonItem[];\n displayId: string;\n orderId: string;\n normalizedBookingId: string;\n }> {\n const body: GraphQLBody<SalesAddonsResponse> =\n await this.client.request<SalesAddonsResponse>(\n SALES_ENDPOINT,\n SALES_ADDONS_QUERY,\n buildSalesAddonsVariables(bookingId),\n );\n\n const edges = body.data?.sales?.edges ?? [];\n if (edges.length === 0) {\n throw new Error(ERROR_BOOKING_NOT_FOUND);\n }\n if (edges.length > 1) {\n throw new Error(ERROR_MULTIPLE_BOOKINGS_FOUND);\n }\n\n const node = edges[0]!.node;\n return {\n items: parseSaleNode(node),\n displayId: node.displayId || \"\",\n orderId: node.order?.id || \"\",\n normalizedBookingId: node.id || \"\",\n };\n }\n\n /**\n * Runs `createQuoteFromOrder` and validates the response, returning the new\n * quote id and the first sale quote refid (empty string when absent).\n */\n private async createQuoteFromOrderOrThrow(\n normalizedOrderId: string,\n ): Promise<{ quoteId: string; saleQuoteRefid: string }> {\n const body: GraphQLBody<CreateQuoteFromOrderResponse> =\n await this.client.request<CreateQuoteFromOrderResponse>(\n SALES_ENDPOINT,\n CREATE_QUOTE_FROM_ORDER_MUTATION,\n { input: { orderId: normalizedOrderId, quoteInput: {} } },\n );\n\n const created = body.data?.createQuoteFromOrder;\n const quote = created?.quote;\n if ((created?.errors && created.errors.length > 0) || !quote?.id) {\n throw new Error(ERROR_CREATE_QUOTE_FAILED);\n }\n return { quoteId: quote.id, saleQuoteRefid: quote.saleQuotes?.[0]?.refid || \"\" };\n }\n\n /** Runs `updateQuoteV2` with the given quoteInput and validates the response. */\n private async updateQuoteOrThrow(\n quoteId: string,\n quoteInput: Record<string, unknown>,\n ): Promise<void> {\n const body: GraphQLBody<UpdateQuoteV2Response> =\n await this.client.request<UpdateQuoteV2Response>(\n SALES_ENDPOINT,\n UPDATE_QUOTE_V2_MUTATION,\n { input: { quoteId, quoteInput } },\n );\n const updated = body.data?.updateQuoteV2;\n if ((updated?.errors && updated.errors.length > 0) || !updated?.quote) {\n throw new Error(ERROR_UPDATE_QUOTE_FAILED);\n }\n }\n\n /** Runs `amendOrder` and validates the response. */\n private async amendOrderOrThrow(\n quoteId: string,\n normalizedOrderId: string,\n ): Promise<void> {\n const body: GraphQLBody<AmendOrderResponse> =\n await this.client.request<AmendOrderResponse>(\n SALES_ENDPOINT,\n AMEND_ORDER_MUTATION,\n { input: { quoteId, orderId: normalizedOrderId } },\n );\n const amended = body.data?.amendOrder;\n if ((amended?.errors && amended.errors.length > 0) || !amended?.order) {\n throw new Error(ERROR_AMEND_ORDER_FAILED);\n }\n }\n\n /**\n * Creates a booking via createQuoteV2 → createOrderFromQuote, optionally\n * marking it paid. IDs must be pre-resolved (no free-text matching) — resolve\n * `activityId` + ticket `resourceOptionId`s from {@link ProductService} and\n * `availabilityTimeId` from {@link AvailabilityService.getAvailabilityTimes}.\n *\n * @example\n * ```ts\n * const created = await peek.getBookingService().create({\n * activityId: \"a_kayak_tour\",\n * availabilityTimeId: \"at_2026_06_20_0900\",\n * tickets: [{ resourceOptionId: \"ro_adult\", quantity: 2 }],\n * guest: { name: \"Sam Rivera\", email: \"sam@example.com\" },\n * markAsPaid: true,\n * idempotencyKey: crypto.randomUUID(),\n * });\n * console.log(created.bookingId, created.displayId, created.balanceFormatted);\n * ```\n *\n * @throws {Error} when `activityId`, `availabilityTimeId`, a ticket\n * `resourceOptionId`/positive `quantity`, or the guest `name` is missing; when\n * `markAsPaid` is set without an `idempotencyKey`; when\n * `requireRequiredQuestions` is set and a required custom question is left\n * unanswered; or when the quote/order mutations fail.\n */\n async create(input: CreateBookingInput): Promise<CreatedBooking> {\n validateCreateInput(input);\n\n // Split the optional list price across the tickets up front — a malformed\n // amount throws here, before any quote exists.\n const ticketCount = input.tickets.reduce((count, ticket) => count + ticket.quantity, 0);\n const listPriceAmounts =\n input.listPrice === undefined ? null : distributeListPrice(input.listPrice, ticketCount);\n\n // Resolve custom-question answers (and, when a list price is set, the\n // activity's currency) before anything is created: a bad answer fails here\n // rather than after a quote exists, and the two reads run in parallel.\n const [questionAnswers, currency] = await Promise.all([\n this.buildQuestionAnswers(input),\n listPriceAmounts ? this.resolveActivityCurrency(input.activityId) : Promise.resolve(\"\"),\n ]);\n\n let seatIndex = 0;\n const tickets = input.tickets.flatMap((ticket) =>\n Array.from({ length: ticket.quantity }, () => {\n const seat: Record<string, unknown> = {\n resourceOptionId: ticket.resourceOptionId,\n reservationStatus: \"CONFIRMED\",\n refid: randomUUID(),\n };\n if (listPriceAmounts) {\n seat.price = { amount: listPriceAmounts[seatIndex]!, currency };\n }\n seatIndex += 1;\n return seat;\n }),\n );\n\n const bookingQuote: Record<string, unknown> = {\n tickets,\n activityId: input.activityId,\n availabilityTimeId: input.availabilityTimeId,\n refid: randomUUID(),\n skipCustomerEmail: input.skipCustomerEmail ?? false,\n guest: {\n name: input.guest.name,\n email: input.guest.email ?? null,\n phone: input.guest.phone ?? null,\n optinMarketing: input.guest.optinMarketing ?? false,\n optinSms: input.guest.optinSms ?? false,\n postalCode: input.guest.postalCode ?? null,\n country: input.guest.country ?? null,\n },\n };\n if (input.operatorNotes) {\n bookingQuote.operatorNotes = input.operatorNotes;\n }\n if (questionAnswers) {\n bookingQuote.questionAnswers = questionAnswers;\n }\n\n const quoteInput: Record<string, unknown> = { bookingQuotes: [bookingQuote] };\n if (input.parentOrderId) {\n quoteInput.source = { clonedFromId: input.parentOrderId };\n }\n\n // Step 1 — create the quote.\n const quoteBody: GraphQLBody<CreateQuoteV2Response> =\n await this.client.request<CreateQuoteV2Response>(SALES_ENDPOINT, CREATE_QUOTE_V2_MUTATION, {\n input: { quoteInput },\n });\n const quoteResult = quoteBody.data?.createQuoteV2;\n if ((quoteResult?.errors && quoteResult.errors.length > 0) || !quoteResult?.quote?.id) {\n throw new Error(\"Failed to create quote\");\n }\n const quoteId = quoteResult.quote.id;\n\n // Step 2 — create the order from the quote.\n const orderBody: GraphQLBody<CreateOrderFromQuoteResponse> =\n await this.client.request<CreateOrderFromQuoteResponse>(\n SALES_ENDPOINT,\n CREATE_ORDER_FROM_QUOTE_MUTATION,\n { input: { quoteId } },\n );\n const orderResult = orderBody.data?.createOrderFromQuote;\n if (orderResult?.errors && orderResult.errors.length > 0) {\n throw new Error(\"Failed to create order from quote\");\n }\n const order = orderResult?.order;\n const sale = order?.sales?.[0];\n if (!order || !sale) {\n throw new Error(\"Order created but no sales found\");\n }\n\n const created: CreatedBooking = {\n orderId: order.id,\n bookingId: sale.id,\n displayId: sale.displayId,\n balanceAmount: sale.balance?.total?.amount ?? \"0.00\",\n balanceCurrency: sale.balance?.total?.currency ?? \"USD\",\n balanceFormatted: sale.balance?.total?.formatted ?? \"$0.00\",\n };\n\n // Step 3 — optionally mark the booking paid.\n if (input.markAsPaid) {\n created.transactionId = await this.markCreatedBookingPaid(created, input);\n }\n\n return created;\n }\n\n /**\n * Resolves the input's custom-question answers into the quote's\n * `questionAnswers` payload (each tagged with a fresh `refid`), or `null` when\n * none were supplied. Fetches the activity's custom questions to validate\n * against; throws on the first unmatched/ambiguous/invalid answer. When\n * `acceptAllCustomQuestionIds` is set the fetch is skipped if every answer is\n * given by id (a by-name answer still needs the list to resolve).\n */\n private async buildQuestionAnswers(\n input: CreateBookingInput,\n ): Promise<Array<Record<string, unknown>> | null> {\n const answers = input.customQuestionAnswers ?? [];\n const requireRequired = input.requireRequiredQuestions ?? false;\n const acceptAllIds = input.acceptAllCustomQuestionIds ?? false;\n // Nothing to resolve and no required-coverage check to enforce — skip the\n // questions fetch entirely.\n if (answers.length === 0 && !requireRequired) {\n return null;\n }\n // When accepting all ids and not enforcing required-question coverage, the\n // activity's questions are only needed to resolve by-name answers — every\n // by-id answer is accepted as-is. Skip the fetch when no answer needs it.\n const needsQuestions =\n !acceptAllIds ||\n requireRequired ||\n answers.some((answer) => !isCustomQuestionId(answer.questionIdOrText));\n const questions = needsQuestions\n ? await this.deps.productService.getCustomQuestions(input.activityId)\n : [];\n const resolved = resolveCustomQuestionAnswers(answers, questions, {\n requireRequired,\n acceptAllIds,\n });\n if (resolved.length === 0) {\n return null;\n }\n return resolved.map((answer) => ({\n ...answer,\n refid: randomUUID(),\n }));\n }\n\n private async markCreatedBookingPaid(\n booking: CreatedBooking,\n input: CreateBookingInput,\n ): Promise<string> {\n const parsedPartial = input.markAsPaidAmount ? parseFloat(input.markAsPaidAmount) : NaN;\n const amount =\n !Number.isNaN(parsedPartial) && parsedPartial > 0\n ? parsedPartial.toFixed(2)\n : booking.balanceAmount;\n\n const body: GraphQLBody<ApplyPaymentToOrderResponse> =\n await this.client.request<ApplyPaymentToOrderResponse>(\n SALES_ENDPOINT,\n APPLY_PAYMENT_TO_ORDER_MUTATION,\n {\n input: {\n amount: { amount, currency: booking.balanceCurrency },\n orderId: booking.orderId,\n paymentSourceId: \"custom/other\",\n idempotencyKey: input.idempotencyKey,\n customerMessage: \"Marked as paid\",\n scopedTo: [booking.bookingId],\n },\n },\n );\n\n const result = body.data?.applyPaymentToOrder;\n if ((result?.errors && result.errors.length > 0) || !result?.transactionId) {\n throw new Error(\"Failed to mark booking as paid\");\n }\n return result.transactionId;\n }\n\n /**\n * Resolves an activity's ISO currency via the product service, falling back to\n * {@link DEFAULT_CURRENCY} when the activity (or its currency) can't be found.\n */\n private async resolveActivityCurrency(activityId: string): Promise<string> {\n const products = await this.deps.productService.getAllProducts();\n const match = products.find((product) => product.productId === activityId);\n return match?.currency || DEFAULT_CURRENCY;\n }\n\n /** Finds the parent item id of an add-on by matching its option id. */\n private async resolveParentItemId(addonOptionId: string): Promise<string> {\n const products = await this.deps.productService.getAllProducts();\n const matched = products.find(\n (product) =>\n product.type === ADD_ON_PRODUCT_TYPE &&\n product.tickets.some((ticket) => ticket.id === addonOptionId),\n );\n if (!matched) {\n throw new Error(\"Add-on not found for the provided addonOptionId\");\n }\n return matched.productId;\n }\n\n private validatePaymentInput(input: MakePaymentInput): void {\n if (\n !input.paymentSourceId ||\n (!input.paymentSourceId.startsWith(PAYMENT_SOURCE_PREFIX) &&\n !ALLOWED_PAYMENT_SOURCE_IDS.includes(input.paymentSourceId))\n ) {\n throw new Error(\n \"paymentSourceId is required and must start with 'ps_' or be one of \" +\n \"'cash/cash', 'custom/other', 'custom/voucher'\",\n );\n }\n assertAmount(input.amount);\n assertCurrency(input.currency);\n assertIdempotencyKey(input.idempotencyKey);\n assertBookingId(input.bookingId);\n }\n\n private validateRefundInput(input: RefundInput): void {\n if (!input.paymentId || !input.paymentId.startsWith(PAYMENT_ID_PREFIX)) {\n throw new Error(\"paymentId is required and must start with 'pmt_'\");\n }\n assertAmount(input.amount);\n assertCurrency(input.currency);\n assertIdempotencyKey(input.idempotencyKey);\n assertBookingId(input.bookingId);\n }\n\n private async fetchPaginated(\n query: string,\n baseParams: {\n startDateTime?: string;\n endDateTime?: string;\n timeslotId?: string;\n searchBy?: BookingTimeRangeSearch[\"searchBy\"];\n productId?: string;\n email?: string;\n searchString?: string;\n },\n includeGuests: boolean,\n includePriceBreakdown: boolean,\n ): Promise<Booking[]> {\n const bookings: Booking[] = [];\n let after: string | null = null;\n\n for (;;) {\n const body: GraphQLBody<BookingsResponse> =\n await this.client.request<BookingsResponse>(\n SALES_ENDPOINT,\n query,\n buildBookingsVariables({ ...baseParams, pageSize: this.pageSize, after }),\n );\n\n const sales = body.data?.sales;\n for (const edge of sales?.edges ?? []) {\n bookings.push(fromBookingNode(edge.node, includeGuests, includePriceBreakdown));\n }\n\n const pageInfo = sales?.pageInfo;\n if (pageInfo?.hasNextPage && pageInfo.endCursor) {\n after = pageInfo.endCursor;\n } else {\n break;\n }\n }\n\n return bookings;\n }\n}\n\nfunction assertAmount(amount: string): void {\n if (!amount || Number.isNaN(Number(amount))) {\n throw new Error(\"amount is required and must be a valid number\");\n }\n}\n\nfunction assertCurrency(currency: string): void {\n if (!currency || !CURRENCY_CODE_REGEX.test(currency)) {\n throw new Error(\"currency is required and must be a 3-letter uppercase code\");\n }\n}\n\nfunction assertIdempotencyKey(idempotencyKey: string): void {\n if (!idempotencyKey) {\n throw new Error(\"idempotencyKey is required\");\n }\n}\n\n/** Throws unless `bookingId` is a valid booking db id (`b_…`) or display id (`B-…`). */\nfunction assertBookingId(bookingId: string): void {\n if (!(BOOKING_DB_ID_REGEX.test(bookingId) || BOOKING_DISPLAY_ID_REGEX.test(bookingId))) {\n throw new Error(ERROR_INVALID_BOOKING_ID);\n }\n}\n\n/** Throws unless `customStatus` is a non-empty (non-whitespace) string. */\nfunction assertCustomStatus(customStatus: string): void {\n if (typeof customStatus !== \"string\" || customStatus.trim().length === 0) {\n throw new Error(ERROR_CUSTOM_STATUS_REQUIRED);\n }\n}\n\n/** Throws unless `value` is a non-empty (non-whitespace) string, naming `field`. */\nfunction assertNonEmptyString(value: unknown, field: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new Error(`${field} is required and must be a non-empty string`);\n }\n}\n\n/** Throws unless `orderId` is a valid order db id (`o_…`) or display id (`O-…`). */\nfunction assertOrderId(orderId: string): void {\n if (!(ORDER_DB_ID_REGEX.test(orderId) || ORDER_DISPLAY_ID_REGEX.test(orderId))) {\n throw new Error(ERROR_INVALID_ORDER_ID);\n }\n}\n\nfunction validateCreateInput(input: CreateBookingInput): void {\n if (!input.activityId) throw new Error(\"activityId is required\");\n if (!input.availabilityTimeId) throw new Error(\"availabilityTimeId is required\");\n if (!input.tickets || input.tickets.length === 0) {\n throw new Error(\"at least one ticket is required\");\n }\n if (input.tickets.some((ticket) => !ticket.resourceOptionId || !(ticket.quantity > 0))) {\n throw new Error(\"each ticket requires a resourceOptionId and a positive quantity\");\n }\n if (!input.guest || !input.guest.name) {\n throw new Error(\"guest name is required\");\n }\n if (input.markAsPaid && !input.idempotencyKey) {\n throw new Error(\"idempotencyKey is required when markAsPaid is set\");\n }\n if (input.parentOrderId) {\n assertOrderId(input.parentOrderId);\n }\n}\n\nfunction parseQuantity(value: unknown): number | null {\n if (typeof value !== \"string\" && typeof value !== \"number\") {\n return null;\n }\n const str = String(value).trim();\n if (!/^\\d+$/.test(str)) {\n return null;\n }\n const num = parseInt(str, 10);\n if (!Number.isFinite(num) || num <= 0) {\n return null;\n }\n return num;\n}\n\n/**\n * Builds the `bookingQuotes` cancellation payload for `updateQuoteV2`. Selects\n * up to `quantity` options across the booking where the item and the option are\n * both still `CONFIRMED` and `optionId === addonOptionId`, grouped by booking\n * item. Each selected option becomes a CANCELED itemOptions entry (by its\n * `optionRefid`); the parent add-on is marked CANCELED only when every one of\n * its options ends up canceled.\n */\nfunction buildCancellation(\n items: AddonItem[],\n addonOptionId: string,\n quantity: number,\n): { bookingQuotes: Array<Record<string, unknown>>; canceledCount: number } {\n let budget = quantity;\n // bookingQuoteRefid -> (itemRefid -> { item, canceledOptionRefids })\n const byBookingQuote = new Map<\n string,\n Map<string, { item: AddonItem; canceledOptionRefids: string[] }>\n >();\n\n for (const item of items) {\n if (budget <= 0) break;\n for (const opt of item.addonItemOptions) {\n if (budget <= 0) break;\n // Only cancel options that are themselves still confirmed — an item can\n // hold a mix of already-canceled and confirmed options for the same\n // optionId, and we must skip the canceled ones.\n if (\n opt.itemReservationStatus !== RESERVATION_STATUS_CONFIRMED ||\n opt.optionReservationStatus !== RESERVATION_STATUS_CONFIRMED ||\n opt.optionId !== addonOptionId\n ) {\n continue;\n }\n\n let itemMap = byBookingQuote.get(item.bookingQuoteRefid);\n if (!itemMap) {\n itemMap = new Map();\n byBookingQuote.set(item.bookingQuoteRefid, itemMap);\n }\n let entry = itemMap.get(opt.itemRefid);\n if (!entry) {\n entry = { item, canceledOptionRefids: [] };\n itemMap.set(opt.itemRefid, entry);\n }\n entry.canceledOptionRefids.push(opt.optionRefid);\n budget -= 1;\n }\n }\n\n const canceledCount = quantity - budget;\n\n const bookingQuotes = Array.from(byBookingQuote.entries()).map(\n ([bookingQuoteRefid, itemMap]) => ({\n refid: bookingQuoteRefid,\n addons: Array.from(itemMap.entries()).map(\n ([itemRefid, { item, canceledOptionRefids }]) => {\n const canceledSet = new Set(canceledOptionRefids);\n const itemOptions = canceledOptionRefids.map((refid) => ({\n reservationStatus: ADDON_OPTION_STATUS_CANCELED,\n refid,\n }));\n\n // Mark the add-on canceled only if every option ends up canceled.\n const allCanceled = item.addonItemOptions.every(\n (o) =>\n o.optionReservationStatus === ADDON_OPTION_STATUS_CANCELED ||\n canceledSet.has(o.optionRefid),\n );\n\n const addon: Record<string, unknown> = { itemOptions, refid: itemRefid };\n if (allCanceled) {\n addon.reservationStatus = ADDON_OPTION_STATUS_CANCELED;\n }\n return addon;\n },\n ),\n }),\n );\n\n return { bookingQuotes, canceledCount };\n}\n","/**\n * Pure functions resolving the daily-note GraphQL unions into the clean\n * {@link DailyNote} model. A not-found / missing note maps to `null`.\n */\nimport type { DailyNote } from \"../../../models/peek/daily-note.js\";\nimport type {\n DailyNoteResponse,\n UpsertDailyNoteResponse,\n} from \"./daily-note-queries.js\";\n\n/** Resolves a daily-note query response into a {@link DailyNote}, or null. */\nexport function toDailyNote(\n response: DailyNoteResponse | undefined,\n): DailyNote | null {\n const union = response?.dailyNote;\n if (!union) {\n return null;\n }\n // Success branch carries a nested `dailyNote`; the not-found branch carries `message`.\n if (\"dailyNote\" in union) {\n return cleanNote(union.dailyNote);\n }\n return null;\n}\n\n/** Resolves an upsert response into the saved {@link DailyNote}, or null. */\nexport function fromUpsertResponse(\n response: UpsertDailyNoteResponse | undefined,\n): DailyNote | null {\n return cleanNote(response?.upsertDailyNote?.dailyNote);\n}\n\nfunction cleanNote(note: DailyNote | null | undefined): DailyNote | null {\n if (!note || typeof note.note !== \"string\") {\n return null;\n }\n return { note: note.note };\n}\n","/**\n * Raw Peek GraphQL query/mutation and response shapes for the daily note.\n * Internal.\n */\nimport type { DailyNote } from \"../../../models/peek/daily-note.js\";\n\n/** The global-note type for the dashboard daily note. */\nexport const GLOBAL_NOTE_TYPE = \"DASHBOARD\";\n\n/** Fetches today's daily note. */\nexport const DAILY_NOTE_TODAY_QUERY = `\n query dailyNote($type: GlobalNoteType!) {\n dailyNote(type: $type) {\n ... on DailyNoteSuccess {\n dailyNote {\n note\n }\n }\n ... on NotFoundError {\n message\n }\n }\n }\n`;\n\n/** Upserts the daily note. */\nexport const UPSERT_DAILY_NOTE_MUTATION = `\n mutation Account($input: UpsertDailyNoteInput!) {\n upsertDailyNote(input: $input) {\n ... on UpsertDailyNoteSuccess {\n dailyNote {\n note\n }\n }\n }\n }\n`;\n\n/** `data` payload of {@link DAILY_NOTE_TODAY_QUERY} (a success/not-found union). */\nexport interface DailyNoteResponse {\n dailyNote: { dailyNote: DailyNote | null } | { message: string };\n}\n\n/** `data` payload of {@link UPSERT_DAILY_NOTE_MUTATION}. */\nexport interface UpsertDailyNoteResponse {\n upsertDailyNote: { dailyNote: DailyNote | null };\n}\n\n/** Builds the variables for {@link UPSERT_DAILY_NOTE_MUTATION}. */\nexport function buildUpsertDailyNoteVariables(note: string): {\n input: { type: string; note: string };\n} {\n return { input: { type: GLOBAL_NOTE_TYPE, note } };\n}\n","/**\n * Daily-note operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getDailyNoteService}.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type { DailyNote } from \"../../../models/peek/daily-note.js\";\nimport { fromUpsertResponse, toDailyNote } from \"./daily-note-converter.js\";\nimport {\n DAILY_NOTE_TODAY_QUERY,\n GLOBAL_NOTE_TYPE,\n UPSERT_DAILY_NOTE_MUTATION,\n buildUpsertDailyNoteVariables,\n type DailyNoteResponse,\n type UpsertDailyNoteResponse,\n} from \"./daily-note-queries.js\";\n\nexport class DailyNoteService {\n constructor(private readonly client: GraphQLClient) {}\n\n /** Returns today's daily note, or null when none is set. */\n async getToday(): Promise<DailyNote | null> {\n const body: GraphQLBody<DailyNoteResponse> =\n await this.client.request<DailyNoteResponse>(SALES_ENDPOINT, DAILY_NOTE_TODAY_QUERY, {\n type: GLOBAL_NOTE_TYPE,\n });\n return toDailyNote(body.data);\n }\n\n /** Upserts the daily note and returns the saved note, or null. */\n async update(note: string): Promise<DailyNote | null> {\n const body: GraphQLBody<UpsertDailyNoteResponse> =\n await this.client.request<UpsertDailyNoteResponse>(\n SALES_ENDPOINT,\n UPSERT_DAILY_NOTE_MUTATION,\n buildUpsertDailyNoteVariables(note),\n );\n return fromUpsertResponse(body.data);\n }\n}\n","/**\n * Mints and caches the short-lived JWT used to authenticate with the Peek\n * gateway. The token is signed on demand and reused until it nears expiry.\n */\nimport * as jwt from \"jsonwebtoken\";\n\nexport interface TokenManagerOptions {\n /** HMAC secret used to sign the JWT. */\n secret: string;\n /** JWT issuer (the app name). */\n issuer: string;\n /** JWT subject (the install ID). */\n installId: string;\n /** Token lifetime in seconds. */\n ttlSeconds: number;\n /** Re-mint the cached token this many seconds before its expiry. */\n leewaySeconds: number;\n}\n\nexport class TokenManager {\n private cached?: { token: string; expiresAtMs: number };\n\n constructor(private readonly options: TokenManagerOptions) {}\n\n /**\n * Returns a valid bearer token, reusing the cached one until it is within\n * `leewaySeconds` of expiring, at which point a fresh token is minted.\n */\n getToken(): string {\n const now = Date.now();\n if (this.cached && now < this.cached.expiresAtMs) {\n return this.cached.token;\n }\n\n const { secret, issuer, installId, ttlSeconds, leewaySeconds } = this.options;\n const token = jwt.sign({}, secret, {\n expiresIn: ttlSeconds,\n issuer,\n subject: installId,\n });\n\n this.cached = {\n token,\n expiresAtMs: now + (ttlSeconds - leewaySeconds) * 1000,\n };\n return token;\n }\n}\n","/**\n * Config shared by every access service in this package (Peek, CNG, …).\n *\n * Each gateway's access service extends {@link BaseAccessServiceConfig} with its\n * own extras (e.g. Peek adds `gatewayKey`/`mode`), so the only real difference\n * between accessors is the transport they build and the services they expose.\n * The shared defaults and the token-manager builder live here too, so that\n * plumbing is written once.\n */\nimport { TokenManager } from \"./internal/token-manager.js\";\nimport type { AccessOptions } from \"./access-options.js\";\nimport type { Logger } from \"./logger.js\";\n\n/** Fields common to every access service's config. */\nexport interface BaseAccessServiceConfig {\n /** Install ID. Becomes the JWT subject. */\n installId: string;\n /** HMAC secret used to sign the JWT. */\n jwtSecret: string;\n /** JWT issuer — the app name / app ID. */\n issuer: string;\n /**\n * The install's **base API URL** — persist the install webhook's `apiUrl` and\n * pass it here. It is the app endpoint with no per-platform routing slug; each\n * service class appends its own slug (e.g. `peek_backoffice_api-v1`, via that\n * platform's endpoint lookup) when it makes a call, so different services can\n * route through different slugs. If the URL you pass still carries this\n * platform's slug it is stripped back off to recover the base; a URL carrying a\n * *different* platform's slug makes the constructor throw. No app-id/gateway\n * segment is inserted, so `appId` is not required. This is the forward-looking\n * way to target an install — prefer it over `baseUrl`/`appId`, which are\n * deprecated (the hardcoded base-URL fallbacks will be removed and a URL will\n * become required in a future release).\n */\n apiUrl?: string;\n /**\n * App ID, inserted into the gateway endpoint path.\n *\n * @deprecated Required only in the legacy `baseUrl` mode. Prefer `apiUrl` (the\n * install's app endpoint), which needs no app-id segment.\n */\n appId?: string;\n\n /**\n * Override the gateway base URL. Default: per-service.\n *\n * @deprecated Prefer `apiUrl` (the install's app endpoint, used as given). The\n * hardcoded per-service default will be removed and a URL will become required.\n */\n baseUrl?: string;\n /** JWT lifetime in seconds. Default: 3600. */\n tokenTtlSeconds?: number;\n /** Re-mint the cached token this many seconds before expiry. Default: 60. */\n tokenRefreshLeewaySeconds?: number;\n /** Backoff delays (ms) for HTTP 429 retries. Default: [1000, 2000, 4000]. */\n retryDelaysMs?: number[];\n /** Optional logger. Default: no-op (silent). */\n logger?: Logger;\n /** Custom `fetch` implementation. Default: the global `fetch`. */\n fetch?: typeof fetch;\n\n /**\n * Cross-cutting access options (PII exposure, …). When omitted, defaults are\n * used ({@link AccessOptions.fullCustomerAccess} `false`). Threaded down to the\n * resource services that read customer data.\n */\n accessOptions?: AccessOptions;\n}\n\n/** Default JWT lifetime (1 hour). */\nexport const DEFAULT_TOKEN_TTL_SECONDS = 3600;\n/** Default leeway before expiry at which a cached token is re-minted. */\nexport const DEFAULT_TOKEN_REFRESH_LEEWAY_SECONDS = 60;\n/** Default HTTP 429 retry backoff. */\nexport const DEFAULT_RETRY_DELAYS_MS = [1000, 2000, 4000];\n\n/**\n * Throws when a required config field is empty, prefixing the message with the\n * concrete service name (e.g. `PeekAccessService: \"installId\" is required`).\n */\nexport function requireNonEmpty(\n value: string,\n name: string,\n serviceName: string,\n): void {\n if (!value) {\n throw new Error(`${serviceName}: \"${name}\" is required`);\n }\n}\n\n/**\n * Matches a backoffice-API extendable slug and captures the platform prefix —\n * e.g. `peek` from `peek_backoffice_api-v1` or `peek-backoffice-api-v1`. Dashes\n * and underscores are interchangeable as separators, so both spellings the app\n * registry emits are recognised. Anchored to the whole segment so an ordinary\n * install-path segment (e.g. `google-things-to-do-integration`) never matches.\n */\nconst EXTENDABLE_SLUG_RE = /^([a-z0-9]+)[-_]backoffice[-_]api[-_]v1$/i;\n\n/**\n * Recovers the **base API URL** from the install's app endpoint (`apiUrl`).\n *\n * The base is the install's app endpoint with no per-platform routing slug — the\n * service classes append their own slug (via their endpoint lookup) when they\n * make calls. Callers may pass the raw base, or a URL that still carries this\n * platform's slug; either way this returns the base:\n *\n * - **No slug present** → the URL is already the base; return it (trailing slash\n * trimmed).\n * - **This platform's slug present** → strip it off (dashes/underscores either\n * way) and return the base.\n * - **A different platform's slug present** → throw, since the URL targets the\n * wrong gateway and silently stripping it would mask a wiring mistake.\n */\nexport function resolveBaseApiUrl(\n apiUrl: string,\n platformSlug: string,\n serviceName: string,\n): string {\n const trimmed = apiUrl.replace(/\\/+$/, \"\");\n const lastSegment = trimmed.slice(trimmed.lastIndexOf(\"/\") + 1);\n const found = EXTENDABLE_SLUG_RE.exec(lastSegment);\n if (!found) return trimmed;\n\n const foundPlatform = found[1]!.toLowerCase();\n const expectedPlatform = EXTENDABLE_SLUG_RE.exec(platformSlug)![1]!.toLowerCase();\n if (foundPlatform !== expectedPlatform) {\n throw new Error(\n `${serviceName}: \"apiUrl\" carries a \"${foundPlatform}\" backoffice ` +\n `slug but this service targets \"${expectedPlatform}\" — pass the ` +\n `install's ${expectedPlatform} app endpoint`,\n );\n }\n // Strip this platform's slug back off to recover the base API URL.\n return trimmed.slice(0, trimmed.lastIndexOf(\"/\"));\n}\n\n/**\n * Builds the shared {@link TokenManager} from the common config fields, applying\n * the shared TTL/leeway defaults. Used by every access service.\n */\nexport function createTokenManager(config: BaseAccessServiceConfig): TokenManager {\n return new TokenManager({\n secret: config.jwtSecret,\n issuer: config.issuer,\n installId: config.installId,\n ttlSeconds: config.tokenTtlSeconds ?? DEFAULT_TOKEN_TTL_SECONDS,\n leewaySeconds:\n config.tokenRefreshLeewaySeconds ?? DEFAULT_TOKEN_REFRESH_LEEWAY_SECONDS,\n });\n}\n","/**\n * Shared HTTP transport core for both gateway clients (Peek GraphQL + CNG REST).\n *\n * The retry/backoff loop and the 418/429 status mapping are identical across\n * both gateways — only URL construction, request method/body, and success-body\n * handling differ. Those differences are supplied by the caller: it builds the\n * `url`/`init`, and its `onResponse` callback runs for every non-418/429 status\n * to produce the final value (or throw a transport-specific error).\n */\nimport { AdminAccountRequiredError, RateLimitError } from \"../errors.js\";\nimport type { Logger } from \"../logger.js\";\n\nexport const RATE_LIMIT_STATUS = 429;\nexport const ADMIN_ACCOUNT_REQUIRED_STATUS = 418;\n\n/** The subset of client options the shared retry loop needs. */\nexport interface HttpRetryOptions {\n /** Backoff delays (ms) applied on successive HTTP 429 responses. */\n retryDelaysMs: number[];\n /** Diagnostics sink. */\n logger: Logger;\n /** `fetch` implementation to use. */\n fetchFn: typeof fetch;\n}\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Reads a response body as JSON, falling back to the raw text when it is not\n * valid JSON. Never throws — a non-JSON error page (e.g. a gateway `404` with a\n * plain-text body) is returned verbatim as a string rather than blowing up the\n * caller with a `SyntaxError` that hides the real HTTP status.\n *\n * Shared by all three transports (Peek GraphQL, CNG REST, ACME REST) so their\n * error paths can carry the raw body regardless of its content type.\n */\nexport async function parseBody(response: Response): Promise<unknown> {\n const text = await response.text();\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\n/**\n * Runs a request through the shared retry loop. Maps HTTP 418 →\n * {@link AdminAccountRequiredError} and HTTP 429 → retry then\n * {@link RateLimitError}; delegates every other response to `onResponse`.\n *\n * @param label a short identifier for the request (endpoint name / REST path),\n * used only in the warn/error log messages.\n */\nexport async function requestWithRetry<T>(\n http: HttpRetryOptions,\n url: string,\n init: RequestInit,\n label: string,\n onResponse: (response: Response) => Promise<T>,\n): Promise<T> {\n const { retryDelaysMs, logger, fetchFn } = http;\n\n for (let attempt = 0; attempt <= retryDelaysMs.length; attempt++) {\n const response = await fetchFn(url, init);\n\n if (response.status === ADMIN_ACCOUNT_REQUIRED_STATUS) {\n logger.warn(`Admin account required for ${label} (HTTP 418)`, { url });\n throw new AdminAccountRequiredError();\n }\n\n if (response.status === RATE_LIMIT_STATUS) {\n const delay = retryDelaysMs[attempt];\n if (delay !== undefined) {\n logger.warn(\n `Rate limited on ${label}, retrying in ${delay}ms ` +\n `(attempt ${attempt + 1}/${retryDelaysMs.length})`,\n );\n await sleep(delay);\n continue;\n }\n logger.error(`Rate limit exceeded for ${label}`, { url });\n throw new RateLimitError();\n }\n\n return onResponse(response);\n }\n\n /* istanbul ignore next -- unreachable: the 429 branch always returns/throws */\n throw new RateLimitError();\n}\n","/**\n * The SDK identification header sent on every outbound gateway request (Peek\n * GraphQL, CNG REST, ACME REST) so the downstream platforms can attribute\n * traffic to this package and its version.\n *\n * The version is a literal rather than a `package.json` read: the dual ESM+CJS\n * build has no portable way to resolve its own `package.json` at runtime\n * (`import.meta.url` is ESM-only, `__dirname` is CJS-only), and a static const\n * keeps the package dependency-light and tree-shakeable. `sdk-headers.test.ts`\n * pins it to `package.json` so the two can never drift.\n */\n\n/** Header name carrying the SDK identifier. */\nexport const SDK_HEADER_NAME = \"x-peek-sdk\";\n\n/** Platform prefix in the header value (`<platform>-<version>`). */\nconst SDK_PLATFORM = \"js\";\n\n/** Must equal the `version` field in `package.json`. */\nexport const SDK_VERSION = \"0.9.3\";\n\n/** The `x-peek-sdk` header value, e.g. `js-0.9.0`. */\nexport const SDK_HEADER_VALUE = `${SDK_PLATFORM}-${SDK_VERSION}`;\n","/**\n * Thin GraphQL-over-HTTP transport built on the global `fetch`. Handles\n * endpoint construction, auth headers, query whitespace collapsing, and\n * GraphQL-specific response handling. The shared retry/backoff loop and 418/429\n * mapping live in `./http-transport.ts` (used by the CNG REST transport too).\n */\nimport { PeekGraphQLError, PeekHttpError } from \"../../errors.js\";\nimport { ApiEndpoints, joinUrl } from \"../api-endpoints.js\";\nimport { parseBody, requestWithRetry } from \"../http-transport.js\";\nimport { SDK_HEADER_NAME, SDK_HEADER_VALUE } from \"../sdk-headers.js\";\nimport type { Logger } from \"../../logger.js\";\n\n/** The raw body of a GraphQL HTTP response. */\nexport interface GraphQLBody<T> {\n data?: T;\n errors?: unknown[];\n}\n\n/** Narrows an unknown parsed body to an inspectable object (not a string/null). */\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\n\nexport interface GraphQLClientOptions {\n /**\n * The install's **base API URL** (no trailing slash, no routing slug). Every\n * GraphQL call POSTs to `baseApiUrl/<slug>`, where the slug comes from\n * {@link endpoints} for the request's endpoint name.\n */\n baseApiUrl: string;\n /** Maps an endpoint name to the relative slug appended to {@link baseApiUrl}. */\n endpoints: ApiEndpoints;\n /** API gateway key sent as the `pk-api-key` header. Omitted from headers when absent (v2 mode). */\n gatewayKey?: string;\n /** Supplies a valid bearer token for each request. */\n getToken: () => string;\n /** Backoff delays (ms) applied on successive HTTP 429 responses. */\n retryDelaysMs: number[];\n /** Diagnostics sink. */\n logger: Logger;\n /** `fetch` implementation to use. */\n fetchFn: typeof fetch;\n}\n\nexport class GraphQLClient {\n constructor(private readonly options: GraphQLClientOptions) {}\n\n /**\n * Executes a GraphQL query against the named endpoint and returns the raw\n * response body. Retries on HTTP 429 per the configured backoff (via the\n * shared {@link requestWithRetry} loop).\n */\n async request<T>(\n endpointName: string,\n query: string,\n variables: object,\n ): Promise<GraphQLBody<T>> {\n const { logger } = this.options;\n const url = this.endpoint(endpointName);\n const collapsedQuery = query.replace(/\\s+/g, \" \").trim();\n\n logger.info(\"Making GraphQL request\", { url, endpointName });\n\n return requestWithRetry(\n this.options,\n url,\n {\n method: \"POST\",\n headers: this.buildHeaders(),\n body: JSON.stringify({ query: collapsedQuery, variables }),\n },\n endpointName,\n async (response) => {\n // Parse the body defensively *before* branching on status: a non-JSON\n // error page (e.g. a `404` with a \"Not Found\" text body) must surface\n // as a typed HTTP error, not a `SyntaxError` that hides the real status.\n const raw = await parseBody(response);\n const body = (isObject(raw) ? raw : {}) as GraphQLBody<T>;\n\n if (body.errors) {\n logger.error(`GraphQL errors for ${endpointName}`, {\n url,\n graphqlErrors: JSON.stringify(body.errors),\n });\n throw new PeekGraphQLError(body.errors);\n }\n\n if (!response.ok) {\n logger.error(`GraphQL request failed with HTTP ${response.status}`, { url });\n throw new PeekHttpError(response.status, url, raw);\n }\n\n return body;\n },\n );\n }\n\n private endpoint(endpointName: string): string {\n const { baseApiUrl, endpoints } = this.options;\n return joinUrl(baseApiUrl, endpoints.pathFor(endpointName));\n }\n\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"X-Peek-Auth\": `Bearer ${this.options.getToken()}`,\n \"Content-Type\": \"application/json\",\n [SDK_HEADER_NAME]: SDK_HEADER_VALUE,\n };\n if (this.options.gatewayKey) {\n headers[\"pk-api-key\"] = this.options.gatewayKey;\n }\n return headers;\n }\n}\n","/**\n * Every platform this package knows about. Exported as a value (not just a\n * union) so runtime code can recognise a reported platform without restating\n * the list. New platforms extend this array.\n */\nexport const PEEK_PLATFORMS = [\"peek\", \"cng\", \"acme\"] as const;\n\n/**\n * Platform that embedded the app for this session. Verification is\n * brand-agnostic — one peek-auth JWT is minted for every platform — so this\n * claim is the single thing that identifies which platform a request came from.\n */\nexport type PeekPlatform = (typeof PEEK_PLATFORMS)[number];\n\n/**\n * User context embedded in a Peek auth token.\n *\n * Every field is nullable: the token is untrusted even after its signature\n * verifies, so a claim may be absent, `null`, or a sentinel (`\"\"`, `\"null\"`)\n * that this package normalizes to `null`. Never assume a field is populated —\n * always null-check.\n */\nexport interface PeekAuthTokenUser {\n /** User's email address, or `null` if the token omits it. */\n email: string | null;\n /**\n * The user's own Peek user ID — it identifies the signed-in person, **not**\n * the account or partner they belong to. Use it only to key the user; never\n * treat it as an account/partner id. `null` when the token omits it.\n */\n id: string | null;\n /** Whether the user has admin privileges, or `null` if the token omits it. */\n isAdmin: boolean | null;\n /** User's locale (e.g. `\"en\"`), or `null` if the token omits it. */\n locale: string | null;\n /** User's display name, or `null` if the token omits it. */\n name: string | null;\n /**\n * Which platform embedded the app for this session, or `null` when the token\n * omits it or reports one this version of the package doesn't recognize.\n */\n platform: PeekPlatform | null;\n}\n\n/** Claims returned by {@link PeekAccessService.verifyPeekAuthToken}. */\nexport interface PeekAuthTokenClaims {\n /** Install ID — the JWT subject (`sub`). Peek-assigned UUID. */\n installId: string;\n /** App display version at time of issuance. */\n displayVersion: string;\n /**\n * Authenticated user context, or `null` when the token carries no `user`\n * block. Do not assume a session token always names a user.\n */\n user: PeekAuthTokenUser | null;\n}\n\n/** The Peek account an install belongs to, as reported on an install webhook. */\nexport interface InstallWebhookAccount {\n /** Peek account ID that owns the install. */\n id: string;\n}\n\n/**\n * Claims returned by `verifyInstallWebhook` — the decoded, signature-verified\n * install-status webhook token.\n *\n * Shares the `app_registry_v2` token family with {@link PeekAuthTokenClaims},\n * but is emitted by the app registry itself for install lifecycle events\n * (installed / uninstalled / status changed) rather than for a user session —\n * so {@link InstallWebhookClaims.user} is `null` for system-initiated events\n * that no user triggered.\n */\nexport interface InstallWebhookClaims {\n /** Install ID — the JWT subject (`sub`). Peek-assigned UUID. */\n installId: string;\n /** The account the install belongs to. */\n account: InstallWebhookAccount;\n /** Install lifecycle status (e.g. `\"installed\"`, `\"uninstalled\"`). */\n status: string;\n /** App display version at time of issuance. Empty string when absent. */\n displayVersion: string;\n /**\n * The user that triggered the event, or `null` for system-initiated events\n * (the whole point of a distinct type from {@link PeekAuthTokenClaims}).\n */\n user: PeekAuthTokenUser | null;\n}\n","/**\n * Shared verification core for the `app_registry_v2` JWT family.\n *\n * Every token Peek's app registry mints — the per-session **peek-auth token**\n * (see {@link PeekAccessService.verifyPeekAuthToken}) and the **install-status\n * webhook token** (see {@link verifyInstallWebhook}) — is signed with the app's\n * HMAC secret and carries the same `issuer`/`audience` and the same snake_case\n * `user` block. This module owns those shared constants and the signature check\n * so the two entry points can't drift apart.\n *\n * Internal only — never re-exported from `src/index.ts`.\n */\nimport * as jwt from \"jsonwebtoken\";\nimport { PEEK_PLATFORMS } from \"../../models/peek/auth-token.js\";\nimport type { PeekAuthTokenUser, PeekPlatform } from \"../../models/peek/auth-token.js\";\n\n/** JWT issuer set by the Peek app registry on all tokens it issues. */\nexport const PEEK_TOKEN_ISSUER = \"app_registry_v2\";\n/** JWT audience set by the Peek app registry on all tokens it issues. */\nexport const PEEK_TOKEN_AUDIENCE = \"Joken\";\n/** Case-insensitive `Bearer ` scheme prefix on an `x-peek-auth` header value. */\nconst BEARER_PREFIX = \"bearer \";\n\n/**\n * Strips a leading `Bearer ` prefix (case-insensitive) so every caller can pass\n * the raw `x-peek-auth` request header value straight through — with or without\n * the scheme — without unwrapping it first. A real `app_registry_v2` JWT is\n * base64url and never starts with `\"bearer \"`, so this is a no-op on well-formed\n * tokens.\n */\nfunction stripBearer(token: string): string {\n const trimmed = token.trim();\n return trimmed.toLowerCase().startsWith(BEARER_PREFIX)\n ? trimmed.slice(BEARER_PREFIX.length).trim()\n : trimmed;\n}\n\n/**\n * The raw, snake_case user block embedded in an `app_registry_v2` token. Every\n * field is optional/nullable: the block is untrusted attacker- **or** registry-\n * shaped input, so a field may be missing, `null`, or a sentinel string. The\n * clean {@link PeekAuthTokenUser} is produced by {@link mapPeekTokenUser}.\n */\nexport interface RawPeekTokenUser {\n email?: string | null;\n id?: string | null;\n is_admin?: boolean | null;\n locale?: string | null;\n name?: string | null;\n platform?: string | null;\n}\n\n/** Strings Peek is known to emit in place of an absent value. */\nconst NULLISH_STRINGS = new Set([\"\", \"null\"]);\n\n/**\n * Normalizes an untrusted string claim: trims it, then collapses an empty string\n * or the literal `\"null\"` (case-insensitive) — both of which Peek has been seen\n * to send for an absent value — to `null`. A non-string (a real `null`,\n * `undefined`, or wrong-typed claim) also becomes `null`.\n */\nexport function cleanTokenString(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n const trimmed = value.trim();\n return NULLISH_STRINGS.has(trimmed.toLowerCase()) ? null : trimmed;\n}\n\n/** Narrows an untrusted platform claim to a known {@link PeekPlatform}, else `null`. */\nfunction cleanTokenPlatform(value: unknown): PeekPlatform | null {\n const cleaned = cleanTokenString(value);\n return cleaned !== null && (PEEK_PLATFORMS as readonly string[]).includes(cleaned)\n ? (cleaned as PeekPlatform)\n : null;\n}\n\n/**\n * Verifies an `app_registry_v2` token's HMAC signature (with `secret`), its\n * expiry, the `\"app_registry_v2\"` issuer, and the `\"Joken\"` audience, then\n * returns the decoded payload cast to `T`. Throws from the `jsonwebtoken`\n * library on any failure (`JsonWebTokenError` / `TokenExpiredError` /\n * `NotBeforeError`).\n *\n * The `token` argument accepts the raw `x-peek-auth` header value: a leading\n * `Bearer ` scheme prefix (case-insensitive) is stripped before verification, so\n * every token entry point in the family tolerates it uniformly.\n */\nexport function verifyPeekJwt<T>(token: string, secret: string): T {\n return jwt.verify(stripBearer(token), secret, {\n issuer: PEEK_TOKEN_ISSUER,\n audience: PEEK_TOKEN_AUDIENCE,\n }) as T;\n}\n\n/**\n * Maps the raw snake_case user block to the clean {@link PeekAuthTokenUser}.\n *\n * The block is untrusted even after the signature verifies: it may be absent\n * entirely (system-initiated events, malformed tokens) and any field inside it\n * may be missing, `null`, or a sentinel like `\"\"`/`\"null\"`. An absent block\n * yields `null`; a present block yields a user whose every field is\n * independently nullable (garbage strings normalized to `null` via\n * {@link cleanTokenString}). No field is required, so this never throws — in\n * particular `id` is the user's own id, not an account/partner id, and its\n * absence is not treated as an error.\n */\nexport function mapPeekTokenUser(\n u: RawPeekTokenUser | null | undefined,\n): PeekAuthTokenUser | null {\n if (!u) return null;\n return {\n email: cleanTokenString(u.email),\n id: cleanTokenString(u.id),\n isAdmin: typeof u.is_admin === \"boolean\" ? u.is_admin : null,\n locale: cleanTokenString(u.locale),\n name: cleanTokenString(u.name),\n platform: cleanTokenPlatform(u.platform),\n };\n}\n","/**\n * Pure function flattening raw membership nodes into the clean\n * {@link Membership} model — one record per variant.\n */\nimport type { Membership } from \"../../../models/peek/membership.js\";\nimport type { MembershipsResponse } from \"./membership-queries.js\";\n\n/** Flattens a memberships response into one {@link Membership} per variant. */\nexport function fromMembershipsResponse(\n response: MembershipsResponse | undefined,\n): Membership[] {\n return (response?.memberships ?? []).flatMap((membership) =>\n (membership.membershipVariants ?? []).map((variant) => ({\n id: membership.id,\n membershipVariantId: variant.id,\n description: variant.description ?? null,\n externalName: variant.externalName,\n imageUrl: variant.imageUrl ?? null,\n internalName: variant.internalName,\n displayName: membership.name,\n })),\n );\n}\n","/**\n * Raw Peek GraphQL query and response shape for memberships. Internal.\n */\n\n/** Fetches all memberships with their variants. */\nexport const MEMBERSHIPS_QUERY = `\n query Sales {\n memberships {\n name\n id\n membershipVariants {\n id\n description\n imageUrl\n externalName\n internalName\n }\n }\n }\n`;\n\n/** A single membership variant node. */\nexport interface MembershipVariantNode {\n id: string;\n description: string | null;\n imageUrl: string | null;\n externalName: string;\n internalName: string;\n}\n\n/** A single membership node as returned by {@link MEMBERSHIPS_QUERY}. */\nexport interface MembershipNode {\n name: string;\n id: string;\n membershipVariants: MembershipVariantNode[];\n}\n\n/** The `data` payload of {@link MEMBERSHIPS_QUERY}. */\nexport interface MembershipsResponse {\n memberships: MembershipNode[];\n}\n\n/** Creates a quote (used here to start a membership purchase). */\nexport const CREATE_QUOTE_V2_MUTATION = `\n mutation CreateQuoteV2($input: CreateQuoteV2Input!) {\n createQuoteV2(input: $input) {\n errors { detail value code }\n quote { id }\n }\n }\n`;\n\n/** Creates a membership order from a quote. */\nexport const CREATE_MEMBERSHIP_ORDER_FROM_QUOTE_MUTATION = `\n mutation CreateOrderFromQuote($input: CreateOrderFromQuoteInput!) {\n createOrderFromQuote(input: $input) {\n errors { code detail value }\n order {\n id\n sales {\n id\n displayId\n ... on SoldMembership {\n id\n displayId\n primaryMember { name id }\n balance { total { amount currency formatted } }\n }\n }\n }\n }\n }\n`;\n\n/** Member details attached to a membership quote. */\nexport interface MembershipMember {\n email: string;\n country?: string;\n formattedAddress?: string;\n membershipCode?: string;\n name?: string;\n phone?: string;\n}\n\ninterface MutationError {\n code: string;\n detail: string;\n value: string | null;\n}\n\n/** `data` payload of {@link CREATE_QUOTE_V2_MUTATION}. */\nexport interface CreateQuoteV2Response {\n createQuoteV2: { errors: MutationError[] | null; quote: { id: string } | null };\n}\n\n/** A sold membership returned by the order mutation. */\nexport interface SoldMembershipSale {\n id: string;\n displayId: string;\n primaryMember?: { id: string; name: string } | null;\n balance?: { total: { amount: string; currency: string; formatted: string } } | null;\n}\n\n/** `data` payload of {@link CREATE_MEMBERSHIP_ORDER_FROM_QUOTE_MUTATION}. */\nexport interface CreateMembershipOrderResponse {\n createOrderFromQuote: {\n errors: MutationError[] | null;\n order: { id: string; sales: SoldMembershipSale[] } | null;\n };\n}\n","/**\n * Membership operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getMembershipService}.\n */\nimport { randomUUID } from \"node:crypto\";\n\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type {\n Membership,\n MembershipPurchaseInput,\n PurchasedMembership,\n} from \"../../../models/peek/membership.js\";\nimport { fromMembershipsResponse } from \"./membership-converter.js\";\nimport {\n CREATE_MEMBERSHIP_ORDER_FROM_QUOTE_MUTATION,\n CREATE_QUOTE_V2_MUTATION,\n MEMBERSHIPS_QUERY,\n type CreateMembershipOrderResponse,\n type CreateQuoteV2Response,\n type MembershipMember,\n type MembershipsResponse,\n} from \"./membership-queries.js\";\n\nconst QUOTE_STATUS_CONFIRMED = \"CONFIRMED\";\nconst DEFAULT_BALANCE_AMOUNT = \"0.00\";\nconst DEFAULT_BALANCE_CURRENCY = \"USD\";\nconst DEFAULT_BALANCE_FORMATTED = \"$0.00\";\nconst EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst COUNTRY_REGEX = /^[A-Z]{2}$/i;\nconst PHONE_REGEX = /^[0-9+\\s()\\-.]+$/;\n\nexport class MembershipService {\n constructor(private readonly client: GraphQLClient) {}\n\n /** Returns all membership variants, flattened into {@link Membership} records. */\n async getAll(): Promise<Membership[]> {\n const body: GraphQLBody<MembershipsResponse> =\n await this.client.request<MembershipsResponse>(SALES_ENDPOINT, MEMBERSHIPS_QUERY, {});\n return fromMembershipsResponse(body.data);\n }\n\n /**\n * Purchases a membership via the two-step quote → order flow. Throws on\n * invalid input or when Peek returns errors.\n */\n async purchase(input: MembershipPurchaseInput): Promise<PurchasedMembership> {\n validatePurchaseInput(input);\n\n const quoteBody: GraphQLBody<CreateQuoteV2Response> =\n await this.client.request<CreateQuoteV2Response>(\n SALES_ENDPOINT,\n CREATE_QUOTE_V2_MUTATION,\n {\n input: {\n quoteInput: {\n membershipQuotes: [\n {\n member: buildMember(input),\n membershipVariantId: input.membershipVariantId,\n refid: randomUUID(),\n status: QUOTE_STATUS_CONFIRMED,\n },\n ],\n },\n },\n },\n );\n\n const quoteResult = quoteBody.data?.createQuoteV2;\n if (quoteResult?.errors && quoteResult.errors.length > 0) {\n throw new Error(`Failed to create membership quote: ${quoteResult.errors[0]!.detail}`);\n }\n const quoteId = quoteResult?.quote?.id;\n if (!quoteId) {\n throw new Error(\"Membership quote created but missing quote id\");\n }\n\n const orderBody: GraphQLBody<CreateMembershipOrderResponse> =\n await this.client.request<CreateMembershipOrderResponse>(\n SALES_ENDPOINT,\n CREATE_MEMBERSHIP_ORDER_FROM_QUOTE_MUTATION,\n { input: { quoteId } },\n );\n\n const orderResult = orderBody.data?.createOrderFromQuote;\n if (orderResult?.errors && orderResult.errors.length > 0) {\n throw new Error(`Failed to create membership order: ${orderResult.errors[0]!.detail}`);\n }\n\n const order = orderResult?.order;\n const sale = order?.sales?.[0];\n if (!order || !sale) {\n throw new Error(\"Membership order created but no sales found\");\n }\n\n return {\n orderId: order.id,\n membershipId: sale.id,\n displayId: sale.displayId,\n primaryMemberId: sale.primaryMember?.id ?? null,\n primaryMemberName: sale.primaryMember?.name ?? null,\n balanceAmount: sale.balance?.total?.amount ?? DEFAULT_BALANCE_AMOUNT,\n balanceCurrency: sale.balance?.total?.currency ?? DEFAULT_BALANCE_CURRENCY,\n balanceFormatted: sale.balance?.total?.formatted ?? DEFAULT_BALANCE_FORMATTED,\n };\n }\n}\n\n/** Builds the GraphQL member, including only non-empty optional fields. */\nfunction buildMember(input: MembershipPurchaseInput): MembershipMember {\n const member: MembershipMember = { email: input.email };\n if (input.country?.trim()) member.country = input.country;\n if (input.formattedAddress?.trim()) member.formattedAddress = input.formattedAddress;\n if (input.membershipCode?.trim()) member.membershipCode = input.membershipCode;\n if (input.name?.trim()) member.name = input.name;\n if (input.phone?.trim()) member.phone = input.phone;\n return member;\n}\n\nfunction validatePurchaseInput(input: MembershipPurchaseInput): void {\n const errors: string[] = [];\n\n if (!input.membershipVariantId || input.membershipVariantId.trim().length === 0) {\n errors.push(\"membershipVariantId is required\");\n }\n if (!input.email || input.email.trim().length === 0) {\n errors.push(\"email is required\");\n } else if (!EMAIL_REGEX.test(input.email)) {\n errors.push(\"email is invalid\");\n }\n if (input.country && !COUNTRY_REGEX.test(input.country)) {\n errors.push(\"country is invalid\");\n }\n if (input.phone && !PHONE_REGEX.test(input.phone)) {\n errors.push(\"phone is invalid\");\n }\n\n if (errors.length > 0) {\n throw new Error(errors.join(\", \"));\n }\n}\n","/**\n * Pure functions mapping raw channel nodes into the clean {@link Channel}\n * model, flattening the agents edge/node structure.\n */\nimport type { Channel } from \"../../../models/peek/channel.js\";\nimport type { ChannelNode, ChannelsResponse } from \"./channel-queries.js\";\n\n/** Converts a channels response into {@link Channel}s. */\nexport function fromChannelsResponse(\n response: ChannelsResponse | undefined,\n): Channel[] {\n return (response?.channels ?? []).map(fromChannelNode);\n}\n\nfunction fromChannelNode(node: ChannelNode): Channel {\n return {\n id: node.id,\n name: node.name,\n notes: node.notes,\n pricingModel: node.pricingModel,\n state: node.state,\n type: node.type,\n agents: (node.agents?.edges ?? []).map((edge) => ({\n email: edge.node.email,\n name: edge.node.name,\n internalNotes: edge.node.internalNotes,\n phone: edge.node.phone,\n })),\n };\n}\n","/**\n * Raw Peek GraphQL query and response shape for reseller channels. Internal.\n *\n * Channels themselves are returned in full; `$first` limits the number of\n * agents fetched per channel.\n */\n\n/** Fetches reseller channels with up to `$first` agents each. */\nexport const CHANNELS_QUERY = `\n query Sales($first: Int) {\n channels {\n id\n agents(first: $first) {\n edges {\n node {\n email\n name\n internalNotes\n phone\n }\n }\n }\n name\n notes\n state\n type\n pricingModel\n }\n }\n`;\n\n/** A single agent node. */\nexport interface AgentNode {\n email: string | null;\n name: string;\n internalNotes: string | null;\n phone: string | null;\n}\n\n/** A single channel node as returned by {@link CHANNELS_QUERY}. */\nexport interface ChannelNode {\n id: string;\n name: string;\n notes: string | null;\n pricingModel: string;\n state: string;\n type: string;\n agents: { edges: Array<{ node: AgentNode }> } | null;\n}\n\n/** The `data` payload of {@link CHANNELS_QUERY}. */\nexport interface ChannelsResponse {\n channels: ChannelNode[];\n}\n","/**\n * Reseller-channel operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getResellerService}.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type { Channel } from \"../../../models/peek/channel.js\";\nimport { fromChannelsResponse } from \"./channel-converter.js\";\nimport { CHANNELS_QUERY, type ChannelsResponse } from \"./channel-queries.js\";\n\n/** Default number of agents fetched per channel. */\nconst DEFAULT_AGENTS_PER_CHANNEL = 10;\n\nexport class ResellerService {\n constructor(private readonly client: GraphQLClient) {}\n\n /**\n * Returns all reseller channels, each with up to `agentsPerChannel` agents\n * (default 10).\n */\n async getAllChannels(\n agentsPerChannel: number = DEFAULT_AGENTS_PER_CHANNEL,\n ): Promise<Channel[]> {\n const body: GraphQLBody<ChannelsResponse> =\n await this.client.request<ChannelsResponse>(SALES_ENDPOINT, CHANNELS_QUERY, {\n first: agentsPerChannel,\n });\n return fromChannelsResponse(body.data);\n }\n}\n","/**\n * Pure functions mapping raw resource-pool nodes into the clean\n * {@link ResourcePool} model.\n */\nimport type {\n ResourcePool,\n ResourcePoolAccountUser,\n} from \"../../../models/peek/resource-pool.js\";\nimport type {\n ResourcePoolNode,\n ResourcePoolsResponse,\n} from \"./resource-pool-queries.js\";\n\n/** Converts a resource-pools response into {@link ResourcePool}s. */\nexport function fromResourcePoolsResponse(\n response: ResourcePoolsResponse | undefined,\n): ResourcePool[] {\n return (response?.resourcePools ?? []).map(fromResourcePoolNode);\n}\n\nfunction fromResourcePoolNode(pool: ResourcePoolNode): ResourcePool {\n return {\n id: pool.id || \"\",\n name: pool.name || \"\",\n imageUrl: pool.imageUrl ?? null,\n mode: pool.mode || \"\",\n colorHex: pool.colorHex ?? null,\n quantity: pool.quantity ?? null,\n category: pool.category || \"\",\n capacity: pool.capacity ?? null,\n resourceTrackingMode: pool.resourceTrackingMode ?? null,\n accountUser: fromAccountUser(pool.accountUser),\n };\n}\n\nfunction fromAccountUser(\n accountUser: { id: string; name: string } | null | undefined,\n): ResourcePoolAccountUser | null {\n if (!accountUser) {\n return null;\n }\n return {\n id: accountUser.id || \"\",\n name: accountUser.name || \"\",\n };\n}\n","/**\n * Raw Peek GraphQL query and response shape for resource pools. Internal.\n */\n\n/** Fetches resource pools matching a mode filter. */\nexport const RESOURCE_POOLS_QUERY = `\n query Sales($filter: ResourcePoolsFilter) {\n resourcePools(filter: $filter) {\n id\n name\n imageUrl\n mode\n colorHex\n quantity\n category\n capacity\n resourceTrackingMode\n accountUser {\n id\n name\n }\n }\n }\n`;\n\n/** A single resource-pool node as returned by {@link RESOURCE_POOLS_QUERY}. */\nexport interface ResourcePoolNode {\n id: string;\n name: string;\n imageUrl: string | null;\n mode: string;\n colorHex: string | null;\n quantity: number | null;\n category: string;\n capacity: number | null;\n resourceTrackingMode: string | null;\n accountUser: { id: string; name: string } | null;\n}\n\n/** The `data` payload of {@link RESOURCE_POOLS_QUERY}. */\nexport interface ResourcePoolsResponse {\n resourcePools: ResourcePoolNode[];\n}\n","/**\n * Resource-pool operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getResourcePoolService}.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type {\n ResourcePool,\n ResourcePoolMode,\n} from \"../../../models/peek/resource-pool.js\";\nimport { fromResourcePoolsResponse } from \"./resource-pool-converter.js\";\nimport {\n RESOURCE_POOLS_QUERY,\n type ResourcePoolsResponse,\n} from \"./resource-pool-queries.js\";\n\n/** Default mode filter (matches the connector). */\nconst DEFAULT_MODE: ResourcePoolMode = \"ALL\";\n\nexport class ResourcePoolService {\n constructor(private readonly client: GraphQLClient) {}\n\n /**\n * Returns all resource pools for the given mode filter (defaults to `\"ALL\"`).\n */\n async getAll(mode: ResourcePoolMode = DEFAULT_MODE): Promise<ResourcePool[]> {\n const body: GraphQLBody<ResourcePoolsResponse> =\n await this.client.request<ResourcePoolsResponse>(\n SALES_ENDPOINT,\n RESOURCE_POOLS_QUERY,\n { filter: { mode } },\n );\n return fromResourcePoolsResponse(body.data);\n }\n}\n","/**\n * Pure, I/O-free mapping from raw review nodes to the clean {@link Review}\n * model. No network, no logging, no clock access.\n */\nimport type {\n Guide,\n ProductReviewSummary,\n Review,\n} from \"../../../models/peek/review.js\";\nimport type {\n ActivityReviewSummaryNode,\n ReviewNode,\n} from \"./review-queries.js\";\n\n/** Length of an ISO `YYYY-MM-DD` date prefix. */\nconst ISO_DATE_LENGTH = 10;\n\n/** Extracts the `YYYY-MM-DD` date prefix from an ISO date-time string. */\nexport function toDateOnly(isoDateTime: string): string {\n return isoDateTime.slice(0, ISO_DATE_LENGTH);\n}\n\n/** Maps a raw review node to the clean {@link Review} model. */\nexport function fromReviewNode(node: ReviewNode): Review {\n const guides: Guide[] = (node.guides ?? []).map((guide) => ({\n id: guide.id,\n name: guide.name,\n }));\n\n return {\n id: node.id,\n productId: node.activity?.id ?? \"\",\n productName: node.activity?.name ?? \"\",\n guides,\n customerName: node.name ?? null,\n customerEmail: node.email ?? null,\n activityDate: toDateOnly(node.purchasedFor),\n reviewDate: toDateOnly(node.reviewedAt),\n rating: node.rating,\n comment: node.comment ?? null,\n };\n}\n\n/**\n * Maps a raw activity node to a clean {@link ProductReviewSummary}. A missing\n * `reviewMeta` (an activity with no reviews) collapses to a null average and\n * zero counts.\n */\nexport function fromActivityReviewSummaryNode(\n node: ActivityReviewSummaryNode,\n): ProductReviewSummary {\n const meta = node.reviewMeta;\n return {\n productId: node.id,\n productName: node.name,\n avgRating: meta?.avgRating ?? null,\n countTotal: meta?.count ?? 0,\n countOneStar: meta?.oneStar ?? 0,\n countTwoStar: meta?.twoStar ?? 0,\n countThreeStar: meta?.threeStar ?? 0,\n countFourStar: meta?.fourStar ?? 0,\n countFiveStar: meta?.fiveStar ?? 0,\n };\n}\n\n/** Maps every activity node to a {@link ProductReviewSummary}. */\nexport function fromActivityReviewSummaryNodes(\n nodes: ActivityReviewSummaryNode[],\n): ProductReviewSummary[] {\n return nodes.map(fromActivityReviewSummaryNode);\n}\n","/**\n * Encode/decode for the Peek reviews connection cursor. Internal.\n *\n * A cursor is the base64 of `range:<start>..<end>,<offset>` where `<offset>` is\n * the **absolute index** of the object in the current result set. {@link\n * encodeCursor} mints the `after` cursor used to skip a fixed number of the\n * newest reviews.\n */\nconst CURSOR_REGEX = /^range:(\\d+)\\.\\.(\\d+),(\\d+)$/;\n\n/** The parsed parts of a reviews cursor. */\nexport interface DecodedCursor {\n /** Inclusive start index of the page window the object belonged to. */\n start: number;\n /** Inclusive end index of the page window the object belonged to. */\n end: number;\n /** Absolute index of the object in the result set. */\n offset: number;\n}\n\n/** Decodes a base64 reviews cursor into its parts. */\nexport function decodeCursor(cursor: string): DecodedCursor {\n const text = Buffer.from(cursor, \"base64\").toString(\"utf8\");\n const match = CURSOR_REGEX.exec(text);\n if (!match) {\n throw new Error(`Unrecognized review cursor: ${cursor}`);\n }\n const [, start, end, offset] = match;\n return { start: Number(start), end: Number(end), offset: Number(offset) };\n}\n\n/** Returns just the absolute offset encoded in a cursor. */\nexport function decodeOffset(cursor: string): number {\n return decodeCursor(cursor).offset;\n}\n\n/**\n * Rebuilds a cursor that points at a given absolute `offset`, mimicking the\n * last edge of a `pageSize` page that ends at `offset`. Used to resume (`after`)\n * pagination from a cached, re-anchored offset. The gateway resolves the next\n * window from the trailing offset.\n */\nexport function encodeCursor(offset: number, pageSize: number): string {\n const start = Math.max(0, offset - pageSize + 1);\n return Buffer.from(`range:${start}..${offset},${offset}`).toString(\"base64\");\n}\n","/**\n * Raw Peek GraphQL query and response shapes for activity reviews. Internal —\n * never re-exported from the public barrel.\n */\n\n/**\n * Fetches a page of reviews, newest-first, optionally filtered by activity and\n * resumed from a cursor. The gateway returns up to `first` reviews per page in\n * descending `reviewedAt` order; pagination walks backwards in time via the\n * last edge's `cursor` as the next `after`.\n */\n/**\n * Builds the reviews query. Without `fullCustomerAccess`, the reviewer's `name` and\n * `email` are not requested (they come back absent → `null` in the converter);\n * the review `comment`, rating, dates, and credited guides are always selected.\n */\nexport function buildReviewsQuery(fullCustomerAccess: boolean): string {\n return `\n query Reviews($first: Int, $filter: ReviewFilter, $after: String) {\n reviews(first: $first, filter: $filter, after: $after) {\n edges {\n node {\n activity {\n id\n name\n }\n guides {\n id\n name\n }\n id\n ${fullCustomerAccess ? \"name\\n email\" : \"\"}\n rating\n comment\n reviewedAt\n purchasedFor\n }\n cursor\n }\n }\n }\n`;\n}\n\n/** A guide node as returned by the gateway. */\nexport interface ReviewGuideNode {\n id: string;\n name: string;\n}\n\n/** A single review node as returned by the gateway. */\nexport interface ReviewNode {\n activity: { id: string; name: string } | null;\n guides: ReviewGuideNode[] | null;\n id: string;\n name: string | null;\n email: string | null;\n rating: number;\n comment: string | null;\n reviewedAt: string;\n purchasedFor: string;\n}\n\n/** A single edge in the reviews connection. */\nexport interface ReviewEdge {\n node: ReviewNode;\n cursor: string;\n}\n\n/** `data` payload of {@link buildReviewsQuery}. */\nexport interface ReviewsResponse {\n reviews: { edges: ReviewEdge[] } | null;\n}\n\n/**\n * Fetches every activity with its aggregate review statistics. The `activities`\n * connection is the same list `getAllProducts` reads; here only the id, name,\n * and `reviewMeta` rating distribution are selected. Carries no PII, so it is\n * unaffected by `fullCustomerAccess`.\n */\nexport const REVIEW_SUMMARIES_QUERY = `\n query ReviewSummaries {\n activities {\n id\n name\n reviewMeta {\n avgRating\n count\n fiveStar\n fourStar\n threeStar\n twoStar\n oneStar\n }\n }\n }\n`;\n\n/** An activity's aggregate review statistics as returned by the gateway. */\nexport interface ReviewMetaNode {\n avgRating: number | null;\n count: number;\n fiveStar: number;\n fourStar: number;\n threeStar: number;\n twoStar: number;\n oneStar: number;\n}\n\n/** A single activity node as returned by {@link REVIEW_SUMMARIES_QUERY}. */\nexport interface ActivityReviewSummaryNode {\n id: string;\n name: string;\n reviewMeta: ReviewMetaNode | null;\n}\n\n/** The `data` payload of {@link REVIEW_SUMMARIES_QUERY}. */\nexport interface ReviewSummariesResponse {\n activities: ActivityReviewSummaryNode[];\n}\n\n/** Variables for {@link buildReviewsQuery}. */\nexport interface ReviewsVariables {\n first: number;\n filter: { activityIds: string[] };\n after: string | null;\n}\n\n/** Builds the variables for {@link buildReviewsQuery}. */\nexport function buildReviewsVariables(params: {\n activityId: string;\n first: number;\n after: string | null;\n}): ReviewsVariables {\n return {\n first: params.first,\n filter: { activityIds: [params.activityId] },\n after: params.after,\n };\n}\n","/**\n * Review operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getReviewService}.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type {\n ProductReviewSummary,\n Review,\n} from \"../../../models/peek/review.js\";\nimport {\n resolveAccessOptions,\n type AccessOptions,\n} from \"../../../access-options.js\";\nimport {\n fromActivityReviewSummaryNodes,\n fromReviewNode,\n} from \"./review-converter.js\";\nimport { encodeCursor } from \"./review-cursor.js\";\nimport {\n buildReviewsQuery,\n buildReviewsVariables,\n REVIEW_SUMMARIES_QUERY,\n type ReviewsResponse,\n type ReviewSummariesResponse,\n} from \"./review-queries.js\";\n\n/** Number of reviews returned when `reviewCount` is omitted. */\nconst DEFAULT_REVIEW_COUNT = 50;\n/** Smallest allowed `reviewCount`. */\nconst MIN_REVIEW_COUNT = 1;\n/** Largest allowed `reviewCount` (a single gateway page). */\nconst MAX_REVIEW_COUNT = 50;\n\nconst ERROR_PRODUCT_ID_REQUIRED = \"productId is required\";\nconst ERROR_INVALID_REVIEW_COUNT = `reviewCount must be an integer between ${MIN_REVIEW_COUNT} and ${MAX_REVIEW_COUNT}`;\nconst ERROR_INVALID_REVIEW_OFFSET = \"reviewOffset must be a non-negative integer\";\n\n/**\n * Reads activity reviews from the gateway, which returns them newest-first\n * (descending `reviewedAt`). {@link ReviewService.getReviews} fetches a single\n * page of up to `reviewCount` reviews, skipping the first `reviewOffset` of\n * them via the connection cursor.\n *\n * Obtain an instance via {@link PeekAccessService.getReviewService}.\n */\nexport class ReviewService {\n /** Whether reviewer PII (name/email) is requested. */\n private readonly fullCustomerAccess: boolean;\n\n constructor(\n private readonly client: GraphQLClient,\n accessOptions?: AccessOptions,\n ) {\n this.fullCustomerAccess = resolveAccessOptions(accessOptions).fullCustomerAccess;\n }\n\n /**\n * Returns up to `reviewCount` reviews for an activity in **descending order\n * by review date (newest first)**, skipping the `reviewOffset` newest reviews\n * before collecting.\n *\n * The gateway cursor resumes *after* a given absolute offset, so to skip the\n * first `reviewOffset` reviews the request is anchored on the review just\n * before the window. A `reviewOffset` of 0 needs no cursor and is sent\n * without one.\n *\n * @param productId - The activity (product) id to fetch reviews for.\n * @param reviewCount - How many reviews to return (1–50). Default: 50.\n * @param reviewOffset - How many of the newest reviews to skip first\n * (0-based). Default: 0 (start at the newest review).\n *\n * @throws {Error} when `productId` is empty, `reviewCount` is not an integer\n * in 1–50, or `reviewOffset` is not a non-negative integer.\n *\n * @example\n * ```ts\n * const reviews = await peek\n * .getReviewService()\n * .getReviews(\"87cdf37f-1872-42cb-b0bd-518312624fc1\", 25, 50);\n * ```\n */\n async getReviews(\n productId: string,\n reviewCount: number = DEFAULT_REVIEW_COUNT,\n reviewOffset = 0,\n ): Promise<Review[]> {\n this.validate(productId, reviewCount, reviewOffset);\n\n const after =\n reviewOffset > 0 ? encodeCursor(reviewOffset - 1, reviewCount) : null;\n\n const body: GraphQLBody<ReviewsResponse> =\n await this.client.request<ReviewsResponse>(\n SALES_ENDPOINT,\n buildReviewsQuery(this.fullCustomerAccess),\n buildReviewsVariables({ activityId: productId, first: reviewCount, after }),\n );\n\n const edges = body.data?.reviews?.edges ?? [];\n return edges.map((edge) => fromReviewNode(edge.node));\n }\n\n /**\n * Returns an aggregate review summary for **every** activity — its average\n * rating and the count of reviews at each star level. This reads the same\n * activity list as `getAllProducts`; it carries no per-review detail or PII, so\n * it is unaffected by `fullCustomerAccess`. An activity with no reviews comes\n * back with a `null` `avgRating` and zero counts.\n *\n * @example\n * ```ts\n * const summaries = await peek.getReviewService().getAllReviewSummaries();\n * for (const s of summaries) {\n * console.log(s.productName, s.avgRating, s.countTotal);\n * }\n * ```\n */\n async getAllReviewSummaries(): Promise<ProductReviewSummary[]> {\n const body: GraphQLBody<ReviewSummariesResponse> =\n await this.client.request<ReviewSummariesResponse>(\n SALES_ENDPOINT,\n REVIEW_SUMMARIES_QUERY,\n {},\n );\n\n return fromActivityReviewSummaryNodes(body.data?.activities ?? []);\n }\n\n private validate(\n productId: string,\n reviewCount: number,\n reviewOffset: number,\n ): void {\n if (!productId) {\n throw new Error(ERROR_PRODUCT_ID_REQUIRED);\n }\n if (\n !Number.isInteger(reviewCount) ||\n reviewCount < MIN_REVIEW_COUNT ||\n reviewCount > MAX_REVIEW_COUNT\n ) {\n throw new Error(ERROR_INVALID_REVIEW_COUNT);\n }\n if (!Number.isInteger(reviewOffset) || reviewOffset < 0) {\n throw new Error(ERROR_INVALID_REVIEW_OFFSET);\n }\n }\n}\n","/**\n * Pure functions mapping raw timeslot nodes into the clean {@link Timeslot}\n * model.\n */\nimport type { AssignedResource, Timeslot } from \"../../../models/peek/timeslot.js\";\nimport type {\n TimeslotNode,\n TimeslotResourceAllocationNode,\n} from \"./timeslot-queries.js\";\n\n/** Converts a list of timeslot nodes for the given activity into {@link Timeslot}s. */\nexport function fromTimeslotNodes(\n nodes: Array<TimeslotNode | null>,\n productId: string,\n): Timeslot[] {\n if (!Array.isArray(nodes) || nodes.length === 0) {\n return [];\n }\n return nodes.map((node) => fromTimeslotNode(node, productId));\n}\n\n/** Converts a single timeslot node into a {@link Timeslot}. A missing node yields a zeroed timeslot. */\nexport function fromTimeslotNode(\n node: TimeslotNode | null | undefined,\n productId: string,\n): Timeslot {\n if (!node) {\n return {\n id: \"\",\n productId,\n totalCapacity: 0,\n availableCapacity: 0,\n maxPartySize: 0,\n bookingCount: 0,\n checkedInCount: 0,\n status: \"\",\n notes: null,\n durationMin: 0,\n date: \"\",\n startTime: null,\n assignedResources: [],\n };\n }\n\n return {\n id: node.id || \"\",\n productId,\n totalCapacity: node.totalCapacity ?? 0,\n availableCapacity: node.availableSpots ?? 0,\n maxPartySize: node.maxPartySize ?? 0,\n bookingCount: node.bookingCount ?? 0,\n checkedInCount: node.checkedInCount ?? 0,\n status: node.status || \"\",\n notes: node.manifestNotes ?? null,\n durationMin: node.minuteLength ?? 0,\n date: node.date || \"\",\n startTime: node.start ?? null,\n assignedResources: mapAssignedResources(selectResourceAllocations(node)),\n };\n}\n\n/** Only allocations with this status are considered assigned. */\nconst ACTIVE_ALLOCATION_STATUS = \"ACTIVE\";\n\n/**\n * Timeslots may carry both inherited (schedule-level) and directly-assigned\n * resource allocations. Prefer inherited; fall back to the regular allocations\n * only when the inherited field is absent or empty.\n */\nfunction selectResourceAllocations(\n node: TimeslotNode,\n): TimeslotResourceAllocationNode[] | null | undefined {\n const inherited = node.inheritedResourceAllocations;\n if (Array.isArray(inherited) && inherited.length > 0) {\n return inherited;\n }\n return node.resourceAllocations;\n}\n\nfunction mapAssignedResources(\n allocations: TimeslotResourceAllocationNode[] | null | undefined,\n): AssignedResource[] {\n if (!Array.isArray(allocations) || allocations.length === 0) {\n return [];\n }\n\n return allocations\n .filter((allocation) => allocation.status === ACTIVE_ALLOCATION_STATUS)\n .map((allocation) => {\n const pool = allocation.resourcePool;\n return {\n name: pool?.name || \"\",\n capacity: pool?.capacity ?? 0,\n category: pool?.category || \"\",\n quantity: allocation.quantity ?? 0,\n accountUserId: pool?.accountUser?.id ?? null,\n };\n });\n}\n","/**\n * Pure guide-matching logic: resolves a caller-supplied guide identifier to a\n * resource-pool id. A guide may be referenced by resource-pool id, by backing\n * account-user id, or by name (directly or via an account user).\n */\nimport type { ResourcePool } from \"../../../models/peek/resource-pool.js\";\n\n/**\n * Resolves a `guideId` to a resource-pool id using `guideResourcePools`\n * (resource pools already filtered to the guide category) and `accountUsers`.\n * Returns the matched pool id, or `null` when nothing matches.\n */\nexport function matchGuideToResourcePool(\n guideId: string,\n guideResourcePools: ResourcePool[],\n accountUsers: Array<{ id: string; name: string }>,\n): string | null {\n // Direct resource-pool id match.\n const directIdMatch = guideResourcePools.find((pool) => pool.id === guideId);\n if (directIdMatch) {\n return directIdMatch.id;\n }\n\n // Match by backing account-user id.\n const accountUserMatch = guideResourcePools.find(\n (pool) => pool.accountUser?.id === guideId,\n );\n if (accountUserMatch) {\n return accountUserMatch.id;\n }\n\n // Match by pool name.\n const nameMatch = guideResourcePools.find((pool) => pool.name === guideId);\n if (nameMatch) {\n return nameMatch.id;\n }\n\n // Resolve via an account user, then match its pool by id or name.\n const matchedUser = accountUsers.find((user) => user.id === guideId);\n if (matchedUser) {\n const userIdMatch = guideResourcePools.find(\n (pool) => pool.accountUser?.id === matchedUser.id,\n );\n /* v8 ignore next 3 -- unreachable: the earlier account-user id match already\n returns when a pool's accountUser.id equals the guideId; kept for source parity. */\n if (userIdMatch) {\n return userIdMatch.id;\n }\n\n const userNameMatch = guideResourcePools.find(\n (pool) => pool.name === matchedUser.name,\n );\n if (userNameMatch) {\n return userNameMatch.id;\n }\n }\n\n return null;\n}\n","/**\n * Raw Peek GraphQL mutation and shapes for bulk resource-allocation requests\n * (used by guide assignment). Internal.\n */\n\n/** Bulk-(un)assigns resources (e.g. guides) to timeslots. */\nexport const RESOURCE_ALLOCATION_BULK_REQUEST_MUTATION = `\n mutation ResourceAllocationBulkRequest($input: ResourceAllocationBulkRequestInput!) {\n resourceAllocationBulkRequest(input: $input) {\n __typename\n ... on ResourceAllocationRequest {\n id\n }\n ... on GenericError {\n __typename\n message\n }\n }\n }\n`;\n\n/** Allocation status: assigning (`ACTIVE`) or unassigning (`REMOVAL`). */\nexport type ResourceAllocationStatus = \"ACTIVE\" | \"REMOVAL\";\n\n/** `data` payload of {@link RESOURCE_ALLOCATION_BULK_REQUEST_MUTATION}. */\nexport interface ResourceAllocationBulkRequestResponse {\n resourceAllocationBulkRequest:\n | { __typename: \"ResourceAllocationRequest\"; id: string }\n | { __typename: \"GenericError\"; message: string };\n}\n\n/** Builds the variables for {@link RESOURCE_ALLOCATION_BULK_REQUEST_MUTATION}. */\nexport function buildResourceAllocationVariables(\n timeslotIds: string[],\n resourcePoolIds: string[],\n status: ResourceAllocationStatus,\n): { input: { timeslotIds: string[]; resourcePoolIds: string[]; status: ResourceAllocationStatus } } {\n return { input: { timeslotIds, resourcePoolIds, status } };\n}\n","/**\n * Raw Peek GraphQL queries/mutations and response shapes for timeslots.\n * Internal.\n */\nimport type { TimeslotFilter } from \"../../../models/peek/timeslot.js\";\n\n/** Fetches timeslots for an activity/date via a filter. */\nexport const TIMESLOTS_QUERY = `\n query Sales($params: TimeslotsFilter!) {\n timeslots(filter: $params) {\n ... on TimeslotsSuccess {\n timeslots {\n id\n bookingCount\n availableSpots\n maxPartySize\n totalCapacity\n checkedInCount\n manifestNotes\n minuteLength\n status\n date\n inheritedResourceAllocations {\n id\n status\n quantity\n resourcePool {\n id\n name\n category\n capacity\n accountUser {\n id\n }\n }\n }\n resourceAllocations {\n quantity\n status\n resourcePool {\n id\n name\n category\n capacity\n accountUser {\n id\n }\n }\n }\n ... on VariableTimeslot {\n start\n }\n ... on FixedTimeslot {\n start\n }\n }\n }\n }\n }\n`;\n\n/** Fetches a single timeslot by id. */\nexport const TIMESLOT_BY_ID_QUERY = `\n query Sales($id: ID!) {\n timeslot(id: $id) {\n ... on ActivityTimeslotSuccess {\n timeslot {\n id\n bookingCount\n availableSpots\n maxPartySize\n totalCapacity\n checkedInCount\n manifestNotes\n minuteLength\n status\n date\n inheritedResourceAllocations {\n id\n status\n quantity\n resourcePool {\n id\n name\n category\n capacity\n accountUser {\n id\n }\n }\n }\n resourceAllocations {\n quantity\n status\n resourcePool {\n id\n name\n category\n capacity\n accountUser {\n id\n }\n }\n }\n ... on VariableTimeslot {\n start\n }\n ... on FixedTimeslot {\n start\n }\n }\n }\n }\n }\n`;\n\n/** Updates a timeslot's manifest notes and/or status. */\nexport const UPDATE_TIMESLOT_MUTATION = `\n mutation Account($input: UpdateTimeslotInput!) {\n updateTimeslot(input: $input) {\n ... on UpdateTimeslotSuccess {\n timeslot {\n id\n manifestNotes\n status\n }\n }\n }\n }\n`;\n\n/**\n * A single resource allocation on a timeslot node. Shared by both the\n * `inheritedResourceAllocations` and `resourceAllocations` selections; the\n * allocation-level `id` is only present on the inherited variant.\n */\nexport interface TimeslotResourceAllocationNode {\n id?: string | null;\n quantity: number | null;\n status: string | null;\n resourcePool: {\n id: string;\n name: string;\n category: string;\n capacity: number | null;\n accountUser: { id: string } | null;\n } | null;\n}\n\n/** A single timeslot node as returned by the timeslot queries. */\nexport interface TimeslotNode {\n id: string;\n bookingCount: number | null;\n availableSpots: number | null;\n maxPartySize: number | null;\n totalCapacity: number | null;\n checkedInCount: number | null;\n manifestNotes: string | null;\n minuteLength: number | null;\n status: string | null;\n date: string | null;\n start?: string | null;\n inheritedResourceAllocations: TimeslotResourceAllocationNode[] | null;\n resourceAllocations: TimeslotResourceAllocationNode[] | null;\n}\n\n/** `data` payload of {@link TIMESLOTS_QUERY}. */\nexport interface TimeslotsResponse {\n timeslots: { timeslots: TimeslotNode[] };\n}\n\n/** `data` payload of {@link TIMESLOT_BY_ID_QUERY}. */\nexport interface SingleTimeslotResponse {\n timeslot: { timeslot: TimeslotNode | null } | null;\n}\n\n/** `data` payload of {@link UPDATE_TIMESLOT_MUTATION}. */\nexport interface UpdateTimeslotResponse {\n updateTimeslot: {\n timeslot: { id: string; manifestNotes: string | null; status: string | null };\n };\n}\n\n/** Input for {@link UPDATE_TIMESLOT_MUTATION}. */\nexport interface UpdateTimeslotInput {\n id: string;\n manifestNotes?: string;\n status?: string;\n}\n\n/** Builds the variables for {@link TIMESLOTS_QUERY}. */\nexport function buildTimeslotVariables(\n productId: string,\n date: string,\n filter: TimeslotFilter,\n): { params: { activityIds: string[]; dateRange: string; hasBookings?: boolean } } {\n const params: {\n activityIds: string[];\n dateRange: string;\n hasBookings?: boolean;\n } = {\n activityIds: [productId],\n dateRange: `[${date},${date}]`,\n };\n\n if (filter === \"withBookings\") {\n params.hasBookings = true;\n } else if (filter === \"withoutBookings\") {\n params.hasBookings = false;\n }\n\n return { params };\n}\n","/**\n * Timeslot operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getTimeslotService}. The\n * `assignGuide` operation composes the resource-pool and account-user services\n * to resolve guides before issuing the allocation request.\n */\nimport type { AccountUserService } from \"../account-users/account-user-service.js\";\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type { ResourcePoolService } from \"../resource-pools/resource-pool-service.js\";\nimport type {\n AssignGuideResult,\n GuideAssignment,\n Timeslot,\n TimeslotFilter,\n UpdateTimeslotResult,\n} from \"../../../models/peek/timeslot.js\";\nimport { fromTimeslotNode, fromTimeslotNodes } from \"./timeslot-converter.js\";\nimport { matchGuideToResourcePool } from \"./guide-matcher.js\";\nimport {\n RESOURCE_ALLOCATION_BULK_REQUEST_MUTATION,\n buildResourceAllocationVariables,\n type ResourceAllocationBulkRequestResponse,\n type ResourceAllocationStatus,\n} from \"./resource-allocation-queries.js\";\nimport {\n TIMESLOTS_QUERY,\n TIMESLOT_BY_ID_QUERY,\n UPDATE_TIMESLOT_MUTATION,\n buildTimeslotVariables,\n type SingleTimeslotResponse,\n type TimeslotsResponse,\n type UpdateTimeslotInput,\n type UpdateTimeslotResponse,\n} from \"./timeslot-queries.js\";\n\nconst GUIDE_CATEGORY = \"guide\";\nconst ERROR_MISSING_TIMESLOTS_OR_GUIDES =\n \"At least one timeslot and one guide are required\";\nconst ERROR_INVALID_ACTION = \"Invalid action. Must be either assign or unassign\";\nconst ERROR_GUIDE_NOT_FOUND = \"Guide not found\";\n\n/** Dependencies the {@link TimeslotService} composes for guide assignment. */\nexport interface TimeslotServiceDeps {\n resourcePoolService: ResourcePoolService;\n accountUserService: AccountUserService;\n}\n\nexport class TimeslotService {\n constructor(\n private readonly client: GraphQLClient,\n private readonly deps: TimeslotServiceDeps,\n ) {}\n\n /** Returns the timeslots for an activity on a given date. */\n async getForDay(\n productId: string,\n date: string,\n filter: TimeslotFilter = \"all\",\n ): Promise<Timeslot[]> {\n const normalizedDate = normalizeDate(date);\n const body: GraphQLBody<TimeslotsResponse> =\n await this.client.request<TimeslotsResponse>(\n SALES_ENDPOINT,\n TIMESLOTS_QUERY,\n buildTimeslotVariables(productId, normalizedDate, filter),\n );\n\n return fromTimeslotNodes(body.data?.timeslots?.timeslots ?? [], productId);\n }\n\n /** Returns a single timeslot by id, or null when not found. */\n async getById(timeslotId: string): Promise<Timeslot | null> {\n const body: GraphQLBody<SingleTimeslotResponse> =\n await this.client.request<SingleTimeslotResponse>(\n SALES_ENDPOINT,\n TIMESLOT_BY_ID_QUERY,\n { id: timeslotId },\n );\n\n const node = body.data?.timeslot?.timeslot;\n if (!node) {\n return null;\n }\n return fromTimeslotNode(node, extractProductId(timeslotId));\n }\n\n /** Sets the timeslot's status (e.g. open/closed). */\n async setAvailability(\n timeslotId: string,\n status: string,\n ): Promise<UpdateTimeslotResult> {\n return this.updateTimeslot({ id: timeslotId, status });\n }\n\n /** Sets the timeslot's manifest notes. */\n async setNotes(\n timeslotId: string,\n manifestNotes: string,\n ): Promise<UpdateTimeslotResult> {\n return this.updateTimeslot({ id: timeslotId, manifestNotes });\n }\n\n /**\n * Assigns or unassigns guides across timeslots. Guides are resolved to\n * resource pools (by pool id, account-user id, or name) before the bulk\n * allocation request is issued.\n *\n * @example\n * ```ts\n * await peek.getTimeslotService().assignGuide({\n * timeslotIds: [\"ts_2026_06_20_0900\"],\n * guideIds: [\"Alex Guide\"], // pool id, account-user id, or name\n * action: \"assign\",\n * });\n * ```\n */\n async assignGuide(assignment: GuideAssignment): Promise<AssignGuideResult> {\n const { timeslotIds, guideIds, action } = assignment;\n\n if (!timeslotIds?.length || !guideIds?.length) {\n throw new Error(ERROR_MISSING_TIMESLOTS_OR_GUIDES);\n }\n if (action !== \"assign\" && action !== \"unassign\") {\n throw new Error(ERROR_INVALID_ACTION);\n }\n\n const [allPools, accountUsers] = await Promise.all([\n this.deps.resourcePoolService.getAll(),\n this.deps.accountUserService.getAll(),\n ]);\n const guidePools = allPools.filter((pool) => pool.category === GUIDE_CATEGORY);\n\n const resourcePoolIds = guideIds.map((guideId) => {\n const matched = matchGuideToResourcePool(guideId, guidePools, accountUsers);\n if (!matched) {\n throw new Error(`${ERROR_GUIDE_NOT_FOUND}: ${guideId}`);\n }\n return matched;\n });\n\n const status: ResourceAllocationStatus =\n action === \"assign\" ? \"ACTIVE\" : \"REMOVAL\";\n\n const body: GraphQLBody<ResourceAllocationBulkRequestResponse> =\n await this.client.request<ResourceAllocationBulkRequestResponse>(\n SALES_ENDPOINT,\n RESOURCE_ALLOCATION_BULK_REQUEST_MUTATION,\n buildResourceAllocationVariables(timeslotIds, resourcePoolIds, status),\n );\n\n const result = body.data?.resourceAllocationBulkRequest;\n if (result?.__typename === \"ResourceAllocationRequest\") {\n return {\n status: \"success\",\n resourceAllocationRequestId: result.id,\n errors: null,\n };\n }\n\n return {\n status: \"error\",\n resourceAllocationRequestId: null,\n errors: [{ message: result?.message ?? \"Unknown error\" }],\n };\n }\n\n private async updateTimeslot(\n input: UpdateTimeslotInput,\n ): Promise<UpdateTimeslotResult> {\n const body: GraphQLBody<UpdateTimeslotResponse> =\n await this.client.request<UpdateTimeslotResponse>(\n SALES_ENDPOINT,\n UPDATE_TIMESLOT_MUTATION,\n { input },\n );\n\n const timeslot = body.data?.updateTimeslot?.timeslot;\n return {\n manifestNotes: timeslot?.manifestNotes ?? null,\n status: timeslot?.status ?? null,\n };\n }\n}\n\n/** Activity timeslot ids are `\"<activityId>|...\"`; the activity id is the product id. */\nfunction extractProductId(timeslotId: string): string {\n /* v8 ignore next -- split always yields at least one element */\n return timeslotId.split(\"|\")[0] ?? \"\";\n}\n\n/** Timeslot day queries expect a `YYYY-MM-DD` date; drop any time component. */\nfunction normalizeDate(date: string): string {\n /* v8 ignore next -- split always yields at least one element */\n return date.split(\"T\")[0] ?? date;\n}\n","/**\n * Shared, pure helper for mapping a raw gateway money node\n * (`{ amount, currency, formatted }`) into the clean {@link PricingMoney} model.\n *\n * Internal only — never re-exported from `src/index.ts`. Converters across\n * resources (products, pricing overrides) reuse this so the `formatted →\n * displayPrice` mapping lives in exactly one place.\n */\nimport type { PricingMoney } from \"../../models/peek/pricing.js\";\n\n/** A raw money node as returned by the gateway. */\nexport interface RawMoney {\n amount: string;\n currency: string;\n /** Human-formatted display string (e.g. `\"$50.00\"`). */\n formatted?: string | null;\n}\n\n/**\n * Maps a raw money node into a {@link PricingMoney}, carrying the gateway's\n * `formatted` string across as `displayPrice`. Returns `null` for an\n * absent/`null` input so callers can pass an optional wire field straight\n * through.\n */\nexport function toPricingMoney(raw?: RawMoney | null): PricingMoney | null {\n if (!raw) return null;\n const money: PricingMoney = { amount: raw.amount, currency: raw.currency };\n if (raw.formatted != null) money.displayPrice = raw.formatted;\n return money;\n}\n","/**\n * Pure functions that map raw Peek GraphQL nodes into the clean {@link Product}\n * model. No I/O — straightforward, testable transformations.\n */\nimport {\n ADD_ON_PRODUCT_TYPE,\n type Product,\n type ProductMeetingLocation,\n} from \"../../../models/peek/product.js\";\nimport { toPricingMoney } from \"../money.js\";\nimport type { ActivityNode, ItemOptionNode } from \"./product-queries.js\";\n\n/** Default display color applied to add-on products. */\nconst ADD_ON_COLOR = \"#FFFFFF\";\n\n/**\n * Builds a {@link ProductMeetingLocation} from the flat activity fields,\n * collapsing to `null` when Peek reports no location detail at all. Each field\n * is independently nullable.\n */\nfunction toMeetingLocation(activity: ActivityNode): ProductMeetingLocation | null {\n const summary = activity.infoMeetingLocation ?? null;\n const address = activity.meetingLocationFormattedAddress ?? null;\n const url = activity.meetingLocationUrl ?? null;\n if (summary === null && address === null && url === null) return null;\n return { summary, address, url };\n}\n\n/** Converts the activities from a products response into {@link Product}s. */\nexport function fromActivities(activities: ActivityNode[]): Product[] {\n return activities.map(fromActivity);\n}\n\n/** Converts a single activity node into a {@link Product}. */\nfunction fromActivity(activity: ActivityNode): Product {\n return {\n // Prefer the primary GraphQL ID for stable product identity.\n productId: activity.id || activity.legacyId || \"\",\n name: activity.name,\n type: activity.type,\n color: activity.colorHex || \"\",\n currency: activity.currency || \"\",\n imageUrl: activity.imageUrl ?? null,\n description: activity.description ?? null,\n meetingLocation: toMeetingLocation(activity),\n tickets: (activity.resourceOptions ?? []).map((option) => ({\n id: option.id,\n name: option.name,\n minPrice: toPricingMoney(option.priceRange?.min),\n maxPrice: toPricingMoney(option.priceRange?.max),\n })),\n };\n}\n\n/**\n * Converts a flat list of item option nodes into add-on {@link Product}s by\n * grouping each option under its parent item. The parent item id becomes the\n * `productId` and its name becomes the product `name`; each option becomes a\n * ticket.\n */\nexport function fromItemOptionNodes(nodes: ItemOptionNode[]): Product[] {\n const grouped = new Map<string, Product>();\n\n for (const node of nodes) {\n const itemId = node.item?.id;\n if (!itemId) continue;\n\n let product = grouped.get(itemId);\n if (!product) {\n product = {\n productId: itemId,\n name: node.item.name,\n type: ADD_ON_PRODUCT_TYPE,\n color: ADD_ON_COLOR,\n currency: \"\",\n imageUrl: null,\n description: null,\n meetingLocation: null,\n tickets: [],\n };\n grouped.set(itemId, product);\n }\n product.tickets.push({\n id: node.id,\n name: node.name,\n minPrice: null,\n maxPrice: null,\n });\n }\n\n return Array.from(grouped.values());\n}\n","/**\n * Pure functions that map raw Peek question configuration nodes into the clean\n * {@link CustomQuestion} model. No I/O — straightforward, testable transforms.\n */\nimport type {\n CustomQuestion,\n CustomQuestionOption,\n} from \"../../../models/peek/custom-question.js\";\nimport type {\n QuestionConfigurationNode,\n RawQuestionOptionNode,\n} from \"./custom-question-queries.js\";\n\n/** Converts an activity's question configurations into {@link CustomQuestion}s. */\nexport function fromQuestionConfigurations(\n configs: QuestionConfigurationNode[],\n): CustomQuestion[] {\n return configs.map(fromQuestionConfiguration);\n}\n\n/** Converts a single question configuration node into a {@link CustomQuestion}. */\nfunction fromQuestionConfiguration(\n config: QuestionConfigurationNode,\n): CustomQuestion {\n const question = config.question;\n return {\n id: question.id,\n order: config.order ?? 0,\n isRequired: config.isRequired ?? false,\n questionText: question.text,\n hintText: question.hint ?? null,\n questionType: question.questionType,\n internalLabel: question.internalLabel ?? null,\n perGuest: question.perGuest ?? false,\n defaultValue: question.answerDefaultValue ?? null,\n options: (question.options ?? []).map(fromQuestionOption),\n };\n}\n\n/** Converts a raw choice-question option node into a {@link CustomQuestionOption}. */\nfunction fromQuestionOption(\n option: RawQuestionOptionNode,\n): CustomQuestionOption {\n return {\n id: option.id,\n order: option.order,\n value: option.text,\n };\n}\n","/**\n * Raw Peek GraphQL queries and response shapes for products. These are an\n * internal implementation detail of the package and are deliberately not\n * re-exported from the public entry point.\n */\n\n/** Fetches all activities (primary bookable products). */\nexport const PRODUCTS_QUERY = `\n query Sales {\n activities {\n name\n legacyId\n id\n deletedAt\n type\n colorHex\n currency\n imageUrl\n description\n meetingLocationFormattedAddress\n meetingLocationUrl\n infoMeetingLocation\n resourceOptions {\n id\n name\n priceRange {\n min {\n currency\n amount\n formatted\n }\n max {\n currency\n amount\n formatted\n }\n }\n }\n }\n }\n`;\n\n/** A raw monetary value on the wire (a `PricingMoney` before conversion). */\nexport interface RawMoneyNode {\n currency: string;\n amount: string;\n formatted?: string;\n}\n\n/** A single activity node as returned by {@link PRODUCTS_QUERY}. */\nexport interface ActivityNode {\n name: string;\n legacyId?: string;\n id: string;\n deletedAt?: string | null;\n type: string;\n colorHex: string;\n currency?: string;\n imageUrl?: string | null;\n description?: string | null;\n meetingLocationFormattedAddress?: string | null;\n meetingLocationUrl?: string | null;\n infoMeetingLocation?: string | null;\n resourceOptions: Array<{\n id: string;\n name: string;\n priceRange?: { min?: RawMoneyNode | null; max?: RawMoneyNode | null } | null;\n }>;\n}\n\n/** The `data` payload of {@link PRODUCTS_QUERY}. */\nexport interface ProductsResponse {\n activities: ActivityNode[];\n}\n\n/** Fetches a single cursor-paginated page of item options (add-ons). */\nexport const ITEM_OPTIONS_QUERY = `\n query GetItemOptions($first: Int, $after: String) {\n itemOptions(first: $first, after: $after) {\n edges {\n cursor\n node {\n id\n name\n description\n item {\n id\n name\n }\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n`;\n\n/** A single item option node as returned by {@link ITEM_OPTIONS_QUERY}. */\nexport interface ItemOptionNode {\n id: string;\n name: string;\n description: string | null;\n item: {\n id: string;\n name: string;\n };\n}\n\n/** The `data` payload of {@link ITEM_OPTIONS_QUERY}. */\nexport interface ItemOptionsData {\n itemOptions: {\n edges: Array<{ cursor: string; node: ItemOptionNode }>;\n pageInfo: {\n hasNextPage: boolean;\n endCursor: string | null;\n };\n };\n}\n","/**\n * Raw Peek GraphQL query and response shapes for an activity's custom\n * questions. These are an internal implementation detail of the package and are\n * deliberately not re-exported from the public entry point.\n */\n\n/** Fetches every custom question configured on a single activity. */\nexport const CUSTOM_QUESTIONS_QUERY = `\n query Sales($id: ID!) {\n activity(id: $id) {\n id\n name\n questionActivityConfigurations {\n isRequired\n order\n question {\n id\n questionType\n text\n answerDefaultValue\n hint\n internalLabel\n perGuest\n ... on ChoiceQuestion {\n options {\n id\n text\n order\n }\n }\n }\n }\n }\n }\n`;\n\n/** A single selectable option on a raw `ChoiceQuestion` node. */\nexport interface RawQuestionOptionNode {\n id: string;\n text: string;\n order: number;\n}\n\n/** A raw question node as returned inside a question configuration. */\nexport interface RawQuestionNode {\n id: string;\n questionType: string;\n text: string;\n answerDefaultValue?: string | null;\n hint?: string | null;\n internalLabel?: string | null;\n perGuest?: boolean | null;\n /** Present only on `ChoiceQuestion` nodes (via the inline fragment). */\n options?: RawQuestionOptionNode[] | null;\n}\n\n/** A single `questionActivityConfigurations` entry pairing config + question. */\nexport interface QuestionConfigurationNode {\n isRequired?: boolean | null;\n order?: number | null;\n question: RawQuestionNode;\n}\n\n/** The `data` payload of {@link CUSTOM_QUESTIONS_QUERY}. */\nexport interface CustomQuestionsResponse {\n activity: {\n id: string;\n name: string;\n questionActivityConfigurations?: QuestionConfigurationNode[] | null;\n } | null;\n}\n","/**\n * Product-related operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getProductService} rather than\n * constructing it directly — the access service wires in the authenticated,\n * shared transport. This class is where product-specific business logic lives.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport {\n ACTIVITY_PRODUCT_TYPE,\n RENTAL_PRODUCT_TYPE,\n type Product,\n} from \"../../../models/peek/product.js\";\nimport type { CustomQuestion } from \"../../../models/peek/custom-question.js\";\nimport { fromActivities, fromItemOptionNodes } from \"./product-converter.js\";\nimport { fromQuestionConfigurations } from \"./custom-question-converter.js\";\nimport {\n ITEM_OPTIONS_QUERY,\n PRODUCTS_QUERY,\n type ItemOptionNode,\n type ItemOptionsData,\n type ProductsResponse,\n} from \"./product-queries.js\";\nimport {\n CUSTOM_QUESTIONS_QUERY,\n type CustomQuestionsResponse,\n} from \"./custom-question-queries.js\";\n\n/** Thrown-error message when a product id is missing or blank. */\nconst ERROR_PRODUCT_ID_REQUIRED = \"A non-empty product id is required.\";\n\n/** Default page size for cursor-paginated item options. */\nconst DEFAULT_ITEM_OPTIONS_PAGE_SIZE = 50;\n\n/** Tuning options for a {@link ProductService}. */\nexport interface ProductServiceOptions {\n /** Page size for cursor-paginated item options. Default: 50. */\n itemOptionsPageSize?: number;\n}\n\nexport class ProductService {\n private readonly itemOptionsPageSize: number;\n\n constructor(\n private readonly client: GraphQLClient,\n options: ProductServiceOptions = {},\n ) {\n this.itemOptionsPageSize =\n options.itemOptionsPageSize ?? DEFAULT_ITEM_OPTIONS_PAGE_SIZE;\n }\n\n /**\n * Returns every product as a single flat list: activities plus add-ons (the\n * latter tagged with the add-on type). Add-ons are gathered across all\n * cursor-paginated pages.\n *\n * @example Split activities from add-ons\n * ```ts\n * import { ADD_ON_PRODUCT_TYPE } from \"@peektravel/app-utilities\";\n *\n * const products = await peek.getProductService().getAllProducts();\n * const activities = products.filter((p) => p.type !== ADD_ON_PRODUCT_TYPE);\n * const addons = products.filter((p) => p.type === ADD_ON_PRODUCT_TYPE);\n * ```\n */\n async getAllProducts(): Promise<Product[]> {\n const [activities, itemOptionNodes] = await Promise.all([\n this.fetchActivities(),\n this.fetchAllItemOptionNodes(),\n ]);\n\n return [...fromActivities(activities), ...fromItemOptionNodes(itemOptionNodes)];\n }\n\n /** Returns products with type {@link ACTIVITY_PRODUCT_TYPE}. */\n async getAllActivities(): Promise<Product[]> {\n const activities = await this.fetchActivities();\n return fromActivities(activities).filter((p) => p.type === ACTIVITY_PRODUCT_TYPE);\n }\n\n /** Returns products with type {@link RENTAL_PRODUCT_TYPE}. */\n async getAllRentals(): Promise<Product[]> {\n const activities = await this.fetchActivities();\n return fromActivities(activities).filter((p) => p.type === RENTAL_PRODUCT_TYPE);\n }\n\n /** Returns only add-on products. */\n async getAllAddons(): Promise<Product[]> {\n const nodes = await this.fetchAllItemOptionNodes();\n return fromItemOptionNodes(nodes);\n }\n\n /**\n * Returns every custom question configured on a single activity, in the order\n * Peek reports them. Choice-style questions (`SELECT_ONE`, `LOCATION`, …)\n * carry their selectable {@link CustomQuestion.options}; free-text/checkbox\n * questions return an empty option list.\n *\n * These are question **definitions**, not customer answers — no PII is\n * involved, so the result is unaffected by `fullCustomerAccess`.\n *\n * @param productId The activity's id.\n * @returns The activity's custom questions, or an empty list when the activity\n * has none or is not found.\n * @throws Error when `productId` is missing or blank.\n */\n async getCustomQuestions(productId: string): Promise<CustomQuestion[]> {\n if (!productId?.trim()) {\n throw new Error(ERROR_PRODUCT_ID_REQUIRED);\n }\n\n const body: GraphQLBody<CustomQuestionsResponse> =\n await this.client.request<CustomQuestionsResponse>(\n SALES_ENDPOINT,\n CUSTOM_QUESTIONS_QUERY,\n { id: productId },\n );\n\n const configs = body.data?.activity?.questionActivityConfigurations ?? [];\n return fromQuestionConfigurations(configs);\n }\n\n private async fetchActivities(): Promise<ProductsResponse[\"activities\"]> {\n const body: GraphQLBody<ProductsResponse> =\n await this.client.request<ProductsResponse>(\n SALES_ENDPOINT,\n PRODUCTS_QUERY,\n {},\n );\n return body.data?.activities ?? [];\n }\n\n private async fetchAllItemOptionNodes(): Promise<ItemOptionNode[]> {\n const all: ItemOptionNode[] = [];\n let after: string | null = null;\n\n for (;;) {\n const body: GraphQLBody<ItemOptionsData> =\n await this.client.request<ItemOptionsData>(\n SALES_ENDPOINT,\n ITEM_OPTIONS_QUERY,\n { first: this.itemOptionsPageSize, after },\n );\n\n const connection = body.data?.itemOptions;\n for (const edge of connection?.edges ?? []) {\n all.push(edge.node);\n }\n\n const pageInfo = connection?.pageInfo;\n if (pageInfo?.hasNextPage && pageInfo.endCursor) {\n after = pageInfo.endCursor;\n } else {\n break;\n }\n }\n\n return all;\n }\n}\n","/**\n * Raw Peek GraphQL query/mutation and response shapes for promo codes.\n * Internal. The promo-code node matches the public {@link PromoCode} model\n * one-to-one, so no converter is needed.\n */\nimport type { PromoCode } from \"../../../models/peek/promo-code.js\";\n\n/** Fetches a cursor-paginated page of promo codes. */\nexport const PROMO_CODES_QUERY = `\n query Sales($first: Int, $after: String) {\n promoCodes(first: $first, after: $after) {\n edges {\n node {\n id\n name\n percentAmount\n perTicketDiscount\n redemptionCode\n fixedAmount {\n amount\n currency\n formatted\n }\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n`;\n\n/** Creates a promo code. Returns the new code's id/name or an InvalidDataError. */\nexport const CREATE_PROMO_CODE_MUTATION = `\n mutation Sales($input: CreatePromoCodeInput!) {\n createPromoCode(input: $input) {\n ... on InvalidDataError {\n message\n }\n ... on PromoCode {\n id\n name\n }\n }\n }\n`;\n\n/** `data` payload of {@link PROMO_CODES_QUERY}. */\nexport interface PromoCodesResponse {\n promoCodes: {\n edges: Array<{ node: PromoCode }>;\n pageInfo: { hasNextPage: boolean; endCursor: string | null };\n };\n}\n\n/** `data` payload of {@link CREATE_PROMO_CODE_MUTATION}. */\nexport interface CreatePromoCodeResponse {\n createPromoCode: { message: string } | { id: string; name: string };\n}\n\n/** Variables for {@link CREATE_PROMO_CODE_MUTATION}. */\nexport interface CreatePromoCodeVariables {\n input: {\n code: string;\n name: string;\n maxRedeemCount?: number;\n fixedAmount?: { amount: string; currency: string };\n percentAmount?: string;\n };\n}\n","/**\n * Promo-code operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getPromoCodeService}.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type {\n CreatePromoCodeInput,\n CreatedPromoCode,\n PromoCode,\n} from \"../../../models/peek/promo-code.js\";\nimport {\n CREATE_PROMO_CODE_MUTATION,\n PROMO_CODES_QUERY,\n type CreatePromoCodeResponse,\n type CreatePromoCodeVariables,\n type PromoCodesResponse,\n} from \"./promo-code-queries.js\";\n\n/** Default page size for cursor-paginated promo codes. */\nconst DEFAULT_PAGE_SIZE = 50;\n/** Default currency for fixed-amount discounts. */\nconst DEFAULT_CURRENCY = \"USD\";\n/** ISO currency codes are three uppercase letters. */\nconst CURRENCY_PATTERN = /^[A-Z]{3}$/;\n\n/** Tuning options for a {@link PromoCodeService}. */\nexport interface PromoCodeServiceOptions {\n /** Page size for cursor pagination. Default: 50. */\n pageSize?: number;\n}\n\nexport class PromoCodeService {\n private readonly pageSize: number;\n\n constructor(\n private readonly client: GraphQLClient,\n options: PromoCodeServiceOptions = {},\n ) {\n this.pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;\n }\n\n /** Returns all promo codes, walking the cursor pagination to the end. */\n async getAll(): Promise<PromoCode[]> {\n const all: PromoCode[] = [];\n let after: string | null = null;\n\n for (;;) {\n const body: GraphQLBody<PromoCodesResponse> =\n await this.client.request<PromoCodesResponse>(SALES_ENDPOINT, PROMO_CODES_QUERY, {\n first: this.pageSize,\n after,\n });\n\n const connection = body.data?.promoCodes;\n for (const edge of connection?.edges ?? []) {\n all.push(edge.node);\n }\n\n const pageInfo = connection?.pageInfo;\n if (pageInfo?.hasNextPage && pageInfo.endCursor) {\n after = pageInfo.endCursor;\n } else {\n break;\n }\n }\n\n return all;\n }\n\n /**\n * Creates a promo code. Throws on invalid input or when Peek returns an\n * InvalidDataError.\n */\n async create(input: CreatePromoCodeInput): Promise<CreatedPromoCode> {\n if (!input.name) throw new Error(\"name is required\");\n if (!input.code) throw new Error(\"code is required\");\n if (!input.amount) throw new Error(\"amount is required\");\n if (!input.discountType) throw new Error(\"discountType is required\");\n if (input.discountType !== \"percent\" && input.discountType !== \"fixed\") {\n throw new Error(\"discountType must be either 'percent' or 'fixed'\");\n }\n if (Number.isNaN(parseFloat(input.amount))) {\n throw new Error(\"amount must be a valid number\");\n }\n const currency = input.currency || DEFAULT_CURRENCY;\n if (!CURRENCY_PATTERN.test(currency)) {\n throw new Error(\"currency must be 3 uppercase letters\");\n }\n\n const variables: CreatePromoCodeVariables = {\n input: {\n code: input.code,\n name: input.name,\n maxRedeemCount: input.maxRedemptions\n ? parseInt(String(input.maxRedemptions), 10)\n : undefined,\n },\n };\n if (input.discountType === \"fixed\") {\n variables.input.fixedAmount = { amount: input.amount, currency };\n } else {\n variables.input.percentAmount = input.amount;\n }\n\n const body: GraphQLBody<CreatePromoCodeResponse> =\n await this.client.request<CreatePromoCodeResponse>(\n SALES_ENDPOINT,\n CREATE_PROMO_CODE_MUTATION,\n variables,\n );\n\n const result = body.data?.createPromoCode;\n if (result && \"message\" in result) {\n throw new Error(result.message);\n }\n if (!result) {\n throw new Error(\"createPromoCode returned no data\");\n }\n return { id: result.id, name: result.name };\n }\n}\n","/**\n * Raw Peek GraphQL mutations, response shapes, and clean→raw variable builders\n * for pricing engines and pricing overrides. Internal — never re-exported.\n *\n * The public {@link UpsertOverridesInput} mirrors the wire input almost exactly;\n * the only transform the builders apply is stripping the `mode` discriminant off\n * each resource-option override down to the bare `price` / `percentageAdjustment`\n * key the API expects. Filters already match the wire shape and pass through.\n */\nimport type {\n ClearOverridesInput,\n CreateEngineInput,\n PricingOverrideFilter,\n UpdateEngineInput,\n UpsertOverridesInput,\n} from \"../../../models/peek/pricing.js\";\n\n// ─── Mutations ───────────────────────────────────────────────────────────────\n\n/** Creates a pricing engine, optionally scoped to a set of activity ids. */\nexport const CREATE_PRICING_ENGINE_MUTATION = `\n mutation CreatePricingEngine($input: CreatePricingEngineInput!) {\n createPricingEngine(input: $input) {\n __typename\n ... on CreatePricingEngineSuccess {\n engine {\n id\n }\n }\n ... on InvalidDataError {\n message\n }\n }\n }\n`;\n\n/** Updates a pricing engine's name and/or activity-id scope. */\nexport const UPDATE_PRICING_ENGINE_MUTATION = `\n mutation UpdatePricingEngine($input: UpdatePricingEngineInput!) {\n updatePricingEngine(input: $input) {\n __typename\n ... on UpdatePricingEngineSuccess {\n engine {\n id\n name\n }\n }\n ... on InvalidDataError {\n message\n }\n ... on NotFoundError {\n id\n message\n }\n }\n }\n`;\n\n/** Deletes a pricing engine. Idempotent — a NotFoundError is treated as success. */\nexport const DELETE_PRICING_ENGINE_MUTATION = `\n mutation DeletePricingEngine($id: ID!) {\n deletePricingEngine(id: $id) {\n __typename\n ... on DeletePricingEngineSuccess {\n engine {\n id\n name\n }\n }\n ... on NotFoundError {\n id\n message\n }\n }\n }\n`;\n\n/** Upserts (or clears, via empty overrides) pricing overrides for a date range. */\nexport const UPSERT_PRICING_OVERRIDES_MUTATION = `\n mutation UpsertPricingOverridesActivityContexts($input: UpsertPricingOverridesActivityContextsInput!) {\n upsertPricingOverridesActivityContexts(input: $input) {\n __typename\n ... on UpsertPricingOverridesActivityContextsSuccess {\n activityContexts {\n date\n activity {\n id\n name\n }\n engine {\n id\n name\n }\n overrides {\n order\n resourceOptions {\n resourceOption {\n id\n name\n }\n override {\n ... on PricingOverridesActivityContextResourceOptionPriceOverride {\n price {\n amount\n currency\n formatted\n }\n }\n ... on PricingOverridesActivityContextResourceOptionPercentageAdjustmentOverride {\n percentageAdjustment\n }\n }\n }\n filters {\n __typename\n ... on PricingOverridesActivityContextStartTimeRangeFilter {\n startTimeRange\n }\n ... on PricingOverridesActivityContextSpotsTakenFilter {\n minSpots\n maxSpots\n }\n }\n }\n }\n }\n ... on InvalidDataError {\n message\n }\n }\n }\n`;\n\n// ─── Filter typenames (used by the converter to tag response filters) ─────────\n\n/** `__typename` of the start-time-range filter in a pricing-override response. */\nexport const START_TIME_RANGE_FILTER_TYPENAME =\n \"PricingOverridesActivityContextStartTimeRangeFilter\";\n/** `__typename` of the spots-taken filter in a pricing-override response. */\nexport const SPOTS_TAKEN_FILTER_TYPENAME =\n \"PricingOverridesActivityContextSpotsTakenFilter\";\n\n// ─── Raw wire shapes: engine mutations ────────────────────────────────────────\n\n/** Raw variables for {@link CREATE_PRICING_ENGINE_MUTATION}. */\nexport interface CreateEngineVariables {\n input: { name: string; filters?: Array<{ activityIds: string[] }> };\n}\n\n/** `data` payload of {@link CREATE_PRICING_ENGINE_MUTATION}. */\nexport interface CreateEngineResponse {\n createPricingEngine:\n | { __typename: \"CreatePricingEngineSuccess\"; engine: { id: string } }\n | { __typename: \"InvalidDataError\"; message: string };\n}\n\n/** Raw variables for {@link UPDATE_PRICING_ENGINE_MUTATION}. */\nexport interface UpdateEngineVariables {\n input: { id: string; name: string; filters: Array<{ activityIds: string[] }> };\n}\n\n/** `data` payload of {@link UPDATE_PRICING_ENGINE_MUTATION}. */\nexport interface UpdateEngineResponse {\n updatePricingEngine:\n | { __typename: \"UpdatePricingEngineSuccess\"; engine: { id: string; name: string } }\n | { __typename: \"InvalidDataError\"; message: string }\n | { __typename: \"NotFoundError\"; id: string; message: string };\n}\n\n/** Raw variables for {@link DELETE_PRICING_ENGINE_MUTATION}. */\nexport interface DeleteEngineVariables {\n id: string;\n}\n\n/** `data` payload of {@link DELETE_PRICING_ENGINE_MUTATION}. */\nexport interface DeleteEngineResponse {\n deletePricingEngine:\n | { __typename: \"DeletePricingEngineSuccess\"; engine: { id: string; name: string } }\n | { __typename: \"NotFoundError\"; id: string; message: string };\n}\n\n// ─── Raw wire shapes: upsert mutation ─────────────────────────────────────────\n\n/** A raw resource-option override on the wire (the `mode` tag stripped). */\nexport type RawResourceOptionOverride =\n | { id: string; price: { amount: string; currency: string } }\n | { id: string; percentageAdjustment: string };\n\n/** A raw override entry on the wire. */\nexport interface RawOverride {\n order: number;\n resourceOptions: RawResourceOptionOverride[];\n filters: PricingOverrideFilter[];\n}\n\n/** The raw upsert input on the wire. */\nexport interface RawUpsertInput {\n engineId: string;\n dateRange: string;\n activities: Array<{ activityId: string; overrides: RawOverride[] }>;\n}\n\n/** Raw variables for {@link UPSERT_PRICING_OVERRIDES_MUTATION}. */\nexport interface UpsertOverridesVariables {\n input: RawUpsertInput;\n}\n\n/** A single resolved resource-option override as returned by the API. */\nexport type RawResolvedOverride =\n | { price: { amount: string; currency: string; formatted?: string } }\n | { percentageAdjustment: string };\n\n/** A single resolved filter as returned by the API (tagged by `__typename`). */\nexport type RawResolvedFilter =\n | { __typename: typeof START_TIME_RANGE_FILTER_TYPENAME; startTimeRange: string }\n | {\n __typename: typeof SPOTS_TAKEN_FILTER_TYPENAME;\n minSpots: number | null;\n maxSpots: number | null;\n };\n\n/** A single resolved activity context as returned by the API. */\nexport interface RawActivityContext {\n date: string;\n activity: { id: string; name: string };\n engine: { id: string; name: string };\n overrides: Array<{\n order: number;\n resourceOptions: Array<{\n resourceOption: { id: string; name: string };\n override: RawResolvedOverride;\n }>;\n filters: RawResolvedFilter[];\n }>;\n}\n\n/** `data` payload of {@link UPSERT_PRICING_OVERRIDES_MUTATION}. */\nexport interface UpsertOverridesResponse {\n upsertPricingOverridesActivityContexts:\n | {\n __typename: \"UpsertPricingOverridesActivityContextsSuccess\";\n activityContexts: RawActivityContext[];\n }\n | { __typename: \"InvalidDataError\"; message: string };\n}\n\n// ─── Clean → raw variable builders ────────────────────────────────────────────\n\n/** Builds the raw create-engine input, attaching an activity-ids filter when scoped. */\nexport function buildCreateEngineInput(\n input: CreateEngineInput,\n): CreateEngineVariables[\"input\"] {\n const activityIds = input.activityIds ?? [];\n return activityIds.length > 0\n ? { name: input.name, filters: [{ activityIds }] }\n : { name: input.name };\n}\n\n/** Builds the raw update-engine input. An empty/omitted scope clears the filter. */\nexport function buildUpdateEngineInput(\n input: UpdateEngineInput,\n): UpdateEngineVariables[\"input\"] {\n const activityIds = input.activityIds ?? [];\n return {\n id: input.engineId,\n name: input.name,\n filters: activityIds.length > 0 ? [{ activityIds }] : [],\n };\n}\n\n/** Maps a clean {@link UpsertOverridesInput} to the raw wire input. */\nexport function buildUpsertInput(input: UpsertOverridesInput): RawUpsertInput {\n return {\n engineId: input.engineId,\n dateRange: input.dateRange,\n activities: input.activities.map((activity) => ({\n activityId: activity.activityId,\n overrides: activity.overrides.map((override) => ({\n order: override.order,\n resourceOptions: override.resourceOptions.map((option) =>\n option.mode === \"fixed\"\n ? {\n id: option.id,\n // Send only the wire fields — `displayPrice` is read-only.\n price: { amount: option.price.amount, currency: option.price.currency },\n }\n : { id: option.id, percentageAdjustment: option.percentageAdjustment },\n ),\n filters: override.filters,\n })),\n })),\n };\n}\n\n/** Builds the raw upsert input that clears all overrides for the given activities. */\nexport function buildClearInput(input: ClearOverridesInput): RawUpsertInput {\n return {\n engineId: input.engineId,\n dateRange: input.dateRange,\n activities: input.activityIds.map((activityId) => ({\n activityId,\n overrides: [],\n })),\n };\n}\n","/**\n * Pure functions mapping raw pricing-override GraphQL nodes into the clean\n * {@link PricingActivityContext} model. No I/O — easy to unit-test.\n *\n * Two normalizations happen here, both erasing quirks of the wire format:\n * - Each resource-option override arrives as either a `price` object or a bare\n * `percentageAdjustment`; we tag it with a `mode` discriminant.\n * - Each filter arrives `__typename`-tagged with `null`-able bounds; we map it\n * back to the same compact {@link PricingOverrideFilter} union used on input,\n * dropping absent (`null`) spots bounds.\n */\nimport type {\n PricingActivityContext,\n PricingOverrideFilter,\n ResolvedOverride,\n ResolvedPricingOverride,\n ResolvedResourceOption,\n} from \"../../../models/peek/pricing.js\";\nimport { toPricingMoney } from \"../money.js\";\nimport {\n SPOTS_TAKEN_FILTER_TYPENAME,\n type RawActivityContext,\n type RawResolvedFilter,\n type RawResolvedOverride,\n} from \"./pricing-queries.js\";\n\n/** Converts the raw activity contexts from an upsert response into clean models. */\nexport function fromActivityContexts(\n contexts: RawActivityContext[],\n): PricingActivityContext[] {\n return contexts.map(fromActivityContext);\n}\n\nfunction fromActivityContext(context: RawActivityContext): PricingActivityContext {\n return {\n date: context.date,\n activity: { id: context.activity.id, name: context.activity.name },\n engine: { id: context.engine.id, name: context.engine.name },\n overrides: context.overrides.map(fromOverride),\n };\n}\n\nfunction fromOverride(\n override: RawActivityContext[\"overrides\"][number],\n): ResolvedPricingOverride {\n return {\n order: override.order,\n resourceOptions: override.resourceOptions.map(fromResourceOption),\n filters: override.filters.map(fromFilter),\n };\n}\n\nfunction fromResourceOption(\n option: RawActivityContext[\"overrides\"][number][\"resourceOptions\"][number],\n): ResolvedResourceOption {\n return {\n resourceOption: {\n id: option.resourceOption.id,\n name: option.resourceOption.name,\n },\n override: fromResolvedOverride(option.override),\n };\n}\n\nfunction fromResolvedOverride(override: RawResolvedOverride): ResolvedOverride {\n return \"price\" in override\n ? { mode: \"fixed\", price: toPricingMoney(override.price)! }\n : { mode: \"percentage\", percentageAdjustment: override.percentageAdjustment };\n}\n\nfunction fromFilter(filter: RawResolvedFilter): PricingOverrideFilter {\n if (filter.__typename === SPOTS_TAKEN_FILTER_TYPENAME) {\n const spotsTaken: { minSpots?: number; maxSpots?: number } = {};\n if (filter.minSpots !== null) spotsTaken.minSpots = filter.minSpots;\n if (filter.maxSpots !== null) spotsTaken.maxSpots = filter.maxSpots;\n return { spotsTaken };\n }\n return { startTimeRange: filter.startTimeRange };\n}\n","/**\n * Pricing-engine and pricing-override operations against the Peek gateway.\n *\n * Obtain an instance via {@link PeekAccessService.getPricingService} rather than\n * constructing it directly.\n *\n * Scope: this service is a thin, faithful wrapper over the Peek pricing\n * primitives. It creates/updates/deletes engines and upserts/clears overrides,\n * validating inputs and mapping the typed-error unions to thrown `Error`s. It\n * does **not** own the domain logic that decides what the overrides should be —\n * segmenting activities across time windows, ordering override tiers, or\n * computing `spotsTaken` bounds. Callers build the {@link UpsertOverridesInput}\n * (see the model docs) and this service sends it as-is.\n */\nimport { SALES_ENDPOINT } from \"../gateway-endpoints.js\";\nimport type { GraphQLBody, GraphQLClient } from \"../graphql-client.js\";\nimport type {\n ClearOverridesInput,\n CreateEngineInput,\n CreatedPricingEngine,\n PricingEngine,\n ResourceOptionOverride,\n UpdateEngineInput,\n UpsertOverridesInput,\n UpsertOverridesResult,\n} from \"../../../models/peek/pricing.js\";\nimport { fromActivityContexts } from \"./pricing-converter.js\";\nimport {\n buildClearInput,\n buildCreateEngineInput,\n buildUpdateEngineInput,\n buildUpsertInput,\n CREATE_PRICING_ENGINE_MUTATION,\n DELETE_PRICING_ENGINE_MUTATION,\n UPDATE_PRICING_ENGINE_MUTATION,\n UPSERT_PRICING_OVERRIDES_MUTATION,\n type CreateEngineResponse,\n type DeleteEngineResponse,\n type UpdateEngineResponse,\n type UpsertOverridesResponse,\n} from \"./pricing-queries.js\";\n\n/** ISO 4217 currency codes are three uppercase letters. */\nconst CURRENCY_PATTERN = /^[A-Z]{3}$/;\n/** A percentage adjustment must be strictly greater than this floor. */\nconst PERCENTAGE_FLOOR = -100;\n\nconst ERROR_NAME_REQUIRED = \"name is required\";\nconst ERROR_ENGINE_ID_REQUIRED = \"engineId is required\";\nconst ERROR_DATE_RANGE_REQUIRED = \"dateRange is required\";\nconst ERROR_ACTIVITIES_REQUIRED = \"activities is required\";\nconst ERROR_ACTIVITY_ID_REQUIRED = \"activityId is required\";\nconst ERROR_TICKET_ID_REQUIRED = \"resource-option id is required\";\nconst ERROR_CURRENCY_FORMAT = \"currency must be 3 uppercase letters\";\nconst ERROR_AMOUNT_NUMBER = \"price amount must be a valid number\";\nconst ERROR_PERCENTAGE_NUMBER = \"percentageAdjustment must be a valid number\";\nconst ERROR_PERCENTAGE_FLOOR = \"percentageAdjustment must be greater than -100\";\nconst ERROR_NO_DATA = \"pricing mutation returned no data\";\n\nexport class PricingService {\n constructor(private readonly client: GraphQLClient) {}\n\n /**\n * Creates a pricing engine. Store the returned id and reuse it on every\n * subsequent override upsert. Throws on an InvalidDataError from Peek.\n */\n async createEngine(input: CreateEngineInput): Promise<CreatedPricingEngine> {\n if (!input.name) throw new Error(ERROR_NAME_REQUIRED);\n\n const body: GraphQLBody<CreateEngineResponse> =\n await this.client.request<CreateEngineResponse>(\n SALES_ENDPOINT,\n CREATE_PRICING_ENGINE_MUTATION,\n { input: buildCreateEngineInput(input) },\n );\n\n const result = body.data?.createPricingEngine;\n if (!result) throw new Error(ERROR_NO_DATA);\n if (result.__typename !== \"CreatePricingEngineSuccess\") {\n throw new Error(result.message);\n }\n return { id: result.engine.id };\n }\n\n /**\n * Updates a pricing engine's name and/or activity scope. Throws on an\n * InvalidDataError or NotFoundError from Peek.\n */\n async updateEngine(input: UpdateEngineInput): Promise<PricingEngine> {\n if (!input.engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);\n if (!input.name) throw new Error(ERROR_NAME_REQUIRED);\n\n const body: GraphQLBody<UpdateEngineResponse> =\n await this.client.request<UpdateEngineResponse>(\n SALES_ENDPOINT,\n UPDATE_PRICING_ENGINE_MUTATION,\n { input: buildUpdateEngineInput(input) },\n );\n\n const result = body.data?.updatePricingEngine;\n if (!result) throw new Error(ERROR_NO_DATA);\n if (result.__typename !== \"UpdatePricingEngineSuccess\") {\n throw new Error(result.message);\n }\n return { id: result.engine.id, name: result.engine.name };\n }\n\n /**\n * Deletes a pricing engine. Idempotent — resolves whether the engine existed\n * or was already gone (Peek's NotFoundError is treated as success).\n */\n async deleteEngine(engineId: string): Promise<void> {\n if (!engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);\n\n await this.client.request<DeleteEngineResponse>(\n SALES_ENDPOINT,\n DELETE_PRICING_ENGINE_MUTATION,\n { id: engineId },\n );\n }\n\n /**\n * Upserts pricing overrides for the engine and date range in `input`. Returns\n * the resolved contexts Peek stored. Throws on an InvalidDataError from Peek.\n */\n async upsertOverrides(input: UpsertOverridesInput): Promise<UpsertOverridesResult> {\n this.validateUpsertInput(input);\n return this.sendUpsert(buildUpsertInput(input));\n }\n\n /**\n * Clears all overrides for the given activities across a date range. This is\n * an upsert with empty overrides — never clear by omitting an activity.\n */\n async clearOverrides(input: ClearOverridesInput): Promise<UpsertOverridesResult> {\n if (!input.engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);\n if (!input.dateRange) throw new Error(ERROR_DATE_RANGE_REQUIRED);\n if (!Array.isArray(input.activityIds)) throw new Error(ERROR_ACTIVITIES_REQUIRED);\n for (const activityId of input.activityIds) {\n if (!activityId) throw new Error(ERROR_ACTIVITY_ID_REQUIRED);\n }\n return this.sendUpsert(buildClearInput(input));\n }\n\n private async sendUpsert(\n rawInput: ReturnType<typeof buildUpsertInput>,\n ): Promise<UpsertOverridesResult> {\n const body: GraphQLBody<UpsertOverridesResponse> =\n await this.client.request<UpsertOverridesResponse>(\n SALES_ENDPOINT,\n UPSERT_PRICING_OVERRIDES_MUTATION,\n { input: rawInput },\n );\n\n const result = body.data?.upsertPricingOverridesActivityContexts;\n if (!result) throw new Error(ERROR_NO_DATA);\n if (result.__typename !== \"UpsertPricingOverridesActivityContextsSuccess\") {\n throw new Error(result.message);\n }\n return { activityContexts: fromActivityContexts(result.activityContexts) };\n }\n\n private validateUpsertInput(input: UpsertOverridesInput): void {\n if (!input.engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);\n if (!input.dateRange) throw new Error(ERROR_DATE_RANGE_REQUIRED);\n if (!Array.isArray(input.activities)) throw new Error(ERROR_ACTIVITIES_REQUIRED);\n\n for (const activity of input.activities) {\n if (!activity.activityId) throw new Error(ERROR_ACTIVITY_ID_REQUIRED);\n for (const override of activity.overrides) {\n for (const option of override.resourceOptions) {\n this.validateResourceOption(option);\n }\n }\n }\n }\n\n private validateResourceOption(option: ResourceOptionOverride): void {\n if (!option.id) throw new Error(ERROR_TICKET_ID_REQUIRED);\n\n if (option.mode === \"fixed\") {\n if (!CURRENCY_PATTERN.test(option.price.currency)) {\n throw new Error(ERROR_CURRENCY_FORMAT);\n }\n if (Number.isNaN(Number.parseFloat(option.price.amount))) {\n throw new Error(ERROR_AMOUNT_NUMBER);\n }\n return;\n }\n\n const percentage = Number.parseFloat(option.percentageAdjustment);\n if (Number.isNaN(percentage)) throw new Error(ERROR_PERCENTAGE_NUMBER);\n if (percentage <= PERCENTAGE_FLOOR) throw new Error(ERROR_PERCENTAGE_FLOOR);\n }\n}\n","/**\n * Minimal structured logger interface the package can write diagnostics to.\n *\n * Consumers may supply their own implementation (e.g. wrapping an existing\n * application logger). When none is provided the package stays completely\n * silent via {@link noopLogger}.\n */\nexport interface Logger {\n info(message: string, context?: Record<string, unknown>): void;\n warn(message: string, context?: Record<string, unknown>): void;\n error(message: string, context?: Record<string, unknown>): void;\n}\n\n/** A {@link Logger} that discards everything. Used as the default. */\nexport const noopLogger: Logger = {\n info() {},\n warn() {},\n error() {},\n};\n","/**\n * Authenticated root entry point to the Peek backoffice GraphQL gateway.\n *\n * Configure one instance per install with everything needed to authenticate and\n * reach the gateway. The access service owns the shared, authenticated\n * transport (it mints and caches tokens on demand) and hands out per-resource\n * service objects — e.g. {@link PeekAccessService.getProductService} — that\n * carry the resource-specific business logic.\n */\nimport { AccountUserService } from \"./internal/peek/account-users/account-user-service.js\";\nimport { AvailabilityService } from \"./internal/peek/availability/availability-service.js\";\nimport { BookingService } from \"./internal/peek/bookings/booking-service.js\";\nimport { DailyNoteService } from \"./internal/peek/daily-notes/daily-note-service.js\";\nimport {\n createTokenManager,\n requireNonEmpty,\n resolveBaseApiUrl,\n DEFAULT_RETRY_DELAYS_MS,\n type BaseAccessServiceConfig,\n} from \"./access-service-config.js\";\nimport {\n resolveAccessOptions,\n type ResolvedAccessOptions,\n} from \"./access-options.js\";\nimport { GraphQLClient } from \"./internal/peek/graphql-client.js\";\nimport {\n mapPeekTokenUser,\n verifyPeekJwt,\n type RawPeekTokenUser,\n} from \"./internal/peek/peek-auth-token.js\";\nimport { MembershipService } from \"./internal/peek/memberships/membership-service.js\";\nimport { ResellerService } from \"./internal/peek/resellers/reseller-service.js\";\nimport { ResourcePoolService } from \"./internal/peek/resource-pools/resource-pool-service.js\";\nimport { ReviewService } from \"./internal/peek/reviews/review-service.js\";\nimport { TimeslotService } from \"./internal/peek/timeslots/timeslot-service.js\";\nimport {\n ProductService,\n type ProductServiceOptions,\n} from \"./internal/peek/products/product-service.js\";\nimport { PromoCodeService } from \"./internal/peek/promo-codes/promo-code-service.js\";\nimport { PricingService } from \"./internal/peek/pricing/pricing-service.js\";\nimport {\n V2_EXTENDABLE_SLUG,\n peekApiEndpoints,\n} from \"./internal/peek/gateway-endpoints.js\";\nimport { noopLogger } from \"./logger.js\";\nimport type { PeekAuthTokenClaims } from \"./models/peek/auth-token.js\";\nimport type { AvailabilityTimesQuery } from \"./models/peek/availability-time.js\";\nimport type {\n BookingReadOptions,\n BookingTimeRangeSearch,\n CreateBookingInput,\n NoteMode,\n} from \"./models/peek/booking.js\";\nimport type { MakePaymentInput, RefundInput } from \"./models/peek/booking-payment.js\";\nimport type { MembershipPurchaseInput } from \"./models/peek/membership.js\";\nimport type { CreatePromoCodeInput } from \"./models/peek/promo-code.js\";\nimport type {\n ClearOverridesInput,\n CreateEngineInput,\n UpdateEngineInput,\n UpsertOverridesInput,\n} from \"./models/peek/pricing.js\";\nimport type { ResourcePoolMode } from \"./models/peek/resource-pool.js\";\nimport type { GuideAssignment, TimeslotFilter } from \"./models/peek/timeslot.js\";\nimport type { AddAddonInput } from \"./internal/peek/bookings/booking-service.js\";\n\n/** Default backoffice GraphQL gateway base URL (v1). */\nconst DEFAULT_BASE_URL = \"https://apps.peekapis.com/backoffice-gql\";\n/** Default gateway base URL when operating in v2 mode. */\nconst DEFAULT_V2_BASE_URL =\n \"https://app-registry.peeklabs.com/installations-api\";\ninterface RawPeekTokenPayload {\n sub: string;\n display_version: string;\n user?: RawPeekTokenUser | null;\n}\n\n/**\n * Configuration for a {@link PeekAccessService} instance. Extends the shared\n * {@link BaseAccessServiceConfig} (install/auth/transport fields) with the\n * Peek-specific extras below.\n */\nexport interface PeekAccessServiceConfig extends BaseAccessServiceConfig {\n /** API gateway key, sent as the `pk-api-key` header. Required in v1 mode; not used in v2. */\n gatewayKey?: string;\n\n /**\n * Gateway mode. `\"v2\"` routes through the app-registry installations API\n * (`baseUrl/appId/peek_backoffice_api-v1/endpointName`) and defaults to the\n * app-registry sandbox base URL. `\"v1\"` (default) uses the standard backoffice\n * GraphQL gateway.\n */\n mode?: \"v2\";\n /** Page size for cursor-paginated item options. Default: 50. */\n itemOptionsPageSize?: number;\n}\n\n/**\n * Authenticated root entry point to the Peek backoffice GraphQL gateway.\n *\n * Construct one instance per install, then call the `get<Resource>Service()`\n * accessors to reach the resource-specific operations. Each accessor returns a\n * memoized service bound to the shared, authenticated transport — the access\n * service mints and caches a short-lived JWT on demand.\n *\n * @example Configure once, then call resource services\n * ```ts\n * import { PeekAccessService, type Product } from \"@peektravel/app-utilities\";\n *\n * const peek = new PeekAccessService({\n * installId: \"install-123\", // JWT subject\n * jwtSecret: process.env.PEEK_INTERNAL_SECRET!, // signs the JWT\n * issuer: process.env.APP_NAME!, // JWT issuer\n * appId: process.env.PEEK_APP_ID!, // gateway path segment\n * gatewayKey: process.env.PEEK_GATEWAY_KEY!, // pk-api-key header\n * });\n *\n * const products: Product[] = await peek.getProductService().getAllProducts();\n * const booking = await peek.getBookingService().getById(\"b_abc123\");\n * ```\n *\n * @throws {Error} from the constructor when any required config field\n * (`installId`, `jwtSecret`, `issuer`, `appId`, `gatewayKey`) is empty.\n */\nexport class PeekAccessService {\n private readonly client: GraphQLClient;\n private readonly productServiceOptions: ProductServiceOptions;\n private readonly accessOptions: ResolvedAccessOptions;\n private readonly jwtSecret: string;\n private readonly issuer: string;\n private productService?: ProductService;\n private accountUserService?: AccountUserService;\n private resourcePoolService?: ResourcePoolService;\n private timeslotService?: TimeslotService;\n private resellerService?: ResellerService;\n private promoCodeService?: PromoCodeService;\n private pricingService?: PricingService;\n private dailyNoteService?: DailyNoteService;\n private availabilityService?: AvailabilityService;\n private membershipService?: MembershipService;\n private readonly bookingServices = new Map<string, BookingService>();\n private reviewService?: ReviewService;\n\n constructor(config: PeekAccessServiceConfig) {\n const hasApiUrl = !!config.apiUrl;\n const isV2 = config.mode === \"v2\";\n requireNonEmpty(config.installId, \"installId\", \"PeekAccessService\");\n requireNonEmpty(config.jwtSecret, \"jwtSecret\", \"PeekAccessService\");\n requireNonEmpty(config.issuer, \"issuer\", \"PeekAccessService\");\n // `appId` is only a URL path segment for the legacy `baseUrl` mode; the\n // registry's `apiUrl` already includes whatever the registry routes on.\n if (!hasApiUrl) requireNonEmpty(config.appId ?? \"\", \"appId\", \"PeekAccessService\");\n // The registry app endpoint authenticates on the JWT alone (like v2), so the\n // `pk-api-key` gateway key is only required in the legacy v1 `baseUrl` mode.\n if (!hasApiUrl && !isV2) requireNonEmpty(config.gatewayKey ?? \"\", \"gatewayKey\", \"PeekAccessService\");\n\n this.jwtSecret = config.jwtSecret;\n this.issuer = config.issuer;\n\n const logger = config.logger ?? noopLogger;\n const tokens = createTokenManager(config);\n\n // Registry modes (an app-endpoint `apiUrl`, or legacy v2) route the `sales`\n // endpoint through the `peek_backoffice_api-v1` slug; the legacy v1 gateway\n // has no slug. `apiUrl` is the base directly (its own slug stripped back off);\n // otherwise the base is `baseUrl/appId`.\n const useRegistrySlug = hasApiUrl || isV2;\n const defaultBaseUrl = isV2 ? DEFAULT_V2_BASE_URL : DEFAULT_BASE_URL;\n const baseApiUrl = hasApiUrl\n ? resolveBaseApiUrl(config.apiUrl!, V2_EXTENDABLE_SLUG, \"PeekAccessService\")\n : `${config.baseUrl ?? defaultBaseUrl}/${config.appId}`;\n this.client = new GraphQLClient({\n baseApiUrl,\n endpoints: peekApiEndpoints(useRegistrySlug),\n gatewayKey: config.gatewayKey,\n getToken: () => tokens.getToken(),\n retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,\n logger,\n fetchFn: config.fetch ?? globalThis.fetch,\n });\n\n this.productServiceOptions = {\n itemOptionsPageSize: config.itemOptionsPageSize,\n };\n this.accessOptions = resolveAccessOptions(config.accessOptions);\n }\n\n /**\n * Verifies a Peek auth token issued by the app registry and returns the\n * decoded claims.\n *\n * Validates the HMAC signature (using this service's `jwtSecret`), the token\n * expiry, the `\"app_registry_v2\"` issuer, and the `\"Joken\"` audience. Pass the\n * raw `x-peek-auth` request header value — a leading `Bearer ` prefix, if\n * present, is stripped for you. Throws from the `jsonwebtoken` library on any\n * failure — callers should catch to distinguish error kinds:\n *\n * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or token\n * malformed\n * - `TokenExpiredError` — past `exp`\n * - `NotBeforeError` — before `nbf`\n *\n * Claim *extraction* is defensive: once the signature verifies, a token with\n * no `user` block yields `claims.user === null`, and any individual user field\n * that is absent or a sentinel (`\"\"`, `\"null\"`) is normalized to `null`. This\n * method never throws on a shape problem — only on a verification failure.\n *\n * @throws {JsonWebTokenError} signature invalid or token malformed\n * @throws {TokenExpiredError} token has expired\n * @throws {NotBeforeError} token not yet valid\n */\n verifyPeekAuthToken(token: string): PeekAuthTokenClaims {\n const payload = verifyPeekJwt<RawPeekTokenPayload>(token, this.jwtSecret);\n return {\n installId: payload.sub,\n displayVersion: payload.display_version,\n user: mapPeekTokenUser(payload.user),\n };\n }\n\n /**\n * Returns the {@link ProductService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getProductService(): ProductService {\n if (!this.productService) {\n this.productService = new ProductService(\n this.client,\n this.productServiceOptions,\n );\n }\n return this.productService;\n }\n\n /**\n * Returns the {@link AccountUserService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getAccountUserService(): AccountUserService {\n if (!this.accountUserService) {\n this.accountUserService = new AccountUserService(this.client);\n }\n return this.accountUserService;\n }\n\n /**\n * Returns the {@link ResourcePoolService} for this install, bound to the\n * shared authenticated transport. The instance is created lazily and reused.\n */\n getResourcePoolService(): ResourcePoolService {\n if (!this.resourcePoolService) {\n this.resourcePoolService = new ResourcePoolService(this.client);\n }\n return this.resourcePoolService;\n }\n\n /**\n * Returns the {@link TimeslotService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused; its\n * guide assignment composes the resource-pool and account-user services.\n */\n getTimeslotService(): TimeslotService {\n if (!this.timeslotService) {\n this.timeslotService = new TimeslotService(this.client, {\n resourcePoolService: this.getResourcePoolService(),\n accountUserService: this.getAccountUserService(),\n });\n }\n return this.timeslotService;\n }\n\n /**\n * Returns the {@link ResellerService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getResellerService(): ResellerService {\n if (!this.resellerService) {\n this.resellerService = new ResellerService(this.client);\n }\n return this.resellerService;\n }\n\n /**\n * Returns the {@link PromoCodeService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getPromoCodeService(): PromoCodeService {\n if (!this.promoCodeService) {\n this.promoCodeService = new PromoCodeService(this.client);\n }\n return this.promoCodeService;\n }\n\n /**\n * Returns the {@link PricingService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getPricingService(): PricingService {\n if (!this.pricingService) {\n this.pricingService = new PricingService(this.client);\n }\n return this.pricingService;\n }\n\n /**\n * Returns the {@link DailyNoteService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getDailyNoteService(): DailyNoteService {\n if (!this.dailyNoteService) {\n this.dailyNoteService = new DailyNoteService(this.client);\n }\n return this.dailyNoteService;\n }\n\n /**\n * Returns the {@link AvailabilityService} for this install, bound to the\n * shared authenticated transport. The instance is created lazily and reused.\n */\n getAvailabilityService(): AvailabilityService {\n if (!this.availabilityService) {\n this.availabilityService = new AvailabilityService(this.client);\n }\n return this.availabilityService;\n }\n\n /**\n * Returns the {@link MembershipService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getMembershipService(): MembershipService {\n if (!this.membershipService) {\n this.membershipService = new MembershipService(this.client);\n }\n return this.membershipService;\n }\n\n /**\n * Returns the {@link BookingService} for this install, bound to the shared\n * authenticated transport. Instances are created lazily and reused per\n * `integrator`.\n *\n * `integrator` scopes `getMetaData` results to a custom integrator id. **Do\n * not set it** unless Peek engineering created a custom integrator id for this\n * integration — omit it and the correct default is used.\n */\n getBookingService(integrator?: string): BookingService {\n const resolved = integrator ?? this.issuer;\n let service = this.bookingServices.get(resolved);\n if (!service) {\n service = new BookingService(\n this.client,\n { productService: this.getProductService() },\n { accessOptions: this.accessOptions, integrator: resolved },\n );\n this.bookingServices.set(resolved, service);\n }\n return service;\n }\n\n /**\n * Returns the {@link ReviewService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getReviewService(): ReviewService {\n if (!this.reviewService) {\n this.reviewService = new ReviewService(this.client, this.accessOptions);\n }\n return this.reviewService;\n }\n\n // ─── Product short-forms ─────────────────────────────────────────────────\n\n /** All products (activities + add-ons). @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ProductService.getAllProducts}. */\n getAllProducts() { return this.getProductService().getAllProducts(); }\n\n /** All activity products (excludes add-ons). @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ProductService.getAllActivities}. */\n getAllActivities() { return this.getProductService().getAllActivities(); }\n\n /** All rental products. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ProductService.getAllRentals}. */\n getAllRentals() { return this.getProductService().getAllRentals(); }\n\n /** All add-on products. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ProductService.getAllAddons}. */\n getAllAddons() { return this.getProductService().getAllAddons(); }\n\n /** An activity's custom questions. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ProductService.getCustomQuestions}. */\n getCustomQuestions(productId: string) { return this.getProductService().getCustomQuestions(productId); }\n\n // ─── Account-user short-forms ─────────────────────────────────────────────\n\n /** All active account users. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link AccountUserService.getAll}. */\n getAllAccountUsers() { return this.getAccountUserService().getAll(); }\n\n /** Account user by id, or null. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link AccountUserService.getById}. */\n getAccountUserById(userId: string) { return this.getAccountUserService().getById(userId); }\n\n // ─── Resource-pool short-forms ────────────────────────────────────────────\n\n /** All resource pools. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ResourcePoolService.getAll}. */\n getAllResourcePools(mode?: ResourcePoolMode) { return this.getResourcePoolService().getAll(mode); }\n\n // ─── Timeslot short-forms ─────────────────────────────────────────────────\n\n /** Timeslots for an activity on a given date. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link TimeslotService.getForDay}. */\n getTimeslotsForDay(productId: string, date: string, filter?: TimeslotFilter) {\n return this.getTimeslotService().getForDay(productId, date, filter);\n }\n\n /** Single timeslot by id. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link TimeslotService.getById}. */\n getTimeslotById(timeslotId: string) { return this.getTimeslotService().getById(timeslotId); }\n\n /** Set timeslot status. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link TimeslotService.setAvailability}. */\n setTimeslotAvailability(timeslotId: string, status: string) {\n return this.getTimeslotService().setAvailability(timeslotId, status);\n }\n\n /** Set timeslot manifest notes. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link TimeslotService.setNotes}. */\n setTimeslotNotes(timeslotId: string, manifestNotes: string) {\n return this.getTimeslotService().setNotes(timeslotId, manifestNotes);\n }\n\n /** Assign or unassign guides on timeslots. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link TimeslotService.assignGuide}. */\n assignTimeslotGuide(assignment: GuideAssignment) {\n return this.getTimeslotService().assignGuide(assignment);\n }\n\n // ─── Reseller short-forms ─────────────────────────────────────────────────\n\n /** All reseller channels. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ResellerService.getAllChannels}. */\n getAllChannels(agentsPerChannel?: number) {\n return this.getResellerService().getAllChannels(agentsPerChannel);\n }\n\n // ─── Promo-code short-forms ───────────────────────────────────────────────\n\n /** All promo codes. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PromoCodeService.getAll}. */\n getAllPromoCodes() { return this.getPromoCodeService().getAll(); }\n\n /** Create a promo code. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PromoCodeService.create}. */\n createPromoCode(input: CreatePromoCodeInput) { return this.getPromoCodeService().create(input); }\n\n // ─── Pricing short-forms ──────────────────────────────────────────────────\n\n /** Create a pricing engine. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PricingService.createEngine}. */\n createPricingEngine(input: CreateEngineInput) { return this.getPricingService().createEngine(input); }\n\n /** Update a pricing engine. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PricingService.updateEngine}. */\n updatePricingEngine(input: UpdateEngineInput) { return this.getPricingService().updateEngine(input); }\n\n /** Delete a pricing engine (idempotent). @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PricingService.deleteEngine}. */\n deletePricingEngine(engineId: string) { return this.getPricingService().deleteEngine(engineId); }\n\n /** Upsert pricing overrides. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PricingService.upsertOverrides}. */\n upsertPricingOverrides(input: UpsertOverridesInput) { return this.getPricingService().upsertOverrides(input); }\n\n /** Clear pricing overrides for a set of activities. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link PricingService.clearOverrides}. */\n clearPricingOverrides(input: ClearOverridesInput) { return this.getPricingService().clearOverrides(input); }\n\n // ─── Daily-note short-forms ───────────────────────────────────────────────\n\n /** Today's daily note. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link DailyNoteService.getToday}. */\n getDailyNoteToday() { return this.getDailyNoteService().getToday(); }\n\n /** Update today's daily note. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link DailyNoteService.update}. */\n updateDailyNote(note: string) { return this.getDailyNoteService().update(note); }\n\n // ─── Availability short-forms ─────────────────────────────────────────────\n\n /** Availability times for an activity. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link AvailabilityService.getAvailabilityTimes}. */\n getAvailabilityTimes(query: AvailabilityTimesQuery) {\n return this.getAvailabilityService().getAvailabilityTimes(query);\n }\n\n // ─── Membership short-forms ───────────────────────────────────────────────\n\n /** All memberships. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link MembershipService.getAll}. */\n getAllMemberships() { return this.getMembershipService().getAll(); }\n\n /** Purchase a membership. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link MembershipService.purchase}. */\n purchaseMembership(input: MembershipPurchaseInput) {\n return this.getMembershipService().purchase(input);\n }\n\n // ─── Booking short-forms ──────────────────────────────────────────────────\n\n /** Booking by id. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.getById}. */\n getBookingById(bookingId: string, options?: BookingReadOptions) {\n return this.getBookingService().getById(bookingId, options);\n }\n\n /** Bookings by time range. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.searchByTimeRange}. */\n searchBookingsByTimeRange(input: BookingTimeRangeSearch) {\n return this.getBookingService().searchByTimeRange(input);\n }\n\n /** Bookings on a timeslot. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.searchByTimeslot}. */\n searchBookingsByTimeslot(timeslotId: string, options?: BookingReadOptions) {\n return this.getBookingService().searchByTimeslot(timeslotId, options);\n }\n\n /** Guests on a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.getGuests}. */\n getBookingGuests(bookingId: string) { return this.getBookingService().getGuests(bookingId); }\n\n /** Payments on file for a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.getPaymentsOnFile}. */\n getBookingPaymentsOnFile(bookingId: string) {\n return this.getBookingService().getPaymentsOnFile(bookingId);\n }\n\n /** Append or overwrite operator notes. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.appendNote}. */\n appendBookingNote(bookingId: string, note: string, mode?: NoteMode) {\n return this.getBookingService().appendNote(bookingId, note, mode);\n }\n\n /** Set booking check-in status. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.setCheckinStatus}. */\n setBookingCheckinStatus(bookingId: string, checkedIn: boolean) {\n return this.getBookingService().setCheckinStatus(bookingId, checkedIn);\n }\n\n /** Cancel a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.cancel}. */\n cancelBooking(bookingId: string, notes?: string) {\n return this.getBookingService().cancel(bookingId, notes);\n }\n\n /** Charge a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.makePayment}. */\n makeBookingPayment(input: MakePaymentInput) { return this.getBookingService().makePayment(input); }\n\n /** Refund a booking payment. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.refund}. */\n refundBooking(input: RefundInput) { return this.getBookingService().refund(input); }\n\n /** Create an invoice link. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.createInvoiceLink}. */\n createBookingInvoiceLink(bookingId: string) {\n return this.getBookingService().createInvoiceLink(bookingId);\n }\n\n /** List add-ons on a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.listAddons}. */\n listBookingAddons(bookingId: string) { return this.getBookingService().listAddons(bookingId); }\n\n /** Add an add-on to a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.addAddon}. */\n addBookingAddon(bookingId: string, input: AddAddonInput) {\n return this.getBookingService().addAddon(bookingId, input);\n }\n\n /** Remove an add-on from a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.removeAddon}. */\n removeBookingAddon(bookingId: string, input: AddAddonInput) {\n return this.getBookingService().removeAddon(bookingId, input);\n }\n\n /** Create a booking. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link BookingService.create}. */\n createBooking(input: CreateBookingInput) { return this.getBookingService().create(input); }\n\n // ─── Review short-forms ───────────────────────────────────────────────────\n\n /** Reviews for an activity. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link ReviewService.getReviews}. */\n getReviews(productId: string, reviewCount?: number, reviewOffset?: number) {\n return this.getReviewService().getReviews(productId, reviewCount, reviewOffset);\n }\n}\n","/**\n * Endpoint routing for the CNG backoffice REST gateway. Shared across the CNG\n * resources so each value lives in exactly one place, with {@link CNG_API_ENDPOINTS}\n * as the simple lookup a new CNG API extends. (The Peek gateway routing lives\n * separately in `../gateway-endpoints.ts`.)\n */\nimport { ApiEndpoints } from \"../api-endpoints.js\";\n\n/**\n * Routing slug inserted between the base API URL and the REST path. This is the\n * only routing difference from the Peek gateway (`peek_backoffice_api-v1`).\n */\nexport const CNG_EXTENDABLE_SLUG = \"cng_backoffice_api-v1\";\n\n/** Endpoint key for the app-registry products list. */\nexport const CNG_PRODUCTS_ENDPOINT = \"products\";\n\n/**\n * REST path (relative to the slug) for the app-registry products list.\n * `active=1` keeps the gateway from returning inactive/archived products, so\n * only bookable activities come back.\n */\nexport const PRODUCTS_PATH = \"api/v2/app-registry/products?active=1\";\n\n/** The endpoint keys the CNG REST transport knows how to route. */\nexport type CngEndpointKey = typeof CNG_PRODUCTS_ENDPOINT;\n\n/**\n * The CNG endpoint lookup — maps each endpoint key to the routing slug appended\n * to the base API URL. Add a new CNG API by adding one entry (with its own slug\n * when it needs a different one).\n */\nexport const CNG_API_ENDPOINTS: ApiEndpoints<CngEndpointKey> = new ApiEndpoints({\n [CNG_PRODUCTS_ENDPOINT]: CNG_EXTENDABLE_SLUG,\n});\n","/**\n * The clean, transport-agnostic data model for a CNG product.\n *\n * The CNG sibling of `../peek/product.ts`. Kept as a separate model because the\n * CNG gateway is a distinct backoffice, but the shape deliberately mirrors the\n * Peek `Product` so consumers can treat both brands uniformly. The raw CNG REST\n * response types and the conversion logic live inside the package and are never\n * exposed here.\n */\n\n/**\n * A bookable activity in a CNG account.\n *\n * `CngAccessService.getAllActivities()` returns these as a flat list.\n *\n * Mapped from the `app-registry/products` REST payload — see\n * `internal/cng/products/product-queries.ts`. That payload carries no\n * product-type discriminator and no sub-options, so `type` is always\n * {@link ACTIVITY_PRODUCT_TYPE} and `tickets` is always empty.\n */\nexport interface Activity {\n /** Stable unique identifier for the activity. */\n productId: string;\n\n /** Human-readable display name. */\n name: string;\n\n /**\n * Product type. Always {@link ACTIVITY_PRODUCT_TYPE} — the CNG products\n * payload has no type discriminator. Kept for parity with the Peek `Product`.\n */\n type: string;\n\n /**\n * Display color as a hex string (e.g. `\"#1A2B3C\"`), from the product's\n * access-control color. Empty string when no color is set.\n */\n color: string;\n\n /**\n * The bookable sub-options (tickets) of this activity. Always empty — CNG\n * exposes no tickets on the products endpoint today.\n */\n tickets: ActivityTicket[];\n}\n\n/** A single bookable sub-option (ticket) of an {@link Activity}. */\nexport interface ActivityTicket {\n /** Unique identifier of the ticket. */\n id: string;\n /** Human-readable name of the ticket. */\n name: string;\n}\n\n/** {@link Activity.type} for standard bookable activities. */\nexport const ACTIVITY_PRODUCT_TYPE = \"ACTIVITY\";\n","/**\n * Pure functions that map raw CNG product nodes into the clean {@link Activity}\n * model. No I/O — straightforward, testable transformations.\n *\n * The CNG products payload carries no product-type discriminator and no\n * sub-options, so every activity reports the {@link ACTIVITY_PRODUCT_TYPE} type\n * and an empty `tickets` list (same as ACME). Only `productId`, `name`, and\n * `color` come from the payload.\n */\nimport { ACTIVITY_PRODUCT_TYPE, type Activity } from \"../../../models/cng/product.js\";\nimport type { ProductNode } from \"./product-queries.js\";\n\n/** Converts a list of raw product nodes into {@link Activity}s. */\nexport function fromProductNodes(nodes: ProductNode[]): Activity[] {\n return nodes.map(fromProductNode);\n}\n\n/** Converts a single raw product node into an {@link Activity}. */\nfunction fromProductNode(node: ProductNode): Activity {\n return {\n productId: node.id == null ? \"\" : String(node.id),\n name: node.name || \"\",\n type: ACTIVITY_PRODUCT_TYPE,\n color: node.access_control_color_hex || \"\",\n tickets: [],\n };\n}\n","/**\n * Product-related operations against the CNG gateway.\n *\n * Obtain an instance via {@link CngAccessService.getProductService} rather than\n * constructing it directly — the access service wires in the authenticated,\n * shared transport. This class is where CNG product-specific business logic\n * lives. Named `CngProductService` to disambiguate from the Peek\n * `ProductService` in the same package.\n */\nimport { CNG_PRODUCTS_ENDPOINT, PRODUCTS_PATH } from \"../endpoints.js\";\nimport type { RestClient } from \"../rest-client.js\";\nimport type { Activity } from \"../../../models/cng/product.js\";\nimport { fromProductNodes } from \"./product-converter.js\";\nimport type { ProductsResponse } from \"./product-queries.js\";\n\nexport class CngProductService {\n constructor(private readonly client: RestClient) {}\n\n /**\n * Returns every activity as a single flat list.\n *\n * @example\n * ```ts\n * const activities = await cng.getProductService().getAllActivities();\n * ```\n */\n async getAllActivities(): Promise<Activity[]> {\n const body = await this.client.get<ProductsResponse>(\n CNG_PRODUCTS_ENDPOINT,\n PRODUCTS_PATH,\n );\n return fromProductNodes(body?.data ?? []);\n }\n}\n","/**\n * Thin REST-over-HTTP transport for the CNG gateway, built on the global\n * `fetch`. Handles endpoint construction, auth headers, and REST-specific\n * response handling. The shared retry/backoff loop and 418/429 mapping live in\n * `../http-transport.ts` (used by the Peek GraphQL transport too).\n *\n * The REST sibling of `../graphql-client.ts`, minus the GraphQL specifics:\n * requests are plain GETs (no `{query, variables}` envelope, no GraphQL `errors`\n * array), and there is no `pk-api-key` header — the CNG gateway authenticates on\n * the app JWT (`X-Peek-Auth`) alone. Both transports share the same\n * `TokenManager`, `Logger`, base error types, and retry loop.\n *\n * HTTP 403 is special-cased: the gateway uses it for \"this app is missing\n * permission X\", which is an expected misconfiguration rather than a fault, so\n * it is logged at `warn` (no stack, no body dump) and raised as the typed\n * {@link CngPermissionError} carrying the named permissions.\n */\nimport { CngApiError, CngPermissionError, FORBIDDEN_STATUS } from \"../../errors.js\";\nimport { ApiEndpoints, joinUrl } from \"../api-endpoints.js\";\nimport { parseBody, requestWithRetry } from \"../http-transport.js\";\nimport { SDK_HEADER_NAME, SDK_HEADER_VALUE } from \"../sdk-headers.js\";\nimport type { Logger } from \"../../logger.js\";\n\n/** Separator between the gateway's prose and the permission name it names. */\nconst PERMISSION_SEPARATOR = \": \";\n\nexport interface RestClientOptions {\n /**\n * The install's **base API URL** (no trailing slash, no routing slug). Each\n * request builds `baseApiUrl/<slug>/<path>`, where the slug comes from\n * {@link endpoints} for the request's endpoint key.\n */\n baseApiUrl: string;\n /** Maps an endpoint key to the relative slug appended to {@link baseApiUrl}. */\n endpoints: ApiEndpoints;\n /** Supplies a valid bearer token for each request. */\n getToken: () => string;\n /** Backoff delays (ms) applied on successive HTTP 429 responses. */\n retryDelaysMs: number[];\n /** Diagnostics sink. */\n logger: Logger;\n /** `fetch` implementation to use. */\n fetchFn: typeof fetch;\n}\n\nexport class RestClient {\n constructor(private readonly options: RestClientOptions) {}\n\n /**\n * Issues a GET against the named REST path and returns the parsed JSON body.\n * Retries on HTTP 429 per the configured backoff (via the shared\n * {@link requestWithRetry} loop).\n *\n * @throws {AdminAccountRequiredError} on HTTP 418\n * @throws {RateLimitError} on HTTP 429 after retries are exhausted\n * @throws {CngPermissionError} on HTTP 403 (app missing a permission)\n * @throws {CngApiError} on any other non-2xx response\n */\n async get<T>(endpoint: string, path: string): Promise<T> {\n const { logger } = this.options;\n const url = this.endpoint(endpoint, path);\n\n logger.info(\"Making CNG request\", { url, path });\n\n return requestWithRetry(\n this.options,\n url,\n { method: \"GET\", headers: this.buildHeaders() },\n path,\n async (response) => {\n const body = await parseBody(response);\n\n if (response.status === FORBIDDEN_STATUS) {\n const permissions = extractMissingPermissions(body);\n // Expected for a misconfigured install — warn, don't error.\n logger.warn(`Missing permission for ${path} (HTTP 403)`, { url, permissions });\n throw new CngPermissionError(permissions, body);\n }\n\n if (!response.ok) {\n logger.error(`CNG request failed with HTTP ${response.status}`, { url });\n throw new CngApiError(response.status, body);\n }\n\n return body as T;\n },\n );\n }\n\n private endpoint(endpoint: string, path: string): string {\n const { baseApiUrl, endpoints } = this.options;\n return joinUrl(baseApiUrl, endpoints.pathFor(endpoint), path);\n }\n\n private buildHeaders(): Record<string, string> {\n return {\n \"X-Peek-Auth\": `Bearer ${this.options.getToken()}`,\n \"Content-Type\": \"application/json\",\n [SDK_HEADER_NAME]: SDK_HEADER_VALUE,\n };\n }\n}\n\n/** Shape of the gateway's 403 body: `{ errors: { permission: [...] }, message }`. */\ninterface ForbiddenBody {\n errors?: { permission?: unknown } | null;\n}\n\n/**\n * Pulls the permission names out of a 403 body. The gateway reports them as\n * sentences (`\"The app does not have the required permission: products:read\"`),\n * so the trailing token after the last `\": \"` is the permission itself; a\n * sentence without one is kept verbatim. Returns an empty list for any body\n * that does not carry `errors.permission` strings.\n */\nfunction extractMissingPermissions(body: unknown): string[] {\n if (typeof body !== \"object\" || body === null) return [];\n const raw = (body as ForbiddenBody).errors?.permission;\n if (!Array.isArray(raw)) return [];\n return raw\n .filter((entry): entry is string => typeof entry === \"string\")\n .map((entry) => entry.split(PERMISSION_SEPARATOR).pop()!.trim())\n .filter((permission) => permission.length > 0);\n}\n","/**\n * Authenticated root entry point to the CNG backoffice REST gateway.\n *\n * The CNG sibling of {@link PeekAccessService}. Configure one instance per\n * install; it owns the shared, authenticated transport (minting/caching tokens\n * on demand) and hands out the {@link CngProductService}.\n *\n * Auth and transport mirror the Peek access service: the same app JWT\n * (`X-Peek-Auth: Bearer`) minted from the Peek app credentials via the shared\n * {@link TokenManager}, routed through the app-registry installations API. The\n * only differences are the extendable slug (`cng_backoffice_api-v1`), REST\n * rather than GraphQL, and no `pk-api-key` header.\n */\nimport {\n createTokenManager,\n requireNonEmpty,\n resolveBaseApiUrl,\n DEFAULT_RETRY_DELAYS_MS,\n type BaseAccessServiceConfig,\n} from \"./access-service-config.js\";\nimport { CNG_API_ENDPOINTS, CNG_EXTENDABLE_SLUG } from \"./internal/cng/endpoints.js\";\nimport { CngProductService } from \"./internal/cng/products/product-service.js\";\nimport { RestClient } from \"./internal/cng/rest-client.js\";\nimport { noopLogger } from \"./logger.js\";\n\n/** Default gateway base URL — the app-registry installations API. */\nconst DEFAULT_BASE_URL = \"https://app-registry.peeklabs.com/installations-api\";\n\n/**\n * Configuration for a {@link CngAccessService} instance. CNG adds no fields\n * beyond {@link BaseAccessServiceConfig} — it authenticates on the app JWT\n * alone (no `pk-api-key`, so no `gatewayKey`).\n */\nexport type CngAccessServiceConfig = BaseAccessServiceConfig;\n\n/**\n * Authenticated root entry point to the CNG backoffice REST gateway.\n *\n * @example\n * ```ts\n * import { CngAccessService, type Activity } from \"@peektravel/app-utilities\";\n *\n * const cng = new CngAccessService({\n * installId: \"install-123\",\n * jwtSecret: process.env.PEEK_APP_SECRET!,\n * issuer: process.env.PEEK_APP_ID!,\n * appId: process.env.PEEK_APP_ID!,\n * });\n *\n * const activities: Activity[] = await cng.getProductService().getAllActivities();\n * ```\n *\n * @throws {Error} from the constructor when any required config field\n * (`installId`, `jwtSecret`, `issuer`, `appId`) is empty.\n */\nexport class CngAccessService {\n private readonly client: RestClient;\n private productService?: CngProductService;\n\n constructor(config: CngAccessServiceConfig) {\n const hasApiUrl = !!config.apiUrl;\n requireNonEmpty(config.installId, \"installId\", \"CngAccessService\");\n requireNonEmpty(config.jwtSecret, \"jwtSecret\", \"CngAccessService\");\n requireNonEmpty(config.issuer, \"issuer\", \"CngAccessService\");\n if (!hasApiUrl) requireNonEmpty(config.appId ?? \"\", \"appId\", \"CngAccessService\");\n\n const logger = config.logger ?? noopLogger;\n const tokens = createTokenManager(config);\n\n const baseApiUrl = hasApiUrl\n ? resolveBaseApiUrl(config.apiUrl!, CNG_EXTENDABLE_SLUG, \"CngAccessService\")\n : `${config.baseUrl ?? DEFAULT_BASE_URL}/${config.appId}`;\n this.client = new RestClient({\n baseApiUrl,\n endpoints: CNG_API_ENDPOINTS,\n getToken: () => tokens.getToken(),\n retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,\n logger,\n fetchFn: config.fetch ?? globalThis.fetch,\n });\n }\n\n /**\n * Returns the {@link CngProductService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getProductService(): CngProductService {\n if (!this.productService) {\n this.productService = new CngProductService(this.client);\n }\n return this.productService;\n }\n\n /** All activities. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link CngProductService.getAllActivities}. */\n getAllActivities() {\n return this.getProductService().getAllActivities();\n }\n}\n","/**\n * Endpoint routing for the ACME backoffice REST gateway. Shared across the ACME\n * resources so each value lives in exactly one place, with {@link ACME_API_ENDPOINTS}\n * as the simple lookup a new ACME API extends. (The CNG gateway routing lives\n * separately in `../cng/endpoints.ts`.)\n */\nimport { ApiEndpoints } from \"../api-endpoints.js\";\n\n/**\n * Routing slug inserted between the base API URL and the REST path. This is the\n * only routing difference from the other gateways (CNG uses\n * `cng_backoffice_api-v1`; Peek uses `peek_backoffice_api-v1`).\n */\nexport const ACME_EXTENDABLE_SLUG = \"acme_backoffice_api-v1\";\n\n/** Endpoint key for the event-template names list. */\nexport const ACME_TEMPLATES_ENDPOINT = \"templates\";\n\n/** REST path (relative to the slug) for the event-template names list. */\nexport const TEMPLATES_PATH = \"v2/b2b/event/templates/names?pageSize=-1&page=1\";\n\n/** The endpoint keys the ACME REST transport knows how to route. */\nexport type AcmeEndpointKey = typeof ACME_TEMPLATES_ENDPOINT;\n\n/**\n * The ACME endpoint lookup — maps each endpoint key to the routing slug appended\n * to the base API URL. Add a new ACME API by adding one entry (with its own slug\n * when it needs a different one).\n */\nexport const ACME_API_ENDPOINTS: ApiEndpoints<AcmeEndpointKey> = new ApiEndpoints({\n [ACME_TEMPLATES_ENDPOINT]: ACME_EXTENDABLE_SLUG,\n});\n","/**\n * The clean, transport-agnostic data model for an ACME event template.\n *\n * The ACME sibling of `../cng/product.ts`. Kept as a separate model because the\n * ACME gateway is a distinct backoffice, but the shape deliberately mirrors the\n * CNG `Activity` so consumers can treat every brand uniformly. The raw ACME\n * REST response types and the conversion logic live inside the package and are\n * never exposed here.\n */\n\n/**\n * A bookable activity in an ACME account (an event template).\n *\n * `AcmeAccessService.getAllActivities()` returns these as a flat list, filtered\n * to published templates only. ACME does not expose tickets today, so\n * {@link AcmeActivity.tickets} is always an empty list.\n */\nexport interface AcmeActivity {\n /** Stable unique identifier for the activity. */\n productId: string;\n\n /** Human-readable display name. */\n name: string;\n\n /** Product type reported by ACME (e.g. `\"standard\"`). */\n type: string;\n\n /**\n * Display color as a hex string (e.g. `\"#00695c\"`). Falls back to a neutral\n * gray (`\"#d1d1d1\"`) when no color is set.\n */\n color: string;\n\n /** The bookable sub-options (tickets) of this activity. Always empty today. */\n tickets: AcmeActivityTicket[];\n}\n\n/** A single bookable sub-option (ticket) of an {@link AcmeActivity}. */\nexport interface AcmeActivityTicket {\n /** Unique identifier of the ticket. */\n id: string;\n /** Human-readable name of the ticket. */\n name: string;\n}\n\n/** {@link AcmeActivity.type} fallback for templates missing a type. */\nexport const ACME_ACTIVITY_TYPE = \"standard\";\n","/**\n * Raw ACME REST response shapes for event templates. Internal implementation\n * detail of the package — deliberately not re-exported from the public entry\n * point.\n *\n * The `v2/b2b/event/templates/names` endpoint returns a `{ list: [...] }`\n * envelope. Each node carries a `reviewState`; only `\"published\"` templates are\n * surfaced as activities (see the converter).\n */\n\n/** The published review state — the only templates surfaced as activities. */\nexport const PUBLISHED_REVIEW_STATE = \"published\";\n\n/** A single template node as returned by the templates/names endpoint. */\nexport interface TemplateNode {\n /** Stable template id. */\n id: string;\n /** Display name. */\n name: string;\n /** Template type (e.g. `\"standard\"`). */\n type?: string;\n /** Admission type (e.g. `\"standard\"`). */\n admissionType?: string;\n /** Publication state; only `\"published\"` templates are surfaced. */\n reviewState?: string;\n /** Display color pair, if set. */\n colorCategory?: {\n backgroundColor?: string | null;\n textColor?: string | null;\n } | null;\n}\n\n/**\n * The templates list payload. Tolerates either a top-level `list` array or a\n * bare array response.\n */\nexport interface TemplatesResponse {\n list?: TemplateNode[];\n}\n","/**\n * Pure functions that map raw ACME template nodes into the clean\n * {@link AcmeActivity} model. No I/O — straightforward, testable\n * transformations.\n *\n * Only `\"published\"` templates are surfaced; ACME does not expose tickets, so\n * every activity carries an empty `tickets` list.\n */\nimport { ACME_ACTIVITY_TYPE, type AcmeActivity } from \"../../../models/acme/product.js\";\nimport { PUBLISHED_REVIEW_STATE, type TemplateNode } from \"./product-queries.js\";\n\n/**\n * Converts a list of raw template nodes into {@link AcmeActivity}s, keeping only\n * published templates.\n */\nexport function fromTemplateNodes(nodes: TemplateNode[]): AcmeActivity[] {\n return nodes\n .filter((node) => node.reviewState === PUBLISHED_REVIEW_STATE)\n .map(fromTemplateNode);\n}\n\n/** Converts a single raw template node into an {@link AcmeActivity}. */\nfunction fromTemplateNode(node: TemplateNode): AcmeActivity {\n return {\n productId: node.id || \"\",\n name: node.name || \"\",\n type: node.type || ACME_ACTIVITY_TYPE,\n color: node.colorCategory?.backgroundColor || \"#d1d1d1\",\n tickets: [],\n };\n}\n","/**\n * Product-related operations against the ACME gateway.\n *\n * Obtain an instance via {@link AcmeAccessService.getProductService} rather than\n * constructing it directly — the access service wires in the authenticated,\n * shared transport. This class is where ACME product-specific business logic\n * lives. Named `AcmeProductService` to disambiguate from the Peek\n * `ProductService` and the CNG `CngProductService` in the same package.\n */\nimport { ACME_TEMPLATES_ENDPOINT, TEMPLATES_PATH } from \"../endpoints.js\";\nimport type { RestClient } from \"../rest-client.js\";\nimport type { AcmeActivity } from \"../../../models/acme/product.js\";\nimport { fromTemplateNodes } from \"./product-converter.js\";\nimport type { TemplatesResponse } from \"./product-queries.js\";\n\nexport class AcmeProductService {\n constructor(private readonly client: RestClient) {}\n\n /**\n * Returns every published event template as a single flat list of activities.\n *\n * @example\n * ```ts\n * const activities = await acme.getProductService().getAllActivities();\n * ```\n */\n async getAllActivities(): Promise<AcmeActivity[]> {\n const body = await this.client.get<TemplatesResponse | TemplatesResponse[\"list\"]>(\n ACME_TEMPLATES_ENDPOINT,\n TEMPLATES_PATH,\n );\n // Tolerate either a { list: [...] } envelope or a bare array.\n const nodes = Array.isArray(body) ? body : (body?.list ?? []);\n return fromTemplateNodes(nodes ?? []);\n }\n}\n","/**\n * Thin REST-over-HTTP transport for the ACME gateway, built on the global\n * `fetch`. Handles endpoint construction, auth headers, and REST-specific\n * response handling. The shared retry/backoff loop and 418/429 mapping live in\n * `../http-transport.ts` (used by the Peek GraphQL and CNG REST transports too).\n *\n * The REST sibling of `../cng/rest-client.ts`: requests are plain GETs (no\n * `{query, variables}` envelope, no GraphQL `errors` array), and there is no\n * `pk-api-key` header — the ACME gateway authenticates on the app JWT\n * (`X-Peek-Auth`) alone. Both transports share the same `TokenManager`,\n * `Logger`, base error types, and retry loop.\n */\nimport { AcmeApiError } from \"../../errors.js\";\nimport { ApiEndpoints, joinUrl } from \"../api-endpoints.js\";\nimport { parseBody, requestWithRetry } from \"../http-transport.js\";\nimport { SDK_HEADER_NAME, SDK_HEADER_VALUE } from \"../sdk-headers.js\";\nimport type { Logger } from \"../../logger.js\";\n\nexport interface RestClientOptions {\n /**\n * The install's **base API URL** (no trailing slash, no routing slug). Each\n * request builds `baseApiUrl/<slug>/<path>`, where the slug comes from\n * {@link endpoints} for the request's endpoint key.\n */\n baseApiUrl: string;\n /** Maps an endpoint key to the relative slug appended to {@link baseApiUrl}. */\n endpoints: ApiEndpoints;\n /** Supplies a valid bearer token for each request. */\n getToken: () => string;\n /** Backoff delays (ms) applied on successive HTTP 429 responses. */\n retryDelaysMs: number[];\n /** Diagnostics sink. */\n logger: Logger;\n /** `fetch` implementation to use. */\n fetchFn: typeof fetch;\n}\n\nexport class RestClient {\n constructor(private readonly options: RestClientOptions) {}\n\n /**\n * Issues a GET against the named REST path and returns the parsed JSON body.\n * Retries on HTTP 429 per the configured backoff (via the shared\n * {@link requestWithRetry} loop).\n *\n * @throws {AdminAccountRequiredError} on HTTP 418\n * @throws {RateLimitError} on HTTP 429 after retries are exhausted\n * @throws {AcmeApiError} on any other non-2xx response\n */\n async get<T>(endpoint: string, path: string): Promise<T> {\n const { logger } = this.options;\n const url = this.endpoint(endpoint, path);\n\n logger.info(\"Making ACME request\", { url, path });\n\n return requestWithRetry(\n this.options,\n url,\n { method: \"GET\", headers: this.buildHeaders() },\n path,\n async (response) => {\n const body = await parseBody(response);\n\n if (!response.ok) {\n logger.error(`ACME request failed with HTTP ${response.status}`, { url });\n throw new AcmeApiError(response.status, body);\n }\n\n return body as T;\n },\n );\n }\n\n private endpoint(endpoint: string, path: string): string {\n const { baseApiUrl, endpoints } = this.options;\n return joinUrl(baseApiUrl, endpoints.pathFor(endpoint), path);\n }\n\n private buildHeaders(): Record<string, string> {\n return {\n \"X-Peek-Auth\": `Bearer ${this.options.getToken()}`,\n \"Content-Type\": \"application/json\",\n [SDK_HEADER_NAME]: SDK_HEADER_VALUE,\n };\n }\n}\n","/**\n * Authenticated root entry point to the ACME backoffice REST gateway.\n *\n * The ACME sibling of {@link PeekAccessService} / {@link CngAccessService}.\n * Configure one instance per install; it owns the shared, authenticated\n * transport (minting/caching tokens on demand) and hands out the\n * {@link AcmeProductService}.\n *\n * Auth and transport mirror the CNG access service: the same app JWT\n * (`X-Peek-Auth: Bearer`) minted from the Peek app credentials via the shared\n * {@link TokenManager}, routed through the app-registry installations API. The\n * only differences are the extendable slug (`acme_backoffice_api-v1`), REST\n * rather than GraphQL, and no `pk-api-key` header.\n */\nimport {\n createTokenManager,\n requireNonEmpty,\n resolveBaseApiUrl,\n DEFAULT_RETRY_DELAYS_MS,\n type BaseAccessServiceConfig,\n} from \"./access-service-config.js\";\nimport { ACME_API_ENDPOINTS, ACME_EXTENDABLE_SLUG } from \"./internal/acme/endpoints.js\";\nimport { AcmeProductService } from \"./internal/acme/products/product-service.js\";\nimport { RestClient } from \"./internal/acme/rest-client.js\";\nimport { noopLogger } from \"./logger.js\";\n\n/** Default gateway base URL — the app-registry installations API. */\nconst DEFAULT_BASE_URL = \"https://app-registry.peeklabs.com/installations-api\";\n\n/**\n * Configuration for an {@link AcmeAccessService} instance. ACME adds no fields\n * beyond {@link BaseAccessServiceConfig} — it authenticates on the app JWT\n * alone (no `pk-api-key`, so no `gatewayKey`).\n */\nexport type AcmeAccessServiceConfig = BaseAccessServiceConfig;\n\n/**\n * Authenticated root entry point to the ACME backoffice REST gateway.\n *\n * @example\n * ```ts\n * import { AcmeAccessService, type AcmeActivity } from \"@peektravel/app-utilities\";\n *\n * const acme = new AcmeAccessService({\n * installId: \"install-123\",\n * jwtSecret: process.env.PEEK_APP_SECRET!,\n * issuer: process.env.PEEK_APP_ID!,\n * appId: process.env.PEEK_APP_ID!,\n * });\n *\n * const activities: AcmeActivity[] = await acme.getProductService().getAllActivities();\n * ```\n *\n * @throws {Error} from the constructor when any required config field\n * (`installId`, `jwtSecret`, `issuer`, `appId`) is empty.\n */\nexport class AcmeAccessService {\n private readonly client: RestClient;\n private productService?: AcmeProductService;\n\n constructor(config: AcmeAccessServiceConfig) {\n const hasApiUrl = !!config.apiUrl;\n requireNonEmpty(config.installId, \"installId\", \"AcmeAccessService\");\n requireNonEmpty(config.jwtSecret, \"jwtSecret\", \"AcmeAccessService\");\n requireNonEmpty(config.issuer, \"issuer\", \"AcmeAccessService\");\n if (!hasApiUrl) requireNonEmpty(config.appId ?? \"\", \"appId\", \"AcmeAccessService\");\n\n const logger = config.logger ?? noopLogger;\n const tokens = createTokenManager(config);\n\n const baseApiUrl = hasApiUrl\n ? resolveBaseApiUrl(config.apiUrl!, ACME_EXTENDABLE_SLUG, \"AcmeAccessService\")\n : `${config.baseUrl ?? DEFAULT_BASE_URL}/${config.appId}`;\n this.client = new RestClient({\n baseApiUrl,\n endpoints: ACME_API_ENDPOINTS,\n getToken: () => tokens.getToken(),\n retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,\n logger,\n fetchFn: config.fetch ?? globalThis.fetch,\n });\n }\n\n /**\n * Returns the {@link AcmeProductService} for this install, bound to the shared\n * authenticated transport. The instance is created lazily and reused.\n */\n getProductService(): AcmeProductService {\n if (!this.productService) {\n this.productService = new AcmeProductService(this.client);\n }\n return this.productService;\n }\n\n /** All activities. @deprecated The access service exposes only its resource-service accessors; call the service directly instead. See {@link AcmeProductService.getAllActivities}. */\n getAllActivities() {\n return this.getProductService().getAllActivities();\n }\n}\n","/**\n * Factory that turns a persisted install (or a parsed install webhook) into the\n * right access service for its platform, wired to the install's own app\n * endpoint.\n *\n * The install webhook is the only source of an install's `platform` and `apiUrl`\n * (see `src/models/peek/install.ts`), and those two facts are exactly what's\n * needed to target it: `platform` picks the service class, and `apiUrl` is used\n * **as given** as that service's endpoint. This helper encodes that mapping so a\n * consumer that persisted an install can construct its client in one call\n * instead of switching on the platform and hand-wiring the URL.\n */\nimport {\n PeekAccessService,\n type PeekAccessServiceConfig,\n} from \"./peek-access-service.js\";\nimport { CngAccessService } from \"./cng-access-service.js\";\nimport { AcmeAccessService } from \"./acme-access-service.js\";\nimport type { PeekPlatform } from \"./models/peek/auth-token.js\";\n\n/**\n * The per-install facts needed to build an access service — a structural subset\n * of {@link InstallWebhook}, so a persisted install record (or the webhook event\n * itself) satisfies it directly.\n */\nexport interface InstallAccessTarget {\n /** Which platform serves the install (the install webhook's `platform`). */\n platform: PeekPlatform | null;\n /**\n * The install's base API URL (the install webhook's `apiUrl`). The chosen\n * access service's service classes append their own backoffice slug when they\n * call; a URL already carrying this platform's slug is stripped back to the\n * base, and one carrying a different platform's slug throws.\n */\n apiUrl: string;\n /** The install id (the install webhook's `installId`) — becomes the JWT subject. */\n installId: string;\n}\n\n/**\n * The per-app credentials/options shared by every access service — everything\n * except the per-install `installId`/`apiUrl` (supplied by the target) and the\n * deprecated `appId`/`baseUrl`/`mode` URL controls (superseded by `apiUrl`).\n * `gatewayKey` is accepted for Peek and ignored by CNG/ACME.\n */\nexport type InstallAccessConfig = Omit<\n PeekAccessServiceConfig,\n \"installId\" | \"apiUrl\" | \"appId\" | \"baseUrl\" | \"mode\"\n>;\n\n/** The union of access services this factory can return, narrowed by `platform`. */\nexport type InstallAccessService =\n | PeekAccessService\n | CngAccessService\n | AcmeAccessService;\n\n/**\n * Builds the access service for `install.platform`, using `install.apiUrl` as\n * the service's endpoint. Narrow the return by `install.platform` (or\n * `instanceof`) to reach a platform-specific surface.\n *\n * @throws {Error} when `install.platform` is `null` or unrecognised — an install\n * with an unknown platform has no service to route to, and silently defaulting\n * would point it at the wrong gateway.\n */\nexport function createAccessServiceForInstall(\n install: InstallAccessTarget,\n config: InstallAccessConfig,\n): InstallAccessService {\n const shared = { ...config, installId: install.installId, apiUrl: install.apiUrl };\n switch (install.platform) {\n case \"peek\":\n return new PeekAccessService(shared);\n case \"cng\":\n return new CngAccessService(shared);\n case \"acme\":\n return new AcmeAccessService(shared);\n default:\n throw new Error(\n `createAccessServiceForInstall: unknown or missing platform ` +\n `\"${install.platform}\" for install \"${install.installId}\"`,\n );\n }\n}\n","/**\n * Public webhook surface for bookings.\n *\n * A Peek \"backoffice\" booking webhook's payload shape is defined by a GraphQL\n * field selection registered with the hook. That registration happens once, in\n * an external system (the App Store `broadcast_to_url` config) — not from\n * consumer code — so this package registers nothing at runtime. It owns the two\n * pieces that must agree:\n *\n * - {@link BOOKING_WEBHOOK_GQL_QUERY} — the canonical selection to paste into\n * that external config. A setup-time artifact surfaced through\n * `docs/webhooks.md` and pinned by a drift-guard test; **internal**, not part\n * of the runtime public API.\n * - {@link parseBookingWebhook} — the only runtime export; turns a delivered\n * payload into a clean {@link Booking} using the very same converter as the\n * read path.\n *\n * Parsing an inbound webhook needs no auth, no network, and no client — it is a\n * pure transform — so it is exported as a standalone function rather than a\n * method on `PeekAccessService` (the receiver may not hold gateway credentials).\n */\nimport type { Booking } from \"../../../models/peek/booking.js\";\nimport { fromBookingNode } from \"./booking-converter.js\";\nimport {\n bookingGuestsFields,\n bookingQueryFields,\n PRICE_BREAKDOWN_FIELDS,\n type BookingNode,\n} from \"./booking-queries.js\";\n\n/** The envelope key the webhook delivery wraps the booking node under. */\nconst PAYLOAD_BOOKING_KEY = \"booking\";\n\n/** The `value` sub-field that anchors the price-breakdown injection. */\nconst VALUE_OPEN_TOKEN = \"value {\";\n\n/**\n * Price-breakdown field names that only appear on `value` when the breakdown was\n * requested — their presence is how {@link parseBookingWebhook} auto-detects it.\n */\nconst PRICE_BREAKDOWN_KEYS = [\n \"convenienceFee\",\n \"deposit\",\n \"discount\",\n \"discountedPrice\",\n \"fees\",\n \"flatPartnerFee\",\n \"price\",\n \"retailPrice\",\n \"taxes\",\n] as const;\n\n/**\n * The canonical GraphQL selection set to register with the booking webhook — the\n * value that goes in the external `output_fields_gql_query` config.\n *\n * It is the **maximal** selection (guests + full price breakdown included), so a\n * single registration captures everything and {@link parseBookingWebhook}\n * auto-detects whatever the payload actually carries. It is the bare selection\n * set (`{ … }`), not a wrapped `query`, because the webhook system supplies the\n * operation around it; whitespace is collapsed so it drops into a JSON config\n * string.\n *\n * Internal: the webhook is configured in an external system, so this is a\n * setup-time artifact (see `docs/webhooks.md`), not a runtime API. A drift-guard\n * test snapshots it so the documented string can't silently rot.\n */\nexport const BOOKING_WEBHOOK_GQL_QUERY = buildMaximalWebhookQuery();\n\nfunction buildMaximalWebhookQuery(): string {\n const fields = bookingQueryFields.replace(\n VALUE_OPEN_TOKEN,\n `${VALUE_OPEN_TOKEN} ${PRICE_BREAKDOWN_FIELDS}`,\n );\n return `{ ${fields} ${bookingGuestsFields} }`.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Parses a delivered booking webhook payload into a clean {@link Booking}.\n *\n * Accepts the raw request body — either the `{ booking: … }` envelope or a bare\n * booking node, and a JSON string is parsed first. Which optional field groups\n * are present is auto-detected from the payload, so there is nothing to keep in\n * sync with the registered query.\n */\nexport function parseBookingWebhook(payload: unknown): Booking {\n const node = extractBookingNode(payload);\n return fromBookingNode(node, hasGuests(node), hasPriceBreakdown(node));\n}\n\n/** Narrows the raw request body down to the booking node, tolerating both shapes. */\nfunction extractBookingNode(payload: unknown): BookingNode {\n let body: unknown = payload;\n if (typeof body === \"string\") {\n try {\n body = JSON.parse(body);\n } catch {\n return {};\n }\n }\n if (!body || typeof body !== \"object\") return {};\n const record = body as Record<string, unknown>;\n const inner = record[PAYLOAD_BOOKING_KEY];\n if (inner && typeof inner === \"object\") return inner as BookingNode;\n return record as BookingNode;\n}\n\nfunction hasGuests(node: BookingNode): boolean {\n return Array.isArray(node.bookingGuests);\n}\n\nfunction hasPriceBreakdown(node: BookingNode): boolean {\n const value = node.value;\n if (!value) return false;\n return PRICE_BREAKDOWN_KEYS.some((key) => key in value);\n}\n","/**\n * Public webhook surface for waivers.\n *\n * Unlike bookings, a waiver webhook needs **no GraphQL registration query** —\n * Peek delivers a fixed payload (the App Store `waiver_webhook_data` output\n * format, with `output_fields_gql_query` left null), so there is nothing to\n * register beyond subscribing to the `agreement_signature_created` event. The\n * package's only job is to parse the delivered payload into a clean\n * {@link Waiver}.\n *\n * Like the booking parser, this is a pure transform — no auth, no network, no\n * client — so it is a standalone function rather than a method on\n * `PeekAccessService` (the receiver may not hold gateway credentials).\n */\nimport type { Waiver } from \"../../../models/peek/waiver.js\";\nimport {\n resolveAccessOptions,\n type AccessOptions,\n} from \"../../../access-options.js\";\n\n/** The envelope key the webhook delivery wraps the waiver node under. */\nconst PAYLOAD_WAIVER_KEY = \"waiver\";\n\n/** Raw, snake_case waiver payload as delivered by the webhook. Internal. */\ninterface WaiverNode {\n agreement_template_id?: string;\n booking_id?: string;\n file_url?: string;\n signed_at?: string;\n signed_by_guardian?: boolean;\n waiver_data?: {\n participant_name?: string | null;\n participant_optin_marketing?: boolean;\n participant_optin_sms?: boolean;\n } | null;\n}\n\n/**\n * Parses a delivered waiver webhook payload into a clean {@link Waiver}.\n *\n * Accepts the raw request body — either the `{ waiver: … }` envelope or a bare\n * waiver node, and a JSON string is parsed first. Never throws on malformed\n * input: a missing/garbled body yields a {@link Waiver} with empty fields.\n *\n * Because a waiver webhook has no GraphQL selection to trim (Peek delivers a\n * fixed payload), the PII fields — the participant `guestName` and the signed\n * document `fileUrl` — are instead redacted here at parse time when `options`\n * does not enable PII. Pass `{ fullCustomerAccess: true }` to keep them.\n */\nexport function parseWaiverWebhook(\n payload: unknown,\n options?: AccessOptions,\n): Waiver {\n const waiver = fromWaiverNode(extractWaiverNode(payload));\n if (!resolveAccessOptions(options).fullCustomerAccess) {\n waiver.guestName = null;\n waiver.fileUrl = \"\";\n }\n return waiver;\n}\n\n/** Pure mapping of a raw waiver node into the clean {@link Waiver} model. */\nexport function fromWaiverNode(node: WaiverNode | null | undefined): Waiver {\n const data = node ?? {};\n const waiverData = data.waiver_data ?? {};\n return {\n templateId: data.agreement_template_id || \"\",\n bookingId: data.booking_id || \"\",\n fileUrl: data.file_url || \"\",\n signedAt: data.signed_at || \"\",\n isSignedByGuardian: Boolean(data.signed_by_guardian),\n guestName: waiverData.participant_name || null,\n isOptinMarketing: Boolean(waiverData.participant_optin_marketing),\n isOptinSms: Boolean(waiverData.participant_optin_sms),\n };\n}\n\n/** Narrows the raw request body down to the waiver node, tolerating both shapes. */\nfunction extractWaiverNode(payload: unknown): WaiverNode {\n let body: unknown = payload;\n if (typeof body === \"string\") {\n try {\n body = JSON.parse(body);\n } catch {\n return {};\n }\n }\n if (!body || typeof body !== \"object\") return {};\n const record = body as Record<string, unknown>;\n const inner = record[PAYLOAD_WAIVER_KEY];\n if (inner && typeof inner === \"object\") return inner as WaiverNode;\n return record as WaiverNode;\n}\n","/**\n * The clean data model for an app-store **install lifecycle event** — the single\n * flat object `parseInstallWebhook` returns for the webhook Peek's app registry\n * POSTs when an app is installed, uninstalled, or updated.\n *\n * That delivery carries two things at once: a **signed `app_registry_v2` JWT**\n * (the security boundary) and a plain **JSON body** (the event payload).\n * `parseInstallWebhook` verifies the JWT and merges both into this shape, so a\n * consumer sees one clean, flat, JSON-safe record instead of two differently\n * shaped payloads. The **JSON body is the source of the event data** — it\n * carries every field below; the verified JWT authenticates the delivery and\n * acts as the **fallback** for the fields it also happens to carry (`installId`,\n * `accountId`, `status`, `displayVersion`, `user`) when the body omits them.\n *\n * It is also the single origin of the account id (and the `apiUrl`/`timezone`)\n * in the whole system: no GraphQL read returns them, so whatever a consumer\n * persists from this event is all it will ever have.\n *\n * **Every install event is a full snapshot — upsert by `installId`.** An\n * `update_installed` event carries the *same complete record* as the original\n * `installed` event, so treat each delivery as an upsert keyed by `installId`\n * and overwrite the stored fields with the incoming ones. This is how the\n * registry pushes changes — e.g. a new `apiUrl` — so a consumer that only reads\n * the first `installed` event and ignores later updates will keep stale data.\n */\nimport type { PeekAuthTokenUser, PeekPlatform } from \"./auth-token.js\";\n\n/**\n * Every install lifecycle status Peek's app registry sends today. Exported so\n * consumers can validate or enumerate without restating the vocabulary.\n */\nexport const INSTALL_STATUSES = [\n \"installed\",\n \"uninstalled\",\n \"update_installed\",\n] as const;\n\n/** Install lifecycle status. */\nexport type InstallStatus = (typeof INSTALL_STATUSES)[number];\n\n/**\n * A verified install lifecycle event — what happened, to which install, and who\n * (if anyone) triggered it — as one flat, JSON-safe record.\n *\n * This is the shape `parseInstallWebhook` returns. It is flat by design: it\n * round-trips through a datastore unchanged, so the same shape the parser\n * returns is the shape a consumer persists and later rehydrates. There is\n * deliberately no nested identity object and no second representation.\n *\n * Every field is read from the **JSON body** first, falling back to the\n * **verified JWT** for the fields it also carries (`installId`, `accountId`,\n * `status`, `displayVersion`, `user`). The delivery is authenticated as a whole\n * by the JWT signature, so the body is trusted within a verified request.\n */\nexport interface InstallWebhook {\n /** Install ID — Peek-assigned UUID. Also the JWT subject (`sub`). */\n installId: string;\n /**\n * Stable Peek account id — the same value Peek calls the **partner ID**.\n * This event is its only source; it cannot be re-fetched later.\n */\n accountId: string;\n /** Partner display name. `\"\"` when the JSON body omits it. */\n accountName: string;\n /**\n * Which Peek platform owns the install, or `null` when the registry reported\n * a platform this version of the package does not know. `null` means \"newer\n * than this package\", **not** \"absent\" — do not coerce it to a default.\n *\n * **Persist and track this per install.** It is not cosmetic: the platform\n * determines which APIs the install is served by, and therefore which access\n * service a consumer must construct for it — `PeekAccessService` for `\"peek\"`,\n * `CngAccessService` for `\"cng\"`, `AcmeAccessService` for `\"acme\"`, each\n * routed at a different gateway. Two installs of the same app can sit on\n * different platforms, so this cannot be inferred from app-level config and\n * has no source other than this event.\n */\n platform: PeekPlatform | null;\n /** Whether this is a test account. Defaults to `false` when not reported. */\n isTest: boolean;\n /**\n * The account's IANA timezone (e.g. `\"America/New_York\"`), or `\"\"` when the\n * body omits it.\n *\n * **Persist this per install.** It has no source other than this event, and\n * downstream date/time handling for the install (scheduling, day boundaries,\n * display) needs the account's own timezone rather than the server's.\n */\n timezone: string;\n /**\n * The **app endpoint URL** the registry serves this install from (the body's\n * `api.url`), or `\"\"` when the body omits it.\n *\n * Use it **as given** as the base URL for this install's API calls — do not\n * decompose it or append your own app id. The registry may tag traffic with an\n * app id in the path; that is the registry's concern and opaque to callers, so\n * hit the URL unmodified.\n *\n * **Persist this per install, and refresh it on every install event.** It is\n * install-specific, has no source other than this webhook, and the registry\n * can change it: an `update_installed` event redelivers the full record with a\n * (possibly new) `apiUrl`, so re-key by `installId` and overwrite the stored\n * URL whenever an event arrives.\n */\n apiUrl: string;\n /**\n * The lifecycle status, or `null` when the registry sent a status this\n * version of the package does not know. Handle `null` explicitly — treating\n * it as a no-op silently drops a lifecycle transition.\n */\n status: InstallStatus | null;\n /** The status exactly as delivered, for logging and for the `null` case. */\n rawStatus: string;\n /** App display version at the time of the event. */\n displayVersion: string;\n /**\n * The user that triggered the event, or `null` for system-initiated events\n * (install lifecycle changes are often system-initiated). Read from the body's\n * `modified_by`, falling back to the JWT's `user`.\n */\n user: PeekAuthTokenUser | null;\n}\n","/**\n * Pure, I/O-free helpers for the install webhook: narrowing an unknown request\n * body to the raw JSON node, and narrowing a delivered `status`/`platform`\n * string to its known union. No network, no logging, no clock.\n *\n * Internal only — never re-exported from `src/index.ts`.\n */\nimport {\n PEEK_PLATFORMS,\n type PeekPlatform,\n} from \"../../../models/peek/auth-token.js\";\nimport {\n INSTALL_STATUSES,\n type InstallStatus,\n} from \"../../../models/peek/install.js\";\nimport type { RawPeekTokenUser } from \"../peek-auth-token.js\";\n\n/** The raw, snake_case account block of an install webhook's JSON body. */\nexport interface InstallWebhookBodyAccount {\n id?: string;\n name?: string;\n platform?: string;\n timezone?: string;\n is_test?: boolean;\n}\n\n/**\n * The raw, snake_case JSON body delivered alongside the install webhook token.\n * This is the **primary source of the event data**: it carries the full\n * `account` block, the per-install `api.url`, the `modified_by` actor, and the\n * `install_id`/`status`/`display_version` the token also carries (the token is\n * the fallback for those). Extraction is defensive — any field may be absent.\n */\nexport interface InstallWebhookBody {\n status?: string;\n install_id?: string;\n display_version?: string;\n account?: InstallWebhookBodyAccount | null;\n /** The per-install backoffice API endpoint block. */\n api?: { url?: string } | null;\n /** The user that triggered the event (same shape as the token's `user`). */\n modified_by?: RawPeekTokenUser | null;\n}\n\n/**\n * Narrows an unknown request body to an {@link InstallWebhookBody}, tolerating a\n * JSON string (parsed first) and returning `{}` for anything non-object or\n * unparseable, so the caller never has to guard.\n */\nexport function extractInstallWebhookBody(payload: unknown): InstallWebhookBody {\n let body: unknown = payload;\n if (typeof body === \"string\") {\n try {\n body = JSON.parse(body);\n } catch {\n return {};\n }\n }\n if (!body || typeof body !== \"object\") return {};\n return body as InstallWebhookBody;\n}\n\n/**\n * Narrows a delivered status to the {@link InstallStatus} union, or `null` when\n * the registry sent one this version of the package does not know.\n */\nexport function toInstallStatus(raw: string): InstallStatus | null {\n return (INSTALL_STATUSES as readonly string[]).includes(raw)\n ? (raw as InstallStatus)\n : null;\n}\n\n/**\n * Narrows a reported platform to the {@link PeekPlatform} union, or `null` when\n * the registry sent one this version of the package does not know.\n */\nexport function toPeekPlatform(raw: string): PeekPlatform | null {\n return (PEEK_PLATFORMS as readonly string[]).includes(raw)\n ? (raw as PeekPlatform)\n : null;\n}\n","/**\n * Public webhook surface for install-status events.\n *\n * Peek's app registry notifies your app of install lifecycle changes (installed,\n * uninstalled, status changed) with a single POST that carries **two** things at\n * once: a **signed `app_registry_v2` JWT** (delivered in the `x-peek-auth`\n * request header) and a plain **JSON body**. The JWT is the security boundary —\n * verifying its\n * signature is what authenticates that the notification really came from Peek\n * before your app acts on it (e.g. de-provisioning an uninstall). The JSON body\n * is the **event payload**: it carries the full account block (name, platform,\n * timezone, test flag), the per-install `api.url`, the acting user, and the\n * install id / status / version.\n *\n * `parseInstallWebhook` verifies the token and reads the event from the body,\n * falling back to the token for the fields it also carries, returning one flat\n * {@link InstallWebhook} so a consumer makes a single call instead of stitching\n * two differently shaped payloads together.\n *\n * This is exported as a standalone function rather than a method on\n * `PeekAccessService` because the receiver has no per-install service to inherit\n * a secret from yet — an install webhook can arrive before the first session, or\n * describe an install that is being torn down. The caller passes the app's\n * signing secret directly (the same secret used to mint peek-auth tokens).\n *\n * The signature/issuer/audience/expiry checks are strict (they are the security\n * boundary); the claim *extraction* is defensive so an unexpected-but-valid\n * payload yields empty fields rather than throwing.\n */\nimport {\n extractInstallWebhookBody,\n toInstallStatus,\n toPeekPlatform,\n} from \"./install-converter.js\";\nimport {\n cleanTokenString,\n mapPeekTokenUser,\n verifyPeekJwt,\n type RawPeekTokenUser,\n} from \"../peek-auth-token.js\";\nimport type { InstallWebhook } from \"../../../models/peek/install.js\";\nimport type { InstallWebhookClaims } from \"../../../models/peek/auth-token.js\";\n\n/** Raw, snake_case payload of an `app_registry_v2` install-webhook token. */\ninterface RawInstallWebhookPayload {\n /** Install ID — the JWT subject. */\n sub?: string;\n /** App display version at time of issuance. */\n display_version?: string;\n /** Install lifecycle status. */\n status?: string;\n /** The account the install belongs to. */\n account?: { id?: string } | null;\n /** The triggering user, or `null` for system-initiated events. */\n user?: RawPeekTokenUser | null;\n}\n\n/**\n * Verifies an install-status webhook token and merges it with the delivered\n * JSON body into one flat {@link InstallWebhook}.\n *\n * The **JSON body** is the source of the event data — `installId`, `accountId`,\n * `accountName`, `platform`, `isTest`, `timezone`, `apiUrl`, `status`,\n * `displayVersion`, and `user`. The **verified token** authenticates the whole\n * delivery and is the **fallback** for the fields it also carries (`installId`,\n * `accountId`, `status`, `displayVersion`, `user`) when the body omits them. A\n * missing or malformed body degrades the body-only fields (`accountName`,\n * `platform`, `isTest`, `timezone`, `apiUrl`) to `\"\"`/`null`/`false` and leans\n * on the token for the rest; it never throws.\n *\n * Signature verification is strict: the HMAC signature (with `secret`), the\n * token expiry, the `\"app_registry_v2\"` issuer, and the `\"Joken\"` audience are\n * all checked — the same checks as {@link PeekAccessService.verifyPeekAuthToken}.\n * Any failure throws from the `jsonwebtoken` library, so callers can branch on\n * the error kind:\n *\n * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed\n * - `TokenExpiredError` — past `exp`\n * - `NotBeforeError` — before `nbf`\n *\n * An unrecognised `status` or `platform` maps to `null` (with the wire status\n * preserved on {@link InstallWebhook.rawStatus}) rather than being coerced —\n * Peek treats any 2xx as delivered and does not redeliver, so handle a `null`\n * `status` explicitly:\n *\n * ```ts\n * const event = parseInstallWebhook(token, req.body, secret);\n * switch (event.status) {\n * case \"installed\": return provision(event);\n * case \"uninstalled\": return deprovision(event);\n * case \"update_installed\": return recordVersion(event);\n * default: throw new Error(`unknown install status: ${event.rawStatus}`);\n * }\n * ```\n *\n * @param token the JWT delivered by the install webhook. Pass the raw\n * `x-peek-auth` header value directly — a leading `Bearer ` prefix, if\n * present, is stripped for you.\n * @param body the delivered JSON body (raw object or a JSON string)\n * @param secret the app's HMAC signing secret (the `jwtSecret` you construct\n * `PeekAccessService` with)\n * @throws {JsonWebTokenError} signature invalid or token malformed\n * @throws {TokenExpiredError} token has expired\n * @throws {NotBeforeError} token not yet valid\n */\nexport function parseInstallWebhook(\n token: string,\n body: unknown,\n secret: string,\n): InstallWebhook {\n const payload = verifyPeekJwt<RawInstallWebhookPayload>(token, secret);\n const parsed = extractInstallWebhookBody(body);\n const account = parsed.account ?? {};\n // The JSON body is the source of the event data; the verified token is the\n // fallback for the fields it also carries. `||` so an empty body value falls\n // through to the token rather than masking it.\n const rawStatus = parsed.status || payload.status || \"\";\n return {\n installId: parsed.install_id || payload.sub || \"\",\n accountId: account.id || payload.account?.id || \"\",\n accountName: account.name || \"\",\n platform: toPeekPlatform(account.platform || \"\"),\n isTest: Boolean(account.is_test),\n timezone: account.timezone || \"\",\n apiUrl: parsed.api?.url || \"\",\n status: toInstallStatus(rawStatus),\n rawStatus,\n displayVersion: parsed.display_version || payload.display_version || \"\",\n user: resolveInstallUser(parsed.modified_by, payload.user),\n };\n}\n\n/**\n * Resolves the acting user, preferring the body's `modified_by` and falling back\n * to the token's `user`; system-initiated events carry neither and yield `null`.\n * The body is preferred only when its `modified_by` carries a *real* id — an\n * absent, empty, or `\"null\"` id (see {@link cleanTokenString}) is treated as no\n * user and defers to the token. {@link mapPeekTokenUser} then maps whichever\n * block wins, tolerating any missing/nullable field.\n */\nfunction resolveInstallUser(\n bodyUser: RawPeekTokenUser | null | undefined,\n tokenUser: RawPeekTokenUser | null | undefined,\n): InstallWebhook[\"user\"] {\n if (cleanTokenString(bodyUser?.id) !== null) return mapPeekTokenUser(bodyUser);\n return mapPeekTokenUser(tokenUser);\n}\n\n/**\n * Verifies an install-status webhook token and returns its clean claims.\n *\n * @deprecated Use {@link parseInstallWebhook} instead. This verifier reads only\n * the signed token, so it cannot report the account **name**, **platform**, or\n * **test** flag that the webhook's JSON body also carries — the caller was left\n * to parse that body separately and stitch the two shapes together.\n * `parseInstallWebhook(token, body, secret)` verifies the same token and returns\n * one flat {@link InstallWebhook} with every field. This function remains only\n * for backwards compatibility.\n *\n * Validates the HMAC signature (with `secret`), the token expiry, the\n * `\"app_registry_v2\"` issuer, and the `\"Joken\"` audience — the same checks as\n * {@link PeekAccessService.verifyPeekAuthToken} — then maps the payload to\n * {@link InstallWebhookClaims}, tolerating a `null` `user` (system events).\n * Throws from the `jsonwebtoken` library on any verification failure:\n *\n * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed\n * - `TokenExpiredError` — past `exp`\n * - `NotBeforeError` — before `nbf`\n *\n * @param token the JWT delivered by the install webhook. Pass the raw\n * `x-peek-auth` header value directly — a leading `Bearer ` prefix, if\n * present, is stripped for you.\n * @param secret the app's HMAC signing secret (the `jwtSecret` you construct\n * `PeekAccessService` with)\n * @throws {JsonWebTokenError} signature invalid or token malformed\n * @throws {TokenExpiredError} token has expired\n * @throws {NotBeforeError} token not yet valid\n */\nexport function verifyInstallWebhook(\n token: string,\n secret: string,\n): InstallWebhookClaims {\n const payload = verifyPeekJwt<RawInstallWebhookPayload>(token, secret);\n return {\n installId: payload.sub ?? \"\",\n account: { id: payload.account?.id ?? \"\" },\n status: payload.status ?? \"\",\n displayVersion: payload.display_version ?? \"\",\n user: mapPeekTokenUser(payload.user),\n };\n}\n"]}
|