@peektravel/app-utilities 0.6.1 → 0.7.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/README.md +48 -50
- package/dist/index.cjs +33 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -82
- package/dist/index.d.ts +93 -82
- package/dist/index.js +33 -42
- package/dist/index.js.map +1 -1
- package/docs/webhooks.md +103 -128
- package/llms.txt +25 -27
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -2426,41 +2426,21 @@ interface Waiver {
|
|
|
2426
2426
|
declare function parseWaiverWebhook(payload: unknown, options?: AccessOptions): Waiver;
|
|
2427
2427
|
|
|
2428
2428
|
/**
|
|
2429
|
-
*
|
|
2430
|
-
*
|
|
2431
|
-
*
|
|
2432
|
-
*
|
|
2433
|
-
*
|
|
2434
|
-
*
|
|
2435
|
-
*
|
|
2436
|
-
*
|
|
2437
|
-
*
|
|
2438
|
-
*
|
|
2439
|
-
*
|
|
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.
|
|
2429
|
+
* The clean data model for an app-store **install lifecycle event** — the single
|
|
2430
|
+
* flat object `parseInstallWebhook` returns for the webhook Peek's app registry
|
|
2431
|
+
* POSTs when an app is installed, uninstalled, or updated.
|
|
2432
|
+
*
|
|
2433
|
+
* That delivery carries two things at once: a **signed `app_registry_v2` JWT**
|
|
2434
|
+
* (the security boundary) and a plain **JSON body** (the enrichment channel).
|
|
2435
|
+
* `parseInstallWebhook` verifies the JWT and merges both into this shape, so a
|
|
2436
|
+
* consumer sees one clean, flat, JSON-safe record instead of two differently
|
|
2437
|
+
* shaped payloads. The verified JWT is authoritative for the fields it carries
|
|
2438
|
+
* (`installId`, `accountId`, `status`, `displayVersion`, `user`); the JSON body
|
|
2439
|
+
* is the only source of `accountName`, `platform`, and `isTest`.
|
|
2460
2440
|
*
|
|
2461
2441
|
* It is also the single origin of the account id in the whole system: no
|
|
2462
|
-
* GraphQL read
|
|
2463
|
-
*
|
|
2442
|
+
* GraphQL read returns it, so whatever a consumer persists from this event is
|
|
2443
|
+
* all it will ever have.
|
|
2464
2444
|
*/
|
|
2465
2445
|
|
|
2466
2446
|
/**
|
|
@@ -2471,21 +2451,27 @@ declare const INSTALL_STATUSES: readonly ["installed", "uninstalled", "update_in
|
|
|
2471
2451
|
/** Install lifecycle status. */
|
|
2472
2452
|
type InstallStatus = (typeof INSTALL_STATUSES)[number];
|
|
2473
2453
|
/**
|
|
2474
|
-
*
|
|
2454
|
+
* A verified install lifecycle event — what happened, to which install, and who
|
|
2455
|
+
* (if anyone) triggered it — as one flat, JSON-safe record.
|
|
2475
2456
|
*
|
|
2476
|
-
*
|
|
2477
|
-
* so the same shape the parser
|
|
2478
|
-
* later rehydrates. There is
|
|
2457
|
+
* This is the shape `parseInstallWebhook` returns. It is flat by design: it
|
|
2458
|
+
* round-trips through a datastore unchanged, so the same shape the parser
|
|
2459
|
+
* returns is the shape a consumer persists and later rehydrates. There is
|
|
2460
|
+
* deliberately no nested identity object and no second representation.
|
|
2461
|
+
*
|
|
2462
|
+
* Fields sourced from the **verified JWT** (`installId`, `accountId`, `status`,
|
|
2463
|
+
* `rawStatus`, `displayVersion`, `user`) are trustworthy; the enrichment fields
|
|
2464
|
+
* (`accountName`, `platform`, `isTest`) come from the unauthenticated JSON body.
|
|
2479
2465
|
*/
|
|
2480
|
-
interface
|
|
2481
|
-
/** Install ID — Peek-assigned UUID. Also the subject
|
|
2466
|
+
interface InstallWebhook {
|
|
2467
|
+
/** Install ID — Peek-assigned UUID. Also the JWT subject (`sub`). */
|
|
2482
2468
|
installId: string;
|
|
2483
2469
|
/**
|
|
2484
2470
|
* Stable Peek account id — the same value Peek calls the **partner ID**.
|
|
2485
2471
|
* This event is its only source; it cannot be re-fetched later.
|
|
2486
2472
|
*/
|
|
2487
2473
|
accountId: string;
|
|
2488
|
-
/** Partner display name. */
|
|
2474
|
+
/** Partner display name. `""` when the JSON body omits it. */
|
|
2489
2475
|
accountName: string;
|
|
2490
2476
|
/**
|
|
2491
2477
|
* Which Peek platform owns the install, or `null` when the registry reported
|
|
@@ -2503,9 +2489,6 @@ interface InstallIdentity {
|
|
|
2503
2489
|
platform: PeekPlatform | null;
|
|
2504
2490
|
/** Whether this is a test account. Defaults to `false` when not reported. */
|
|
2505
2491
|
isTest: boolean;
|
|
2506
|
-
}
|
|
2507
|
-
/** A parsed install lifecycle event: what happened, to which install. */
|
|
2508
|
-
interface InstallEvent {
|
|
2509
2492
|
/**
|
|
2510
2493
|
* The lifecycle status, or `null` when the registry sent a status this
|
|
2511
2494
|
* version of the package does not know. Handle `null` explicitly — treating
|
|
@@ -2516,59 +2499,87 @@ interface InstallEvent {
|
|
|
2516
2499
|
rawStatus: string;
|
|
2517
2500
|
/** App display version at the time of the event. */
|
|
2518
2501
|
displayVersion: string;
|
|
2519
|
-
/**
|
|
2520
|
-
|
|
2502
|
+
/**
|
|
2503
|
+
* The user that triggered the event, or `null` for system-initiated events
|
|
2504
|
+
* (install lifecycle changes are often system-initiated). From the JWT.
|
|
2505
|
+
*/
|
|
2506
|
+
user: PeekAuthTokenUser | null;
|
|
2521
2507
|
}
|
|
2522
2508
|
|
|
2523
2509
|
/**
|
|
2524
|
-
*
|
|
2525
|
-
*
|
|
2510
|
+
* Verifies an install-status webhook token and merges it with the delivered
|
|
2511
|
+
* JSON body into one flat {@link InstallWebhook}.
|
|
2526
2512
|
*
|
|
2527
|
-
*
|
|
2528
|
-
* `
|
|
2529
|
-
*
|
|
2530
|
-
*
|
|
2531
|
-
*
|
|
2513
|
+
* The **verified token** is the authoritative source of `installId`,
|
|
2514
|
+
* `accountId`, `status`, `displayVersion`, and `user`. The **JSON body** — which
|
|
2515
|
+
* is not signed and so is trusted only for fields the token cannot carry —
|
|
2516
|
+
* supplies `accountName`, `platform`, and `isTest`. A missing or malformed body
|
|
2517
|
+
* degrades those three to `""`/`null`/`false`; it never overrides an
|
|
2518
|
+
* authenticated field and never throws.
|
|
2532
2519
|
*
|
|
2533
|
-
*
|
|
2534
|
-
*
|
|
2535
|
-
*
|
|
2536
|
-
*
|
|
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}.
|
|
2520
|
+
* Signature verification is strict: the HMAC signature (with `secret`), the
|
|
2521
|
+
* token expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience are
|
|
2522
|
+
* all checked — the same checks as {@link PeekAccessService.verifyPeekAuthToken}.
|
|
2523
|
+
* Any failure throws from the `jsonwebtoken` library, so callers can branch on
|
|
2524
|
+
* the error kind:
|
|
2549
2525
|
*
|
|
2550
|
-
*
|
|
2551
|
-
*
|
|
2552
|
-
* `
|
|
2526
|
+
* - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed
|
|
2527
|
+
* - `TokenExpiredError` — past `exp`
|
|
2528
|
+
* - `NotBeforeError` — before `nbf`
|
|
2553
2529
|
*
|
|
2554
|
-
*
|
|
2555
|
-
*
|
|
2556
|
-
* not
|
|
2530
|
+
* An unrecognised `status` or `platform` maps to `null` (with the wire status
|
|
2531
|
+
* preserved on {@link InstallWebhook.rawStatus}) rather than being coerced —
|
|
2532
|
+
* Peek treats any 2xx as delivered and does not redeliver, so handle a `null`
|
|
2533
|
+
* `status` explicitly:
|
|
2557
2534
|
*
|
|
2558
2535
|
* ```ts
|
|
2559
|
-
* const event =
|
|
2536
|
+
* const event = parseInstallWebhook(token, req.body, secret);
|
|
2560
2537
|
* switch (event.status) {
|
|
2561
|
-
* case "installed": return provision(event
|
|
2562
|
-
* case "uninstalled": return deprovision(event
|
|
2563
|
-
* case "update_installed": return recordVersion(event
|
|
2538
|
+
* case "installed": return provision(event);
|
|
2539
|
+
* case "uninstalled": return deprovision(event);
|
|
2540
|
+
* case "update_installed": return recordVersion(event);
|
|
2564
2541
|
* default: throw new Error(`unknown install status: ${event.rawStatus}`);
|
|
2565
2542
|
* }
|
|
2566
2543
|
* ```
|
|
2567
2544
|
*
|
|
2568
|
-
*
|
|
2569
|
-
*
|
|
2545
|
+
* @param token the raw JWT delivered by the install webhook (no `Bearer` prefix)
|
|
2546
|
+
* @param body the delivered JSON body (raw object or a JSON string)
|
|
2547
|
+
* @param secret the app's HMAC signing secret (the `jwtSecret` you construct
|
|
2548
|
+
* `PeekAccessService` with)
|
|
2549
|
+
* @throws {JsonWebTokenError} signature invalid or token malformed
|
|
2550
|
+
* @throws {TokenExpiredError} token has expired
|
|
2551
|
+
* @throws {NotBeforeError} token not yet valid
|
|
2570
2552
|
*/
|
|
2571
|
-
declare function
|
|
2553
|
+
declare function parseInstallWebhook(token: string, body: unknown, secret: string): InstallWebhook;
|
|
2554
|
+
/**
|
|
2555
|
+
* Verifies an install-status webhook token and returns its clean claims.
|
|
2556
|
+
*
|
|
2557
|
+
* @deprecated Use {@link parseInstallWebhook} instead. This verifier reads only
|
|
2558
|
+
* the signed token, so it cannot report the account **name**, **platform**, or
|
|
2559
|
+
* **test** flag that the webhook's JSON body also carries — the caller was left
|
|
2560
|
+
* to parse that body separately and stitch the two shapes together.
|
|
2561
|
+
* `parseInstallWebhook(token, body, secret)` verifies the same token and returns
|
|
2562
|
+
* one flat {@link InstallWebhook} with every field. This function remains only
|
|
2563
|
+
* for backwards compatibility.
|
|
2564
|
+
*
|
|
2565
|
+
* Validates the HMAC signature (with `secret`), the token expiry, the
|
|
2566
|
+
* `"app_registry_v2"` issuer, and the `"Joken"` audience — the same checks as
|
|
2567
|
+
* {@link PeekAccessService.verifyPeekAuthToken} — then maps the payload to
|
|
2568
|
+
* {@link InstallWebhookClaims}, tolerating a `null` `user` (system events).
|
|
2569
|
+
* Throws from the `jsonwebtoken` library on any verification failure:
|
|
2570
|
+
*
|
|
2571
|
+
* - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed
|
|
2572
|
+
* - `TokenExpiredError` — past `exp`
|
|
2573
|
+
* - `NotBeforeError` — before `nbf`
|
|
2574
|
+
*
|
|
2575
|
+
* @param token the raw JWT delivered by the install webhook (no `Bearer` prefix)
|
|
2576
|
+
* @param secret the app's HMAC signing secret (the `jwtSecret` you construct
|
|
2577
|
+
* `PeekAccessService` with)
|
|
2578
|
+
* @throws {JsonWebTokenError} signature invalid or token malformed
|
|
2579
|
+
* @throws {TokenExpiredError} token has expired
|
|
2580
|
+
* @throws {NotBeforeError} token not yet valid
|
|
2581
|
+
*/
|
|
2582
|
+
declare function verifyInstallWebhook(token: string, secret: string): InstallWebhookClaims;
|
|
2572
2583
|
|
|
2573
2584
|
/**
|
|
2574
2585
|
* Typed errors thrown by the package. Each mirrors a failure mode of the Peek
|
|
@@ -2681,4 +2692,4 @@ declare class AcmeApiError extends Error {
|
|
|
2681
2692
|
constructor(statusCode: number, body: unknown, message?: string);
|
|
2682
2693
|
}
|
|
2683
2694
|
|
|
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
|
|
2695
|
+
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
|
@@ -2426,41 +2426,21 @@ interface Waiver {
|
|
|
2426
2426
|
declare function parseWaiverWebhook(payload: unknown, options?: AccessOptions): Waiver;
|
|
2427
2427
|
|
|
2428
2428
|
/**
|
|
2429
|
-
*
|
|
2430
|
-
*
|
|
2431
|
-
*
|
|
2432
|
-
*
|
|
2433
|
-
*
|
|
2434
|
-
*
|
|
2435
|
-
*
|
|
2436
|
-
*
|
|
2437
|
-
*
|
|
2438
|
-
*
|
|
2439
|
-
*
|
|
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.
|
|
2429
|
+
* The clean data model for an app-store **install lifecycle event** — the single
|
|
2430
|
+
* flat object `parseInstallWebhook` returns for the webhook Peek's app registry
|
|
2431
|
+
* POSTs when an app is installed, uninstalled, or updated.
|
|
2432
|
+
*
|
|
2433
|
+
* That delivery carries two things at once: a **signed `app_registry_v2` JWT**
|
|
2434
|
+
* (the security boundary) and a plain **JSON body** (the enrichment channel).
|
|
2435
|
+
* `parseInstallWebhook` verifies the JWT and merges both into this shape, so a
|
|
2436
|
+
* consumer sees one clean, flat, JSON-safe record instead of two differently
|
|
2437
|
+
* shaped payloads. The verified JWT is authoritative for the fields it carries
|
|
2438
|
+
* (`installId`, `accountId`, `status`, `displayVersion`, `user`); the JSON body
|
|
2439
|
+
* is the only source of `accountName`, `platform`, and `isTest`.
|
|
2460
2440
|
*
|
|
2461
2441
|
* It is also the single origin of the account id in the whole system: no
|
|
2462
|
-
* GraphQL read
|
|
2463
|
-
*
|
|
2442
|
+
* GraphQL read returns it, so whatever a consumer persists from this event is
|
|
2443
|
+
* all it will ever have.
|
|
2464
2444
|
*/
|
|
2465
2445
|
|
|
2466
2446
|
/**
|
|
@@ -2471,21 +2451,27 @@ declare const INSTALL_STATUSES: readonly ["installed", "uninstalled", "update_in
|
|
|
2471
2451
|
/** Install lifecycle status. */
|
|
2472
2452
|
type InstallStatus = (typeof INSTALL_STATUSES)[number];
|
|
2473
2453
|
/**
|
|
2474
|
-
*
|
|
2454
|
+
* A verified install lifecycle event — what happened, to which install, and who
|
|
2455
|
+
* (if anyone) triggered it — as one flat, JSON-safe record.
|
|
2475
2456
|
*
|
|
2476
|
-
*
|
|
2477
|
-
* so the same shape the parser
|
|
2478
|
-
* later rehydrates. There is
|
|
2457
|
+
* This is the shape `parseInstallWebhook` returns. It is flat by design: it
|
|
2458
|
+
* round-trips through a datastore unchanged, so the same shape the parser
|
|
2459
|
+
* returns is the shape a consumer persists and later rehydrates. There is
|
|
2460
|
+
* deliberately no nested identity object and no second representation.
|
|
2461
|
+
*
|
|
2462
|
+
* Fields sourced from the **verified JWT** (`installId`, `accountId`, `status`,
|
|
2463
|
+
* `rawStatus`, `displayVersion`, `user`) are trustworthy; the enrichment fields
|
|
2464
|
+
* (`accountName`, `platform`, `isTest`) come from the unauthenticated JSON body.
|
|
2479
2465
|
*/
|
|
2480
|
-
interface
|
|
2481
|
-
/** Install ID — Peek-assigned UUID. Also the subject
|
|
2466
|
+
interface InstallWebhook {
|
|
2467
|
+
/** Install ID — Peek-assigned UUID. Also the JWT subject (`sub`). */
|
|
2482
2468
|
installId: string;
|
|
2483
2469
|
/**
|
|
2484
2470
|
* Stable Peek account id — the same value Peek calls the **partner ID**.
|
|
2485
2471
|
* This event is its only source; it cannot be re-fetched later.
|
|
2486
2472
|
*/
|
|
2487
2473
|
accountId: string;
|
|
2488
|
-
/** Partner display name. */
|
|
2474
|
+
/** Partner display name. `""` when the JSON body omits it. */
|
|
2489
2475
|
accountName: string;
|
|
2490
2476
|
/**
|
|
2491
2477
|
* Which Peek platform owns the install, or `null` when the registry reported
|
|
@@ -2503,9 +2489,6 @@ interface InstallIdentity {
|
|
|
2503
2489
|
platform: PeekPlatform | null;
|
|
2504
2490
|
/** Whether this is a test account. Defaults to `false` when not reported. */
|
|
2505
2491
|
isTest: boolean;
|
|
2506
|
-
}
|
|
2507
|
-
/** A parsed install lifecycle event: what happened, to which install. */
|
|
2508
|
-
interface InstallEvent {
|
|
2509
2492
|
/**
|
|
2510
2493
|
* The lifecycle status, or `null` when the registry sent a status this
|
|
2511
2494
|
* version of the package does not know. Handle `null` explicitly — treating
|
|
@@ -2516,59 +2499,87 @@ interface InstallEvent {
|
|
|
2516
2499
|
rawStatus: string;
|
|
2517
2500
|
/** App display version at the time of the event. */
|
|
2518
2501
|
displayVersion: string;
|
|
2519
|
-
/**
|
|
2520
|
-
|
|
2502
|
+
/**
|
|
2503
|
+
* The user that triggered the event, or `null` for system-initiated events
|
|
2504
|
+
* (install lifecycle changes are often system-initiated). From the JWT.
|
|
2505
|
+
*/
|
|
2506
|
+
user: PeekAuthTokenUser | null;
|
|
2521
2507
|
}
|
|
2522
2508
|
|
|
2523
2509
|
/**
|
|
2524
|
-
*
|
|
2525
|
-
*
|
|
2510
|
+
* Verifies an install-status webhook token and merges it with the delivered
|
|
2511
|
+
* JSON body into one flat {@link InstallWebhook}.
|
|
2526
2512
|
*
|
|
2527
|
-
*
|
|
2528
|
-
* `
|
|
2529
|
-
*
|
|
2530
|
-
*
|
|
2531
|
-
*
|
|
2513
|
+
* The **verified token** is the authoritative source of `installId`,
|
|
2514
|
+
* `accountId`, `status`, `displayVersion`, and `user`. The **JSON body** — which
|
|
2515
|
+
* is not signed and so is trusted only for fields the token cannot carry —
|
|
2516
|
+
* supplies `accountName`, `platform`, and `isTest`. A missing or malformed body
|
|
2517
|
+
* degrades those three to `""`/`null`/`false`; it never overrides an
|
|
2518
|
+
* authenticated field and never throws.
|
|
2532
2519
|
*
|
|
2533
|
-
*
|
|
2534
|
-
*
|
|
2535
|
-
*
|
|
2536
|
-
*
|
|
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}.
|
|
2520
|
+
* Signature verification is strict: the HMAC signature (with `secret`), the
|
|
2521
|
+
* token expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience are
|
|
2522
|
+
* all checked — the same checks as {@link PeekAccessService.verifyPeekAuthToken}.
|
|
2523
|
+
* Any failure throws from the `jsonwebtoken` library, so callers can branch on
|
|
2524
|
+
* the error kind:
|
|
2549
2525
|
*
|
|
2550
|
-
*
|
|
2551
|
-
*
|
|
2552
|
-
* `
|
|
2526
|
+
* - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed
|
|
2527
|
+
* - `TokenExpiredError` — past `exp`
|
|
2528
|
+
* - `NotBeforeError` — before `nbf`
|
|
2553
2529
|
*
|
|
2554
|
-
*
|
|
2555
|
-
*
|
|
2556
|
-
* not
|
|
2530
|
+
* An unrecognised `status` or `platform` maps to `null` (with the wire status
|
|
2531
|
+
* preserved on {@link InstallWebhook.rawStatus}) rather than being coerced —
|
|
2532
|
+
* Peek treats any 2xx as delivered and does not redeliver, so handle a `null`
|
|
2533
|
+
* `status` explicitly:
|
|
2557
2534
|
*
|
|
2558
2535
|
* ```ts
|
|
2559
|
-
* const event =
|
|
2536
|
+
* const event = parseInstallWebhook(token, req.body, secret);
|
|
2560
2537
|
* switch (event.status) {
|
|
2561
|
-
* case "installed": return provision(event
|
|
2562
|
-
* case "uninstalled": return deprovision(event
|
|
2563
|
-
* case "update_installed": return recordVersion(event
|
|
2538
|
+
* case "installed": return provision(event);
|
|
2539
|
+
* case "uninstalled": return deprovision(event);
|
|
2540
|
+
* case "update_installed": return recordVersion(event);
|
|
2564
2541
|
* default: throw new Error(`unknown install status: ${event.rawStatus}`);
|
|
2565
2542
|
* }
|
|
2566
2543
|
* ```
|
|
2567
2544
|
*
|
|
2568
|
-
*
|
|
2569
|
-
*
|
|
2545
|
+
* @param token the raw JWT delivered by the install webhook (no `Bearer` prefix)
|
|
2546
|
+
* @param body the delivered JSON body (raw object or a JSON string)
|
|
2547
|
+
* @param secret the app's HMAC signing secret (the `jwtSecret` you construct
|
|
2548
|
+
* `PeekAccessService` with)
|
|
2549
|
+
* @throws {JsonWebTokenError} signature invalid or token malformed
|
|
2550
|
+
* @throws {TokenExpiredError} token has expired
|
|
2551
|
+
* @throws {NotBeforeError} token not yet valid
|
|
2570
2552
|
*/
|
|
2571
|
-
declare function
|
|
2553
|
+
declare function parseInstallWebhook(token: string, body: unknown, secret: string): InstallWebhook;
|
|
2554
|
+
/**
|
|
2555
|
+
* Verifies an install-status webhook token and returns its clean claims.
|
|
2556
|
+
*
|
|
2557
|
+
* @deprecated Use {@link parseInstallWebhook} instead. This verifier reads only
|
|
2558
|
+
* the signed token, so it cannot report the account **name**, **platform**, or
|
|
2559
|
+
* **test** flag that the webhook's JSON body also carries — the caller was left
|
|
2560
|
+
* to parse that body separately and stitch the two shapes together.
|
|
2561
|
+
* `parseInstallWebhook(token, body, secret)` verifies the same token and returns
|
|
2562
|
+
* one flat {@link InstallWebhook} with every field. This function remains only
|
|
2563
|
+
* for backwards compatibility.
|
|
2564
|
+
*
|
|
2565
|
+
* Validates the HMAC signature (with `secret`), the token expiry, the
|
|
2566
|
+
* `"app_registry_v2"` issuer, and the `"Joken"` audience — the same checks as
|
|
2567
|
+
* {@link PeekAccessService.verifyPeekAuthToken} — then maps the payload to
|
|
2568
|
+
* {@link InstallWebhookClaims}, tolerating a `null` `user` (system events).
|
|
2569
|
+
* Throws from the `jsonwebtoken` library on any verification failure:
|
|
2570
|
+
*
|
|
2571
|
+
* - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or malformed
|
|
2572
|
+
* - `TokenExpiredError` — past `exp`
|
|
2573
|
+
* - `NotBeforeError` — before `nbf`
|
|
2574
|
+
*
|
|
2575
|
+
* @param token the raw JWT delivered by the install webhook (no `Bearer` prefix)
|
|
2576
|
+
* @param secret the app's HMAC signing secret (the `jwtSecret` you construct
|
|
2577
|
+
* `PeekAccessService` with)
|
|
2578
|
+
* @throws {JsonWebTokenError} signature invalid or token malformed
|
|
2579
|
+
* @throws {TokenExpiredError} token has expired
|
|
2580
|
+
* @throws {NotBeforeError} token not yet valid
|
|
2581
|
+
*/
|
|
2582
|
+
declare function verifyInstallWebhook(token: string, secret: string): InstallWebhookClaims;
|
|
2572
2583
|
|
|
2573
2584
|
/**
|
|
2574
2585
|
* Typed errors thrown by the package. Each mirrors a failure mode of the Peek
|
|
@@ -2681,4 +2692,4 @@ declare class AcmeApiError extends Error {
|
|
|
2681
2692
|
constructor(statusCode: number, body: unknown, message?: string);
|
|
2682
2693
|
}
|
|
2683
2694
|
|
|
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
|
|
2695
|
+
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.js
CHANGED
|
@@ -4249,18 +4249,6 @@ function extractWaiverNode(payload) {
|
|
|
4249
4249
|
return record;
|
|
4250
4250
|
}
|
|
4251
4251
|
|
|
4252
|
-
// src/internal/peek/installs/install-webhook.ts
|
|
4253
|
-
function verifyInstallWebhook(token, secret) {
|
|
4254
|
-
const payload = verifyPeekJwt(token, secret);
|
|
4255
|
-
return {
|
|
4256
|
-
installId: payload.sub ?? "",
|
|
4257
|
-
account: { id: payload.account?.id ?? "" },
|
|
4258
|
-
status: payload.status ?? "",
|
|
4259
|
-
displayVersion: payload.display_version ?? "",
|
|
4260
|
-
user: payload.user ? mapPeekTokenUser(payload.user) : null
|
|
4261
|
-
};
|
|
4262
|
-
}
|
|
4263
|
-
|
|
4264
4252
|
// src/models/peek/auth-token.ts
|
|
4265
4253
|
var PEEK_PLATFORMS = ["peek", "cng", "acme"];
|
|
4266
4254
|
|
|
@@ -4272,50 +4260,53 @@ var INSTALL_STATUSES = [
|
|
|
4272
4260
|
];
|
|
4273
4261
|
|
|
4274
4262
|
// src/internal/peek/installs/install-converter.ts
|
|
4263
|
+
function extractInstallWebhookBody(payload) {
|
|
4264
|
+
let body = payload;
|
|
4265
|
+
if (typeof body === "string") {
|
|
4266
|
+
try {
|
|
4267
|
+
body = JSON.parse(body);
|
|
4268
|
+
} catch {
|
|
4269
|
+
return {};
|
|
4270
|
+
}
|
|
4271
|
+
}
|
|
4272
|
+
if (!body || typeof body !== "object") return {};
|
|
4273
|
+
return body;
|
|
4274
|
+
}
|
|
4275
4275
|
function toInstallStatus(raw) {
|
|
4276
4276
|
return INSTALL_STATUSES.includes(raw) ? raw : null;
|
|
4277
4277
|
}
|
|
4278
4278
|
function toPeekPlatform(raw) {
|
|
4279
4279
|
return PEEK_PLATFORMS.includes(raw) ? raw : null;
|
|
4280
4280
|
}
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4281
|
+
|
|
4282
|
+
// src/internal/peek/installs/install-webhook.ts
|
|
4283
|
+
function parseInstallWebhook(token, body, secret) {
|
|
4284
|
+
const payload = verifyPeekJwt(token, secret);
|
|
4285
|
+
const account = extractInstallWebhookBody(body).account ?? {};
|
|
4286
|
+
const rawStatus = payload.status ?? "";
|
|
4284
4287
|
return {
|
|
4285
|
-
installId:
|
|
4286
|
-
accountId: account
|
|
4288
|
+
installId: payload.sub ?? "",
|
|
4289
|
+
accountId: payload.account?.id ?? "",
|
|
4287
4290
|
accountName: account.name || "",
|
|
4288
4291
|
platform: toPeekPlatform(account.platform || ""),
|
|
4289
|
-
isTest: Boolean(account.is_test)
|
|
4290
|
-
};
|
|
4291
|
-
}
|
|
4292
|
-
function fromInstallEventNode(node) {
|
|
4293
|
-
const rawStatus = node?.status || "";
|
|
4294
|
-
return {
|
|
4292
|
+
isTest: Boolean(account.is_test),
|
|
4295
4293
|
status: toInstallStatus(rawStatus),
|
|
4296
4294
|
rawStatus,
|
|
4297
|
-
displayVersion:
|
|
4298
|
-
|
|
4295
|
+
displayVersion: payload.display_version ?? "",
|
|
4296
|
+
user: payload.user ? mapPeekTokenUser(payload.user) : null
|
|
4299
4297
|
};
|
|
4300
4298
|
}
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
}
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
body = JSON.parse(body);
|
|
4311
|
-
} catch {
|
|
4312
|
-
return {};
|
|
4313
|
-
}
|
|
4314
|
-
}
|
|
4315
|
-
if (!body || typeof body !== "object") return {};
|
|
4316
|
-
return body;
|
|
4299
|
+
function verifyInstallWebhook(token, secret) {
|
|
4300
|
+
const payload = verifyPeekJwt(token, secret);
|
|
4301
|
+
return {
|
|
4302
|
+
installId: payload.sub ?? "",
|
|
4303
|
+
account: { id: payload.account?.id ?? "" },
|
|
4304
|
+
status: payload.status ?? "",
|
|
4305
|
+
displayVersion: payload.display_version ?? "",
|
|
4306
|
+
user: payload.user ? mapPeekTokenUser(payload.user) : null
|
|
4307
|
+
};
|
|
4317
4308
|
}
|
|
4318
4309
|
|
|
4319
|
-
export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, AccountUserService, AcmeAccessService, AcmeApiError, AcmeProductService, AdminAccountRequiredError, AvailabilityService, BookingService, CngAccessService, CngApiError, CngProductService, DailyNoteService, INSTALL_STATUSES, InvalidPeekTokenError, MembershipService, PeekAccessService, PeekGraphQLError, PeekHttpError, PiiAccessDisabledError, PricingService, ProductService, PromoCodeService, RENTAL_PRODUCT_TYPE, RateLimitError, ResellerService, ResourcePoolService, ReviewService, TimeslotService, noopLogger, parseBookingWebhook,
|
|
4310
|
+
export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, AccountUserService, AcmeAccessService, AcmeApiError, AcmeProductService, AdminAccountRequiredError, AvailabilityService, BookingService, CngAccessService, CngApiError, CngProductService, DailyNoteService, INSTALL_STATUSES, InvalidPeekTokenError, MembershipService, PeekAccessService, PeekGraphQLError, PeekHttpError, PiiAccessDisabledError, PricingService, ProductService, PromoCodeService, RENTAL_PRODUCT_TYPE, RateLimitError, ResellerService, ResourcePoolService, ReviewService, TimeslotService, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
|
|
4320
4311
|
//# sourceMappingURL=index.js.map
|
|
4321
4312
|
//# sourceMappingURL=index.js.map
|