@peektravel/app-utilities 0.5.2 → 0.5.3
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 +69 -14
- package/dist/index.cjs +102 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -5
- package/dist/index.d.ts +76 -5
- package/dist/index.js +101 -40
- package/dist/index.js.map +1 -1
- package/dist/ui/index.cjs +35 -1
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.js +35 -1
- package/dist/ui/index.js.map +1 -1
- package/docs/ui.md +26 -2
- package/docs/webhooks.md +80 -9
- package/llms.txt +28 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -109,8 +109,14 @@ Two kinds of failures surface as exceptions:
|
|
|
109
109
|
rights). Carries `.statusCode === 418`.
|
|
110
110
|
- `RateLimitError` — HTTP 429 after the configured `retryDelaysMs` backoff was
|
|
111
111
|
exhausted. Carries `.statusCode === 429`.
|
|
112
|
-
- `PeekGraphQLError` — the response contained a GraphQL `errors` array
|
|
113
|
-
on `.graphqlErrors`.
|
|
112
|
+
- `PeekGraphQLError` — the response contained a GraphQL `errors` array (a
|
|
113
|
+
resolver-level failure), preserved on `.graphqlErrors`.
|
|
114
|
+
- `PeekHttpError` — the gateway returned a non-2xx HTTP status (other than
|
|
115
|
+
418/429) with no GraphQL `errors` array — a transport-level failure such as
|
|
116
|
+
`401` (auth/secret wrong), `404` (wrong app id / not provisioned), or `5xx`.
|
|
117
|
+
Carries `.statusCode`, `.url`, and the raw `.body` (parsed JSON when possible,
|
|
118
|
+
otherwise the response text). Surfaced *before* the body is parsed as JSON, so
|
|
119
|
+
a non-JSON error page reports its real status instead of a JSON parse error.
|
|
114
120
|
- `PiiAccessDisabledError` — a payment / booking-modification operation was
|
|
115
121
|
called on an access service created without `fullCustomerAccess` (see [Access options
|
|
116
122
|
/ PII](#access-options--pii)). Carries `.operation` (the blocked method name).
|
|
@@ -127,6 +133,7 @@ import {
|
|
|
127
133
|
RateLimitError,
|
|
128
134
|
AdminAccountRequiredError,
|
|
129
135
|
PeekGraphQLError,
|
|
136
|
+
PeekHttpError,
|
|
130
137
|
} from '@peektravel/app-utilities';
|
|
131
138
|
|
|
132
139
|
try {
|
|
@@ -136,6 +143,8 @@ try {
|
|
|
136
143
|
// back off and retry later
|
|
137
144
|
} else if (err instanceof AdminAccountRequiredError) {
|
|
138
145
|
// this install can't perform admin-only operations
|
|
146
|
+
} else if (err instanceof PeekHttpError) {
|
|
147
|
+
console.error(err.statusCode, err.url, err.body); // which config is wrong
|
|
139
148
|
} else if (err instanceof PeekGraphQLError) {
|
|
140
149
|
console.error(err.graphqlErrors); // raw gateway errors
|
|
141
150
|
} else {
|
|
@@ -229,16 +238,20 @@ Functions runtime) resolve correctly. Its only runtime dependency is
|
|
|
229
238
|
|
|
230
239
|
## Webhooks
|
|
231
240
|
|
|
232
|
-
Receiver apps can consume Peek **booking** and **
|
|
233
|
-
hand-writing
|
|
234
|
-
auth/network) that returns a
|
|
241
|
+
Receiver apps can consume Peek **booking**, **waiver**, and **install-status**
|
|
242
|
+
webhooks without hand-writing the payload handling. The booking and waiver
|
|
243
|
+
webhooks have a pure parser (construct nothing — no auth/network) that returns a
|
|
244
|
+
clean model; the install-status webhook delivers a signed token, so its helper
|
|
245
|
+
**verifies** it:
|
|
235
246
|
|
|
236
247
|
```ts
|
|
237
248
|
import {
|
|
238
249
|
parseBookingWebhook,
|
|
239
250
|
parseWaiverWebhook,
|
|
251
|
+
verifyInstallWebhook,
|
|
240
252
|
type Booking,
|
|
241
253
|
type Waiver,
|
|
254
|
+
type InstallWebhookClaims,
|
|
242
255
|
} from "@peektravel/app-utilities";
|
|
243
256
|
|
|
244
257
|
app.post("/booking-webhook", (req, res) => {
|
|
@@ -251,17 +264,38 @@ app.post("/waiver-webhook", (req, res) => {
|
|
|
251
264
|
const waiver: Waiver = parseWaiverWebhook(req.body, { fullCustomerAccess: true });
|
|
252
265
|
res.sendStatus(200);
|
|
253
266
|
});
|
|
267
|
+
|
|
268
|
+
app.post("/install-webhook", (req, res) => {
|
|
269
|
+
try {
|
|
270
|
+
// The payload IS a signed JWT — verify signature/issuer/audience/expiry:
|
|
271
|
+
const claims: InstallWebhookClaims = verifyInstallWebhook(req.body, process.env.PEEK_INTERNAL_SECRET!);
|
|
272
|
+
if (claims.status === "uninstalled") {
|
|
273
|
+
/* tear down this install */
|
|
274
|
+
}
|
|
275
|
+
res.sendStatus(200);
|
|
276
|
+
} catch {
|
|
277
|
+
res.sendStatus(401); // bad signature / issuer / audience / expired
|
|
278
|
+
}
|
|
279
|
+
});
|
|
254
280
|
```
|
|
255
281
|
|
|
256
|
-
|
|
257
|
-
on malformed input
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
282
|
+
The booking and waiver parsers tolerate the delivery envelope / a bare node / a
|
|
283
|
+
JSON string and never throw on malformed input; **authenticating those deliveries
|
|
284
|
+
is the receiver's job**. `parseWaiverWebhook` also takes an optional
|
|
285
|
+
`AccessOptions` (`{ fullCustomerAccess }`) and redacts the participant `guestName`
|
|
286
|
+
+ document `fileUrl` by default — see [Access options / PII](#access-options--pii)
|
|
287
|
+
below. `verifyInstallWebhook(token, secret)` is different: the payload is a signed
|
|
288
|
+
`app_registry_v2` JWT, so it validates the HMAC signature, expiry, issuer, and
|
|
289
|
+
`"Joken"` audience (the same checks as `verifyPeekAuthToken`) and returns typed
|
|
290
|
+
claims (`installId`, `account.id`, `status`, `displayVersion`, and a **nullable**
|
|
291
|
+
`user` for system-initiated events), throwing the underlying `jsonwebtoken` error
|
|
292
|
+
on any failure. The booking and waiver webhooks differ on registration: a
|
|
293
|
+
**booking** webhook's payload shape is set by a GraphQL query configured **once in
|
|
294
|
+
an external system** (the App Store `broadcast_to_url` config) — this package
|
|
295
|
+
documents and drift-guards the exact query to paste there — whereas the **waiver**
|
|
296
|
+
and **install-status** webhooks have fixed payloads, so you just subscribe to
|
|
297
|
+
their event with no query. **The query to register and the full guide:
|
|
298
|
+
[`docs/webhooks.md`](docs/webhooks.md) (shipped).**
|
|
265
299
|
|
|
266
300
|
## UI components (`/ui`)
|
|
267
301
|
|
|
@@ -299,6 +333,27 @@ attribute. Exported classes/types and helpers (`iconSvg`, `registerIcon`,
|
|
|
299
333
|
`portal`, `position`, `toast`) are available from `@peektravel/app-utilities/ui`
|
|
300
334
|
for subclassing or typing.
|
|
301
335
|
|
|
336
|
+
### Using the components from React 19
|
|
337
|
+
|
|
338
|
+
React 19 sets JSX props on a custom element as DOM **properties**
|
|
339
|
+
(`el.searchable = true`), not attributes. That's handled for you: every
|
|
340
|
+
reflected/read-only accessor accepts assignment, so `<ody-dropdown-single
|
|
341
|
+
searchable options={items} />` and friends work without the
|
|
342
|
+
`Cannot set property … which has only a getter` crash that a getter-only
|
|
343
|
+
property would otherwise cause. Two things worth knowing:
|
|
344
|
+
|
|
345
|
+
- **Boolean and data props reflect to the attribute**, so they take effect as
|
|
346
|
+
expected. Pass booleans as real booleans (`searchable={true}`) and rich data
|
|
347
|
+
as values (`options={items}`) — the object is reflected as a JSON attribute.
|
|
348
|
+
- **Read-only state accessors are inert to assignment.** Props that mirror live
|
|
349
|
+
internal state (`isOpen`, `isVisible`) ignore writes — drive them through the
|
|
350
|
+
imperative methods on a `ref` (`ref.current.openPopover()`, `.show()`) and read
|
|
351
|
+
them back through the component's `CustomEvent`s, not by setting the prop.
|
|
352
|
+
|
|
353
|
+
TypeScript still types these accessors as read-only, so a direct
|
|
354
|
+
`el.isOpen = true` in TS is flagged — the setters are a runtime safety net for
|
|
355
|
+
framework-driven assignment, not an invitation to write to derived state.
|
|
356
|
+
|
|
302
357
|
**Try the gallery:** `npm run sample` builds the package and serves
|
|
303
358
|
`examples/ui-gallery.html`, which shows every component with its variants.
|
|
304
359
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var jwt = require('jsonwebtoken');
|
|
4
3
|
var crypto = require('crypto');
|
|
4
|
+
var jwt = require('jsonwebtoken');
|
|
5
5
|
|
|
6
6
|
function _interopNamespace(e) {
|
|
7
7
|
if (e && e.__esModule) return e;
|
|
@@ -23,8 +23,6 @@ function _interopNamespace(e) {
|
|
|
23
23
|
|
|
24
24
|
var jwt__namespace = /*#__PURE__*/_interopNamespace(jwt);
|
|
25
25
|
|
|
26
|
-
// src/peek-access-service.ts
|
|
27
|
-
|
|
28
26
|
// src/internal/peek/gateway-endpoints.ts
|
|
29
27
|
var SALES_ENDPOINT = "sales";
|
|
30
28
|
var V2_EXTENDABLE_SLUG = "peek_backoffice_api-v1";
|
|
@@ -234,6 +232,21 @@ var PeekGraphQLError = class extends Error {
|
|
|
234
232
|
this.graphqlErrors = graphqlErrors;
|
|
235
233
|
}
|
|
236
234
|
};
|
|
235
|
+
var PeekHttpError = class extends Error {
|
|
236
|
+
/** The HTTP status that triggered this error. */
|
|
237
|
+
statusCode;
|
|
238
|
+
/** The request URL that produced the failing response. */
|
|
239
|
+
url;
|
|
240
|
+
/** The raw response body (parsed JSON when possible, otherwise text). */
|
|
241
|
+
body;
|
|
242
|
+
constructor(statusCode, url, body, message) {
|
|
243
|
+
super(message ?? `Peek request failed with HTTP ${statusCode}`);
|
|
244
|
+
this.name = "PeekHttpError";
|
|
245
|
+
this.statusCode = statusCode;
|
|
246
|
+
this.url = url;
|
|
247
|
+
this.body = body;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
237
250
|
var PiiAccessDisabledError = class extends Error {
|
|
238
251
|
/** The name of the operation that was blocked (e.g. `"makePayment"`). */
|
|
239
252
|
operation;
|
|
@@ -1944,6 +1957,14 @@ function createTokenManager(config) {
|
|
|
1944
1957
|
var RATE_LIMIT_STATUS = 429;
|
|
1945
1958
|
var ADMIN_ACCOUNT_REQUIRED_STATUS = 418;
|
|
1946
1959
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1960
|
+
async function parseBody(response) {
|
|
1961
|
+
const text = await response.text();
|
|
1962
|
+
try {
|
|
1963
|
+
return JSON.parse(text);
|
|
1964
|
+
} catch {
|
|
1965
|
+
return text;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1947
1968
|
async function requestWithRetry(http, url, init, label, onResponse) {
|
|
1948
1969
|
const { retryDelaysMs, logger, fetchFn } = http;
|
|
1949
1970
|
for (let attempt = 0; attempt <= retryDelaysMs.length; attempt++) {
|
|
@@ -1970,6 +1991,7 @@ async function requestWithRetry(http, url, init, label, onResponse) {
|
|
|
1970
1991
|
}
|
|
1971
1992
|
|
|
1972
1993
|
// src/internal/peek/graphql-client.ts
|
|
1994
|
+
var isObject = (value) => typeof value === "object" && value !== null;
|
|
1973
1995
|
var GraphQLClient = class {
|
|
1974
1996
|
constructor(options) {
|
|
1975
1997
|
this.options = options;
|
|
@@ -1995,7 +2017,8 @@ var GraphQLClient = class {
|
|
|
1995
2017
|
},
|
|
1996
2018
|
endpointName,
|
|
1997
2019
|
async (response) => {
|
|
1998
|
-
const
|
|
2020
|
+
const raw = await parseBody(response);
|
|
2021
|
+
const body = isObject(raw) ? raw : {};
|
|
1999
2022
|
if (body.errors) {
|
|
2000
2023
|
logger.error(`GraphQL errors for ${endpointName}`, {
|
|
2001
2024
|
url,
|
|
@@ -2005,7 +2028,7 @@ var GraphQLClient = class {
|
|
|
2005
2028
|
}
|
|
2006
2029
|
if (!response.ok) {
|
|
2007
2030
|
logger.error(`GraphQL request failed with HTTP ${response.status}`, { url });
|
|
2008
|
-
throw new
|
|
2031
|
+
throw new PeekHttpError(response.status, url, raw);
|
|
2009
2032
|
}
|
|
2010
2033
|
return body;
|
|
2011
2034
|
}
|
|
@@ -2027,6 +2050,24 @@ var GraphQLClient = class {
|
|
|
2027
2050
|
return headers;
|
|
2028
2051
|
}
|
|
2029
2052
|
};
|
|
2053
|
+
var PEEK_TOKEN_ISSUER = "app_registry_v2";
|
|
2054
|
+
var PEEK_TOKEN_AUDIENCE = "Joken";
|
|
2055
|
+
function verifyPeekJwt(token, secret) {
|
|
2056
|
+
return jwt__namespace.verify(token, secret, {
|
|
2057
|
+
issuer: PEEK_TOKEN_ISSUER,
|
|
2058
|
+
audience: PEEK_TOKEN_AUDIENCE
|
|
2059
|
+
});
|
|
2060
|
+
}
|
|
2061
|
+
function mapPeekTokenUser(u) {
|
|
2062
|
+
return {
|
|
2063
|
+
email: u.email,
|
|
2064
|
+
id: u.id,
|
|
2065
|
+
isAdmin: u.is_admin,
|
|
2066
|
+
locale: u.locale,
|
|
2067
|
+
name: u.name,
|
|
2068
|
+
platform: u.platform
|
|
2069
|
+
};
|
|
2070
|
+
}
|
|
2030
2071
|
|
|
2031
2072
|
// src/internal/peek/memberships/membership-converter.ts
|
|
2032
2073
|
function fromMembershipsResponse(response) {
|
|
@@ -2495,10 +2536,17 @@ function fromTimeslotNode(node, productId) {
|
|
|
2495
2536
|
durationMin: node.minuteLength ?? 0,
|
|
2496
2537
|
date: node.date || "",
|
|
2497
2538
|
startTime: node.start ?? null,
|
|
2498
|
-
assignedResources: mapAssignedResources(node
|
|
2539
|
+
assignedResources: mapAssignedResources(selectResourceAllocations(node))
|
|
2499
2540
|
};
|
|
2500
2541
|
}
|
|
2501
2542
|
var ACTIVE_ALLOCATION_STATUS = "ACTIVE";
|
|
2543
|
+
function selectResourceAllocations(node) {
|
|
2544
|
+
const inherited = node.inheritedResourceAllocations;
|
|
2545
|
+
if (Array.isArray(inherited) && inherited.length > 0) {
|
|
2546
|
+
return inherited;
|
|
2547
|
+
}
|
|
2548
|
+
return node.resourceAllocations;
|
|
2549
|
+
}
|
|
2502
2550
|
function mapAssignedResources(allocations) {
|
|
2503
2551
|
if (!Array.isArray(allocations) || allocations.length === 0) {
|
|
2504
2552
|
return [];
|
|
@@ -2585,9 +2633,24 @@ var TIMESLOTS_QUERY = `
|
|
|
2585
2633
|
status
|
|
2586
2634
|
date
|
|
2587
2635
|
inheritedResourceAllocations {
|
|
2636
|
+
id
|
|
2637
|
+
status
|
|
2638
|
+
quantity
|
|
2639
|
+
resourcePool {
|
|
2640
|
+
id
|
|
2641
|
+
name
|
|
2642
|
+
category
|
|
2643
|
+
capacity
|
|
2644
|
+
accountUser {
|
|
2645
|
+
id
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
resourceAllocations {
|
|
2588
2650
|
quantity
|
|
2589
2651
|
status
|
|
2590
2652
|
resourcePool {
|
|
2653
|
+
id
|
|
2591
2654
|
name
|
|
2592
2655
|
category
|
|
2593
2656
|
capacity
|
|
@@ -2623,9 +2686,24 @@ var TIMESLOT_BY_ID_QUERY = `
|
|
|
2623
2686
|
status
|
|
2624
2687
|
date
|
|
2625
2688
|
inheritedResourceAllocations {
|
|
2689
|
+
id
|
|
2690
|
+
status
|
|
2691
|
+
quantity
|
|
2692
|
+
resourcePool {
|
|
2693
|
+
id
|
|
2694
|
+
name
|
|
2695
|
+
category
|
|
2696
|
+
capacity
|
|
2697
|
+
accountUser {
|
|
2698
|
+
id
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
resourceAllocations {
|
|
2626
2703
|
quantity
|
|
2627
2704
|
status
|
|
2628
2705
|
resourcePool {
|
|
2706
|
+
id
|
|
2629
2707
|
name
|
|
2630
2708
|
category
|
|
2631
2709
|
capacity
|
|
@@ -3430,7 +3508,6 @@ var noopLogger = {
|
|
|
3430
3508
|
// src/peek-access-service.ts
|
|
3431
3509
|
var DEFAULT_BASE_URL = "https://apps.peekapis.com/backoffice-gql";
|
|
3432
3510
|
var DEFAULT_V2_BASE_URL = "https://app-registry.peeklabs.com/installations-api";
|
|
3433
|
-
var PEEK_TOKEN_ISSUER = "app_registry_v2";
|
|
3434
3511
|
var PeekAccessService = class {
|
|
3435
3512
|
client;
|
|
3436
3513
|
productServiceOptions;
|
|
@@ -3493,21 +3570,11 @@ var PeekAccessService = class {
|
|
|
3493
3570
|
* @throws {NotBeforeError} token not yet valid
|
|
3494
3571
|
*/
|
|
3495
3572
|
verifyPeekAuthToken(token) {
|
|
3496
|
-
const payload =
|
|
3497
|
-
issuer: PEEK_TOKEN_ISSUER
|
|
3498
|
-
});
|
|
3499
|
-
const { user: u } = payload;
|
|
3573
|
+
const payload = verifyPeekJwt(token, this.jwtSecret);
|
|
3500
3574
|
return {
|
|
3501
3575
|
installId: payload.sub,
|
|
3502
3576
|
displayVersion: payload.display_version,
|
|
3503
|
-
user:
|
|
3504
|
-
email: u.email,
|
|
3505
|
-
id: u.id,
|
|
3506
|
-
isAdmin: u.is_admin,
|
|
3507
|
-
locale: u.locale,
|
|
3508
|
-
name: u.name,
|
|
3509
|
-
platform: u.platform
|
|
3510
|
-
}
|
|
3577
|
+
user: mapPeekTokenUser(payload.user)
|
|
3511
3578
|
};
|
|
3512
3579
|
}
|
|
3513
3580
|
/**
|
|
@@ -3891,7 +3958,7 @@ var RestClient = class {
|
|
|
3891
3958
|
{ method: "GET", headers: this.buildHeaders() },
|
|
3892
3959
|
path,
|
|
3893
3960
|
async (response) => {
|
|
3894
|
-
const body = await
|
|
3961
|
+
const body = await parseBody(response);
|
|
3895
3962
|
if (!response.ok) {
|
|
3896
3963
|
logger.error(`CNG request failed with HTTP ${response.status}`, { url });
|
|
3897
3964
|
throw new CngApiError(response.status, body);
|
|
@@ -3900,15 +3967,6 @@ var RestClient = class {
|
|
|
3900
3967
|
}
|
|
3901
3968
|
);
|
|
3902
3969
|
}
|
|
3903
|
-
/** Reads the response body as JSON, falling back to raw text when unparseable. */
|
|
3904
|
-
async parseBody(response) {
|
|
3905
|
-
const text = await response.text();
|
|
3906
|
-
try {
|
|
3907
|
-
return JSON.parse(text);
|
|
3908
|
-
} catch {
|
|
3909
|
-
return text;
|
|
3910
|
-
}
|
|
3911
|
-
}
|
|
3912
3970
|
endpoint(path) {
|
|
3913
3971
|
const { baseUrl, appId, extendableSlug } = this.options;
|
|
3914
3972
|
return `${baseUrl}/${appId}/${extendableSlug}/${path}`;
|
|
@@ -4031,7 +4089,7 @@ var RestClient2 = class {
|
|
|
4031
4089
|
{ method: "GET", headers: this.buildHeaders() },
|
|
4032
4090
|
path,
|
|
4033
4091
|
async (response) => {
|
|
4034
|
-
const body = await
|
|
4092
|
+
const body = await parseBody(response);
|
|
4035
4093
|
if (!response.ok) {
|
|
4036
4094
|
logger.error(`ACME request failed with HTTP ${response.status}`, { url });
|
|
4037
4095
|
throw new AcmeApiError(response.status, body);
|
|
@@ -4040,15 +4098,6 @@ var RestClient2 = class {
|
|
|
4040
4098
|
}
|
|
4041
4099
|
);
|
|
4042
4100
|
}
|
|
4043
|
-
/** Reads the response body as JSON, falling back to raw text when unparseable. */
|
|
4044
|
-
async parseBody(response) {
|
|
4045
|
-
const text = await response.text();
|
|
4046
|
-
try {
|
|
4047
|
-
return JSON.parse(text);
|
|
4048
|
-
} catch {
|
|
4049
|
-
return text;
|
|
4050
|
-
}
|
|
4051
|
-
}
|
|
4052
4101
|
endpoint(path) {
|
|
4053
4102
|
const { baseUrl, appId, extendableSlug } = this.options;
|
|
4054
4103
|
return `${baseUrl}/${appId}/${extendableSlug}/${path}`;
|
|
@@ -4189,6 +4238,18 @@ function extractWaiverNode(payload) {
|
|
|
4189
4238
|
return record;
|
|
4190
4239
|
}
|
|
4191
4240
|
|
|
4241
|
+
// src/internal/peek/installs/install-webhook.ts
|
|
4242
|
+
function verifyInstallWebhook(token, secret) {
|
|
4243
|
+
const payload = verifyPeekJwt(token, secret);
|
|
4244
|
+
return {
|
|
4245
|
+
installId: payload.sub ?? "",
|
|
4246
|
+
account: { id: payload.account?.id ?? "" },
|
|
4247
|
+
status: payload.status ?? "",
|
|
4248
|
+
displayVersion: payload.display_version ?? "",
|
|
4249
|
+
user: payload.user ? mapPeekTokenUser(payload.user) : null
|
|
4250
|
+
};
|
|
4251
|
+
}
|
|
4252
|
+
|
|
4192
4253
|
exports.ACTIVITY_PRODUCT_TYPE = ACTIVITY_PRODUCT_TYPE;
|
|
4193
4254
|
exports.ADD_ON_PRODUCT_TYPE = ADD_ON_PRODUCT_TYPE;
|
|
4194
4255
|
exports.AccountUserService = AccountUserService;
|
|
@@ -4205,6 +4266,7 @@ exports.DailyNoteService = DailyNoteService;
|
|
|
4205
4266
|
exports.MembershipService = MembershipService;
|
|
4206
4267
|
exports.PeekAccessService = PeekAccessService;
|
|
4207
4268
|
exports.PeekGraphQLError = PeekGraphQLError;
|
|
4269
|
+
exports.PeekHttpError = PeekHttpError;
|
|
4208
4270
|
exports.PiiAccessDisabledError = PiiAccessDisabledError;
|
|
4209
4271
|
exports.PricingService = PricingService;
|
|
4210
4272
|
exports.ProductService = ProductService;
|
|
@@ -4218,5 +4280,6 @@ exports.TimeslotService = TimeslotService;
|
|
|
4218
4280
|
exports.noopLogger = noopLogger;
|
|
4219
4281
|
exports.parseBookingWebhook = parseBookingWebhook;
|
|
4220
4282
|
exports.parseWaiverWebhook = parseWaiverWebhook;
|
|
4283
|
+
exports.verifyInstallWebhook = verifyInstallWebhook;
|
|
4221
4284
|
//# sourceMappingURL=index.cjs.map
|
|
4222
4285
|
//# sourceMappingURL=index.cjs.map
|