@peektravel/app-utilities 0.4.1 → 0.5.1

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/dist/index.cjs CHANGED
@@ -203,6 +203,73 @@ var AvailabilityService = class {
203
203
  }
204
204
  };
205
205
 
206
+ // src/access-options.ts
207
+ function resolveAccessOptions(options) {
208
+ return { fullCustomerAccess: options?.fullCustomerAccess ?? false };
209
+ }
210
+
211
+ // src/errors.ts
212
+ var AdminAccountRequiredError = class extends Error {
213
+ /** The HTTP status that triggered this error. */
214
+ statusCode = 418;
215
+ constructor(message = "Admin account required") {
216
+ super(message);
217
+ this.name = "AdminAccountRequiredError";
218
+ }
219
+ };
220
+ var RateLimitError = class extends Error {
221
+ /** The HTTP status that triggered this error. */
222
+ statusCode = 429;
223
+ constructor(message = "Rate limit exceeded") {
224
+ super(message);
225
+ this.name = "RateLimitError";
226
+ }
227
+ };
228
+ var PeekGraphQLError = class extends Error {
229
+ /** The raw `errors` array returned by the GraphQL endpoint. */
230
+ graphqlErrors;
231
+ constructor(graphqlErrors, message = "GraphQL request failed") {
232
+ super(message);
233
+ this.name = "PeekGraphQLError";
234
+ this.graphqlErrors = graphqlErrors;
235
+ }
236
+ };
237
+ var PiiAccessDisabledError = class extends Error {
238
+ /** The name of the operation that was blocked (e.g. `"makePayment"`). */
239
+ operation;
240
+ constructor(operation) {
241
+ super(
242
+ `"${operation}" is disabled because this access service was created without "fullCustomerAccess"; enable it to allow payment and booking-modification operations`
243
+ );
244
+ this.name = "PiiAccessDisabledError";
245
+ this.operation = operation;
246
+ }
247
+ };
248
+ var CngApiError = class extends Error {
249
+ /** The HTTP status that triggered this error. */
250
+ statusCode;
251
+ /** The raw response body (parsed JSON when possible, otherwise text). */
252
+ body;
253
+ constructor(statusCode, body, message) {
254
+ super(message ?? `CNG request failed with HTTP ${statusCode}`);
255
+ this.name = "CngApiError";
256
+ this.statusCode = statusCode;
257
+ this.body = body;
258
+ }
259
+ };
260
+ var AcmeApiError = class extends Error {
261
+ /** The HTTP status that triggered this error. */
262
+ statusCode;
263
+ /** The raw response body (parsed JSON when possible, otherwise text). */
264
+ body;
265
+ constructor(statusCode, body, message) {
266
+ super(message ?? `ACME request failed with HTTP ${statusCode}`);
267
+ this.name = "AcmeApiError";
268
+ this.statusCode = statusCode;
269
+ this.body = body;
270
+ }
271
+ };
272
+
206
273
  // src/models/peek/product.ts
207
274
  var ACTIVITY_PRODUCT_TYPE = "ACTIVITY";
208
275
  var RENTAL_PRODUCT_TYPE = "RENTAL";
@@ -214,17 +281,8 @@ var SEARCH_BY_ACTIVITY_DATE = "activityDate";
214
281
  function normalizeBookingId(bookingId) {
215
282
  return bookingId.toLowerCase().replace(/-/g, "_");
216
283
  }
217
- var guestFields = `
218
- id
219
- name
220
- country
221
- dateOfBirth
222
- email
223
- isGdpr
224
- isParticipant
225
- optinSms
226
- optinMarketing
227
- phone
284
+ var GUEST_IDENTITY_PII_FIELDS = "name country dateOfBirth email isGdpr";
285
+ var GUEST_CONTACT_PII_FIELDS = `phone
228
286
  postalCode
229
287
  fieldResponses {
230
288
  id
@@ -234,9 +292,20 @@ var guestFields = `
234
292
  name
235
293
  }
236
294
  }
237
- }
295
+ }`;
296
+ function buildGuestFields(fullCustomerAccess) {
297
+ return `
298
+ id
299
+ ${fullCustomerAccess ? GUEST_IDENTITY_PII_FIELDS : ""}
300
+ isParticipant
301
+ optinSms
302
+ optinMarketing
303
+ ${fullCustomerAccess ? GUEST_CONTACT_PII_FIELDS : ""}
238
304
  `;
239
- var bookingGuestsFields = `
305
+ }
306
+ function buildBookingGuestsFields(fullCustomerAccess) {
307
+ const guestFields = buildGuestFields(fullCustomerAccess);
308
+ return `
240
309
  bookingGuests {
241
310
  ${guestFields}
242
311
  }
@@ -244,10 +313,9 @@ var bookingGuestsFields = `
244
313
  ${guestFields}
245
314
  }
246
315
  `;
247
- var bookingQueryFields = `
248
- displayId
249
- id
250
- primaryGuest {
316
+ }
317
+ var bookingGuestsFields = buildBookingGuestsFields(true);
318
+ var BOOKING_PRIMARY_GUEST_PII_FIELDS = `primaryGuest {
251
319
  name
252
320
  email
253
321
  phone
@@ -255,7 +323,26 @@ var bookingQueryFields = `
255
323
  optinSms
256
324
  isGdpr
257
325
  postalCode
326
+ }`;
327
+ var BOOKING_QUESTION_ANSWERS_PII_FIELDS = `questionAnswers {
328
+ answer
329
+ questionText
330
+ questionLocationSnapshot {
331
+ latitude
332
+ longitude
333
+ }
258
334
  }
335
+ tickets {
336
+ questionAnswers {
337
+ answer
338
+ questionText
339
+ }
340
+ }`;
341
+ function buildBookingQueryFields(fullCustomerAccess) {
342
+ return `
343
+ displayId
344
+ id
345
+ ${fullCustomerAccess ? BOOKING_PRIMARY_GUEST_PII_FIELDS : ""}
259
346
  activitySnapshot {
260
347
  type
261
348
  name
@@ -285,7 +372,7 @@ var bookingQueryFields = `
285
372
  endsAt
286
373
  endsAtUtc
287
374
  availabilityTimeId
288
- bookingPortalUrl
375
+ ${fullCustomerAccess ? "bookingPortalUrl" : ""}
289
376
  operatorNotes
290
377
  value {
291
378
  total {
@@ -327,20 +414,7 @@ var bookingQueryFields = `
327
414
  }
328
415
  }
329
416
  }
330
- questionAnswers {
331
- answer
332
- questionText
333
- questionLocationSnapshot {
334
- latitude
335
- longitude
336
- }
337
- }
338
- tickets {
339
- questionAnswers {
340
- answer
341
- questionText
342
- }
343
- }
417
+ ${fullCustomerAccess ? BOOKING_QUESTION_ANSWERS_PII_FIELDS : ""}
344
418
  resourcePoolAssignments {
345
419
  quantity
346
420
  resourcePool {
@@ -358,6 +432,8 @@ var bookingQueryFields = `
358
432
  }
359
433
  }
360
434
  `;
435
+ }
436
+ var bookingQueryFields = buildBookingQueryFields(true);
361
437
  var PRICE_BREAKDOWN_FIELDS = `
362
438
  convenienceFee { amount formatted }
363
439
  deposit { amount formatted }
@@ -376,9 +452,10 @@ var TICKET_VALUE_FIELDS = `
376
452
  total { amount formatted }
377
453
  }
378
454
  `;
379
- function buildBookingsListingQuery(includeGuests, includePriceBreakdown) {
380
- const guestsSection = includeGuests ? bookingGuestsFields : "";
381
- const fields = includePriceBreakdown ? bookingQueryFields.replace("value {", `value { ${PRICE_BREAKDOWN_FIELDS}`).replace("ticketQuantities {", `ticketQuantities { ${TICKET_VALUE_FIELDS}`) : bookingQueryFields;
455
+ function buildBookingsListingQuery(includeGuests, includePriceBreakdown, fullCustomerAccess = true) {
456
+ const guestsSection = includeGuests ? buildBookingGuestsFields(fullCustomerAccess) : "";
457
+ const baseFields = buildBookingQueryFields(fullCustomerAccess);
458
+ const fields = includePriceBreakdown ? baseFields.replace("value {", `value { ${PRICE_BREAKDOWN_FIELDS}`).replace("ticketQuantities {", `ticketQuantities { ${TICKET_VALUE_FIELDS}`) : baseFields;
382
459
  return `
383
460
  query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {
384
461
  sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {
@@ -395,7 +472,8 @@ function buildBookingsListingQuery(includeGuests, includePriceBreakdown) {
395
472
  }
396
473
  `;
397
474
  }
398
- var BOOKING_GUESTS_QUERY = `
475
+ function buildBookingGuestsQuery(fullCustomerAccess) {
476
+ return `
399
477
  query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {
400
478
  sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {
401
479
  pageInfo { endCursor hasNextPage }
@@ -404,13 +482,14 @@ var BOOKING_GUESTS_QUERY = `
404
482
  ... on Booking {
405
483
  displayId
406
484
  id
407
- ${bookingGuestsFields}
485
+ ${buildBookingGuestsFields(fullCustomerAccess)}
408
486
  }
409
487
  }
410
488
  }
411
489
  }
412
490
  }
413
491
  `;
492
+ }
414
493
  var BOOKING_PAYMENTS_ON_FILE_QUERY = `
415
494
  query Sales($after: String, $first: Int, $filter: SalesFilter!, $orderBy: SalesOrdering) {
416
495
  sales(after: $after, first: $first, filter: $filter, orderBy: $orderBy) {
@@ -996,10 +1075,23 @@ var BookingService = class {
996
1075
  this.client = client;
997
1076
  this.deps = deps;
998
1077
  this.pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE2;
1078
+ this.fullCustomerAccess = resolveAccessOptions(options.accessOptions).fullCustomerAccess;
999
1079
  }
1000
1080
  client;
1001
1081
  deps;
1002
1082
  pageSize;
1083
+ /** Whether customer PII is requested and payment operations are allowed. */
1084
+ fullCustomerAccess;
1085
+ /**
1086
+ * Throws a {@link PiiAccessDisabledError} for `operation` when this service was
1087
+ * created without `fullCustomerAccess` — used to gate payment and booking-modification
1088
+ * operations that touch customer financial data.
1089
+ */
1090
+ assertPiiEnabled(operation) {
1091
+ if (!this.fullCustomerAccess) {
1092
+ throw new PiiAccessDisabledError(operation);
1093
+ }
1094
+ }
1003
1095
  /**
1004
1096
  * Returns a single booking by id, or null when not found. The `bookingId` is
1005
1097
  * normalized internally (lowercased, `-` → `_`), so `B-ABC123` and `b_abc123`
@@ -1021,7 +1113,7 @@ var BookingService = class {
1021
1113
  const includePriceBreakdown = options.includePriceBreakdown ?? false;
1022
1114
  const body = await this.client.request(
1023
1115
  SALES_ENDPOINT,
1024
- buildBookingsListingQuery(includeGuests, includePriceBreakdown),
1116
+ buildBookingsListingQuery(includeGuests, includePriceBreakdown, this.fullCustomerAccess),
1025
1117
  buildBookingsVariables({
1026
1118
  pageSize: this.pageSize,
1027
1119
  after: null,
@@ -1039,7 +1131,7 @@ var BookingService = class {
1039
1131
  const includeGuests = input.includeGuests ?? false;
1040
1132
  const includePriceBreakdown = input.includePriceBreakdown ?? false;
1041
1133
  return this.fetchPaginated(
1042
- buildBookingsListingQuery(includeGuests, includePriceBreakdown),
1134
+ buildBookingsListingQuery(includeGuests, includePriceBreakdown, this.fullCustomerAccess),
1043
1135
  {
1044
1136
  startDateTime: input.start,
1045
1137
  endDateTime: input.end,
@@ -1057,7 +1149,7 @@ var BookingService = class {
1057
1149
  const includeGuests = options.includeGuests ?? false;
1058
1150
  const includePriceBreakdown = options.includePriceBreakdown ?? false;
1059
1151
  return this.fetchPaginated(
1060
- buildBookingsListingQuery(includeGuests, includePriceBreakdown),
1152
+ buildBookingsListingQuery(includeGuests, includePriceBreakdown, this.fullCustomerAccess),
1061
1153
  { timeslotId },
1062
1154
  includeGuests,
1063
1155
  includePriceBreakdown
@@ -1068,7 +1160,7 @@ var BookingService = class {
1068
1160
  assertBookingId(bookingId);
1069
1161
  const body = await this.client.request(
1070
1162
  SALES_ENDPOINT,
1071
- BOOKING_GUESTS_QUERY,
1163
+ buildBookingGuestsQuery(this.fullCustomerAccess),
1072
1164
  buildBookingsVariables({
1073
1165
  pageSize: this.pageSize,
1074
1166
  after: null,
@@ -1079,6 +1171,7 @@ var BookingService = class {
1079
1171
  }
1080
1172
  /** Returns the payments on file for a booking, or null when not found. */
1081
1173
  async getPaymentsOnFile(bookingId) {
1174
+ this.assertPiiEnabled("getPaymentsOnFile");
1082
1175
  assertBookingId(bookingId);
1083
1176
  const normalized = normalizeBookingId(bookingId);
1084
1177
  const body = await this.client.request(
@@ -1163,6 +1256,7 @@ ${note}`;
1163
1256
  * charge fails.
1164
1257
  */
1165
1258
  async makePayment(input) {
1259
+ this.assertPiiEnabled("makePayment");
1166
1260
  this.validatePaymentInput(input);
1167
1261
  const normalized = normalizeBookingId(input.bookingId);
1168
1262
  const onFile = await this.getPaymentsOnFile(normalized);
@@ -1205,6 +1299,7 @@ ${note}`;
1205
1299
  * payments-on-file, then applies the refund.
1206
1300
  */
1207
1301
  async refund(input) {
1302
+ this.assertPiiEnabled("refund");
1208
1303
  this.validateRefundInput(input);
1209
1304
  const normalized = normalizeBookingId(input.bookingId);
1210
1305
  const onFile = await this.getPaymentsOnFile(normalized);
@@ -1245,6 +1340,7 @@ ${note}`;
1245
1340
  }
1246
1341
  /** Creates an invoice link for a booking's order. */
1247
1342
  async createInvoiceLink(bookingId) {
1343
+ this.assertPiiEnabled("createInvoiceLink");
1248
1344
  assertBookingId(bookingId);
1249
1345
  const normalized = normalizeBookingId(bookingId);
1250
1346
  const booking = await this.getById(normalized);
@@ -1300,6 +1396,7 @@ ${note}`;
1300
1396
  * the underlying quote/order mutations fail.
1301
1397
  */
1302
1398
  async addAddon(bookingId, input) {
1399
+ this.assertPiiEnabled("addAddon");
1303
1400
  assertBookingId(bookingId);
1304
1401
  const addonOptionId = (input?.addonOptionId || input?.addonId || "").trim();
1305
1402
  if (!addonOptionId) {
@@ -1353,6 +1450,7 @@ ${note}`;
1353
1450
  * variables. Returns the booking's add-ons after the change.
1354
1451
  */
1355
1452
  async removeAddon(bookingId, input) {
1453
+ this.assertPiiEnabled("removeAddon");
1356
1454
  assertBookingId(bookingId);
1357
1455
  const addonOptionId = (input?.addonOptionId || input?.addonId || "").trim();
1358
1456
  if (!addonOptionId) {
@@ -1842,57 +1940,6 @@ function createTokenManager(config) {
1842
1940
  });
1843
1941
  }
1844
1942
 
1845
- // src/errors.ts
1846
- var AdminAccountRequiredError = class extends Error {
1847
- /** The HTTP status that triggered this error. */
1848
- statusCode = 418;
1849
- constructor(message = "Admin account required") {
1850
- super(message);
1851
- this.name = "AdminAccountRequiredError";
1852
- }
1853
- };
1854
- var RateLimitError = class extends Error {
1855
- /** The HTTP status that triggered this error. */
1856
- statusCode = 429;
1857
- constructor(message = "Rate limit exceeded") {
1858
- super(message);
1859
- this.name = "RateLimitError";
1860
- }
1861
- };
1862
- var PeekGraphQLError = class extends Error {
1863
- /** The raw `errors` array returned by the GraphQL endpoint. */
1864
- graphqlErrors;
1865
- constructor(graphqlErrors, message = "GraphQL request failed") {
1866
- super(message);
1867
- this.name = "PeekGraphQLError";
1868
- this.graphqlErrors = graphqlErrors;
1869
- }
1870
- };
1871
- var CngApiError = class extends Error {
1872
- /** The HTTP status that triggered this error. */
1873
- statusCode;
1874
- /** The raw response body (parsed JSON when possible, otherwise text). */
1875
- body;
1876
- constructor(statusCode, body, message) {
1877
- super(message ?? `CNG request failed with HTTP ${statusCode}`);
1878
- this.name = "CngApiError";
1879
- this.statusCode = statusCode;
1880
- this.body = body;
1881
- }
1882
- };
1883
- var AcmeApiError = class extends Error {
1884
- /** The HTTP status that triggered this error. */
1885
- statusCode;
1886
- /** The raw response body (parsed JSON when possible, otherwise text). */
1887
- body;
1888
- constructor(statusCode, body, message) {
1889
- super(message ?? `ACME request failed with HTTP ${statusCode}`);
1890
- this.name = "AcmeApiError";
1891
- this.statusCode = statusCode;
1892
- this.body = body;
1893
- }
1894
- };
1895
-
1896
1943
  // src/internal/http-transport.ts
1897
1944
  var RATE_LIMIT_STATUS = 429;
1898
1945
  var ADMIN_ACCOUNT_REQUIRED_STATUS = 418;
@@ -2311,7 +2358,8 @@ function encodeCursor(offset, pageSize) {
2311
2358
  }
2312
2359
 
2313
2360
  // src/internal/peek/reviews/review-queries.ts
2314
- var REVIEWS_QUERY = `
2361
+ function buildReviewsQuery(fullCustomerAccess) {
2362
+ return `
2315
2363
  query Reviews($first: Int, $filter: ReviewFilter, $after: String) {
2316
2364
  reviews(first: $first, filter: $filter, after: $after) {
2317
2365
  edges {
@@ -2325,8 +2373,7 @@ var REVIEWS_QUERY = `
2325
2373
  name
2326
2374
  }
2327
2375
  id
2328
- name
2329
- email
2376
+ ${fullCustomerAccess ? "name\n email" : ""}
2330
2377
  rating
2331
2378
  comment
2332
2379
  reviewedAt
@@ -2337,6 +2384,7 @@ var REVIEWS_QUERY = `
2337
2384
  }
2338
2385
  }
2339
2386
  `;
2387
+ }
2340
2388
  function buildReviewsVariables(params) {
2341
2389
  return {
2342
2390
  first: params.first,
@@ -2353,10 +2401,13 @@ var ERROR_PRODUCT_ID_REQUIRED = "productId is required";
2353
2401
  var ERROR_INVALID_REVIEW_COUNT = `reviewCount must be an integer between ${MIN_REVIEW_COUNT} and ${MAX_REVIEW_COUNT}`;
2354
2402
  var ERROR_INVALID_REVIEW_OFFSET = "reviewOffset must be a non-negative integer";
2355
2403
  var ReviewService = class {
2356
- constructor(client) {
2404
+ constructor(client, accessOptions) {
2357
2405
  this.client = client;
2406
+ this.fullCustomerAccess = resolveAccessOptions(accessOptions).fullCustomerAccess;
2358
2407
  }
2359
2408
  client;
2409
+ /** Whether reviewer PII (name/email) is requested. */
2410
+ fullCustomerAccess;
2360
2411
  /**
2361
2412
  * Returns up to `reviewCount` reviews for an activity in **descending order
2362
2413
  * by review date (newest first)**, skipping the `reviewOffset` newest reviews
@@ -2387,7 +2438,7 @@ var ReviewService = class {
2387
2438
  const after = reviewOffset > 0 ? encodeCursor(reviewOffset - 1, reviewCount) : null;
2388
2439
  const body = await this.client.request(
2389
2440
  SALES_ENDPOINT,
2390
- REVIEWS_QUERY,
2441
+ buildReviewsQuery(this.fullCustomerAccess),
2391
2442
  buildReviewsVariables({ activityId: productId, first: reviewCount, after })
2392
2443
  );
2393
2444
  const edges = body.data?.reviews?.edges ?? [];
@@ -2749,6 +2800,7 @@ function fromActivity(activity) {
2749
2800
  name: activity.name,
2750
2801
  type: activity.type,
2751
2802
  color: activity.colorHex || "",
2803
+ currency: activity.currency || "",
2752
2804
  tickets: (activity.resourceOptions ?? []).map((option) => ({
2753
2805
  id: option.id,
2754
2806
  name: option.name
@@ -2767,6 +2819,7 @@ function fromItemOptionNodes(nodes) {
2767
2819
  name: node.item.name,
2768
2820
  type: ADD_ON_PRODUCT_TYPE,
2769
2821
  color: ADD_ON_COLOR,
2822
+ currency: "",
2770
2823
  tickets: []
2771
2824
  };
2772
2825
  grouped.set(itemId, product);
@@ -2786,6 +2839,7 @@ var PRODUCTS_QUERY = `
2786
2839
  deletedAt
2787
2840
  type
2788
2841
  colorHex
2842
+ currency
2789
2843
  resourceOptions {
2790
2844
  id
2791
2845
  name
@@ -3012,6 +3066,325 @@ var PromoCodeService = class {
3012
3066
  }
3013
3067
  };
3014
3068
 
3069
+ // src/internal/peek/pricing/pricing-queries.ts
3070
+ var CREATE_PRICING_ENGINE_MUTATION = `
3071
+ mutation CreatePricingEngine($input: CreatePricingEngineInput!) {
3072
+ createPricingEngine(input: $input) {
3073
+ __typename
3074
+ ... on CreatePricingEngineSuccess {
3075
+ engine {
3076
+ id
3077
+ }
3078
+ }
3079
+ ... on InvalidDataError {
3080
+ message
3081
+ }
3082
+ }
3083
+ }
3084
+ `;
3085
+ var UPDATE_PRICING_ENGINE_MUTATION = `
3086
+ mutation UpdatePricingEngine($input: UpdatePricingEngineInput!) {
3087
+ updatePricingEngine(input: $input) {
3088
+ __typename
3089
+ ... on UpdatePricingEngineSuccess {
3090
+ engine {
3091
+ id
3092
+ name
3093
+ }
3094
+ }
3095
+ ... on InvalidDataError {
3096
+ message
3097
+ }
3098
+ ... on NotFoundError {
3099
+ id
3100
+ message
3101
+ }
3102
+ }
3103
+ }
3104
+ `;
3105
+ var DELETE_PRICING_ENGINE_MUTATION = `
3106
+ mutation DeletePricingEngine($id: ID!) {
3107
+ deletePricingEngine(id: $id) {
3108
+ __typename
3109
+ ... on DeletePricingEngineSuccess {
3110
+ engine {
3111
+ id
3112
+ name
3113
+ }
3114
+ }
3115
+ ... on NotFoundError {
3116
+ id
3117
+ message
3118
+ }
3119
+ }
3120
+ }
3121
+ `;
3122
+ var UPSERT_PRICING_OVERRIDES_MUTATION = `
3123
+ mutation UpsertPricingOverridesActivityContexts($input: UpsertPricingOverridesActivityContextsInput!) {
3124
+ upsertPricingOverridesActivityContexts(input: $input) {
3125
+ __typename
3126
+ ... on UpsertPricingOverridesActivityContextsSuccess {
3127
+ activityContexts {
3128
+ date
3129
+ activity {
3130
+ id
3131
+ name
3132
+ }
3133
+ engine {
3134
+ id
3135
+ name
3136
+ }
3137
+ overrides {
3138
+ order
3139
+ resourceOptions {
3140
+ resourceOption {
3141
+ id
3142
+ name
3143
+ }
3144
+ override {
3145
+ ... on PricingOverridesActivityContextResourceOptionPriceOverride {
3146
+ price {
3147
+ amount
3148
+ currency
3149
+ }
3150
+ }
3151
+ ... on PricingOverridesActivityContextResourceOptionPercentageAdjustmentOverride {
3152
+ percentageAdjustment
3153
+ }
3154
+ }
3155
+ }
3156
+ filters {
3157
+ __typename
3158
+ ... on PricingOverridesActivityContextStartTimeRangeFilter {
3159
+ startTimeRange
3160
+ }
3161
+ ... on PricingOverridesActivityContextSpotsTakenFilter {
3162
+ minSpots
3163
+ maxSpots
3164
+ }
3165
+ }
3166
+ }
3167
+ }
3168
+ }
3169
+ ... on InvalidDataError {
3170
+ message
3171
+ }
3172
+ }
3173
+ }
3174
+ `;
3175
+ var SPOTS_TAKEN_FILTER_TYPENAME = "PricingOverridesActivityContextSpotsTakenFilter";
3176
+ function buildCreateEngineInput(input) {
3177
+ const activityIds = input.activityIds ?? [];
3178
+ return activityIds.length > 0 ? { name: input.name, filters: [{ activityIds }] } : { name: input.name };
3179
+ }
3180
+ function buildUpdateEngineInput(input) {
3181
+ const activityIds = input.activityIds ?? [];
3182
+ return {
3183
+ id: input.engineId,
3184
+ name: input.name,
3185
+ filters: activityIds.length > 0 ? [{ activityIds }] : []
3186
+ };
3187
+ }
3188
+ function buildUpsertInput(input) {
3189
+ return {
3190
+ engineId: input.engineId,
3191
+ dateRange: input.dateRange,
3192
+ activities: input.activities.map((activity) => ({
3193
+ activityId: activity.activityId,
3194
+ overrides: activity.overrides.map((override) => ({
3195
+ order: override.order,
3196
+ resourceOptions: override.resourceOptions.map(
3197
+ (option) => option.mode === "fixed" ? { id: option.id, price: option.price } : { id: option.id, percentageAdjustment: option.percentageAdjustment }
3198
+ ),
3199
+ filters: override.filters
3200
+ }))
3201
+ }))
3202
+ };
3203
+ }
3204
+ function buildClearInput(input) {
3205
+ return {
3206
+ engineId: input.engineId,
3207
+ dateRange: input.dateRange,
3208
+ activities: input.activityIds.map((activityId) => ({
3209
+ activityId,
3210
+ overrides: []
3211
+ }))
3212
+ };
3213
+ }
3214
+
3215
+ // src/internal/peek/pricing/pricing-converter.ts
3216
+ function fromActivityContexts(contexts) {
3217
+ return contexts.map(fromActivityContext);
3218
+ }
3219
+ function fromActivityContext(context) {
3220
+ return {
3221
+ date: context.date,
3222
+ activity: { id: context.activity.id, name: context.activity.name },
3223
+ engine: { id: context.engine.id, name: context.engine.name },
3224
+ overrides: context.overrides.map(fromOverride)
3225
+ };
3226
+ }
3227
+ function fromOverride(override) {
3228
+ return {
3229
+ order: override.order,
3230
+ resourceOptions: override.resourceOptions.map(fromResourceOption),
3231
+ filters: override.filters.map(fromFilter)
3232
+ };
3233
+ }
3234
+ function fromResourceOption(option) {
3235
+ return {
3236
+ resourceOption: {
3237
+ id: option.resourceOption.id,
3238
+ name: option.resourceOption.name
3239
+ },
3240
+ override: fromResolvedOverride(option.override)
3241
+ };
3242
+ }
3243
+ function fromResolvedOverride(override) {
3244
+ return "price" in override ? { mode: "fixed", price: override.price } : { mode: "percentage", percentageAdjustment: override.percentageAdjustment };
3245
+ }
3246
+ function fromFilter(filter) {
3247
+ if (filter.__typename === SPOTS_TAKEN_FILTER_TYPENAME) {
3248
+ const spotsTaken = {};
3249
+ if (filter.minSpots !== null) spotsTaken.minSpots = filter.minSpots;
3250
+ if (filter.maxSpots !== null) spotsTaken.maxSpots = filter.maxSpots;
3251
+ return { spotsTaken };
3252
+ }
3253
+ return { startTimeRange: filter.startTimeRange };
3254
+ }
3255
+
3256
+ // src/internal/peek/pricing/pricing-service.ts
3257
+ var CURRENCY_PATTERN2 = /^[A-Z]{3}$/;
3258
+ var PERCENTAGE_FLOOR = -100;
3259
+ var ERROR_NAME_REQUIRED = "name is required";
3260
+ var ERROR_ENGINE_ID_REQUIRED = "engineId is required";
3261
+ var ERROR_DATE_RANGE_REQUIRED = "dateRange is required";
3262
+ var ERROR_ACTIVITIES_REQUIRED = "activities is required";
3263
+ var ERROR_ACTIVITY_ID_REQUIRED = "activityId is required";
3264
+ var ERROR_TICKET_ID_REQUIRED = "resource-option id is required";
3265
+ var ERROR_CURRENCY_FORMAT = "currency must be 3 uppercase letters";
3266
+ var ERROR_AMOUNT_NUMBER = "price amount must be a valid number";
3267
+ var ERROR_PERCENTAGE_NUMBER = "percentageAdjustment must be a valid number";
3268
+ var ERROR_PERCENTAGE_FLOOR = "percentageAdjustment must be greater than -100";
3269
+ var ERROR_NO_DATA = "pricing mutation returned no data";
3270
+ var PricingService = class {
3271
+ constructor(client) {
3272
+ this.client = client;
3273
+ }
3274
+ client;
3275
+ /**
3276
+ * Creates a pricing engine. Store the returned id and reuse it on every
3277
+ * subsequent override upsert. Throws on an InvalidDataError from Peek.
3278
+ */
3279
+ async createEngine(input) {
3280
+ if (!input.name) throw new Error(ERROR_NAME_REQUIRED);
3281
+ const body = await this.client.request(
3282
+ SALES_ENDPOINT,
3283
+ CREATE_PRICING_ENGINE_MUTATION,
3284
+ { input: buildCreateEngineInput(input) }
3285
+ );
3286
+ const result = body.data?.createPricingEngine;
3287
+ if (!result) throw new Error(ERROR_NO_DATA);
3288
+ if (result.__typename !== "CreatePricingEngineSuccess") {
3289
+ throw new Error(result.message);
3290
+ }
3291
+ return { id: result.engine.id };
3292
+ }
3293
+ /**
3294
+ * Updates a pricing engine's name and/or activity scope. Throws on an
3295
+ * InvalidDataError or NotFoundError from Peek.
3296
+ */
3297
+ async updateEngine(input) {
3298
+ if (!input.engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);
3299
+ if (!input.name) throw new Error(ERROR_NAME_REQUIRED);
3300
+ const body = await this.client.request(
3301
+ SALES_ENDPOINT,
3302
+ UPDATE_PRICING_ENGINE_MUTATION,
3303
+ { input: buildUpdateEngineInput(input) }
3304
+ );
3305
+ const result = body.data?.updatePricingEngine;
3306
+ if (!result) throw new Error(ERROR_NO_DATA);
3307
+ if (result.__typename !== "UpdatePricingEngineSuccess") {
3308
+ throw new Error(result.message);
3309
+ }
3310
+ return { id: result.engine.id, name: result.engine.name };
3311
+ }
3312
+ /**
3313
+ * Deletes a pricing engine. Idempotent — resolves whether the engine existed
3314
+ * or was already gone (Peek's NotFoundError is treated as success).
3315
+ */
3316
+ async deleteEngine(engineId) {
3317
+ if (!engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);
3318
+ await this.client.request(
3319
+ SALES_ENDPOINT,
3320
+ DELETE_PRICING_ENGINE_MUTATION,
3321
+ { id: engineId }
3322
+ );
3323
+ }
3324
+ /**
3325
+ * Upserts pricing overrides for the engine and date range in `input`. Returns
3326
+ * the resolved contexts Peek stored. Throws on an InvalidDataError from Peek.
3327
+ */
3328
+ async upsertOverrides(input) {
3329
+ this.validateUpsertInput(input);
3330
+ return this.sendUpsert(buildUpsertInput(input));
3331
+ }
3332
+ /**
3333
+ * Clears all overrides for the given activities across a date range. This is
3334
+ * an upsert with empty overrides — never clear by omitting an activity.
3335
+ */
3336
+ async clearOverrides(input) {
3337
+ if (!input.engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);
3338
+ if (!input.dateRange) throw new Error(ERROR_DATE_RANGE_REQUIRED);
3339
+ if (!Array.isArray(input.activityIds)) throw new Error(ERROR_ACTIVITIES_REQUIRED);
3340
+ for (const activityId of input.activityIds) {
3341
+ if (!activityId) throw new Error(ERROR_ACTIVITY_ID_REQUIRED);
3342
+ }
3343
+ return this.sendUpsert(buildClearInput(input));
3344
+ }
3345
+ async sendUpsert(rawInput) {
3346
+ const body = await this.client.request(
3347
+ SALES_ENDPOINT,
3348
+ UPSERT_PRICING_OVERRIDES_MUTATION,
3349
+ { input: rawInput }
3350
+ );
3351
+ const result = body.data?.upsertPricingOverridesActivityContexts;
3352
+ if (!result) throw new Error(ERROR_NO_DATA);
3353
+ if (result.__typename !== "UpsertPricingOverridesActivityContextsSuccess") {
3354
+ throw new Error(result.message);
3355
+ }
3356
+ return { activityContexts: fromActivityContexts(result.activityContexts) };
3357
+ }
3358
+ validateUpsertInput(input) {
3359
+ if (!input.engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);
3360
+ if (!input.dateRange) throw new Error(ERROR_DATE_RANGE_REQUIRED);
3361
+ if (!Array.isArray(input.activities)) throw new Error(ERROR_ACTIVITIES_REQUIRED);
3362
+ for (const activity of input.activities) {
3363
+ if (!activity.activityId) throw new Error(ERROR_ACTIVITY_ID_REQUIRED);
3364
+ for (const override of activity.overrides) {
3365
+ for (const option of override.resourceOptions) {
3366
+ this.validateResourceOption(option);
3367
+ }
3368
+ }
3369
+ }
3370
+ }
3371
+ validateResourceOption(option) {
3372
+ if (!option.id) throw new Error(ERROR_TICKET_ID_REQUIRED);
3373
+ if (option.mode === "fixed") {
3374
+ if (!CURRENCY_PATTERN2.test(option.price.currency)) {
3375
+ throw new Error(ERROR_CURRENCY_FORMAT);
3376
+ }
3377
+ if (Number.isNaN(Number.parseFloat(option.price.amount))) {
3378
+ throw new Error(ERROR_AMOUNT_NUMBER);
3379
+ }
3380
+ return;
3381
+ }
3382
+ const percentage = Number.parseFloat(option.percentageAdjustment);
3383
+ if (Number.isNaN(percentage)) throw new Error(ERROR_PERCENTAGE_NUMBER);
3384
+ if (percentage <= PERCENTAGE_FLOOR) throw new Error(ERROR_PERCENTAGE_FLOOR);
3385
+ }
3386
+ };
3387
+
3015
3388
  // src/logger.ts
3016
3389
  var noopLogger = {
3017
3390
  info() {
@@ -3029,6 +3402,7 @@ var PEEK_TOKEN_ISSUER = "app_registry_v2";
3029
3402
  var PeekAccessService = class {
3030
3403
  client;
3031
3404
  productServiceOptions;
3405
+ accessOptions;
3032
3406
  jwtSecret;
3033
3407
  productService;
3034
3408
  accountUserService;
@@ -3036,6 +3410,7 @@ var PeekAccessService = class {
3036
3410
  timeslotService;
3037
3411
  resellerService;
3038
3412
  promoCodeService;
3413
+ pricingService;
3039
3414
  dailyNoteService;
3040
3415
  availabilityService;
3041
3416
  membershipService;
@@ -3065,6 +3440,7 @@ var PeekAccessService = class {
3065
3440
  this.productServiceOptions = {
3066
3441
  itemOptionsPageSize: config.itemOptionsPageSize
3067
3442
  };
3443
+ this.accessOptions = resolveAccessOptions(config.accessOptions);
3068
3444
  }
3069
3445
  /**
3070
3446
  * Verifies a Peek auth token issued by the app registry and returns the
@@ -3169,6 +3545,16 @@ var PeekAccessService = class {
3169
3545
  }
3170
3546
  return this.promoCodeService;
3171
3547
  }
3548
+ /**
3549
+ * Returns the {@link PricingService} for this install, bound to the shared
3550
+ * authenticated transport. The instance is created lazily and reused.
3551
+ */
3552
+ getPricingService() {
3553
+ if (!this.pricingService) {
3554
+ this.pricingService = new PricingService(this.client);
3555
+ }
3556
+ return this.pricingService;
3557
+ }
3172
3558
  /**
3173
3559
  * Returns the {@link DailyNoteService} for this install, bound to the shared
3174
3560
  * authenticated transport. The instance is created lazily and reused.
@@ -3205,9 +3591,11 @@ var PeekAccessService = class {
3205
3591
  */
3206
3592
  getBookingService() {
3207
3593
  if (!this.bookingService) {
3208
- this.bookingService = new BookingService(this.client, {
3209
- productService: this.getProductService()
3210
- });
3594
+ this.bookingService = new BookingService(
3595
+ this.client,
3596
+ { productService: this.getProductService() },
3597
+ { accessOptions: this.accessOptions }
3598
+ );
3211
3599
  }
3212
3600
  return this.bookingService;
3213
3601
  }
@@ -3217,7 +3605,7 @@ var PeekAccessService = class {
3217
3605
  */
3218
3606
  getReviewService() {
3219
3607
  if (!this.reviewService) {
3220
- this.reviewService = new ReviewService(this.client);
3608
+ this.reviewService = new ReviewService(this.client, this.accessOptions);
3221
3609
  }
3222
3610
  return this.reviewService;
3223
3611
  }
@@ -3287,6 +3675,27 @@ var PeekAccessService = class {
3287
3675
  createPromoCode(input) {
3288
3676
  return this.getPromoCodeService().create(input);
3289
3677
  }
3678
+ // ─── Pricing short-forms ──────────────────────────────────────────────────
3679
+ /** Create a pricing engine. Delegates to {@link PricingService.createEngine}. */
3680
+ createPricingEngine(input) {
3681
+ return this.getPricingService().createEngine(input);
3682
+ }
3683
+ /** Update a pricing engine. Delegates to {@link PricingService.updateEngine}. */
3684
+ updatePricingEngine(input) {
3685
+ return this.getPricingService().updateEngine(input);
3686
+ }
3687
+ /** Delete a pricing engine (idempotent). Delegates to {@link PricingService.deleteEngine}. */
3688
+ deletePricingEngine(engineId) {
3689
+ return this.getPricingService().deleteEngine(engineId);
3690
+ }
3691
+ /** Upsert pricing overrides. Delegates to {@link PricingService.upsertOverrides}. */
3692
+ upsertPricingOverrides(input) {
3693
+ return this.getPricingService().upsertOverrides(input);
3694
+ }
3695
+ /** Clear pricing overrides for a set of activities. Delegates to {@link PricingService.clearOverrides}. */
3696
+ clearPricingOverrides(input) {
3697
+ return this.getPricingService().clearOverrides(input);
3698
+ }
3290
3699
  // ─── Daily-note short-forms ───────────────────────────────────────────────
3291
3700
  /** Today's daily note. Delegates to {@link DailyNoteService.getToday}. */
3292
3701
  getDailyNoteToday() {
@@ -3710,8 +4119,13 @@ function hasPriceBreakdown(node) {
3710
4119
 
3711
4120
  // src/internal/peek/waivers/waiver-webhook.ts
3712
4121
  var PAYLOAD_WAIVER_KEY = "waiver";
3713
- function parseWaiverWebhook(payload) {
3714
- return fromWaiverNode(extractWaiverNode(payload));
4122
+ function parseWaiverWebhook(payload, options) {
4123
+ const waiver = fromWaiverNode(extractWaiverNode(payload));
4124
+ if (!resolveAccessOptions(options).fullCustomerAccess) {
4125
+ waiver.guestName = null;
4126
+ waiver.fileUrl = "";
4127
+ }
4128
+ return waiver;
3715
4129
  }
3716
4130
  function fromWaiverNode(node) {
3717
4131
  const data = node ?? {};
@@ -3759,6 +4173,8 @@ exports.DailyNoteService = DailyNoteService;
3759
4173
  exports.MembershipService = MembershipService;
3760
4174
  exports.PeekAccessService = PeekAccessService;
3761
4175
  exports.PeekGraphQLError = PeekGraphQLError;
4176
+ exports.PiiAccessDisabledError = PiiAccessDisabledError;
4177
+ exports.PricingService = PricingService;
3762
4178
  exports.ProductService = ProductService;
3763
4179
  exports.PromoCodeService = PromoCodeService;
3764
4180
  exports.RENTAL_PRODUCT_TYPE = RENTAL_PRODUCT_TYPE;