@peektravel/app-utilities 0.2.10 → 0.3.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.d.cts CHANGED
@@ -44,7 +44,8 @@ declare class GraphQLClient {
44
44
  constructor(options: GraphQLClientOptions);
45
45
  /**
46
46
  * Executes a GraphQL query against the named endpoint and returns the raw
47
- * response body. Retries on HTTP 429 per the configured backoff.
47
+ * response body. Retries on HTTP 429 per the configured backoff (via the
48
+ * shared {@link requestWithRetry} loop).
48
49
  */
49
50
  request<T>(endpointName: string, query: string, variables: object): Promise<GraphQLBody<T>>;
50
51
  private endpoint;
@@ -1193,6 +1194,40 @@ declare class DailyNoteService {
1193
1194
  update(note: string): Promise<DailyNote | null>;
1194
1195
  }
1195
1196
 
1197
+ /**
1198
+ * Config shared by every access service in this package (Peek, CNG, …).
1199
+ *
1200
+ * Each gateway's access service extends {@link BaseAccessServiceConfig} with its
1201
+ * own extras (e.g. Peek adds `gatewayKey`/`mode`), so the only real difference
1202
+ * between accessors is the transport they build and the services they expose.
1203
+ * The shared defaults and the token-manager builder live here too, so that
1204
+ * plumbing is written once.
1205
+ */
1206
+
1207
+ /** Fields common to every access service's config. */
1208
+ interface BaseAccessServiceConfig {
1209
+ /** Install ID. Becomes the JWT subject. */
1210
+ installId: string;
1211
+ /** HMAC secret used to sign the JWT. */
1212
+ jwtSecret: string;
1213
+ /** JWT issuer — the app name / app ID. */
1214
+ issuer: string;
1215
+ /** App ID, used in the gateway endpoint path. */
1216
+ appId: string;
1217
+ /** Override the gateway base URL. Default: per-service. */
1218
+ baseUrl?: string;
1219
+ /** JWT lifetime in seconds. Default: 3600. */
1220
+ tokenTtlSeconds?: number;
1221
+ /** Re-mint the cached token this many seconds before expiry. Default: 60. */
1222
+ tokenRefreshLeewaySeconds?: number;
1223
+ /** Backoff delays (ms) for HTTP 429 retries. Default: [1000, 2000, 4000]. */
1224
+ retryDelaysMs?: number[];
1225
+ /** Optional logger. Default: no-op (silent). */
1226
+ logger?: Logger;
1227
+ /** Custom `fetch` implementation. Default: the global `fetch`. */
1228
+ fetch?: typeof fetch;
1229
+ }
1230
+
1196
1231
  declare class MembershipService {
1197
1232
  private readonly client;
1198
1233
  constructor(client: GraphQLClient);
@@ -1391,6 +1426,13 @@ declare class PromoCodeService {
1391
1426
  create(input: CreatePromoCodeInput): Promise<CreatedPromoCode>;
1392
1427
  }
1393
1428
 
1429
+ /**
1430
+ * Platform that embedded the app for this session. Verification is
1431
+ * brand-agnostic — one peek-auth JWT is minted for every platform — so this
1432
+ * claim is the single thing that identifies which platform a request came from.
1433
+ * New platforms extend this union.
1434
+ */
1435
+ type PeekPlatform = "peek" | "cng" | "acme";
1394
1436
  /** User context embedded in a Peek auth token. */
1395
1437
  interface PeekAuthTokenUser {
1396
1438
  /** User's email address. */
@@ -1403,6 +1445,8 @@ interface PeekAuthTokenUser {
1403
1445
  locale: string;
1404
1446
  /** User's display name. */
1405
1447
  name: string;
1448
+ /** Which platform embedded the app for this session. */
1449
+ platform: PeekPlatform;
1406
1450
  }
1407
1451
  /** Claims returned by {@link PeekAccessService.verifyPeekAuthToken}. */
1408
1452
  interface PeekAuthTokenClaims {
@@ -1414,16 +1458,12 @@ interface PeekAuthTokenClaims {
1414
1458
  user: PeekAuthTokenUser;
1415
1459
  }
1416
1460
 
1417
- /** Configuration for a {@link PeekAccessService} instance. */
1418
- interface PeekAccessServiceConfig {
1419
- /** Peek install ID. Becomes the JWT subject. */
1420
- installId: string;
1421
- /** HMAC secret used to sign the JWT (the Peek internal secret). */
1422
- jwtSecret: string;
1423
- /** JWT issuer — the app name. */
1424
- issuer: string;
1425
- /** Peek app ID, used in the gateway endpoint path. */
1426
- appId: string;
1461
+ /**
1462
+ * Configuration for a {@link PeekAccessService} instance. Extends the shared
1463
+ * {@link BaseAccessServiceConfig} (install/auth/transport fields) with the
1464
+ * Peek-specific extras below.
1465
+ */
1466
+ interface PeekAccessServiceConfig extends BaseAccessServiceConfig {
1427
1467
  /** API gateway key, sent as the `pk-api-key` header. Required in v1 mode; not used in v2. */
1428
1468
  gatewayKey?: string;
1429
1469
  /**
@@ -1433,18 +1473,6 @@ interface PeekAccessServiceConfig {
1433
1473
  * GraphQL gateway.
1434
1474
  */
1435
1475
  mode?: "v2";
1436
- /** Override the gateway base URL. Default: Peek production gateway (v1) or app-registry sandbox (v2). */
1437
- baseUrl?: string;
1438
- /** JWT lifetime in seconds. Default: 3600. */
1439
- tokenTtlSeconds?: number;
1440
- /** Re-mint the cached token this many seconds before expiry. Default: 60. */
1441
- tokenRefreshLeewaySeconds?: number;
1442
- /** Backoff delays (ms) for HTTP 429 retries. Default: [1000, 2000, 4000]. */
1443
- retryDelaysMs?: number[];
1444
- /** Optional logger. Default: no-op (silent). */
1445
- logger?: Logger;
1446
- /** Custom `fetch` implementation. Default: the global `fetch`. */
1447
- fetch?: typeof fetch;
1448
1476
  /** Page size for cursor-paginated item options. Default: 50. */
1449
1477
  itemOptionsPageSize?: number;
1450
1478
  }
@@ -1640,6 +1668,135 @@ declare class PeekAccessService {
1640
1668
  getReviews(productId: string, reviewCount?: number, reviewOffset?: number): Promise<Review[]>;
1641
1669
  }
1642
1670
 
1671
+ interface RestClientOptions {
1672
+ /** Base URL of the backoffice gateway (no trailing slash). */
1673
+ baseUrl: string;
1674
+ /** App ID, used in the endpoint path. */
1675
+ appId: string;
1676
+ /** Fixed extendable slug inserted between `appId` and the REST path. */
1677
+ extendableSlug: string;
1678
+ /** Supplies a valid bearer token for each request. */
1679
+ getToken: () => string;
1680
+ /** Backoff delays (ms) applied on successive HTTP 429 responses. */
1681
+ retryDelaysMs: number[];
1682
+ /** Diagnostics sink. */
1683
+ logger: Logger;
1684
+ /** `fetch` implementation to use. */
1685
+ fetchFn: typeof fetch;
1686
+ }
1687
+ declare class RestClient {
1688
+ private readonly options;
1689
+ constructor(options: RestClientOptions);
1690
+ /**
1691
+ * Issues a GET against the named REST path and returns the parsed JSON body.
1692
+ * Retries on HTTP 429 per the configured backoff (via the shared
1693
+ * {@link requestWithRetry} loop).
1694
+ *
1695
+ * @throws {AdminAccountRequiredError} on HTTP 418
1696
+ * @throws {RateLimitError} on HTTP 429 after retries are exhausted
1697
+ * @throws {CngApiError} on any other non-2xx response
1698
+ */
1699
+ get<T>(path: string): Promise<T>;
1700
+ /** Reads the response body as JSON, falling back to raw text when unparseable. */
1701
+ private parseBody;
1702
+ private endpoint;
1703
+ private buildHeaders;
1704
+ }
1705
+
1706
+ /**
1707
+ * The clean, transport-agnostic data model for a CNG product.
1708
+ *
1709
+ * The CNG sibling of `../peek/product.ts`. Kept as a separate model because the
1710
+ * CNG gateway is a distinct backoffice, but the shape deliberately mirrors the
1711
+ * Peek `Product` so consumers can treat both brands uniformly. The raw CNG REST
1712
+ * response types and the conversion logic live inside the package and are never
1713
+ * exposed here.
1714
+ */
1715
+ /**
1716
+ * A bookable activity in a CNG account.
1717
+ *
1718
+ * `CngAccessService.getAllActivities()` returns these as a flat list.
1719
+ *
1720
+ * NOTE: field mapping is a best-guess placeholder until the real
1721
+ * `commerce-config/products` response shape is confirmed — see
1722
+ * `internal/cng/products/product-queries.ts`.
1723
+ */
1724
+ interface Activity {
1725
+ /** Stable unique identifier for the activity. */
1726
+ productId: string;
1727
+ /** Human-readable display name. */
1728
+ name: string;
1729
+ /** Product type reported by CNG (e.g. `"ACTIVITY"`). */
1730
+ type: string;
1731
+ /**
1732
+ * Display color as a hex string (e.g. `"#1A2B3C"`). Empty string when no
1733
+ * color is set.
1734
+ */
1735
+ color: string;
1736
+ /** The bookable sub-options (tickets) of this activity. */
1737
+ tickets: ActivityTicket[];
1738
+ }
1739
+ /** A single bookable sub-option (ticket) of an {@link Activity}. */
1740
+ interface ActivityTicket {
1741
+ /** Unique identifier of the ticket. */
1742
+ id: string;
1743
+ /** Human-readable name of the ticket. */
1744
+ name: string;
1745
+ }
1746
+
1747
+ declare class CngProductService {
1748
+ private readonly client;
1749
+ constructor(client: RestClient);
1750
+ /**
1751
+ * Returns every activity as a single flat list.
1752
+ *
1753
+ * @example
1754
+ * ```ts
1755
+ * const activities = await cng.getProductService().getAllActivities();
1756
+ * ```
1757
+ */
1758
+ getAllActivities(): Promise<Activity[]>;
1759
+ }
1760
+
1761
+ /**
1762
+ * Configuration for a {@link CngAccessService} instance. CNG adds no fields
1763
+ * beyond {@link BaseAccessServiceConfig} — it authenticates on the app JWT
1764
+ * alone (no `pk-api-key`, so no `gatewayKey`).
1765
+ */
1766
+ type CngAccessServiceConfig = BaseAccessServiceConfig;
1767
+ /**
1768
+ * Authenticated root entry point to the CNG backoffice REST gateway.
1769
+ *
1770
+ * @example
1771
+ * ```ts
1772
+ * import { CngAccessService, type Activity } from "@peektravel/app-utilities";
1773
+ *
1774
+ * const cng = new CngAccessService({
1775
+ * installId: "install-123",
1776
+ * jwtSecret: process.env.PEEK_APP_SECRET!,
1777
+ * issuer: process.env.PEEK_APP_ID!,
1778
+ * appId: process.env.PEEK_APP_ID!,
1779
+ * });
1780
+ *
1781
+ * const activities: Activity[] = await cng.getAllActivities();
1782
+ * ```
1783
+ *
1784
+ * @throws {Error} from the constructor when any required config field
1785
+ * (`installId`, `jwtSecret`, `issuer`, `appId`) is empty.
1786
+ */
1787
+ declare class CngAccessService {
1788
+ private readonly client;
1789
+ private productService?;
1790
+ constructor(config: CngAccessServiceConfig);
1791
+ /**
1792
+ * Returns the {@link CngProductService} for this install, bound to the shared
1793
+ * authenticated transport. The instance is created lazily and reused.
1794
+ */
1795
+ getProductService(): CngProductService;
1796
+ /** All activities. Delegates to {@link CngProductService.getAllActivities}. */
1797
+ getAllActivities(): Promise<Activity[]>;
1798
+ }
1799
+
1643
1800
  /**
1644
1801
  * Public webhook surface for bookings.
1645
1802
  *
@@ -1722,8 +1879,11 @@ declare function parseWaiverWebhook(payload: unknown): Waiver;
1722
1879
 
1723
1880
  /**
1724
1881
  * Typed errors thrown by the package. Each mirrors a failure mode of the Peek
1725
- * GraphQL gateway so callers can branch on the error type rather than parsing
1726
- * messages.
1882
+ * GraphQL gateway (or the CNG REST gateway) so callers can branch on the error
1883
+ * type rather than parsing messages.
1884
+ *
1885
+ * `AdminAccountRequiredError` and `RateLimitError` are shared by both gateways.
1886
+ * `PeekGraphQLError` is Peek-only; `CngApiError` is CNG-only.
1727
1887
  */
1728
1888
  /**
1729
1889
  * Thrown when the gateway responds with HTTP 418, indicating the install is not
@@ -1752,5 +1912,18 @@ declare class PeekGraphQLError extends Error {
1752
1912
  readonly graphqlErrors: unknown[];
1753
1913
  constructor(graphqlErrors: unknown[], message?: string);
1754
1914
  }
1915
+ /**
1916
+ * Thrown when the CNG REST gateway returns a non-2xx response that is not one
1917
+ * of the specifically-handled statuses (418/429). The offending status is
1918
+ * preserved on {@link CngApiError.statusCode}, and the raw response body (parsed
1919
+ * JSON when possible, otherwise the raw text) on {@link CngApiError.body}.
1920
+ */
1921
+ declare class CngApiError extends Error {
1922
+ /** The HTTP status that triggered this error. */
1923
+ readonly statusCode: number;
1924
+ /** The raw response body (parsed JSON when possible, otherwise text). */
1925
+ readonly body: unknown;
1926
+ constructor(statusCode: number, body: unknown, message?: string);
1927
+ }
1755
1928
 
1756
- export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, type AccountUser, AccountUserService, type AccountUserServiceOptions, 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 CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreatePromoCodeInput, type CreatedBooking, type CreatedPromoCode, type CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, 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, type Price, type Product, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RENTAL_PRODUCT_TYPE, RateLimitError, type RefundInput, type RefundResult, ResellerService, type Resource, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateTimeslotResult, type Waiver, noopLogger, parseBookingWebhook, parseWaiverWebhook };
1929
+ export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, type AccountUser, AccountUserService, type AccountUserServiceOptions, type Activity, 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, CngAccessService, type CngAccessServiceConfig, CngApiError, CngProductService, type CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreatePromoCodeInput, type CreatedBooking, type CreatedPromoCode, type CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, 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, type PeekPlatform, type Price, type Product, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RENTAL_PRODUCT_TYPE, RateLimitError, type RefundInput, type RefundResult, ResellerService, type Resource, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateTimeslotResult, type Waiver, noopLogger, parseBookingWebhook, parseWaiverWebhook };
package/dist/index.d.ts CHANGED
@@ -44,7 +44,8 @@ declare class GraphQLClient {
44
44
  constructor(options: GraphQLClientOptions);
45
45
  /**
46
46
  * Executes a GraphQL query against the named endpoint and returns the raw
47
- * response body. Retries on HTTP 429 per the configured backoff.
47
+ * response body. Retries on HTTP 429 per the configured backoff (via the
48
+ * shared {@link requestWithRetry} loop).
48
49
  */
49
50
  request<T>(endpointName: string, query: string, variables: object): Promise<GraphQLBody<T>>;
50
51
  private endpoint;
@@ -1193,6 +1194,40 @@ declare class DailyNoteService {
1193
1194
  update(note: string): Promise<DailyNote | null>;
1194
1195
  }
1195
1196
 
1197
+ /**
1198
+ * Config shared by every access service in this package (Peek, CNG, …).
1199
+ *
1200
+ * Each gateway's access service extends {@link BaseAccessServiceConfig} with its
1201
+ * own extras (e.g. Peek adds `gatewayKey`/`mode`), so the only real difference
1202
+ * between accessors is the transport they build and the services they expose.
1203
+ * The shared defaults and the token-manager builder live here too, so that
1204
+ * plumbing is written once.
1205
+ */
1206
+
1207
+ /** Fields common to every access service's config. */
1208
+ interface BaseAccessServiceConfig {
1209
+ /** Install ID. Becomes the JWT subject. */
1210
+ installId: string;
1211
+ /** HMAC secret used to sign the JWT. */
1212
+ jwtSecret: string;
1213
+ /** JWT issuer — the app name / app ID. */
1214
+ issuer: string;
1215
+ /** App ID, used in the gateway endpoint path. */
1216
+ appId: string;
1217
+ /** Override the gateway base URL. Default: per-service. */
1218
+ baseUrl?: string;
1219
+ /** JWT lifetime in seconds. Default: 3600. */
1220
+ tokenTtlSeconds?: number;
1221
+ /** Re-mint the cached token this many seconds before expiry. Default: 60. */
1222
+ tokenRefreshLeewaySeconds?: number;
1223
+ /** Backoff delays (ms) for HTTP 429 retries. Default: [1000, 2000, 4000]. */
1224
+ retryDelaysMs?: number[];
1225
+ /** Optional logger. Default: no-op (silent). */
1226
+ logger?: Logger;
1227
+ /** Custom `fetch` implementation. Default: the global `fetch`. */
1228
+ fetch?: typeof fetch;
1229
+ }
1230
+
1196
1231
  declare class MembershipService {
1197
1232
  private readonly client;
1198
1233
  constructor(client: GraphQLClient);
@@ -1391,6 +1426,13 @@ declare class PromoCodeService {
1391
1426
  create(input: CreatePromoCodeInput): Promise<CreatedPromoCode>;
1392
1427
  }
1393
1428
 
1429
+ /**
1430
+ * Platform that embedded the app for this session. Verification is
1431
+ * brand-agnostic — one peek-auth JWT is minted for every platform — so this
1432
+ * claim is the single thing that identifies which platform a request came from.
1433
+ * New platforms extend this union.
1434
+ */
1435
+ type PeekPlatform = "peek" | "cng" | "acme";
1394
1436
  /** User context embedded in a Peek auth token. */
1395
1437
  interface PeekAuthTokenUser {
1396
1438
  /** User's email address. */
@@ -1403,6 +1445,8 @@ interface PeekAuthTokenUser {
1403
1445
  locale: string;
1404
1446
  /** User's display name. */
1405
1447
  name: string;
1448
+ /** Which platform embedded the app for this session. */
1449
+ platform: PeekPlatform;
1406
1450
  }
1407
1451
  /** Claims returned by {@link PeekAccessService.verifyPeekAuthToken}. */
1408
1452
  interface PeekAuthTokenClaims {
@@ -1414,16 +1458,12 @@ interface PeekAuthTokenClaims {
1414
1458
  user: PeekAuthTokenUser;
1415
1459
  }
1416
1460
 
1417
- /** Configuration for a {@link PeekAccessService} instance. */
1418
- interface PeekAccessServiceConfig {
1419
- /** Peek install ID. Becomes the JWT subject. */
1420
- installId: string;
1421
- /** HMAC secret used to sign the JWT (the Peek internal secret). */
1422
- jwtSecret: string;
1423
- /** JWT issuer — the app name. */
1424
- issuer: string;
1425
- /** Peek app ID, used in the gateway endpoint path. */
1426
- appId: string;
1461
+ /**
1462
+ * Configuration for a {@link PeekAccessService} instance. Extends the shared
1463
+ * {@link BaseAccessServiceConfig} (install/auth/transport fields) with the
1464
+ * Peek-specific extras below.
1465
+ */
1466
+ interface PeekAccessServiceConfig extends BaseAccessServiceConfig {
1427
1467
  /** API gateway key, sent as the `pk-api-key` header. Required in v1 mode; not used in v2. */
1428
1468
  gatewayKey?: string;
1429
1469
  /**
@@ -1433,18 +1473,6 @@ interface PeekAccessServiceConfig {
1433
1473
  * GraphQL gateway.
1434
1474
  */
1435
1475
  mode?: "v2";
1436
- /** Override the gateway base URL. Default: Peek production gateway (v1) or app-registry sandbox (v2). */
1437
- baseUrl?: string;
1438
- /** JWT lifetime in seconds. Default: 3600. */
1439
- tokenTtlSeconds?: number;
1440
- /** Re-mint the cached token this many seconds before expiry. Default: 60. */
1441
- tokenRefreshLeewaySeconds?: number;
1442
- /** Backoff delays (ms) for HTTP 429 retries. Default: [1000, 2000, 4000]. */
1443
- retryDelaysMs?: number[];
1444
- /** Optional logger. Default: no-op (silent). */
1445
- logger?: Logger;
1446
- /** Custom `fetch` implementation. Default: the global `fetch`. */
1447
- fetch?: typeof fetch;
1448
1476
  /** Page size for cursor-paginated item options. Default: 50. */
1449
1477
  itemOptionsPageSize?: number;
1450
1478
  }
@@ -1640,6 +1668,135 @@ declare class PeekAccessService {
1640
1668
  getReviews(productId: string, reviewCount?: number, reviewOffset?: number): Promise<Review[]>;
1641
1669
  }
1642
1670
 
1671
+ interface RestClientOptions {
1672
+ /** Base URL of the backoffice gateway (no trailing slash). */
1673
+ baseUrl: string;
1674
+ /** App ID, used in the endpoint path. */
1675
+ appId: string;
1676
+ /** Fixed extendable slug inserted between `appId` and the REST path. */
1677
+ extendableSlug: string;
1678
+ /** Supplies a valid bearer token for each request. */
1679
+ getToken: () => string;
1680
+ /** Backoff delays (ms) applied on successive HTTP 429 responses. */
1681
+ retryDelaysMs: number[];
1682
+ /** Diagnostics sink. */
1683
+ logger: Logger;
1684
+ /** `fetch` implementation to use. */
1685
+ fetchFn: typeof fetch;
1686
+ }
1687
+ declare class RestClient {
1688
+ private readonly options;
1689
+ constructor(options: RestClientOptions);
1690
+ /**
1691
+ * Issues a GET against the named REST path and returns the parsed JSON body.
1692
+ * Retries on HTTP 429 per the configured backoff (via the shared
1693
+ * {@link requestWithRetry} loop).
1694
+ *
1695
+ * @throws {AdminAccountRequiredError} on HTTP 418
1696
+ * @throws {RateLimitError} on HTTP 429 after retries are exhausted
1697
+ * @throws {CngApiError} on any other non-2xx response
1698
+ */
1699
+ get<T>(path: string): Promise<T>;
1700
+ /** Reads the response body as JSON, falling back to raw text when unparseable. */
1701
+ private parseBody;
1702
+ private endpoint;
1703
+ private buildHeaders;
1704
+ }
1705
+
1706
+ /**
1707
+ * The clean, transport-agnostic data model for a CNG product.
1708
+ *
1709
+ * The CNG sibling of `../peek/product.ts`. Kept as a separate model because the
1710
+ * CNG gateway is a distinct backoffice, but the shape deliberately mirrors the
1711
+ * Peek `Product` so consumers can treat both brands uniformly. The raw CNG REST
1712
+ * response types and the conversion logic live inside the package and are never
1713
+ * exposed here.
1714
+ */
1715
+ /**
1716
+ * A bookable activity in a CNG account.
1717
+ *
1718
+ * `CngAccessService.getAllActivities()` returns these as a flat list.
1719
+ *
1720
+ * NOTE: field mapping is a best-guess placeholder until the real
1721
+ * `commerce-config/products` response shape is confirmed — see
1722
+ * `internal/cng/products/product-queries.ts`.
1723
+ */
1724
+ interface Activity {
1725
+ /** Stable unique identifier for the activity. */
1726
+ productId: string;
1727
+ /** Human-readable display name. */
1728
+ name: string;
1729
+ /** Product type reported by CNG (e.g. `"ACTIVITY"`). */
1730
+ type: string;
1731
+ /**
1732
+ * Display color as a hex string (e.g. `"#1A2B3C"`). Empty string when no
1733
+ * color is set.
1734
+ */
1735
+ color: string;
1736
+ /** The bookable sub-options (tickets) of this activity. */
1737
+ tickets: ActivityTicket[];
1738
+ }
1739
+ /** A single bookable sub-option (ticket) of an {@link Activity}. */
1740
+ interface ActivityTicket {
1741
+ /** Unique identifier of the ticket. */
1742
+ id: string;
1743
+ /** Human-readable name of the ticket. */
1744
+ name: string;
1745
+ }
1746
+
1747
+ declare class CngProductService {
1748
+ private readonly client;
1749
+ constructor(client: RestClient);
1750
+ /**
1751
+ * Returns every activity as a single flat list.
1752
+ *
1753
+ * @example
1754
+ * ```ts
1755
+ * const activities = await cng.getProductService().getAllActivities();
1756
+ * ```
1757
+ */
1758
+ getAllActivities(): Promise<Activity[]>;
1759
+ }
1760
+
1761
+ /**
1762
+ * Configuration for a {@link CngAccessService} instance. CNG adds no fields
1763
+ * beyond {@link BaseAccessServiceConfig} — it authenticates on the app JWT
1764
+ * alone (no `pk-api-key`, so no `gatewayKey`).
1765
+ */
1766
+ type CngAccessServiceConfig = BaseAccessServiceConfig;
1767
+ /**
1768
+ * Authenticated root entry point to the CNG backoffice REST gateway.
1769
+ *
1770
+ * @example
1771
+ * ```ts
1772
+ * import { CngAccessService, type Activity } from "@peektravel/app-utilities";
1773
+ *
1774
+ * const cng = new CngAccessService({
1775
+ * installId: "install-123",
1776
+ * jwtSecret: process.env.PEEK_APP_SECRET!,
1777
+ * issuer: process.env.PEEK_APP_ID!,
1778
+ * appId: process.env.PEEK_APP_ID!,
1779
+ * });
1780
+ *
1781
+ * const activities: Activity[] = await cng.getAllActivities();
1782
+ * ```
1783
+ *
1784
+ * @throws {Error} from the constructor when any required config field
1785
+ * (`installId`, `jwtSecret`, `issuer`, `appId`) is empty.
1786
+ */
1787
+ declare class CngAccessService {
1788
+ private readonly client;
1789
+ private productService?;
1790
+ constructor(config: CngAccessServiceConfig);
1791
+ /**
1792
+ * Returns the {@link CngProductService} for this install, bound to the shared
1793
+ * authenticated transport. The instance is created lazily and reused.
1794
+ */
1795
+ getProductService(): CngProductService;
1796
+ /** All activities. Delegates to {@link CngProductService.getAllActivities}. */
1797
+ getAllActivities(): Promise<Activity[]>;
1798
+ }
1799
+
1643
1800
  /**
1644
1801
  * Public webhook surface for bookings.
1645
1802
  *
@@ -1722,8 +1879,11 @@ declare function parseWaiverWebhook(payload: unknown): Waiver;
1722
1879
 
1723
1880
  /**
1724
1881
  * Typed errors thrown by the package. Each mirrors a failure mode of the Peek
1725
- * GraphQL gateway so callers can branch on the error type rather than parsing
1726
- * messages.
1882
+ * GraphQL gateway (or the CNG REST gateway) so callers can branch on the error
1883
+ * type rather than parsing messages.
1884
+ *
1885
+ * `AdminAccountRequiredError` and `RateLimitError` are shared by both gateways.
1886
+ * `PeekGraphQLError` is Peek-only; `CngApiError` is CNG-only.
1727
1887
  */
1728
1888
  /**
1729
1889
  * Thrown when the gateway responds with HTTP 418, indicating the install is not
@@ -1752,5 +1912,18 @@ declare class PeekGraphQLError extends Error {
1752
1912
  readonly graphqlErrors: unknown[];
1753
1913
  constructor(graphqlErrors: unknown[], message?: string);
1754
1914
  }
1915
+ /**
1916
+ * Thrown when the CNG REST gateway returns a non-2xx response that is not one
1917
+ * of the specifically-handled statuses (418/429). The offending status is
1918
+ * preserved on {@link CngApiError.statusCode}, and the raw response body (parsed
1919
+ * JSON when possible, otherwise the raw text) on {@link CngApiError.body}.
1920
+ */
1921
+ declare class CngApiError extends Error {
1922
+ /** The HTTP status that triggered this error. */
1923
+ readonly statusCode: number;
1924
+ /** The raw response body (parsed JSON when possible, otherwise text). */
1925
+ readonly body: unknown;
1926
+ constructor(statusCode: number, body: unknown, message?: string);
1927
+ }
1755
1928
 
1756
- export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, type AccountUser, AccountUserService, type AccountUserServiceOptions, 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 CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreatePromoCodeInput, type CreatedBooking, type CreatedPromoCode, type CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, 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, type Price, type Product, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RENTAL_PRODUCT_TYPE, RateLimitError, type RefundInput, type RefundResult, ResellerService, type Resource, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateTimeslotResult, type Waiver, noopLogger, parseBookingWebhook, parseWaiverWebhook };
1929
+ export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, type AccountUser, AccountUserService, type AccountUserServiceOptions, type Activity, 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, CngAccessService, type CngAccessServiceConfig, CngApiError, CngProductService, type CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreatePromoCodeInput, type CreatedBooking, type CreatedPromoCode, type CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, 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, type PeekPlatform, type Price, type Product, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RENTAL_PRODUCT_TYPE, RateLimitError, type RefundInput, type RefundResult, ResellerService, type Resource, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateTimeslotResult, type Waiver, noopLogger, parseBookingWebhook, parseWaiverWebhook };