@peektravel/app-utilities 0.7.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -8
- package/dist/index.cjs +64 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +181 -43
- package/dist/index.d.ts +181 -43
- package/dist/index.js +64 -25
- package/dist/index.js.map +1 -1
- package/dist/ui/index.cjs +26 -0
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +77 -3
- package/dist/ui/index.d.ts +77 -3
- package/dist/ui/index.js +25 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/odyssey.css +24 -2
- package/dist/ui/tokens.css +10 -1
- package/docs/ui.md +63 -14
- package/docs/webhooks.md +118 -31
- package/llms.txt +38 -16
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -19,10 +19,20 @@ interface GraphQLBody<T> {
|
|
|
19
19
|
errors?: unknown[];
|
|
20
20
|
}
|
|
21
21
|
interface GraphQLClientOptions {
|
|
22
|
-
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
/**
|
|
23
|
+
* The install's app endpoint URL (the install webhook's `apiUrl`). When set it
|
|
24
|
+
* is the **sole request URL** — every GraphQL call POSTs to it unmodified, and
|
|
25
|
+
* `baseUrl`/`appId`/`endpointPathPrefix`/`endpointName` are ignored for URL
|
|
26
|
+
* construction. Takes precedence over `baseUrl`.
|
|
27
|
+
*/
|
|
28
|
+
apiUrl?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Base URL of the backoffice GraphQL gateway (no trailing slash). Used only
|
|
31
|
+
* when `apiUrl` is not set; the URL is `baseUrl/appId/[prefix/]endpointName`.
|
|
32
|
+
*/
|
|
33
|
+
baseUrl?: string;
|
|
34
|
+
/** Peek app ID, used in the endpoint path (legacy `baseUrl` mode only). */
|
|
35
|
+
appId?: string;
|
|
26
36
|
/** API gateway key sent as the `pk-api-key` header. Omitted from headers when absent (v2 mode). */
|
|
27
37
|
gatewayKey?: string;
|
|
28
38
|
/** Supplies a valid bearer token for each request. */
|
|
@@ -1536,9 +1546,29 @@ interface BaseAccessServiceConfig {
|
|
|
1536
1546
|
jwtSecret: string;
|
|
1537
1547
|
/** JWT issuer — the app name / app ID. */
|
|
1538
1548
|
issuer: string;
|
|
1539
|
-
/**
|
|
1540
|
-
|
|
1541
|
-
|
|
1549
|
+
/**
|
|
1550
|
+
* The install's **app endpoint URL** — persist the install webhook's `apiUrl`
|
|
1551
|
+
* and pass it here. When set it is used **as given**: for Peek it is the sole
|
|
1552
|
+
* request URL (every call POSTs to it); for CNG/ACME it is the base and the
|
|
1553
|
+
* REST path is appended. No app-id/gateway segment is inserted, so `appId` is
|
|
1554
|
+
* not required. This is the forward-looking way to target an install — prefer
|
|
1555
|
+
* it over `baseUrl`/`appId`, which are deprecated (the hardcoded base-URL
|
|
1556
|
+
* fallbacks will be removed and a URL will become required in a future release).
|
|
1557
|
+
*/
|
|
1558
|
+
apiUrl?: string;
|
|
1559
|
+
/**
|
|
1560
|
+
* App ID, inserted into the gateway endpoint path.
|
|
1561
|
+
*
|
|
1562
|
+
* @deprecated Required only in the legacy `baseUrl` mode. Prefer `apiUrl` (the
|
|
1563
|
+
* install's app endpoint), which needs no app-id segment.
|
|
1564
|
+
*/
|
|
1565
|
+
appId?: string;
|
|
1566
|
+
/**
|
|
1567
|
+
* Override the gateway base URL. Default: per-service.
|
|
1568
|
+
*
|
|
1569
|
+
* @deprecated Prefer `apiUrl` (the install's app endpoint, used as given). The
|
|
1570
|
+
* hardcoded per-service default will be removed and a URL will become required.
|
|
1571
|
+
*/
|
|
1542
1572
|
baseUrl?: string;
|
|
1543
1573
|
/** JWT lifetime in seconds. Default: 3600. */
|
|
1544
1574
|
tokenTtlSeconds?: number;
|
|
@@ -1926,9 +1956,10 @@ declare class PeekAccessService {
|
|
|
1926
1956
|
* decoded claims.
|
|
1927
1957
|
*
|
|
1928
1958
|
* Validates the HMAC signature (using this service's `jwtSecret`), the token
|
|
1929
|
-
* expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience.
|
|
1930
|
-
*
|
|
1931
|
-
*
|
|
1959
|
+
* expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience. Pass the
|
|
1960
|
+
* raw `x-peek-auth` request header value — a leading `Bearer ` prefix, if
|
|
1961
|
+
* present, is stripped for you. Throws from the `jsonwebtoken` library on any
|
|
1962
|
+
* failure — callers should catch to distinguish error kinds:
|
|
1932
1963
|
*
|
|
1933
1964
|
* - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or token
|
|
1934
1965
|
* malformed
|
|
@@ -2089,12 +2120,22 @@ declare class PeekAccessService {
|
|
|
2089
2120
|
}
|
|
2090
2121
|
|
|
2091
2122
|
interface RestClientOptions$1 {
|
|
2092
|
-
/**
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2123
|
+
/**
|
|
2124
|
+
* The install's app endpoint URL (the install webhook's `apiUrl`). When set it
|
|
2125
|
+
* is the **base URL** and only the REST path is appended (`apiUrl/path`) —
|
|
2126
|
+
* `baseUrl`/`appId`/`extendableSlug` are ignored. Takes precedence over
|
|
2127
|
+
* `baseUrl`.
|
|
2128
|
+
*/
|
|
2129
|
+
apiUrl?: string;
|
|
2130
|
+
/**
|
|
2131
|
+
* Base URL of the backoffice gateway (no trailing slash). Used only when
|
|
2132
|
+
* `apiUrl` is not set; the URL is `baseUrl/appId/extendableSlug/path`.
|
|
2133
|
+
*/
|
|
2134
|
+
baseUrl?: string;
|
|
2135
|
+
/** App ID, used in the endpoint path (legacy `baseUrl` mode only). */
|
|
2136
|
+
appId?: string;
|
|
2137
|
+
/** Fixed extendable slug inserted between `appId` and the REST path (legacy mode). */
|
|
2138
|
+
extendableSlug?: string;
|
|
2098
2139
|
/** Supplies a valid bearer token for each request. */
|
|
2099
2140
|
getToken: () => string;
|
|
2100
2141
|
/** Backoff delays (ms) applied on successive HTTP 429 responses. */
|
|
@@ -2216,12 +2257,22 @@ declare class CngAccessService {
|
|
|
2216
2257
|
}
|
|
2217
2258
|
|
|
2218
2259
|
interface RestClientOptions {
|
|
2219
|
-
/**
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2260
|
+
/**
|
|
2261
|
+
* The install's app endpoint URL (the install webhook's `apiUrl`). When set it
|
|
2262
|
+
* is the **base URL** and only the REST path is appended (`apiUrl/path`) —
|
|
2263
|
+
* `baseUrl`/`appId`/`extendableSlug` are ignored. Takes precedence over
|
|
2264
|
+
* `baseUrl`.
|
|
2265
|
+
*/
|
|
2266
|
+
apiUrl?: string;
|
|
2267
|
+
/**
|
|
2268
|
+
* Base URL of the backoffice gateway (no trailing slash). Used only when
|
|
2269
|
+
* `apiUrl` is not set; the URL is `baseUrl/appId/extendableSlug/path`.
|
|
2270
|
+
*/
|
|
2271
|
+
baseUrl?: string;
|
|
2272
|
+
/** App ID, used in the endpoint path (legacy `baseUrl` mode only). */
|
|
2273
|
+
appId?: string;
|
|
2274
|
+
/** Fixed extendable slug inserted between `appId` and the REST path (legacy mode). */
|
|
2275
|
+
extendableSlug?: string;
|
|
2225
2276
|
/** Supplies a valid bearer token for each request. */
|
|
2226
2277
|
getToken: () => string;
|
|
2227
2278
|
/** Backoff delays (ms) applied on successive HTTP 429 responses. */
|
|
@@ -2340,6 +2391,52 @@ declare class AcmeAccessService {
|
|
|
2340
2391
|
getAllActivities(): Promise<AcmeActivity[]>;
|
|
2341
2392
|
}
|
|
2342
2393
|
|
|
2394
|
+
/**
|
|
2395
|
+
* Factory that turns a persisted install (or a parsed install webhook) into the
|
|
2396
|
+
* right access service for its platform, wired to the install's own app
|
|
2397
|
+
* endpoint.
|
|
2398
|
+
*
|
|
2399
|
+
* The install webhook is the only source of an install's `platform` and `apiUrl`
|
|
2400
|
+
* (see `src/models/peek/install.ts`), and those two facts are exactly what's
|
|
2401
|
+
* needed to target it: `platform` picks the service class, and `apiUrl` is used
|
|
2402
|
+
* **as given** as that service's endpoint. This helper encodes that mapping so a
|
|
2403
|
+
* consumer that persisted an install can construct its client in one call
|
|
2404
|
+
* instead of switching on the platform and hand-wiring the URL.
|
|
2405
|
+
*/
|
|
2406
|
+
|
|
2407
|
+
/**
|
|
2408
|
+
* The per-install facts needed to build an access service — a structural subset
|
|
2409
|
+
* of {@link InstallWebhook}, so a persisted install record (or the webhook event
|
|
2410
|
+
* itself) satisfies it directly.
|
|
2411
|
+
*/
|
|
2412
|
+
interface InstallAccessTarget {
|
|
2413
|
+
/** Which platform serves the install (the install webhook's `platform`). */
|
|
2414
|
+
platform: PeekPlatform | null;
|
|
2415
|
+
/** The install's app endpoint URL (the install webhook's `apiUrl`), used as given. */
|
|
2416
|
+
apiUrl: string;
|
|
2417
|
+
/** The install id (the install webhook's `installId`) — becomes the JWT subject. */
|
|
2418
|
+
installId: string;
|
|
2419
|
+
}
|
|
2420
|
+
/**
|
|
2421
|
+
* The per-app credentials/options shared by every access service — everything
|
|
2422
|
+
* except the per-install `installId`/`apiUrl` (supplied by the target) and the
|
|
2423
|
+
* deprecated `appId`/`baseUrl`/`mode` URL controls (superseded by `apiUrl`).
|
|
2424
|
+
* `gatewayKey` is accepted for Peek and ignored by CNG/ACME.
|
|
2425
|
+
*/
|
|
2426
|
+
type InstallAccessConfig = Omit<PeekAccessServiceConfig, "installId" | "apiUrl" | "appId" | "baseUrl" | "mode">;
|
|
2427
|
+
/** The union of access services this factory can return, narrowed by `platform`. */
|
|
2428
|
+
type InstallAccessService = PeekAccessService | CngAccessService | AcmeAccessService;
|
|
2429
|
+
/**
|
|
2430
|
+
* Builds the access service for `install.platform`, using `install.apiUrl` as
|
|
2431
|
+
* the service's endpoint. Narrow the return by `install.platform` (or
|
|
2432
|
+
* `instanceof`) to reach a platform-specific surface.
|
|
2433
|
+
*
|
|
2434
|
+
* @throws {Error} when `install.platform` is `null` or unrecognised — an install
|
|
2435
|
+
* with an unknown platform has no service to route to, and silently defaulting
|
|
2436
|
+
* would point it at the wrong gateway.
|
|
2437
|
+
*/
|
|
2438
|
+
declare function createAccessServiceForInstall(install: InstallAccessTarget, config: InstallAccessConfig): InstallAccessService;
|
|
2439
|
+
|
|
2343
2440
|
/**
|
|
2344
2441
|
* Public webhook surface for bookings.
|
|
2345
2442
|
*
|
|
@@ -2431,16 +2528,24 @@ declare function parseWaiverWebhook(payload: unknown, options?: AccessOptions):
|
|
|
2431
2528
|
* POSTs when an app is installed, uninstalled, or updated.
|
|
2432
2529
|
*
|
|
2433
2530
|
* That delivery carries two things at once: a **signed `app_registry_v2` JWT**
|
|
2434
|
-
* (the security boundary) and a plain **JSON body** (the
|
|
2531
|
+
* (the security boundary) and a plain **JSON body** (the event payload).
|
|
2435
2532
|
* `parseInstallWebhook` verifies the JWT and merges both into this shape, so a
|
|
2436
2533
|
* consumer sees one clean, flat, JSON-safe record instead of two differently
|
|
2437
|
-
* shaped payloads. The
|
|
2438
|
-
*
|
|
2439
|
-
*
|
|
2440
|
-
*
|
|
2441
|
-
*
|
|
2442
|
-
*
|
|
2443
|
-
*
|
|
2534
|
+
* shaped payloads. The **JSON body is the source of the event data** — it
|
|
2535
|
+
* carries every field below; the verified JWT authenticates the delivery and
|
|
2536
|
+
* acts as the **fallback** for the fields it also happens to carry (`installId`,
|
|
2537
|
+
* `accountId`, `status`, `displayVersion`, `user`) when the body omits them.
|
|
2538
|
+
*
|
|
2539
|
+
* It is also the single origin of the account id (and the `apiUrl`/`timezone`)
|
|
2540
|
+
* in the whole system: no GraphQL read returns them, so whatever a consumer
|
|
2541
|
+
* persists from this event is all it will ever have.
|
|
2542
|
+
*
|
|
2543
|
+
* **Every install event is a full snapshot — upsert by `installId`.** An
|
|
2544
|
+
* `update_installed` event carries the *same complete record* as the original
|
|
2545
|
+
* `installed` event, so treat each delivery as an upsert keyed by `installId`
|
|
2546
|
+
* and overwrite the stored fields with the incoming ones. This is how the
|
|
2547
|
+
* registry pushes changes — e.g. a new `apiUrl` — so a consumer that only reads
|
|
2548
|
+
* the first `installed` event and ignores later updates will keep stale data.
|
|
2444
2549
|
*/
|
|
2445
2550
|
|
|
2446
2551
|
/**
|
|
@@ -2459,9 +2564,10 @@ type InstallStatus = (typeof INSTALL_STATUSES)[number];
|
|
|
2459
2564
|
* returns is the shape a consumer persists and later rehydrates. There is
|
|
2460
2565
|
* deliberately no nested identity object and no second representation.
|
|
2461
2566
|
*
|
|
2462
|
-
*
|
|
2463
|
-
*
|
|
2464
|
-
*
|
|
2567
|
+
* Every field is read from the **JSON body** first, falling back to the
|
|
2568
|
+
* **verified JWT** for the fields it also carries (`installId`, `accountId`,
|
|
2569
|
+
* `status`, `displayVersion`, `user`). The delivery is authenticated as a whole
|
|
2570
|
+
* by the JWT signature, so the body is trusted within a verified request.
|
|
2465
2571
|
*/
|
|
2466
2572
|
interface InstallWebhook {
|
|
2467
2573
|
/** Install ID — Peek-assigned UUID. Also the JWT subject (`sub`). */
|
|
@@ -2489,6 +2595,31 @@ interface InstallWebhook {
|
|
|
2489
2595
|
platform: PeekPlatform | null;
|
|
2490
2596
|
/** Whether this is a test account. Defaults to `false` when not reported. */
|
|
2491
2597
|
isTest: boolean;
|
|
2598
|
+
/**
|
|
2599
|
+
* The account's IANA timezone (e.g. `"America/New_York"`), or `""` when the
|
|
2600
|
+
* body omits it.
|
|
2601
|
+
*
|
|
2602
|
+
* **Persist this per install.** It has no source other than this event, and
|
|
2603
|
+
* downstream date/time handling for the install (scheduling, day boundaries,
|
|
2604
|
+
* display) needs the account's own timezone rather than the server's.
|
|
2605
|
+
*/
|
|
2606
|
+
timezone: string;
|
|
2607
|
+
/**
|
|
2608
|
+
* The **app endpoint URL** the registry serves this install from (the body's
|
|
2609
|
+
* `api.url`), or `""` when the body omits it.
|
|
2610
|
+
*
|
|
2611
|
+
* Use it **as given** as the base URL for this install's API calls — do not
|
|
2612
|
+
* decompose it or append your own app id. The registry may tag traffic with an
|
|
2613
|
+
* app id in the path; that is the registry's concern and opaque to callers, so
|
|
2614
|
+
* hit the URL unmodified.
|
|
2615
|
+
*
|
|
2616
|
+
* **Persist this per install, and refresh it on every install event.** It is
|
|
2617
|
+
* install-specific, has no source other than this webhook, and the registry
|
|
2618
|
+
* can change it: an `update_installed` event redelivers the full record with a
|
|
2619
|
+
* (possibly new) `apiUrl`, so re-key by `installId` and overwrite the stored
|
|
2620
|
+
* URL whenever an event arrives.
|
|
2621
|
+
*/
|
|
2622
|
+
apiUrl: string;
|
|
2492
2623
|
/**
|
|
2493
2624
|
* The lifecycle status, or `null` when the registry sent a status this
|
|
2494
2625
|
* version of the package does not know. Handle `null` explicitly — treating
|
|
@@ -2501,7 +2632,8 @@ interface InstallWebhook {
|
|
|
2501
2632
|
displayVersion: string;
|
|
2502
2633
|
/**
|
|
2503
2634
|
* The user that triggered the event, or `null` for system-initiated events
|
|
2504
|
-
* (install lifecycle changes are often system-initiated).
|
|
2635
|
+
* (install lifecycle changes are often system-initiated). Read from the body's
|
|
2636
|
+
* `modified_by`, falling back to the JWT's `user`.
|
|
2505
2637
|
*/
|
|
2506
2638
|
user: PeekAuthTokenUser | null;
|
|
2507
2639
|
}
|
|
@@ -2510,12 +2642,14 @@ interface InstallWebhook {
|
|
|
2510
2642
|
* Verifies an install-status webhook token and merges it with the delivered
|
|
2511
2643
|
* JSON body into one flat {@link InstallWebhook}.
|
|
2512
2644
|
*
|
|
2513
|
-
* The **
|
|
2514
|
-
* `
|
|
2515
|
-
*
|
|
2516
|
-
*
|
|
2517
|
-
*
|
|
2518
|
-
*
|
|
2645
|
+
* The **JSON body** is the source of the event data — `installId`, `accountId`,
|
|
2646
|
+
* `accountName`, `platform`, `isTest`, `timezone`, `apiUrl`, `status`,
|
|
2647
|
+
* `displayVersion`, and `user`. The **verified token** authenticates the whole
|
|
2648
|
+
* delivery and is the **fallback** for the fields it also carries (`installId`,
|
|
2649
|
+
* `accountId`, `status`, `displayVersion`, `user`) when the body omits them. A
|
|
2650
|
+
* missing or malformed body degrades the body-only fields (`accountName`,
|
|
2651
|
+
* `platform`, `isTest`, `timezone`, `apiUrl`) to `""`/`null`/`false` and leans
|
|
2652
|
+
* on the token for the rest; it never throws.
|
|
2519
2653
|
*
|
|
2520
2654
|
* Signature verification is strict: the HMAC signature (with `secret`), the
|
|
2521
2655
|
* token expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience are
|
|
@@ -2542,7 +2676,9 @@ interface InstallWebhook {
|
|
|
2542
2676
|
* }
|
|
2543
2677
|
* ```
|
|
2544
2678
|
*
|
|
2545
|
-
* @param token the
|
|
2679
|
+
* @param token the JWT delivered by the install webhook. Pass the raw
|
|
2680
|
+
* `x-peek-auth` header value directly — a leading `Bearer ` prefix, if
|
|
2681
|
+
* present, is stripped for you.
|
|
2546
2682
|
* @param body the delivered JSON body (raw object or a JSON string)
|
|
2547
2683
|
* @param secret the app's HMAC signing secret (the `jwtSecret` you construct
|
|
2548
2684
|
* `PeekAccessService` with)
|
|
@@ -2572,7 +2708,9 @@ declare function parseInstallWebhook(token: string, body: unknown, secret: strin
|
|
|
2572
2708
|
* - `TokenExpiredError` — past `exp`
|
|
2573
2709
|
* - `NotBeforeError` — before `nbf`
|
|
2574
2710
|
*
|
|
2575
|
-
* @param token the
|
|
2711
|
+
* @param token the JWT delivered by the install webhook. Pass the raw
|
|
2712
|
+
* `x-peek-auth` header value directly — a leading `Bearer ` prefix, if
|
|
2713
|
+
* present, is stripped for you.
|
|
2576
2714
|
* @param secret the app's HMAC signing secret (the `jwtSecret` you construct
|
|
2577
2715
|
* `PeekAccessService` with)
|
|
2578
2716
|
* @throws {JsonWebTokenError} signature invalid or token malformed
|
|
@@ -2692,4 +2830,4 @@ declare class AcmeApiError extends Error {
|
|
|
2692
2830
|
constructor(statusCode: number, body: unknown, message?: string);
|
|
2693
2831
|
}
|
|
2694
2832
|
|
|
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 };
|
|
2833
|
+
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 InstallAccessConfig, type InstallAccessService, type InstallAccessTarget, 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, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
|
package/dist/index.js
CHANGED
|
@@ -2022,7 +2022,8 @@ var GraphQLClient = class {
|
|
|
2022
2022
|
);
|
|
2023
2023
|
}
|
|
2024
2024
|
endpoint(endpointName) {
|
|
2025
|
-
const { baseUrl, appId, endpointPathPrefix } = this.options;
|
|
2025
|
+
const { apiUrl, baseUrl, appId, endpointPathPrefix } = this.options;
|
|
2026
|
+
if (apiUrl) return apiUrl;
|
|
2026
2027
|
const prefix = endpointPathPrefix ? `${endpointPathPrefix}/` : "";
|
|
2027
2028
|
return `${baseUrl}/${appId}/${prefix}${endpointName}`;
|
|
2028
2029
|
}
|
|
@@ -2039,8 +2040,13 @@ var GraphQLClient = class {
|
|
|
2039
2040
|
};
|
|
2040
2041
|
var PEEK_TOKEN_ISSUER = "app_registry_v2";
|
|
2041
2042
|
var PEEK_TOKEN_AUDIENCE = "Joken";
|
|
2043
|
+
var BEARER_PREFIX = "bearer ";
|
|
2044
|
+
function stripBearer(token) {
|
|
2045
|
+
const trimmed = token.trim();
|
|
2046
|
+
return trimmed.toLowerCase().startsWith(BEARER_PREFIX) ? trimmed.slice(BEARER_PREFIX.length).trim() : trimmed;
|
|
2047
|
+
}
|
|
2042
2048
|
function verifyPeekJwt(token, secret) {
|
|
2043
|
-
return jwt.verify(token, secret, {
|
|
2049
|
+
return jwt.verify(stripBearer(token), secret, {
|
|
2044
2050
|
issuer: PEEK_TOKEN_ISSUER,
|
|
2045
2051
|
audience: PEEK_TOKEN_AUDIENCE
|
|
2046
2052
|
});
|
|
@@ -3534,25 +3540,27 @@ var PeekAccessService = class {
|
|
|
3534
3540
|
bookingService;
|
|
3535
3541
|
reviewService;
|
|
3536
3542
|
constructor(config) {
|
|
3543
|
+
const hasApiUrl = !!config.apiUrl;
|
|
3537
3544
|
const isV2 = config.mode === "v2";
|
|
3538
3545
|
requireNonEmpty(config.installId, "installId", "PeekAccessService");
|
|
3539
3546
|
requireNonEmpty(config.jwtSecret, "jwtSecret", "PeekAccessService");
|
|
3540
3547
|
requireNonEmpty(config.issuer, "issuer", "PeekAccessService");
|
|
3541
|
-
requireNonEmpty(config.appId, "appId", "PeekAccessService");
|
|
3542
|
-
if (!isV2) requireNonEmpty(config.gatewayKey ?? "", "gatewayKey", "PeekAccessService");
|
|
3548
|
+
if (!hasApiUrl) requireNonEmpty(config.appId ?? "", "appId", "PeekAccessService");
|
|
3549
|
+
if (!hasApiUrl && !isV2) requireNonEmpty(config.gatewayKey ?? "", "gatewayKey", "PeekAccessService");
|
|
3543
3550
|
this.jwtSecret = config.jwtSecret;
|
|
3544
3551
|
const logger = config.logger ?? noopLogger;
|
|
3545
3552
|
const tokens = createTokenManager(config);
|
|
3546
3553
|
const defaultBaseUrl = isV2 ? DEFAULT_V2_BASE_URL : DEFAULT_BASE_URL;
|
|
3547
3554
|
this.client = new GraphQLClient({
|
|
3548
|
-
|
|
3549
|
-
|
|
3555
|
+
apiUrl: config.apiUrl,
|
|
3556
|
+
baseUrl: hasApiUrl ? void 0 : config.baseUrl ?? defaultBaseUrl,
|
|
3557
|
+
appId: hasApiUrl ? void 0 : config.appId,
|
|
3550
3558
|
gatewayKey: config.gatewayKey,
|
|
3551
3559
|
getToken: () => tokens.getToken(),
|
|
3552
3560
|
retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,
|
|
3553
3561
|
logger,
|
|
3554
3562
|
fetchFn: config.fetch ?? globalThis.fetch,
|
|
3555
|
-
endpointPathPrefix: isV2 ? V2_EXTENDABLE_SLUG : void 0
|
|
3563
|
+
endpointPathPrefix: !hasApiUrl && isV2 ? V2_EXTENDABLE_SLUG : void 0
|
|
3556
3564
|
});
|
|
3557
3565
|
this.productServiceOptions = {
|
|
3558
3566
|
itemOptionsPageSize: config.itemOptionsPageSize
|
|
@@ -3564,9 +3572,10 @@ var PeekAccessService = class {
|
|
|
3564
3572
|
* decoded claims.
|
|
3565
3573
|
*
|
|
3566
3574
|
* Validates the HMAC signature (using this service's `jwtSecret`), the token
|
|
3567
|
-
* expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience.
|
|
3568
|
-
*
|
|
3569
|
-
*
|
|
3575
|
+
* expiry, the `"app_registry_v2"` issuer, and the `"Joken"` audience. Pass the
|
|
3576
|
+
* raw `x-peek-auth` request header value — a leading `Bearer ` prefix, if
|
|
3577
|
+
* present, is stripped for you. Throws from the `jsonwebtoken` library on any
|
|
3578
|
+
* failure — callers should catch to distinguish error kinds:
|
|
3570
3579
|
*
|
|
3571
3580
|
* - `JsonWebTokenError` — signature invalid, wrong issuer/audience, or token
|
|
3572
3581
|
* malformed
|
|
@@ -3979,7 +3988,8 @@ var RestClient = class {
|
|
|
3979
3988
|
);
|
|
3980
3989
|
}
|
|
3981
3990
|
endpoint(path) {
|
|
3982
|
-
const { baseUrl, appId, extendableSlug } = this.options;
|
|
3991
|
+
const { apiUrl, baseUrl, appId, extendableSlug } = this.options;
|
|
3992
|
+
if (apiUrl) return `${apiUrl}/${path}`;
|
|
3983
3993
|
return `${baseUrl}/${appId}/${extendableSlug}/${path}`;
|
|
3984
3994
|
}
|
|
3985
3995
|
buildHeaders() {
|
|
@@ -3996,15 +4006,17 @@ var CngAccessService = class {
|
|
|
3996
4006
|
client;
|
|
3997
4007
|
productService;
|
|
3998
4008
|
constructor(config) {
|
|
4009
|
+
const hasApiUrl = !!config.apiUrl;
|
|
3999
4010
|
requireNonEmpty(config.installId, "installId", "CngAccessService");
|
|
4000
4011
|
requireNonEmpty(config.jwtSecret, "jwtSecret", "CngAccessService");
|
|
4001
4012
|
requireNonEmpty(config.issuer, "issuer", "CngAccessService");
|
|
4002
|
-
requireNonEmpty(config.appId, "appId", "CngAccessService");
|
|
4013
|
+
if (!hasApiUrl) requireNonEmpty(config.appId ?? "", "appId", "CngAccessService");
|
|
4003
4014
|
const logger = config.logger ?? noopLogger;
|
|
4004
4015
|
const tokens = createTokenManager(config);
|
|
4005
4016
|
this.client = new RestClient({
|
|
4006
|
-
|
|
4007
|
-
|
|
4017
|
+
apiUrl: config.apiUrl,
|
|
4018
|
+
baseUrl: hasApiUrl ? void 0 : config.baseUrl ?? DEFAULT_BASE_URL2,
|
|
4019
|
+
appId: hasApiUrl ? void 0 : config.appId,
|
|
4008
4020
|
extendableSlug: CNG_EXTENDABLE_SLUG,
|
|
4009
4021
|
getToken: () => tokens.getToken(),
|
|
4010
4022
|
retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,
|
|
@@ -4110,7 +4122,8 @@ var RestClient2 = class {
|
|
|
4110
4122
|
);
|
|
4111
4123
|
}
|
|
4112
4124
|
endpoint(path) {
|
|
4113
|
-
const { baseUrl, appId, extendableSlug } = this.options;
|
|
4125
|
+
const { apiUrl, baseUrl, appId, extendableSlug } = this.options;
|
|
4126
|
+
if (apiUrl) return `${apiUrl}/${path}`;
|
|
4114
4127
|
return `${baseUrl}/${appId}/${extendableSlug}/${path}`;
|
|
4115
4128
|
}
|
|
4116
4129
|
buildHeaders() {
|
|
@@ -4127,15 +4140,17 @@ var AcmeAccessService = class {
|
|
|
4127
4140
|
client;
|
|
4128
4141
|
productService;
|
|
4129
4142
|
constructor(config) {
|
|
4143
|
+
const hasApiUrl = !!config.apiUrl;
|
|
4130
4144
|
requireNonEmpty(config.installId, "installId", "AcmeAccessService");
|
|
4131
4145
|
requireNonEmpty(config.jwtSecret, "jwtSecret", "AcmeAccessService");
|
|
4132
4146
|
requireNonEmpty(config.issuer, "issuer", "AcmeAccessService");
|
|
4133
|
-
requireNonEmpty(config.appId, "appId", "AcmeAccessService");
|
|
4147
|
+
if (!hasApiUrl) requireNonEmpty(config.appId ?? "", "appId", "AcmeAccessService");
|
|
4134
4148
|
const logger = config.logger ?? noopLogger;
|
|
4135
4149
|
const tokens = createTokenManager(config);
|
|
4136
4150
|
this.client = new RestClient2({
|
|
4137
|
-
|
|
4138
|
-
|
|
4151
|
+
apiUrl: config.apiUrl,
|
|
4152
|
+
baseUrl: hasApiUrl ? void 0 : config.baseUrl ?? DEFAULT_BASE_URL3,
|
|
4153
|
+
appId: hasApiUrl ? void 0 : config.appId,
|
|
4139
4154
|
extendableSlug: ACME_EXTENDABLE_SLUG,
|
|
4140
4155
|
getToken: () => tokens.getToken(),
|
|
4141
4156
|
retryDelaysMs: config.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS,
|
|
@@ -4159,6 +4174,23 @@ var AcmeAccessService = class {
|
|
|
4159
4174
|
}
|
|
4160
4175
|
};
|
|
4161
4176
|
|
|
4177
|
+
// src/access-service-factory.ts
|
|
4178
|
+
function createAccessServiceForInstall(install, config) {
|
|
4179
|
+
const shared = { ...config, installId: install.installId, apiUrl: install.apiUrl };
|
|
4180
|
+
switch (install.platform) {
|
|
4181
|
+
case "peek":
|
|
4182
|
+
return new PeekAccessService(shared);
|
|
4183
|
+
case "cng":
|
|
4184
|
+
return new CngAccessService(shared);
|
|
4185
|
+
case "acme":
|
|
4186
|
+
return new AcmeAccessService(shared);
|
|
4187
|
+
default:
|
|
4188
|
+
throw new Error(
|
|
4189
|
+
`createAccessServiceForInstall: unknown or missing platform "${install.platform}" for install "${install.installId}"`
|
|
4190
|
+
);
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4193
|
+
|
|
4162
4194
|
// src/internal/peek/bookings/booking-webhook.ts
|
|
4163
4195
|
var PAYLOAD_BOOKING_KEY = "booking";
|
|
4164
4196
|
var VALUE_OPEN_TOKEN = "value {";
|
|
@@ -4282,20 +4314,27 @@ function toPeekPlatform(raw) {
|
|
|
4282
4314
|
// src/internal/peek/installs/install-webhook.ts
|
|
4283
4315
|
function parseInstallWebhook(token, body, secret) {
|
|
4284
4316
|
const payload = verifyPeekJwt(token, secret);
|
|
4285
|
-
const
|
|
4286
|
-
const
|
|
4317
|
+
const parsed = extractInstallWebhookBody(body);
|
|
4318
|
+
const account = parsed.account ?? {};
|
|
4319
|
+
const rawStatus = parsed.status || payload.status || "";
|
|
4287
4320
|
return {
|
|
4288
|
-
installId: payload.sub
|
|
4289
|
-
accountId: payload.account?.id
|
|
4321
|
+
installId: parsed.install_id || payload.sub || "",
|
|
4322
|
+
accountId: account.id || payload.account?.id || "",
|
|
4290
4323
|
accountName: account.name || "",
|
|
4291
4324
|
platform: toPeekPlatform(account.platform || ""),
|
|
4292
4325
|
isTest: Boolean(account.is_test),
|
|
4326
|
+
timezone: account.timezone || "",
|
|
4327
|
+
apiUrl: parsed.api?.url || "",
|
|
4293
4328
|
status: toInstallStatus(rawStatus),
|
|
4294
4329
|
rawStatus,
|
|
4295
|
-
displayVersion: payload.display_version
|
|
4296
|
-
user:
|
|
4330
|
+
displayVersion: parsed.display_version || payload.display_version || "",
|
|
4331
|
+
user: resolveInstallUser(parsed.modified_by, payload.user)
|
|
4297
4332
|
};
|
|
4298
4333
|
}
|
|
4334
|
+
function resolveInstallUser(bodyUser, tokenUser) {
|
|
4335
|
+
if (bodyUser?.id) return mapPeekTokenUser(bodyUser);
|
|
4336
|
+
return tokenUser ? mapPeekTokenUser(tokenUser) : null;
|
|
4337
|
+
}
|
|
4299
4338
|
function verifyInstallWebhook(token, secret) {
|
|
4300
4339
|
const payload = verifyPeekJwt(token, secret);
|
|
4301
4340
|
return {
|
|
@@ -4307,6 +4346,6 @@ function verifyInstallWebhook(token, secret) {
|
|
|
4307
4346
|
};
|
|
4308
4347
|
}
|
|
4309
4348
|
|
|
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 };
|
|
4349
|
+
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, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
|
|
4311
4350
|
//# sourceMappingURL=index.js.map
|
|
4312
4351
|
//# sourceMappingURL=index.js.map
|