@peektravel/app-utilities 0.6.1 → 0.7.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
@@ -1926,9 +1926,10 @@ declare class PeekAccessService {
1926
1926
  * decoded claims.
1927
1927
  *
1928
1928
  * Validates the HMAC signature (using this service's `jwtSecret`), the token
1929
- * expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience. Throws
1930
- * from the `jsonwebtoken` library on any failure — callers should catch to
1931
- * distinguish error kinds:
1929
+ * expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience. Pass the
1930
+ * raw `x-peek-auth` request header value — a leading `Bearer ` prefix, if
1931
+ * present, is stripped for you. Throws from the `jsonwebtoken` library on any
1932
+ * failure — callers should catch to distinguish error kinds:
1932
1933
  *
1933
1934
  * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or token
1934
1935
  * malformed
@@ -2426,41 +2427,21 @@ interface Waiver {
2426
2427
  declare function parseWaiverWebhook(payload: unknown, options?: AccessOptions): Waiver;
2427
2428
 
2428
2429
  /**
2429
- * Verifies an install-status webhook token and returns its clean claims.
2430
+ * The clean data model for an app-store **install lifecycle event** — the single
2431
+ * flat object `parseInstallWebhook` returns for the webhook Peek's app registry
2432
+ * POSTs when an app is installed, uninstalled, or updated.
2430
2433
  *
2431
- * Validates the HMAC signature (with `secret`), the token expiry, the
2432
- * `"app_registry_v2"` issuer, and the `"Joken"` audience — the same checks as
2433
- * {@link PeekAccessService.verifyPeekAuthToken} — then maps the payload to
2434
- * {@link InstallWebhookClaims}, tolerating a `null` `user` (system events).
2435
- * Throws from the `jsonwebtoken` library on any verification failure, so callers
2436
- * can branch on the error kind:
2437
- *
2438
- * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed
2439
- * - `TokenExpiredError` — past `exp`
2440
- * - `NotBeforeError` — before `nbf`
2441
- *
2442
- * @param token the raw JWT delivered by the install webhook (no `Bearer` prefix)
2443
- * @param secret the app's HMAC signing secret (the `jwtSecret` you construct
2444
- * `PeekAccessService` with)
2445
- * @throws {JsonWebTokenError} signature invalid or token malformed
2446
- * @throws {TokenExpiredError} token has expired
2447
- * @throws {NotBeforeError} token not yet valid
2448
- */
2449
- declare function verifyInstallWebhook(token: string, secret: string): InstallWebhookClaims;
2450
-
2451
- /**
2452
- * The clean data model for an app-store **install lifecycle event** — the JSON
2453
- * webhook body Peek's app registry POSTs when an app is installed, uninstalled,
2454
- * or updated.
2455
- *
2456
- * This is the sibling of the signed-JWT channel behind `verifyInstallWebhook`
2457
- * (see `models/peek/auth-token.ts`). The two carry the same event; this one is
2458
- * the richer of the pair, because only it reports the account **name**,
2459
- * **platform**, and **test** flag.
2434
+ * That delivery carries two things at once: a **signed `app_registry_v2` JWT**
2435
+ * (the security boundary) and a plain **JSON body** (the enrichment channel).
2436
+ * `parseInstallWebhook` verifies the JWT and merges both into this shape, so a
2437
+ * consumer sees one clean, flat, JSON-safe record instead of two differently
2438
+ * shaped payloads. The verified JWT is authoritative for the fields it carries
2439
+ * (`installId`, `accountId`, `status`, `displayVersion`, `user`); the JSON body
2440
+ * is the only source of `accountName`, `platform`, and `isTest`.
2460
2441
  *
2461
2442
  * It is also the single origin of the account id in the whole system: no
2462
- * GraphQL read and no peek-auth token returns it, so whatever a consumer
2463
- * persists from this event is all it will ever have.
2443
+ * GraphQL read returns it, so whatever a consumer persists from this event is
2444
+ * all it will ever have.
2464
2445
  */
2465
2446
 
2466
2447
  /**
@@ -2471,21 +2452,27 @@ declare const INSTALL_STATUSES: readonly ["installed", "uninstalled", "update_in
2471
2452
  /** Install lifecycle status. */
2472
2453
  type InstallStatus = (typeof INSTALL_STATUSES)[number];
2473
2454
  /**
2474
- * Who an install is — the core account data, in one object.
2455
+ * A verified install lifecycle event — what happened, to which install, and who
2456
+ * (if anyone) triggered it — as one flat, JSON-safe record.
2457
+ *
2458
+ * This is the shape `parseInstallWebhook` returns. It is flat by design: it
2459
+ * round-trips through a datastore unchanged, so the same shape the parser
2460
+ * returns is the shape a consumer persists and later rehydrates. There is
2461
+ * deliberately no nested identity object and no second representation.
2475
2462
  *
2476
- * Flat and JSON-safe by design: it round-trips through a datastore unchanged,
2477
- * so the same shape the parser returns is the shape a consumer persists and
2478
- * later rehydrates. There is deliberately no second representation.
2463
+ * Fields sourced from the **verified JWT** (`installId`, `accountId`, `status`,
2464
+ * `rawStatus`, `displayVersion`, `user`) are trustworthy; the enrichment fields
2465
+ * (`accountName`, `platform`, `isTest`) come from the unauthenticated JSON body.
2479
2466
  */
2480
- interface InstallIdentity {
2481
- /** Install ID — Peek-assigned UUID. Also the subject of every peek-auth JWT. */
2467
+ interface InstallWebhook {
2468
+ /** Install ID — Peek-assigned UUID. Also the JWT subject (`sub`). */
2482
2469
  installId: string;
2483
2470
  /**
2484
2471
  * Stable Peek account id — the same value Peek calls the **partner ID**.
2485
2472
  * This event is its only source; it cannot be re-fetched later.
2486
2473
  */
2487
2474
  accountId: string;
2488
- /** Partner display name. */
2475
+ /** Partner display name. `""` when the JSON body omits it. */
2489
2476
  accountName: string;
2490
2477
  /**
2491
2478
  * Which Peek platform owns the install, or `null` when the registry reported
@@ -2503,9 +2490,6 @@ interface InstallIdentity {
2503
2490
  platform: PeekPlatform | null;
2504
2491
  /** Whether this is a test account. Defaults to `false` when not reported. */
2505
2492
  isTest: boolean;
2506
- }
2507
- /** A parsed install lifecycle event: what happened, to which install. */
2508
- interface InstallEvent {
2509
2493
  /**
2510
2494
  * The lifecycle status, or `null` when the registry sent a status this
2511
2495
  * version of the package does not know. Handle `null` explicitly — treating
@@ -2516,59 +2500,91 @@ interface InstallEvent {
2516
2500
  rawStatus: string;
2517
2501
  /** App display version at the time of the event. */
2518
2502
  displayVersion: string;
2519
- /** The install's core account data. */
2520
- identity: InstallIdentity;
2503
+ /**
2504
+ * The user that triggered the event, or `null` for system-initiated events
2505
+ * (install lifecycle changes are often system-initiated). From the JWT.
2506
+ */
2507
+ user: PeekAuthTokenUser | null;
2521
2508
  }
2522
2509
 
2523
2510
  /**
2524
- * Public webhook surface for the **install-event** channel — the JSON body
2525
- * Peek's app registry POSTs on install, uninstall, and update.
2511
+ * Verifies an install-status webhook token and merges it with the delivered
2512
+ * JSON body into one flat {@link InstallWebhook}.
2526
2513
  *
2527
- * This is the second of the two install channels. Its sibling,
2528
- * `verifyInstallWebhook`, receives the same lifecycle event as a signed
2529
- * `app_registry_v2` JWT; that payload authenticates itself but carries only the
2530
- * account **id**. This one carries the account's name, platform, and test flag
2531
- * as well, which makes it the authoritative source of {@link InstallIdentity}.
2514
+ * The **verified token** is the authoritative source of `installId`,
2515
+ * `accountId`, `status`, `displayVersion`, and `user`. The **JSON body** — which
2516
+ * is not signed and so is trusted only for fields the token cannot carry —
2517
+ * supplies `accountName`, `platform`, and `isTest`. A missing or malformed body
2518
+ * degrades those three to `""`/`null`/`false`; it never overrides an
2519
+ * authenticated field and never throws.
2532
2520
  *
2533
- * Like the booking and waiver parsers, this is a pure transform — no auth, no
2534
- * network, no client — so it is a standalone function rather than a method on
2535
- * `PeekAccessService`. The receiver holds no gateway credentials for an install
2536
- * it has not recorded yet, and an uninstall describes one being torn down.
2537
- *
2538
- * **It never throws.** The sender is first-party and the payload contract is
2539
- * Peek's own, so defending against malformed input would be defending against a
2540
- * case that does not arise. What the parser does guard is the contract
2541
- * *growing*: an unrecognised `status` or `platform` surfaces as `null` rather
2542
- * than being coerced into a known value, so a newer registry can never be
2543
- * silently mistaken for an older one.
2544
- */
2545
-
2546
- /**
2547
- * Parses a delivered install-event webhook body into a clean
2548
- * {@link InstallEvent}.
2521
+ * Signature verification is strict: the HMAC signature (with `secret`), the
2522
+ * token expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience are
2523
+ * all checked — the same checks as {@link PeekAccessService.verifyPeekAuthToken}.
2524
+ * Any failure throws from the `jsonwebtoken` library, so callers can branch on
2525
+ * the error kind:
2549
2526
  *
2550
- * Accepts the raw request body, or a JSON string, which is parsed first.
2551
- * Missing fields map to `""`/`false`; an unknown `status` or `platform` maps to
2552
- * `null` with the wire value preserved on {@link InstallEvent.rawStatus}.
2527
+ * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed
2528
+ * - `TokenExpiredError` — past `exp`
2529
+ * - `NotBeforeError` — before `nbf`
2553
2530
  *
2554
- * Handle a `null` `status` explicitly. Peek treats any 2xx as delivered and
2555
- * will not redeliver, so responding successfully to a status the package does
2556
- * not recognise silently drops a lifecycle transition:
2531
+ * An unrecognised `status` or `platform` maps to `null` (with the wire status
2532
+ * preserved on {@link InstallWebhook.rawStatus}) rather than being coerced —
2533
+ * Peek treats any 2xx as delivered and does not redeliver, so handle a `null`
2534
+ * `status` explicitly:
2557
2535
  *
2558
2536
  * ```ts
2559
- * const event = parseInstallEvent(req.body);
2537
+ * const event = parseInstallWebhook(token, req.body, secret);
2560
2538
  * switch (event.status) {
2561
- * case "installed": return provision(event.identity, event.displayVersion);
2562
- * case "uninstalled": return deprovision(event.identity);
2563
- * case "update_installed": return recordVersion(event.identity, event.displayVersion);
2539
+ * case "installed": return provision(event);
2540
+ * case "uninstalled": return deprovision(event);
2541
+ * case "update_installed": return recordVersion(event);
2564
2542
  * default: throw new Error(`unknown install status: ${event.rawStatus}`);
2565
2543
  * }
2566
2544
  * ```
2567
2545
  *
2568
- * Persist `event.identity` as a unit: it is flat and JSON-safe, and its
2569
- * `accountId` (the partner ID) has no other source in the system.
2546
+ * @param token the JWT delivered by the install webhook. Pass the raw
2547
+ * `x-peek-auth` header value directly — a leading `Bearer ` prefix, if
2548
+ * present, is stripped for you.
2549
+ * @param body the delivered JSON body (raw object or a JSON string)
2550
+ * @param secret the app's HMAC signing secret (the `jwtSecret` you construct
2551
+ * `PeekAccessService` with)
2552
+ * @throws {JsonWebTokenError} signature invalid or token malformed
2553
+ * @throws {TokenExpiredError} token has expired
2554
+ * @throws {NotBeforeError} token not yet valid
2570
2555
  */
2571
- declare function parseInstallEvent(payload: unknown): InstallEvent;
2556
+ declare function parseInstallWebhook(token: string, body: unknown, secret: string): InstallWebhook;
2557
+ /**
2558
+ * Verifies an install-status webhook token and returns its clean claims.
2559
+ *
2560
+ * @deprecated Use {@link parseInstallWebhook} instead. This verifier reads only
2561
+ * the signed token, so it cannot report the account **name**, **platform**, or
2562
+ * **test** flag that the webhook's JSON body also carries — the caller was left
2563
+ * to parse that body separately and stitch the two shapes together.
2564
+ * `parseInstallWebhook(token, body, secret)` verifies the same token and returns
2565
+ * one flat {@link InstallWebhook} with every field. This function remains only
2566
+ * for backwards compatibility.
2567
+ *
2568
+ * Validates the HMAC signature (with `secret`), the token expiry, the
2569
+ * `"app_registry_v2"` issuer, and the `"Joken"` audience — the same checks as
2570
+ * {@link PeekAccessService.verifyPeekAuthToken} — then maps the payload to
2571
+ * {@link InstallWebhookClaims}, tolerating a `null` `user` (system events).
2572
+ * Throws from the `jsonwebtoken` library on any verification failure:
2573
+ *
2574
+ * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed
2575
+ * - `TokenExpiredError` — past `exp`
2576
+ * - `NotBeforeError` — before `nbf`
2577
+ *
2578
+ * @param token the JWT delivered by the install webhook. Pass the raw
2579
+ * `x-peek-auth` header value directly — a leading `Bearer ` prefix, if
2580
+ * present, is stripped for you.
2581
+ * @param secret the app's HMAC signing secret (the `jwtSecret` you construct
2582
+ * `PeekAccessService` with)
2583
+ * @throws {JsonWebTokenError} signature invalid or token malformed
2584
+ * @throws {TokenExpiredError} token has expired
2585
+ * @throws {NotBeforeError} token not yet valid
2586
+ */
2587
+ declare function verifyInstallWebhook(token: string, secret: string): InstallWebhookClaims;
2572
2588
 
2573
2589
  /**
2574
2590
  * Typed errors thrown by the package. Each mirrors a failure mode of the Peek
@@ -2681,4 +2697,4 @@ declare class AcmeApiError extends Error {
2681
2697
  constructor(statusCode: number, body: unknown, message?: string);
2682
2698
  }
2683
2699
 
2684
- 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 CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, INSTALL_STATUSES, type InstallEvent, type InstallIdentity, type InstallStatus, type InstallWebhookAccount, type InstallWebhookClaims, InvalidPeekTokenError, 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, noopLogger, parseBookingWebhook, parseInstallEvent, parseWaiverWebhook, verifyInstallWebhook };
2700
+ 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 CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, INSTALL_STATUSES, type InstallStatus, type InstallWebhook, type InstallWebhookAccount, type InstallWebhookClaims, InvalidPeekTokenError, 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, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
package/dist/index.d.ts CHANGED
@@ -1926,9 +1926,10 @@ declare class PeekAccessService {
1926
1926
  * decoded claims.
1927
1927
  *
1928
1928
  * Validates the HMAC signature (using this service's `jwtSecret`), the token
1929
- * expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience. Throws
1930
- * from the `jsonwebtoken` library on any failure — callers should catch to
1931
- * distinguish error kinds:
1929
+ * expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience. Pass the
1930
+ * raw `x-peek-auth` request header value — a leading `Bearer ` prefix, if
1931
+ * present, is stripped for you. Throws from the `jsonwebtoken` library on any
1932
+ * failure — callers should catch to distinguish error kinds:
1932
1933
  *
1933
1934
  * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or token
1934
1935
  * malformed
@@ -2426,41 +2427,21 @@ interface Waiver {
2426
2427
  declare function parseWaiverWebhook(payload: unknown, options?: AccessOptions): Waiver;
2427
2428
 
2428
2429
  /**
2429
- * Verifies an install-status webhook token and returns its clean claims.
2430
+ * The clean data model for an app-store **install lifecycle event** — the single
2431
+ * flat object `parseInstallWebhook` returns for the webhook Peek's app registry
2432
+ * POSTs when an app is installed, uninstalled, or updated.
2430
2433
  *
2431
- * Validates the HMAC signature (with `secret`), the token expiry, the
2432
- * `"app_registry_v2"` issuer, and the `"Joken"` audience — the same checks as
2433
- * {@link PeekAccessService.verifyPeekAuthToken} — then maps the payload to
2434
- * {@link InstallWebhookClaims}, tolerating a `null` `user` (system events).
2435
- * Throws from the `jsonwebtoken` library on any verification failure, so callers
2436
- * can branch on the error kind:
2437
- *
2438
- * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed
2439
- * - `TokenExpiredError` — past `exp`
2440
- * - `NotBeforeError` — before `nbf`
2441
- *
2442
- * @param token the raw JWT delivered by the install webhook (no `Bearer` prefix)
2443
- * @param secret the app's HMAC signing secret (the `jwtSecret` you construct
2444
- * `PeekAccessService` with)
2445
- * @throws {JsonWebTokenError} signature invalid or token malformed
2446
- * @throws {TokenExpiredError} token has expired
2447
- * @throws {NotBeforeError} token not yet valid
2448
- */
2449
- declare function verifyInstallWebhook(token: string, secret: string): InstallWebhookClaims;
2450
-
2451
- /**
2452
- * The clean data model for an app-store **install lifecycle event** — the JSON
2453
- * webhook body Peek's app registry POSTs when an app is installed, uninstalled,
2454
- * or updated.
2455
- *
2456
- * This is the sibling of the signed-JWT channel behind `verifyInstallWebhook`
2457
- * (see `models/peek/auth-token.ts`). The two carry the same event; this one is
2458
- * the richer of the pair, because only it reports the account **name**,
2459
- * **platform**, and **test** flag.
2434
+ * That delivery carries two things at once: a **signed `app_registry_v2` JWT**
2435
+ * (the security boundary) and a plain **JSON body** (the enrichment channel).
2436
+ * `parseInstallWebhook` verifies the JWT and merges both into this shape, so a
2437
+ * consumer sees one clean, flat, JSON-safe record instead of two differently
2438
+ * shaped payloads. The verified JWT is authoritative for the fields it carries
2439
+ * (`installId`, `accountId`, `status`, `displayVersion`, `user`); the JSON body
2440
+ * is the only source of `accountName`, `platform`, and `isTest`.
2460
2441
  *
2461
2442
  * It is also the single origin of the account id in the whole system: no
2462
- * GraphQL read and no peek-auth token returns it, so whatever a consumer
2463
- * persists from this event is all it will ever have.
2443
+ * GraphQL read returns it, so whatever a consumer persists from this event is
2444
+ * all it will ever have.
2464
2445
  */
2465
2446
 
2466
2447
  /**
@@ -2471,21 +2452,27 @@ declare const INSTALL_STATUSES: readonly ["installed", "uninstalled", "update_in
2471
2452
  /** Install lifecycle status. */
2472
2453
  type InstallStatus = (typeof INSTALL_STATUSES)[number];
2473
2454
  /**
2474
- * Who an install is — the core account data, in one object.
2455
+ * A verified install lifecycle event — what happened, to which install, and who
2456
+ * (if anyone) triggered it — as one flat, JSON-safe record.
2457
+ *
2458
+ * This is the shape `parseInstallWebhook` returns. It is flat by design: it
2459
+ * round-trips through a datastore unchanged, so the same shape the parser
2460
+ * returns is the shape a consumer persists and later rehydrates. There is
2461
+ * deliberately no nested identity object and no second representation.
2475
2462
  *
2476
- * Flat and JSON-safe by design: it round-trips through a datastore unchanged,
2477
- * so the same shape the parser returns is the shape a consumer persists and
2478
- * later rehydrates. There is deliberately no second representation.
2463
+ * Fields sourced from the **verified JWT** (`installId`, `accountId`, `status`,
2464
+ * `rawStatus`, `displayVersion`, `user`) are trustworthy; the enrichment fields
2465
+ * (`accountName`, `platform`, `isTest`) come from the unauthenticated JSON body.
2479
2466
  */
2480
- interface InstallIdentity {
2481
- /** Install ID — Peek-assigned UUID. Also the subject of every peek-auth JWT. */
2467
+ interface InstallWebhook {
2468
+ /** Install ID — Peek-assigned UUID. Also the JWT subject (`sub`). */
2482
2469
  installId: string;
2483
2470
  /**
2484
2471
  * Stable Peek account id — the same value Peek calls the **partner ID**.
2485
2472
  * This event is its only source; it cannot be re-fetched later.
2486
2473
  */
2487
2474
  accountId: string;
2488
- /** Partner display name. */
2475
+ /** Partner display name. `""` when the JSON body omits it. */
2489
2476
  accountName: string;
2490
2477
  /**
2491
2478
  * Which Peek platform owns the install, or `null` when the registry reported
@@ -2503,9 +2490,6 @@ interface InstallIdentity {
2503
2490
  platform: PeekPlatform | null;
2504
2491
  /** Whether this is a test account. Defaults to `false` when not reported. */
2505
2492
  isTest: boolean;
2506
- }
2507
- /** A parsed install lifecycle event: what happened, to which install. */
2508
- interface InstallEvent {
2509
2493
  /**
2510
2494
  * The lifecycle status, or `null` when the registry sent a status this
2511
2495
  * version of the package does not know. Handle `null` explicitly — treating
@@ -2516,59 +2500,91 @@ interface InstallEvent {
2516
2500
  rawStatus: string;
2517
2501
  /** App display version at the time of the event. */
2518
2502
  displayVersion: string;
2519
- /** The install's core account data. */
2520
- identity: InstallIdentity;
2503
+ /**
2504
+ * The user that triggered the event, or `null` for system-initiated events
2505
+ * (install lifecycle changes are often system-initiated). From the JWT.
2506
+ */
2507
+ user: PeekAuthTokenUser | null;
2521
2508
  }
2522
2509
 
2523
2510
  /**
2524
- * Public webhook surface for the **install-event** channel — the JSON body
2525
- * Peek's app registry POSTs on install, uninstall, and update.
2511
+ * Verifies an install-status webhook token and merges it with the delivered
2512
+ * JSON body into one flat {@link InstallWebhook}.
2526
2513
  *
2527
- * This is the second of the two install channels. Its sibling,
2528
- * `verifyInstallWebhook`, receives the same lifecycle event as a signed
2529
- * `app_registry_v2` JWT; that payload authenticates itself but carries only the
2530
- * account **id**. This one carries the account's name, platform, and test flag
2531
- * as well, which makes it the authoritative source of {@link InstallIdentity}.
2514
+ * The **verified token** is the authoritative source of `installId`,
2515
+ * `accountId`, `status`, `displayVersion`, and `user`. The **JSON body** — which
2516
+ * is not signed and so is trusted only for fields the token cannot carry —
2517
+ * supplies `accountName`, `platform`, and `isTest`. A missing or malformed body
2518
+ * degrades those three to `""`/`null`/`false`; it never overrides an
2519
+ * authenticated field and never throws.
2532
2520
  *
2533
- * Like the booking and waiver parsers, this is a pure transform — no auth, no
2534
- * network, no client — so it is a standalone function rather than a method on
2535
- * `PeekAccessService`. The receiver holds no gateway credentials for an install
2536
- * it has not recorded yet, and an uninstall describes one being torn down.
2537
- *
2538
- * **It never throws.** The sender is first-party and the payload contract is
2539
- * Peek's own, so defending against malformed input would be defending against a
2540
- * case that does not arise. What the parser does guard is the contract
2541
- * *growing*: an unrecognised `status` or `platform` surfaces as `null` rather
2542
- * than being coerced into a known value, so a newer registry can never be
2543
- * silently mistaken for an older one.
2544
- */
2545
-
2546
- /**
2547
- * Parses a delivered install-event webhook body into a clean
2548
- * {@link InstallEvent}.
2521
+ * Signature verification is strict: the HMAC signature (with `secret`), the
2522
+ * token expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience are
2523
+ * all checked — the same checks as {@link PeekAccessService.verifyPeekAuthToken}.
2524
+ * Any failure throws from the `jsonwebtoken` library, so callers can branch on
2525
+ * the error kind:
2549
2526
  *
2550
- * Accepts the raw request body, or a JSON string, which is parsed first.
2551
- * Missing fields map to `""`/`false`; an unknown `status` or `platform` maps to
2552
- * `null` with the wire value preserved on {@link InstallEvent.rawStatus}.
2527
+ * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed
2528
+ * - `TokenExpiredError` — past `exp`
2529
+ * - `NotBeforeError` — before `nbf`
2553
2530
  *
2554
- * Handle a `null` `status` explicitly. Peek treats any 2xx as delivered and
2555
- * will not redeliver, so responding successfully to a status the package does
2556
- * not recognise silently drops a lifecycle transition:
2531
+ * An unrecognised `status` or `platform` maps to `null` (with the wire status
2532
+ * preserved on {@link InstallWebhook.rawStatus}) rather than being coerced —
2533
+ * Peek treats any 2xx as delivered and does not redeliver, so handle a `null`
2534
+ * `status` explicitly:
2557
2535
  *
2558
2536
  * ```ts
2559
- * const event = parseInstallEvent(req.body);
2537
+ * const event = parseInstallWebhook(token, req.body, secret);
2560
2538
  * switch (event.status) {
2561
- * case "installed": return provision(event.identity, event.displayVersion);
2562
- * case "uninstalled": return deprovision(event.identity);
2563
- * case "update_installed": return recordVersion(event.identity, event.displayVersion);
2539
+ * case "installed": return provision(event);
2540
+ * case "uninstalled": return deprovision(event);
2541
+ * case "update_installed": return recordVersion(event);
2564
2542
  * default: throw new Error(`unknown install status: ${event.rawStatus}`);
2565
2543
  * }
2566
2544
  * ```
2567
2545
  *
2568
- * Persist `event.identity` as a unit: it is flat and JSON-safe, and its
2569
- * `accountId` (the partner ID) has no other source in the system.
2546
+ * @param token the JWT delivered by the install webhook. Pass the raw
2547
+ * `x-peek-auth` header value directly — a leading `Bearer ` prefix, if
2548
+ * present, is stripped for you.
2549
+ * @param body the delivered JSON body (raw object or a JSON string)
2550
+ * @param secret the app's HMAC signing secret (the `jwtSecret` you construct
2551
+ * `PeekAccessService` with)
2552
+ * @throws {JsonWebTokenError} signature invalid or token malformed
2553
+ * @throws {TokenExpiredError} token has expired
2554
+ * @throws {NotBeforeError} token not yet valid
2570
2555
  */
2571
- declare function parseInstallEvent(payload: unknown): InstallEvent;
2556
+ declare function parseInstallWebhook(token: string, body: unknown, secret: string): InstallWebhook;
2557
+ /**
2558
+ * Verifies an install-status webhook token and returns its clean claims.
2559
+ *
2560
+ * @deprecated Use {@link parseInstallWebhook} instead. This verifier reads only
2561
+ * the signed token, so it cannot report the account **name**, **platform**, or
2562
+ * **test** flag that the webhook's JSON body also carries — the caller was left
2563
+ * to parse that body separately and stitch the two shapes together.
2564
+ * `parseInstallWebhook(token, body, secret)` verifies the same token and returns
2565
+ * one flat {@link InstallWebhook} with every field. This function remains only
2566
+ * for backwards compatibility.
2567
+ *
2568
+ * Validates the HMAC signature (with `secret`), the token expiry, the
2569
+ * `"app_registry_v2"` issuer, and the `"Joken"` audience — the same checks as
2570
+ * {@link PeekAccessService.verifyPeekAuthToken} — then maps the payload to
2571
+ * {@link InstallWebhookClaims}, tolerating a `null` `user` (system events).
2572
+ * Throws from the `jsonwebtoken` library on any verification failure:
2573
+ *
2574
+ * - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed
2575
+ * - `TokenExpiredError` — past `exp`
2576
+ * - `NotBeforeError` — before `nbf`
2577
+ *
2578
+ * @param token the JWT delivered by the install webhook. Pass the raw
2579
+ * `x-peek-auth` header value directly — a leading `Bearer ` prefix, if
2580
+ * present, is stripped for you.
2581
+ * @param secret the app's HMAC signing secret (the `jwtSecret` you construct
2582
+ * `PeekAccessService` with)
2583
+ * @throws {JsonWebTokenError} signature invalid or token malformed
2584
+ * @throws {TokenExpiredError} token has expired
2585
+ * @throws {NotBeforeError} token not yet valid
2586
+ */
2587
+ declare function verifyInstallWebhook(token: string, secret: string): InstallWebhookClaims;
2572
2588
 
2573
2589
  /**
2574
2590
  * Typed errors thrown by the package. Each mirrors a failure mode of the Peek
@@ -2681,4 +2697,4 @@ declare class AcmeApiError extends Error {
2681
2697
  constructor(statusCode: number, body: unknown, message?: string);
2682
2698
  }
2683
2699
 
2684
- 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 CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, INSTALL_STATUSES, type InstallEvent, type InstallIdentity, type InstallStatus, type InstallWebhookAccount, type InstallWebhookClaims, InvalidPeekTokenError, 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, noopLogger, parseBookingWebhook, parseInstallEvent, parseWaiverWebhook, verifyInstallWebhook };
2700
+ 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 CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, INSTALL_STATUSES, type InstallStatus, type InstallWebhook, type InstallWebhookAccount, type InstallWebhookClaims, InvalidPeekTokenError, 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, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };