@peektravel/app-utilities 0.3.0 → 0.4.0

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
@@ -1880,6 +1880,18 @@ var CngApiError = class extends Error {
1880
1880
  this.body = body;
1881
1881
  }
1882
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
+ };
1883
1895
 
1884
1896
  // src/internal/http-transport.ts
1885
1897
  var RATE_LIMIT_STATUS = 429;
@@ -3085,7 +3097,8 @@ var PeekAccessService = class {
3085
3097
  id: u.id,
3086
3098
  isAdmin: u.is_admin,
3087
3099
  locale: u.locale,
3088
- name: u.name
3100
+ name: u.name,
3101
+ platform: u.platform
3089
3102
  }
3090
3103
  };
3091
3104
  }
@@ -3505,6 +3518,146 @@ var CngAccessService = class {
3505
3518
  }
3506
3519
  };
3507
3520
 
3521
+ // src/internal/acme/endpoints.ts
3522
+ var ACME_EXTENDABLE_SLUG = "acme_backoffice_api@v1";
3523
+ var TEMPLATES_PATH = "v2/b2b/event/templates/names?pageSize=-1&page=1";
3524
+
3525
+ // src/models/acme/product.ts
3526
+ var ACME_ACTIVITY_TYPE = "standard";
3527
+
3528
+ // src/internal/acme/products/product-queries.ts
3529
+ var PUBLISHED_REVIEW_STATE = "published";
3530
+
3531
+ // src/internal/acme/products/product-converter.ts
3532
+ function fromTemplateNodes(nodes) {
3533
+ return nodes.filter((node) => node.reviewState === PUBLISHED_REVIEW_STATE).map(fromTemplateNode);
3534
+ }
3535
+ function fromTemplateNode(node) {
3536
+ return {
3537
+ productId: node.id || "",
3538
+ name: node.name || "",
3539
+ type: node.type || ACME_ACTIVITY_TYPE,
3540
+ color: node.colorCategory?.backgroundColor || "#d1d1d1",
3541
+ tickets: []
3542
+ };
3543
+ }
3544
+
3545
+ // src/internal/acme/products/product-service.ts
3546
+ var AcmeProductService = class {
3547
+ constructor(client) {
3548
+ this.client = client;
3549
+ }
3550
+ client;
3551
+ /**
3552
+ * Returns every published event template as a single flat list of activities.
3553
+ *
3554
+ * @example
3555
+ * ```ts
3556
+ * const activities = await acme.getProductService().getAllActivities();
3557
+ * ```
3558
+ */
3559
+ async getAllActivities() {
3560
+ const body = await this.client.get(
3561
+ TEMPLATES_PATH
3562
+ );
3563
+ const nodes = Array.isArray(body) ? body : body?.list ?? [];
3564
+ return fromTemplateNodes(nodes ?? []);
3565
+ }
3566
+ };
3567
+
3568
+ // src/internal/acme/rest-client.ts
3569
+ var RestClient2 = class {
3570
+ constructor(options) {
3571
+ this.options = options;
3572
+ }
3573
+ options;
3574
+ /**
3575
+ * Issues a GET against the named REST path and returns the parsed JSON body.
3576
+ * Retries on HTTP 429 per the configured backoff (via the shared
3577
+ * {@link requestWithRetry} loop).
3578
+ *
3579
+ * @throws {AdminAccountRequiredError} on HTTP 418
3580
+ * @throws {RateLimitError} on HTTP 429 after retries are exhausted
3581
+ * @throws {AcmeApiError} on any other non-2xx response
3582
+ */
3583
+ async get(path) {
3584
+ const { logger } = this.options;
3585
+ const url = this.endpoint(path);
3586
+ logger.info("Making ACME request", { url, path });
3587
+ return requestWithRetry(
3588
+ this.options,
3589
+ url,
3590
+ { method: "GET", headers: this.buildHeaders() },
3591
+ path,
3592
+ async (response) => {
3593
+ const body = await this.parseBody(response);
3594
+ if (!response.ok) {
3595
+ logger.error(`ACME request failed with HTTP ${response.status}`, { url });
3596
+ throw new AcmeApiError(response.status, body);
3597
+ }
3598
+ return body;
3599
+ }
3600
+ );
3601
+ }
3602
+ /** Reads the response body as JSON, falling back to raw text when unparseable. */
3603
+ async parseBody(response) {
3604
+ const text = await response.text();
3605
+ try {
3606
+ return JSON.parse(text);
3607
+ } catch {
3608
+ return text;
3609
+ }
3610
+ }
3611
+ endpoint(path) {
3612
+ const { baseUrl, appId, extendableSlug } = this.options;
3613
+ return `${baseUrl}/${appId}/${extendableSlug}/${path}`;
3614
+ }
3615
+ buildHeaders() {
3616
+ return {
3617
+ "X-Peek-Auth": `Bearer ${this.options.getToken()}`,
3618
+ "Content-Type": "application/json"
3619
+ };
3620
+ }
3621
+ };
3622
+
3623
+ // src/acme-access-service.ts
3624
+ var DEFAULT_BASE_URL3 = "https://app-registry.peeklabs.com/installations-api";
3625
+ var AcmeAccessService = class {
3626
+ client;
3627
+ productService;
3628
+ constructor(config) {
3629
+ requireNonEmpty(config.installId, "installId", "AcmeAccessService");
3630
+ requireNonEmpty(config.jwtSecret, "jwtSecret", "AcmeAccessService");
3631
+ requireNonEmpty(config.issuer, "issuer", "AcmeAccessService");
3632
+ requireNonEmpty(config.appId, "appId", "AcmeAccessService");
3633
+ const logger = config.logger ?? noopLogger;
3634
+ const tokens = createTokenManager(config);
3635
+ this.client = new RestClient2({
3636
+ baseUrl: config.baseUrl ?? DEFAULT_BASE_URL3,
3637
+ appId: config.appId,
3638
+ extendableSlug: ACME_EXTENDABLE_SLUG,
3639
+ getToken: () => tokens.getToken(),
3640
+ retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,
3641
+ logger,
3642
+ fetchFn: config.fetch ?? globalThis.fetch
3643
+ });
3644
+ }
3645
+ /**
3646
+ * Returns the {@link AcmeProductService} for this install, bound to the shared
3647
+ * authenticated transport. The instance is created lazily and reused.
3648
+ */
3649
+ getProductService() {
3650
+ if (!this.productService) {
3651
+ this.productService = new AcmeProductService(this.client);
3652
+ }
3653
+ return this.productService;
3654
+ }
3655
+ /** All activities. Delegates to {@link AcmeProductService.getAllActivities}. */
3656
+ getAllActivities() {
3657
+ return this.getProductService().getAllActivities();
3658
+ }
3659
+ };
3660
+
3508
3661
  // src/internal/peek/bookings/booking-webhook.ts
3509
3662
  var PAYLOAD_BOOKING_KEY = "booking";
3510
3663
  var VALUE_OPEN_TOKEN = "value {";
@@ -3593,6 +3746,9 @@ function extractWaiverNode(payload) {
3593
3746
  exports.ACTIVITY_PRODUCT_TYPE = ACTIVITY_PRODUCT_TYPE;
3594
3747
  exports.ADD_ON_PRODUCT_TYPE = ADD_ON_PRODUCT_TYPE;
3595
3748
  exports.AccountUserService = AccountUserService;
3749
+ exports.AcmeAccessService = AcmeAccessService;
3750
+ exports.AcmeApiError = AcmeApiError;
3751
+ exports.AcmeProductService = AcmeProductService;
3596
3752
  exports.AdminAccountRequiredError = AdminAccountRequiredError;
3597
3753
  exports.AvailabilityService = AvailabilityService;
3598
3754
  exports.BookingService = BookingService;