@peektravel/app-utilities 0.8.1 → 0.8.2

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.d.cts CHANGED
@@ -2300,6 +2300,7 @@ declare class RestClient$1 {
2300
2300
  *
2301
2301
  * @throws {AdminAccountRequiredError} on HTTP 418
2302
2302
  * @throws {RateLimitError} on HTTP 429 after retries are exhausted
2303
+ * @throws {CngPermissionError} on HTTP 403 (app missing a permission)
2303
2304
  * @throws {CngApiError} on any other non-2xx response
2304
2305
  */
2305
2306
  get<T>(path: string): Promise<T>;
@@ -2321,23 +2322,30 @@ declare class RestClient$1 {
2321
2322
  *
2322
2323
  * `CngAccessService.getAllActivities()` returns these as a flat list.
2323
2324
  *
2324
- * NOTE: field mapping is a best-guess placeholder until the real
2325
- * `commerce-config/products` response shape is confirmed — see
2326
- * `internal/cng/products/product-queries.ts`.
2325
+ * Mapped from the `app-registry/products` REST payload — see
2326
+ * `internal/cng/products/product-queries.ts`. That payload carries no
2327
+ * product-type discriminator and no sub-options, so `type` is always
2328
+ * {@link ACTIVITY_PRODUCT_TYPE} and `tickets` is always empty.
2327
2329
  */
2328
2330
  interface Activity {
2329
2331
  /** Stable unique identifier for the activity. */
2330
2332
  productId: string;
2331
2333
  /** Human-readable display name. */
2332
2334
  name: string;
2333
- /** Product type reported by CNG (e.g. `"ACTIVITY"`). */
2335
+ /**
2336
+ * Product type. Always {@link ACTIVITY_PRODUCT_TYPE} — the CNG products
2337
+ * payload has no type discriminator. Kept for parity with the Peek `Product`.
2338
+ */
2334
2339
  type: string;
2335
2340
  /**
2336
- * Display color as a hex string (e.g. `"#1A2B3C"`). Empty string when no
2337
- * color is set.
2341
+ * Display color as a hex string (e.g. `"#1A2B3C"`), from the product's
2342
+ * access-control color. Empty string when no color is set.
2338
2343
  */
2339
2344
  color: string;
2340
- /** The bookable sub-options (tickets) of this activity. */
2345
+ /**
2346
+ * The bookable sub-options (tickets) of this activity. Always empty — CNG
2347
+ * exposes no tickets on the products endpoint today.
2348
+ */
2341
2349
  tickets: ActivityTicket[];
2342
2350
  }
2343
2351
  /** A single bookable sub-option (ticket) of an {@link Activity}. */
@@ -2864,15 +2872,6 @@ declare function parseInstallWebhook(token: string, body: unknown, secret: strin
2864
2872
  */
2865
2873
  declare function verifyInstallWebhook(token: string, secret: string): InstallWebhookClaims;
2866
2874
 
2867
- /**
2868
- * Typed errors thrown by the package. Each mirrors a failure mode of the Peek
2869
- * GraphQL gateway (or the CNG REST gateway) so callers can branch on the error
2870
- * type rather than parsing messages.
2871
- *
2872
- * `AdminAccountRequiredError` and `RateLimitError` are shared by all gateways.
2873
- * `PeekGraphQLError` is Peek-only; `CngApiError` is CNG-only; `AcmeApiError` is
2874
- * ACME-only.
2875
- */
2876
2875
  /**
2877
2876
  * Thrown when the gateway responds with HTTP 418, indicating the install is not
2878
2877
  * permitted to perform the request because an admin account is required.
@@ -2947,6 +2946,32 @@ declare class CngApiError extends Error {
2947
2946
  readonly body: unknown;
2948
2947
  constructor(statusCode: number, body: unknown, message?: string);
2949
2948
  }
2949
+ /**
2950
+ * Thrown when the CNG REST gateway responds with HTTP 403 because the app lacks
2951
+ * a permission the endpoint requires (e.g. `products:read`). This is an
2952
+ * **expected** failure for a misconfigured install — not a bug — so the
2953
+ * transport logs it at `warn` rather than `error` and leaves presentation to the
2954
+ * caller, which can branch on the type and surface the missing permission
2955
+ * however its UI prefers.
2956
+ *
2957
+ * The permission names the gateway named are on
2958
+ * {@link CngPermissionError.permissions} (empty when the body does not name
2959
+ * any), so a caller can render them without re-parsing the raw body. Thrown in
2960
+ * place of {@link CngApiError} for 403s only; every other non-2xx status still
2961
+ * throws `CngApiError`.
2962
+ */
2963
+ declare class CngPermissionError extends Error {
2964
+ /** The HTTP status that triggered this error. */
2965
+ readonly statusCode = 403;
2966
+ /**
2967
+ * The permissions the gateway reported as missing, e.g. `["products:read"]`.
2968
+ * Empty when the response body did not name any.
2969
+ */
2970
+ readonly permissions: string[];
2971
+ /** The raw response body (parsed JSON when possible, otherwise text). */
2972
+ readonly body: unknown;
2973
+ constructor(permissions: string[], body: unknown, message?: string);
2974
+ }
2950
2975
  /**
2951
2976
  * Thrown when the ACME REST gateway returns a non-2xx response that is not one
2952
2977
  * of the specifically-handled statuses (418/429). The offending status is
@@ -2962,4 +2987,4 @@ declare class AcmeApiError extends Error {
2962
2987
  constructor(statusCode: number, body: unknown, message?: string);
2963
2988
  }
2964
2989
 
2965
- export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, type AccessOptions, type AccountUser, AccountUserService, type AccountUserServiceOptions, AcmeAccessService, type AcmeAccessServiceConfig, type AcmeActivity, type AcmeActivityTicket, AcmeApiError, AcmeProductService, type Activity, type ActivityOverrides, type ActivityTicket, type AddAddonInput, AdminAccountRequiredError, type Agent, type AssignGuideResult, type AssignedActivity, type AssignedResource, type Availability, AvailabilityService, type AvailabilityTime, type AvailabilityTimesQuery, type Booking, type BookingAddon, type BookingAddonMoney, type BookingAddonOption, type BookingAddons, type BookingAddonsMutationResult, type BookingPaymentsOnFile, type BookingReadOptions, type BookingSearchBy, BookingService, type BookingServiceOptions, type BookingTimeRangeSearch, type CancelBookingResult, type Channel, type ClearOverridesInput, CngAccessService, type CngAccessServiceConfig, CngApiError, CngProductService, type CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreateEngineInput, type CreatePromoCodeInput, type CreatedBooking, type CreatedPricingEngine, type CreatedPromoCode, type CustomQuestion, type CustomQuestionAnswer, type CustomQuestionAnswerInput, type CustomQuestionOption, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, INSTALL_STATUSES, type InstallAccessConfig, type InstallAccessService, type InstallAccessTarget, type InstallStatus, type InstallWebhook, type InstallWebhookAccount, type InstallWebhookClaims, type InvoiceLinkResult, type Logger, type MakePaymentInput, type MakePaymentResult, type Membership, type MembershipPurchaseInput, MembershipService, type NoteMode, type Payment, type PaymentSource, PeekAccessService, type PeekAccessServiceConfig, type PeekAuthTokenClaims, type PeekAuthTokenUser, PeekGraphQLError, PeekHttpError, type PeekPlatform, PiiAccessDisabledError, type Price, type PricingActivityContext, type PricingEngine, type PricingMoney, type PricingNamedRef, type PricingOverride, type PricingOverrideFilter, PricingService, type Product, type ProductMeetingLocation, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RENTAL_PRODUCT_TYPE, RateLimitError, type RefundInput, type RefundResult, ResellerService, type ResolvedOverride, type ResolvedPricingOverride, type ResolvedResourceOption, type Resource, type ResourceOptionOverride, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateEngineInput, type UpdateTimeslotResult, type UpsertOverridesInput, type UpsertOverridesResult, type Waiver, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
2990
+ export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, type AccessOptions, type AccountUser, AccountUserService, type AccountUserServiceOptions, AcmeAccessService, type AcmeAccessServiceConfig, type AcmeActivity, type AcmeActivityTicket, AcmeApiError, AcmeProductService, type Activity, type ActivityOverrides, type ActivityTicket, type AddAddonInput, AdminAccountRequiredError, type Agent, type AssignGuideResult, type AssignedActivity, type AssignedResource, type Availability, AvailabilityService, type AvailabilityTime, type AvailabilityTimesQuery, type Booking, type BookingAddon, type BookingAddonMoney, type BookingAddonOption, type BookingAddons, type BookingAddonsMutationResult, type BookingPaymentsOnFile, type BookingReadOptions, type BookingSearchBy, BookingService, type BookingServiceOptions, type BookingTimeRangeSearch, type CancelBookingResult, type Channel, type ClearOverridesInput, CngAccessService, type CngAccessServiceConfig, CngApiError, CngPermissionError, CngProductService, type CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreateEngineInput, type CreatePromoCodeInput, type CreatedBooking, type CreatedPricingEngine, type CreatedPromoCode, type CustomQuestion, type CustomQuestionAnswer, type CustomQuestionAnswerInput, type CustomQuestionOption, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, INSTALL_STATUSES, type InstallAccessConfig, type InstallAccessService, type InstallAccessTarget, type InstallStatus, type InstallWebhook, type InstallWebhookAccount, type InstallWebhookClaims, type InvoiceLinkResult, type Logger, type MakePaymentInput, type MakePaymentResult, type Membership, type MembershipPurchaseInput, MembershipService, type NoteMode, type Payment, type PaymentSource, PeekAccessService, type PeekAccessServiceConfig, type PeekAuthTokenClaims, type PeekAuthTokenUser, PeekGraphQLError, PeekHttpError, type PeekPlatform, PiiAccessDisabledError, type Price, type PricingActivityContext, type PricingEngine, type PricingMoney, type PricingNamedRef, type PricingOverride, type PricingOverrideFilter, PricingService, type Product, type ProductMeetingLocation, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RENTAL_PRODUCT_TYPE, RateLimitError, type RefundInput, type RefundResult, ResellerService, type ResolvedOverride, type ResolvedPricingOverride, type ResolvedResourceOption, type Resource, type ResourceOptionOverride, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateEngineInput, type UpdateTimeslotResult, type UpsertOverridesInput, type UpsertOverridesResult, type Waiver, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
package/dist/index.d.ts CHANGED
@@ -2300,6 +2300,7 @@ declare class RestClient$1 {
2300
2300
  *
2301
2301
  * @throws {AdminAccountRequiredError} on HTTP 418
2302
2302
  * @throws {RateLimitError} on HTTP 429 after retries are exhausted
2303
+ * @throws {CngPermissionError} on HTTP 403 (app missing a permission)
2303
2304
  * @throws {CngApiError} on any other non-2xx response
2304
2305
  */
2305
2306
  get<T>(path: string): Promise<T>;
@@ -2321,23 +2322,30 @@ declare class RestClient$1 {
2321
2322
  *
2322
2323
  * `CngAccessService.getAllActivities()` returns these as a flat list.
2323
2324
  *
2324
- * NOTE: field mapping is a best-guess placeholder until the real
2325
- * `commerce-config/products` response shape is confirmed — see
2326
- * `internal/cng/products/product-queries.ts`.
2325
+ * Mapped from the `app-registry/products` REST payload — see
2326
+ * `internal/cng/products/product-queries.ts`. That payload carries no
2327
+ * product-type discriminator and no sub-options, so `type` is always
2328
+ * {@link ACTIVITY_PRODUCT_TYPE} and `tickets` is always empty.
2327
2329
  */
2328
2330
  interface Activity {
2329
2331
  /** Stable unique identifier for the activity. */
2330
2332
  productId: string;
2331
2333
  /** Human-readable display name. */
2332
2334
  name: string;
2333
- /** Product type reported by CNG (e.g. `"ACTIVITY"`). */
2335
+ /**
2336
+ * Product type. Always {@link ACTIVITY_PRODUCT_TYPE} — the CNG products
2337
+ * payload has no type discriminator. Kept for parity with the Peek `Product`.
2338
+ */
2334
2339
  type: string;
2335
2340
  /**
2336
- * Display color as a hex string (e.g. `"#1A2B3C"`). Empty string when no
2337
- * color is set.
2341
+ * Display color as a hex string (e.g. `"#1A2B3C"`), from the product's
2342
+ * access-control color. Empty string when no color is set.
2338
2343
  */
2339
2344
  color: string;
2340
- /** The bookable sub-options (tickets) of this activity. */
2345
+ /**
2346
+ * The bookable sub-options (tickets) of this activity. Always empty — CNG
2347
+ * exposes no tickets on the products endpoint today.
2348
+ */
2341
2349
  tickets: ActivityTicket[];
2342
2350
  }
2343
2351
  /** A single bookable sub-option (ticket) of an {@link Activity}. */
@@ -2864,15 +2872,6 @@ declare function parseInstallWebhook(token: string, body: unknown, secret: strin
2864
2872
  */
2865
2873
  declare function verifyInstallWebhook(token: string, secret: string): InstallWebhookClaims;
2866
2874
 
2867
- /**
2868
- * Typed errors thrown by the package. Each mirrors a failure mode of the Peek
2869
- * GraphQL gateway (or the CNG REST gateway) so callers can branch on the error
2870
- * type rather than parsing messages.
2871
- *
2872
- * `AdminAccountRequiredError` and `RateLimitError` are shared by all gateways.
2873
- * `PeekGraphQLError` is Peek-only; `CngApiError` is CNG-only; `AcmeApiError` is
2874
- * ACME-only.
2875
- */
2876
2875
  /**
2877
2876
  * Thrown when the gateway responds with HTTP 418, indicating the install is not
2878
2877
  * permitted to perform the request because an admin account is required.
@@ -2947,6 +2946,32 @@ declare class CngApiError extends Error {
2947
2946
  readonly body: unknown;
2948
2947
  constructor(statusCode: number, body: unknown, message?: string);
2949
2948
  }
2949
+ /**
2950
+ * Thrown when the CNG REST gateway responds with HTTP 403 because the app lacks
2951
+ * a permission the endpoint requires (e.g. `products:read`). This is an
2952
+ * **expected** failure for a misconfigured install — not a bug — so the
2953
+ * transport logs it at `warn` rather than `error` and leaves presentation to the
2954
+ * caller, which can branch on the type and surface the missing permission
2955
+ * however its UI prefers.
2956
+ *
2957
+ * The permission names the gateway named are on
2958
+ * {@link CngPermissionError.permissions} (empty when the body does not name
2959
+ * any), so a caller can render them without re-parsing the raw body. Thrown in
2960
+ * place of {@link CngApiError} for 403s only; every other non-2xx status still
2961
+ * throws `CngApiError`.
2962
+ */
2963
+ declare class CngPermissionError extends Error {
2964
+ /** The HTTP status that triggered this error. */
2965
+ readonly statusCode = 403;
2966
+ /**
2967
+ * The permissions the gateway reported as missing, e.g. `["products:read"]`.
2968
+ * Empty when the response body did not name any.
2969
+ */
2970
+ readonly permissions: string[];
2971
+ /** The raw response body (parsed JSON when possible, otherwise text). */
2972
+ readonly body: unknown;
2973
+ constructor(permissions: string[], body: unknown, message?: string);
2974
+ }
2950
2975
  /**
2951
2976
  * Thrown when the ACME REST gateway returns a non-2xx response that is not one
2952
2977
  * of the specifically-handled statuses (418/429). The offending status is
@@ -2962,4 +2987,4 @@ declare class AcmeApiError extends Error {
2962
2987
  constructor(statusCode: number, body: unknown, message?: string);
2963
2988
  }
2964
2989
 
2965
- export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, type AccessOptions, type AccountUser, AccountUserService, type AccountUserServiceOptions, AcmeAccessService, type AcmeAccessServiceConfig, type AcmeActivity, type AcmeActivityTicket, AcmeApiError, AcmeProductService, type Activity, type ActivityOverrides, type ActivityTicket, type AddAddonInput, AdminAccountRequiredError, type Agent, type AssignGuideResult, type AssignedActivity, type AssignedResource, type Availability, AvailabilityService, type AvailabilityTime, type AvailabilityTimesQuery, type Booking, type BookingAddon, type BookingAddonMoney, type BookingAddonOption, type BookingAddons, type BookingAddonsMutationResult, type BookingPaymentsOnFile, type BookingReadOptions, type BookingSearchBy, BookingService, type BookingServiceOptions, type BookingTimeRangeSearch, type CancelBookingResult, type Channel, type ClearOverridesInput, CngAccessService, type CngAccessServiceConfig, CngApiError, CngProductService, type CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreateEngineInput, type CreatePromoCodeInput, type CreatedBooking, type CreatedPricingEngine, type CreatedPromoCode, type CustomQuestion, type CustomQuestionAnswer, type CustomQuestionAnswerInput, type CustomQuestionOption, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, INSTALL_STATUSES, type InstallAccessConfig, type InstallAccessService, type InstallAccessTarget, type InstallStatus, type InstallWebhook, type InstallWebhookAccount, type InstallWebhookClaims, type InvoiceLinkResult, type Logger, type MakePaymentInput, type MakePaymentResult, type Membership, type MembershipPurchaseInput, MembershipService, type NoteMode, type Payment, type PaymentSource, PeekAccessService, type PeekAccessServiceConfig, type PeekAuthTokenClaims, type PeekAuthTokenUser, PeekGraphQLError, PeekHttpError, type PeekPlatform, PiiAccessDisabledError, type Price, type PricingActivityContext, type PricingEngine, type PricingMoney, type PricingNamedRef, type PricingOverride, type PricingOverrideFilter, PricingService, type Product, type ProductMeetingLocation, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RENTAL_PRODUCT_TYPE, RateLimitError, type RefundInput, type RefundResult, ResellerService, type ResolvedOverride, type ResolvedPricingOverride, type ResolvedResourceOption, type Resource, type ResourceOptionOverride, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateEngineInput, type UpdateTimeslotResult, type UpsertOverridesInput, type UpsertOverridesResult, type Waiver, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
2990
+ export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, type AccessOptions, type AccountUser, AccountUserService, type AccountUserServiceOptions, AcmeAccessService, type AcmeAccessServiceConfig, type AcmeActivity, type AcmeActivityTicket, AcmeApiError, AcmeProductService, type Activity, type ActivityOverrides, type ActivityTicket, type AddAddonInput, AdminAccountRequiredError, type Agent, type AssignGuideResult, type AssignedActivity, type AssignedResource, type Availability, AvailabilityService, type AvailabilityTime, type AvailabilityTimesQuery, type Booking, type BookingAddon, type BookingAddonMoney, type BookingAddonOption, type BookingAddons, type BookingAddonsMutationResult, type BookingPaymentsOnFile, type BookingReadOptions, type BookingSearchBy, BookingService, type BookingServiceOptions, type BookingTimeRangeSearch, type CancelBookingResult, type Channel, type ClearOverridesInput, CngAccessService, type CngAccessServiceConfig, CngApiError, CngPermissionError, CngProductService, type CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreateEngineInput, type CreatePromoCodeInput, type CreatedBooking, type CreatedPricingEngine, type CreatedPromoCode, type CustomQuestion, type CustomQuestionAnswer, type CustomQuestionAnswerInput, type CustomQuestionOption, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, INSTALL_STATUSES, type InstallAccessConfig, type InstallAccessService, type InstallAccessTarget, type InstallStatus, type InstallWebhook, type InstallWebhookAccount, type InstallWebhookClaims, type InvoiceLinkResult, type Logger, type MakePaymentInput, type MakePaymentResult, type Membership, type MembershipPurchaseInput, MembershipService, type NoteMode, type Payment, type PaymentSource, PeekAccessService, type PeekAccessServiceConfig, type PeekAuthTokenClaims, type PeekAuthTokenUser, PeekGraphQLError, PeekHttpError, type PeekPlatform, PiiAccessDisabledError, type Price, type PricingActivityContext, type PricingEngine, type PricingMoney, type PricingNamedRef, type PricingOverride, type PricingOverrideFilter, PricingService, type Product, type ProductMeetingLocation, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RENTAL_PRODUCT_TYPE, RateLimitError, type RefundInput, type RefundResult, ResellerService, type ResolvedOverride, type ResolvedPricingOverride, type ResolvedResourceOption, type Resource, type ResourceOptionOverride, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateEngineInput, type UpdateTimeslotResult, type UpsertOverridesInput, type UpsertOverridesResult, type Waiver, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
package/dist/index.js CHANGED
@@ -185,6 +185,13 @@ function resolveAccessOptions(options) {
185
185
  }
186
186
 
187
187
  // src/errors.ts
188
+ var FORBIDDEN_STATUS = 403;
189
+ var PERMISSION_MESSAGE_PREFIX = "CNG request forbidden: the app is missing the required permission";
190
+ var PERMISSION_MESSAGE_UNKNOWN = "CNG request forbidden: the app is missing a required permission";
191
+ function buildPermissionMessage(permissions) {
192
+ if (permissions.length === 0) return PERMISSION_MESSAGE_UNKNOWN;
193
+ return `${PERMISSION_MESSAGE_PREFIX}${permissions.length > 1 ? "s" : ""}: ${permissions.join(", ")}`;
194
+ }
188
195
  var AdminAccountRequiredError = class extends Error {
189
196
  /** The HTTP status that triggered this error. */
190
197
  statusCode = 418;
@@ -248,6 +255,23 @@ var CngApiError = class extends Error {
248
255
  this.body = body;
249
256
  }
250
257
  };
258
+ var CngPermissionError = class extends Error {
259
+ /** The HTTP status that triggered this error. */
260
+ statusCode = FORBIDDEN_STATUS;
261
+ /**
262
+ * The permissions the gateway reported as missing, e.g. `["products:read"]`.
263
+ * Empty when the response body did not name any.
264
+ */
265
+ permissions;
266
+ /** The raw response body (parsed JSON when possible, otherwise text). */
267
+ body;
268
+ constructor(permissions, body, message) {
269
+ super(message ?? buildPermissionMessage(permissions));
270
+ this.name = "CngPermissionError";
271
+ this.permissions = permissions;
272
+ this.body = body;
273
+ }
274
+ };
251
275
  var AcmeApiError = class extends Error {
252
276
  /** The HTTP status that triggered this error. */
253
277
  statusCode;
@@ -4134,7 +4158,7 @@ var PeekAccessService = class {
4134
4158
 
4135
4159
  // src/internal/cng/endpoints.ts
4136
4160
  var CNG_EXTENDABLE_SLUG = "cng_backoffice_api-v1";
4137
- var PRODUCTS_PATH = "api/v2/commerce-config/products";
4161
+ var PRODUCTS_PATH = "api/v2/app-registry/products?active=1";
4138
4162
 
4139
4163
  // src/models/cng/product.ts
4140
4164
  var ACTIVITY_PRODUCT_TYPE2 = "ACTIVITY";
@@ -4145,14 +4169,11 @@ function fromProductNodes(nodes) {
4145
4169
  }
4146
4170
  function fromProductNode(node) {
4147
4171
  return {
4148
- productId: node.id || "",
4172
+ productId: node.id == null ? "" : String(node.id),
4149
4173
  name: node.name || "",
4150
- type: node.product_type || ACTIVITY_PRODUCT_TYPE2,
4151
- color: node.color_hex || "",
4152
- tickets: (node.tickets ?? []).map((ticket) => ({
4153
- id: ticket.id,
4154
- name: ticket.name
4155
- }))
4174
+ type: ACTIVITY_PRODUCT_TYPE2,
4175
+ color: node.access_control_color_hex || "",
4176
+ tickets: []
4156
4177
  };
4157
4178
  }
4158
4179
 
@@ -4171,15 +4192,13 @@ var CngProductService = class {
4171
4192
  * ```
4172
4193
  */
4173
4194
  async getAllActivities() {
4174
- const body = await this.client.get(
4175
- PRODUCTS_PATH
4176
- );
4177
- const nodes = Array.isArray(body) ? body : body?.products ?? [];
4178
- return fromProductNodes(nodes ?? []);
4195
+ const body = await this.client.get(PRODUCTS_PATH);
4196
+ return fromProductNodes(body?.data ?? []);
4179
4197
  }
4180
4198
  };
4181
4199
 
4182
4200
  // src/internal/cng/rest-client.ts
4201
+ var PERMISSION_SEPARATOR = ": ";
4183
4202
  var RestClient = class {
4184
4203
  constructor(options) {
4185
4204
  this.options = options;
@@ -4192,6 +4211,7 @@ var RestClient = class {
4192
4211
  *
4193
4212
  * @throws {AdminAccountRequiredError} on HTTP 418
4194
4213
  * @throws {RateLimitError} on HTTP 429 after retries are exhausted
4214
+ * @throws {CngPermissionError} on HTTP 403 (app missing a permission)
4195
4215
  * @throws {CngApiError} on any other non-2xx response
4196
4216
  */
4197
4217
  async get(path) {
@@ -4205,6 +4225,11 @@ var RestClient = class {
4205
4225
  path,
4206
4226
  async (response) => {
4207
4227
  const body = await parseBody(response);
4228
+ if (response.status === FORBIDDEN_STATUS) {
4229
+ const permissions = extractMissingPermissions(body);
4230
+ logger.warn(`Missing permission for ${path} (HTTP 403)`, { url, permissions });
4231
+ throw new CngPermissionError(permissions, body);
4232
+ }
4208
4233
  if (!response.ok) {
4209
4234
  logger.error(`CNG request failed with HTTP ${response.status}`, { url });
4210
4235
  throw new CngApiError(response.status, body);
@@ -4225,6 +4250,12 @@ var RestClient = class {
4225
4250
  };
4226
4251
  }
4227
4252
  };
4253
+ function extractMissingPermissions(body) {
4254
+ if (typeof body !== "object" || body === null) return [];
4255
+ const raw = body.errors?.permission;
4256
+ if (!Array.isArray(raw)) return [];
4257
+ return raw.filter((entry) => typeof entry === "string").map((entry) => entry.split(PERMISSION_SEPARATOR).pop().trim()).filter((permission) => permission.length > 0);
4258
+ }
4228
4259
 
4229
4260
  // src/cng-access-service.ts
4230
4261
  var DEFAULT_BASE_URL2 = "https://app-registry.peeklabs.com/installations-api";
@@ -4569,6 +4600,6 @@ function verifyInstallWebhook(token, secret) {
4569
4600
  };
4570
4601
  }
4571
4602
 
4572
- export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, AccountUserService, AcmeAccessService, AcmeApiError, AcmeProductService, AdminAccountRequiredError, AvailabilityService, BookingService, CngAccessService, CngApiError, CngProductService, DailyNoteService, INSTALL_STATUSES, MembershipService, PeekAccessService, PeekGraphQLError, PeekHttpError, PiiAccessDisabledError, PricingService, ProductService, PromoCodeService, RENTAL_PRODUCT_TYPE, RateLimitError, ResellerService, ResourcePoolService, ReviewService, TimeslotService, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
4603
+ export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, AccountUserService, AcmeAccessService, AcmeApiError, AcmeProductService, AdminAccountRequiredError, AvailabilityService, BookingService, CngAccessService, CngApiError, CngPermissionError, CngProductService, DailyNoteService, INSTALL_STATUSES, MembershipService, PeekAccessService, PeekGraphQLError, PeekHttpError, PiiAccessDisabledError, PricingService, ProductService, PromoCodeService, RENTAL_PRODUCT_TYPE, RateLimitError, ResellerService, ResourcePoolService, ReviewService, TimeslotService, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
4573
4604
  //# sourceMappingURL=index.js.map
4574
4605
  //# sourceMappingURL=index.js.map