@peektravel/app-utilities 0.8.0 → 0.8.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/dist/index.cjs +74 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -19
- package/dist/index.d.ts +53 -19
- package/dist/index.js +74 -22
- package/dist/index.js.map +1 -1
- package/llms.txt +14 -3
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -896,6 +896,14 @@ interface CreateBookingInput {
|
|
|
896
896
|
* invalid checkbox value fails creation before any quote is made.
|
|
897
897
|
*/
|
|
898
898
|
customQuestionAnswers?: CustomQuestionAnswerInput[];
|
|
899
|
+
/**
|
|
900
|
+
* When `true`, creation fails if any of the activity's required custom
|
|
901
|
+
* questions (per-guest questions excluded) is left unanswered. Because this
|
|
902
|
+
* enforces coverage against the activity's questions, it forces custom-question
|
|
903
|
+
* validation to run even when `customQuestionAnswers` is empty or omitted.
|
|
904
|
+
* Default: `false`.
|
|
905
|
+
*/
|
|
906
|
+
requireRequiredQuestions?: boolean;
|
|
899
907
|
/** Suppress the customer confirmation email. Default: false. */
|
|
900
908
|
skipCustomerEmail?: boolean;
|
|
901
909
|
/** Clone the quote from an existing order. */
|
|
@@ -1268,8 +1276,9 @@ declare class BookingService {
|
|
|
1268
1276
|
*
|
|
1269
1277
|
* @throws {Error} when `activityId`, `availabilityTimeId`, a ticket
|
|
1270
1278
|
* `resourceOptionId`/positive `quantity`, or the guest `name` is missing; when
|
|
1271
|
-
* `markAsPaid` is set without an `idempotencyKey`;
|
|
1272
|
-
*
|
|
1279
|
+
* `markAsPaid` is set without an `idempotencyKey`; when
|
|
1280
|
+
* `requireRequiredQuestions` is set and a required custom question is left
|
|
1281
|
+
* unanswered; or when the quote/order mutations fail.
|
|
1273
1282
|
*/
|
|
1274
1283
|
create(input: CreateBookingInput): Promise<CreatedBooking>;
|
|
1275
1284
|
/**
|
|
@@ -2291,6 +2300,7 @@ declare class RestClient$1 {
|
|
|
2291
2300
|
*
|
|
2292
2301
|
* @throws {AdminAccountRequiredError} on HTTP 418
|
|
2293
2302
|
* @throws {RateLimitError} on HTTP 429 after retries are exhausted
|
|
2303
|
+
* @throws {CngPermissionError} on HTTP 403 (app missing a permission)
|
|
2294
2304
|
* @throws {CngApiError} on any other non-2xx response
|
|
2295
2305
|
*/
|
|
2296
2306
|
get<T>(path: string): Promise<T>;
|
|
@@ -2312,23 +2322,30 @@ declare class RestClient$1 {
|
|
|
2312
2322
|
*
|
|
2313
2323
|
* `CngAccessService.getAllActivities()` returns these as a flat list.
|
|
2314
2324
|
*
|
|
2315
|
-
*
|
|
2316
|
-
* `
|
|
2317
|
-
*
|
|
2325
|
+
* Mapped from the `app-registry/products` REST payload — see
|
|
2326
|
+
* `internal/cng/products/product-queries.ts`. That payload carries no
|
|
2327
|
+
* product-type discriminator and no sub-options, so `type` is always
|
|
2328
|
+
* {@link ACTIVITY_PRODUCT_TYPE} and `tickets` is always empty.
|
|
2318
2329
|
*/
|
|
2319
2330
|
interface Activity {
|
|
2320
2331
|
/** Stable unique identifier for the activity. */
|
|
2321
2332
|
productId: string;
|
|
2322
2333
|
/** Human-readable display name. */
|
|
2323
2334
|
name: string;
|
|
2324
|
-
/**
|
|
2335
|
+
/**
|
|
2336
|
+
* Product type. Always {@link ACTIVITY_PRODUCT_TYPE} — the CNG products
|
|
2337
|
+
* payload has no type discriminator. Kept for parity with the Peek `Product`.
|
|
2338
|
+
*/
|
|
2325
2339
|
type: string;
|
|
2326
2340
|
/**
|
|
2327
|
-
* Display color as a hex string (e.g. `"#1A2B3C"`)
|
|
2328
|
-
* color is set.
|
|
2341
|
+
* Display color as a hex string (e.g. `"#1A2B3C"`), from the product's
|
|
2342
|
+
* access-control color. Empty string when no color is set.
|
|
2329
2343
|
*/
|
|
2330
2344
|
color: string;
|
|
2331
|
-
/**
|
|
2345
|
+
/**
|
|
2346
|
+
* The bookable sub-options (tickets) of this activity. Always empty — CNG
|
|
2347
|
+
* exposes no tickets on the products endpoint today.
|
|
2348
|
+
*/
|
|
2332
2349
|
tickets: ActivityTicket[];
|
|
2333
2350
|
}
|
|
2334
2351
|
/** A single bookable sub-option (ticket) of an {@link Activity}. */
|
|
@@ -2855,15 +2872,6 @@ declare function parseInstallWebhook(token: string, body: unknown, secret: strin
|
|
|
2855
2872
|
*/
|
|
2856
2873
|
declare function verifyInstallWebhook(token: string, secret: string): InstallWebhookClaims;
|
|
2857
2874
|
|
|
2858
|
-
/**
|
|
2859
|
-
* Typed errors thrown by the package. Each mirrors a failure mode of the Peek
|
|
2860
|
-
* GraphQL gateway (or the CNG REST gateway) so callers can branch on the error
|
|
2861
|
-
* type rather than parsing messages.
|
|
2862
|
-
*
|
|
2863
|
-
* `AdminAccountRequiredError` and `RateLimitError` are shared by all gateways.
|
|
2864
|
-
* `PeekGraphQLError` is Peek-only; `CngApiError` is CNG-only; `AcmeApiError` is
|
|
2865
|
-
* ACME-only.
|
|
2866
|
-
*/
|
|
2867
2875
|
/**
|
|
2868
2876
|
* Thrown when the gateway responds with HTTP 418, indicating the install is not
|
|
2869
2877
|
* permitted to perform the request because an admin account is required.
|
|
@@ -2938,6 +2946,32 @@ declare class CngApiError extends Error {
|
|
|
2938
2946
|
readonly body: unknown;
|
|
2939
2947
|
constructor(statusCode: number, body: unknown, message?: string);
|
|
2940
2948
|
}
|
|
2949
|
+
/**
|
|
2950
|
+
* Thrown when the CNG REST gateway responds with HTTP 403 because the app lacks
|
|
2951
|
+
* a permission the endpoint requires (e.g. `products:read`). This is an
|
|
2952
|
+
* **expected** failure for a misconfigured install — not a bug — so the
|
|
2953
|
+
* transport logs it at `warn` rather than `error` and leaves presentation to the
|
|
2954
|
+
* caller, which can branch on the type and surface the missing permission
|
|
2955
|
+
* however its UI prefers.
|
|
2956
|
+
*
|
|
2957
|
+
* The permission names the gateway named are on
|
|
2958
|
+
* {@link CngPermissionError.permissions} (empty when the body does not name
|
|
2959
|
+
* any), so a caller can render them without re-parsing the raw body. Thrown in
|
|
2960
|
+
* place of {@link CngApiError} for 403s only; every other non-2xx status still
|
|
2961
|
+
* throws `CngApiError`.
|
|
2962
|
+
*/
|
|
2963
|
+
declare class CngPermissionError extends Error {
|
|
2964
|
+
/** The HTTP status that triggered this error. */
|
|
2965
|
+
readonly statusCode = 403;
|
|
2966
|
+
/**
|
|
2967
|
+
* The permissions the gateway reported as missing, e.g. `["products:read"]`.
|
|
2968
|
+
* Empty when the response body did not name any.
|
|
2969
|
+
*/
|
|
2970
|
+
readonly permissions: string[];
|
|
2971
|
+
/** The raw response body (parsed JSON when possible, otherwise text). */
|
|
2972
|
+
readonly body: unknown;
|
|
2973
|
+
constructor(permissions: string[], body: unknown, message?: string);
|
|
2974
|
+
}
|
|
2941
2975
|
/**
|
|
2942
2976
|
* Thrown when the ACME REST gateway returns a non-2xx response that is not one
|
|
2943
2977
|
* of the specifically-handled statuses (418/429). The offending status is
|
|
@@ -2953,4 +2987,4 @@ declare class AcmeApiError extends Error {
|
|
|
2953
2987
|
constructor(statusCode: number, body: unknown, message?: string);
|
|
2954
2988
|
}
|
|
2955
2989
|
|
|
2956
|
-
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 CustomQuestion, type CustomQuestionAnswer, type CustomQuestionAnswerInput, type CustomQuestionOption, 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, 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 };
|
|
2990
|
+
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, CngPermissionError, CngProductService, type CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreateEngineInput, type CreatePromoCodeInput, type CreatedBooking, type CreatedPricingEngine, type CreatedPromoCode, type CustomQuestion, type CustomQuestionAnswer, type CustomQuestionAnswerInput, type CustomQuestionOption, 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, 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.d.ts
CHANGED
|
@@ -896,6 +896,14 @@ interface CreateBookingInput {
|
|
|
896
896
|
* invalid checkbox value fails creation before any quote is made.
|
|
897
897
|
*/
|
|
898
898
|
customQuestionAnswers?: CustomQuestionAnswerInput[];
|
|
899
|
+
/**
|
|
900
|
+
* When `true`, creation fails if any of the activity's required custom
|
|
901
|
+
* questions (per-guest questions excluded) is left unanswered. Because this
|
|
902
|
+
* enforces coverage against the activity's questions, it forces custom-question
|
|
903
|
+
* validation to run even when `customQuestionAnswers` is empty or omitted.
|
|
904
|
+
* Default: `false`.
|
|
905
|
+
*/
|
|
906
|
+
requireRequiredQuestions?: boolean;
|
|
899
907
|
/** Suppress the customer confirmation email. Default: false. */
|
|
900
908
|
skipCustomerEmail?: boolean;
|
|
901
909
|
/** Clone the quote from an existing order. */
|
|
@@ -1268,8 +1276,9 @@ declare class BookingService {
|
|
|
1268
1276
|
*
|
|
1269
1277
|
* @throws {Error} when `activityId`, `availabilityTimeId`, a ticket
|
|
1270
1278
|
* `resourceOptionId`/positive `quantity`, or the guest `name` is missing; when
|
|
1271
|
-
* `markAsPaid` is set without an `idempotencyKey`;
|
|
1272
|
-
*
|
|
1279
|
+
* `markAsPaid` is set without an `idempotencyKey`; when
|
|
1280
|
+
* `requireRequiredQuestions` is set and a required custom question is left
|
|
1281
|
+
* unanswered; or when the quote/order mutations fail.
|
|
1273
1282
|
*/
|
|
1274
1283
|
create(input: CreateBookingInput): Promise<CreatedBooking>;
|
|
1275
1284
|
/**
|
|
@@ -2291,6 +2300,7 @@ declare class RestClient$1 {
|
|
|
2291
2300
|
*
|
|
2292
2301
|
* @throws {AdminAccountRequiredError} on HTTP 418
|
|
2293
2302
|
* @throws {RateLimitError} on HTTP 429 after retries are exhausted
|
|
2303
|
+
* @throws {CngPermissionError} on HTTP 403 (app missing a permission)
|
|
2294
2304
|
* @throws {CngApiError} on any other non-2xx response
|
|
2295
2305
|
*/
|
|
2296
2306
|
get<T>(path: string): Promise<T>;
|
|
@@ -2312,23 +2322,30 @@ declare class RestClient$1 {
|
|
|
2312
2322
|
*
|
|
2313
2323
|
* `CngAccessService.getAllActivities()` returns these as a flat list.
|
|
2314
2324
|
*
|
|
2315
|
-
*
|
|
2316
|
-
* `
|
|
2317
|
-
*
|
|
2325
|
+
* Mapped from the `app-registry/products` REST payload — see
|
|
2326
|
+
* `internal/cng/products/product-queries.ts`. That payload carries no
|
|
2327
|
+
* product-type discriminator and no sub-options, so `type` is always
|
|
2328
|
+
* {@link ACTIVITY_PRODUCT_TYPE} and `tickets` is always empty.
|
|
2318
2329
|
*/
|
|
2319
2330
|
interface Activity {
|
|
2320
2331
|
/** Stable unique identifier for the activity. */
|
|
2321
2332
|
productId: string;
|
|
2322
2333
|
/** Human-readable display name. */
|
|
2323
2334
|
name: string;
|
|
2324
|
-
/**
|
|
2335
|
+
/**
|
|
2336
|
+
* Product type. Always {@link ACTIVITY_PRODUCT_TYPE} — the CNG products
|
|
2337
|
+
* payload has no type discriminator. Kept for parity with the Peek `Product`.
|
|
2338
|
+
*/
|
|
2325
2339
|
type: string;
|
|
2326
2340
|
/**
|
|
2327
|
-
* Display color as a hex string (e.g. `"#1A2B3C"`)
|
|
2328
|
-
* color is set.
|
|
2341
|
+
* Display color as a hex string (e.g. `"#1A2B3C"`), from the product's
|
|
2342
|
+
* access-control color. Empty string when no color is set.
|
|
2329
2343
|
*/
|
|
2330
2344
|
color: string;
|
|
2331
|
-
/**
|
|
2345
|
+
/**
|
|
2346
|
+
* The bookable sub-options (tickets) of this activity. Always empty — CNG
|
|
2347
|
+
* exposes no tickets on the products endpoint today.
|
|
2348
|
+
*/
|
|
2332
2349
|
tickets: ActivityTicket[];
|
|
2333
2350
|
}
|
|
2334
2351
|
/** A single bookable sub-option (ticket) of an {@link Activity}. */
|
|
@@ -2855,15 +2872,6 @@ declare function parseInstallWebhook(token: string, body: unknown, secret: strin
|
|
|
2855
2872
|
*/
|
|
2856
2873
|
declare function verifyInstallWebhook(token: string, secret: string): InstallWebhookClaims;
|
|
2857
2874
|
|
|
2858
|
-
/**
|
|
2859
|
-
* Typed errors thrown by the package. Each mirrors a failure mode of the Peek
|
|
2860
|
-
* GraphQL gateway (or the CNG REST gateway) so callers can branch on the error
|
|
2861
|
-
* type rather than parsing messages.
|
|
2862
|
-
*
|
|
2863
|
-
* `AdminAccountRequiredError` and `RateLimitError` are shared by all gateways.
|
|
2864
|
-
* `PeekGraphQLError` is Peek-only; `CngApiError` is CNG-only; `AcmeApiError` is
|
|
2865
|
-
* ACME-only.
|
|
2866
|
-
*/
|
|
2867
2875
|
/**
|
|
2868
2876
|
* Thrown when the gateway responds with HTTP 418, indicating the install is not
|
|
2869
2877
|
* permitted to perform the request because an admin account is required.
|
|
@@ -2938,6 +2946,32 @@ declare class CngApiError extends Error {
|
|
|
2938
2946
|
readonly body: unknown;
|
|
2939
2947
|
constructor(statusCode: number, body: unknown, message?: string);
|
|
2940
2948
|
}
|
|
2949
|
+
/**
|
|
2950
|
+
* Thrown when the CNG REST gateway responds with HTTP 403 because the app lacks
|
|
2951
|
+
* a permission the endpoint requires (e.g. `products:read`). This is an
|
|
2952
|
+
* **expected** failure for a misconfigured install — not a bug — so the
|
|
2953
|
+
* transport logs it at `warn` rather than `error` and leaves presentation to the
|
|
2954
|
+
* caller, which can branch on the type and surface the missing permission
|
|
2955
|
+
* however its UI prefers.
|
|
2956
|
+
*
|
|
2957
|
+
* The permission names the gateway named are on
|
|
2958
|
+
* {@link CngPermissionError.permissions} (empty when the body does not name
|
|
2959
|
+
* any), so a caller can render them without re-parsing the raw body. Thrown in
|
|
2960
|
+
* place of {@link CngApiError} for 403s only; every other non-2xx status still
|
|
2961
|
+
* throws `CngApiError`.
|
|
2962
|
+
*/
|
|
2963
|
+
declare class CngPermissionError extends Error {
|
|
2964
|
+
/** The HTTP status that triggered this error. */
|
|
2965
|
+
readonly statusCode = 403;
|
|
2966
|
+
/**
|
|
2967
|
+
* The permissions the gateway reported as missing, e.g. `["products:read"]`.
|
|
2968
|
+
* Empty when the response body did not name any.
|
|
2969
|
+
*/
|
|
2970
|
+
readonly permissions: string[];
|
|
2971
|
+
/** The raw response body (parsed JSON when possible, otherwise text). */
|
|
2972
|
+
readonly body: unknown;
|
|
2973
|
+
constructor(permissions: string[], body: unknown, message?: string);
|
|
2974
|
+
}
|
|
2941
2975
|
/**
|
|
2942
2976
|
* Thrown when the ACME REST gateway returns a non-2xx response that is not one
|
|
2943
2977
|
* of the specifically-handled statuses (418/429). The offending status is
|
|
@@ -2953,4 +2987,4 @@ declare class AcmeApiError extends Error {
|
|
|
2953
2987
|
constructor(statusCode: number, body: unknown, message?: string);
|
|
2954
2988
|
}
|
|
2955
2989
|
|
|
2956
|
-
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 CustomQuestion, type CustomQuestionAnswer, type CustomQuestionAnswerInput, type CustomQuestionOption, 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, 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 };
|
|
2990
|
+
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, CngPermissionError, CngProductService, type CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreateEngineInput, type CreatePromoCodeInput, type CreatedBooking, type CreatedPricingEngine, type CreatedPromoCode, type CustomQuestion, type CustomQuestionAnswer, type CustomQuestionAnswerInput, type CustomQuestionOption, 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, 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
|
@@ -185,6 +185,13 @@ function resolveAccessOptions(options) {
|
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
// src/errors.ts
|
|
188
|
+
var FORBIDDEN_STATUS = 403;
|
|
189
|
+
var PERMISSION_MESSAGE_PREFIX = "CNG request forbidden: the app is missing the required permission";
|
|
190
|
+
var PERMISSION_MESSAGE_UNKNOWN = "CNG request forbidden: the app is missing a required permission";
|
|
191
|
+
function buildPermissionMessage(permissions) {
|
|
192
|
+
if (permissions.length === 0) return PERMISSION_MESSAGE_UNKNOWN;
|
|
193
|
+
return `${PERMISSION_MESSAGE_PREFIX}${permissions.length > 1 ? "s" : ""}: ${permissions.join(", ")}`;
|
|
194
|
+
}
|
|
188
195
|
var AdminAccountRequiredError = class extends Error {
|
|
189
196
|
/** The HTTP status that triggered this error. */
|
|
190
197
|
statusCode = 418;
|
|
@@ -248,6 +255,23 @@ var CngApiError = class extends Error {
|
|
|
248
255
|
this.body = body;
|
|
249
256
|
}
|
|
250
257
|
};
|
|
258
|
+
var CngPermissionError = class extends Error {
|
|
259
|
+
/** The HTTP status that triggered this error. */
|
|
260
|
+
statusCode = FORBIDDEN_STATUS;
|
|
261
|
+
/**
|
|
262
|
+
* The permissions the gateway reported as missing, e.g. `["products:read"]`.
|
|
263
|
+
* Empty when the response body did not name any.
|
|
264
|
+
*/
|
|
265
|
+
permissions;
|
|
266
|
+
/** The raw response body (parsed JSON when possible, otherwise text). */
|
|
267
|
+
body;
|
|
268
|
+
constructor(permissions, body, message) {
|
|
269
|
+
super(message ?? buildPermissionMessage(permissions));
|
|
270
|
+
this.name = "CngPermissionError";
|
|
271
|
+
this.permissions = permissions;
|
|
272
|
+
this.body = body;
|
|
273
|
+
}
|
|
274
|
+
};
|
|
251
275
|
var AcmeApiError = class extends Error {
|
|
252
276
|
/** The HTTP status that triggered this error. */
|
|
253
277
|
statusCode;
|
|
@@ -1059,6 +1083,7 @@ var errInvalidCheckbox = (v, id) => `Checkbox answer for question "${id}" must b
|
|
|
1059
1083
|
var errUnknownOptionId = (v, id) => `No option matches id "${v}" for question "${id}"`;
|
|
1060
1084
|
var errNoOptionMatch = (v, id) => `No option matches "${v}" for question "${id}"`;
|
|
1061
1085
|
var errAmbiguousOption = (v, id) => `Option "${v}" matches more than one option for question "${id}"`;
|
|
1086
|
+
var errMissingRequired = (text, id) => `Custom question "${text}" (${id}) is required but was not answered`;
|
|
1062
1087
|
function normalize(value) {
|
|
1063
1088
|
return value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1064
1089
|
}
|
|
@@ -1123,8 +1148,20 @@ function resolveOne(answer, questions) {
|
|
|
1123
1148
|
throw new Error(errUnsupportedType(question.questionType, question.id));
|
|
1124
1149
|
}
|
|
1125
1150
|
}
|
|
1126
|
-
function resolveCustomQuestionAnswers(answers, questions) {
|
|
1127
|
-
|
|
1151
|
+
function resolveCustomQuestionAnswers(answers, questions, options) {
|
|
1152
|
+
const resolved = answers.map((answer) => resolveOne(answer, questions));
|
|
1153
|
+
if (options?.requireRequired) {
|
|
1154
|
+
assertRequiredAnswered(resolved, questions);
|
|
1155
|
+
}
|
|
1156
|
+
return resolved;
|
|
1157
|
+
}
|
|
1158
|
+
function assertRequiredAnswered(resolved, questions) {
|
|
1159
|
+
const answered = new Set(resolved.map((answer) => answer.questionId));
|
|
1160
|
+
for (const question of questions) {
|
|
1161
|
+
if (question.isRequired && !question.perGuest && !answered.has(question.id)) {
|
|
1162
|
+
throw new Error(errMissingRequired(question.questionText, question.id));
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1128
1165
|
}
|
|
1129
1166
|
|
|
1130
1167
|
// src/internal/peek/bookings/booking-service.ts
|
|
@@ -1641,8 +1678,9 @@ ${note}`;
|
|
|
1641
1678
|
*
|
|
1642
1679
|
* @throws {Error} when `activityId`, `availabilityTimeId`, a ticket
|
|
1643
1680
|
* `resourceOptionId`/positive `quantity`, or the guest `name` is missing; when
|
|
1644
|
-
* `markAsPaid` is set without an `idempotencyKey`;
|
|
1645
|
-
*
|
|
1681
|
+
* `markAsPaid` is set without an `idempotencyKey`; when
|
|
1682
|
+
* `requireRequiredQuestions` is set and a required custom question is left
|
|
1683
|
+
* unanswered; or when the quote/order mutations fail.
|
|
1646
1684
|
*/
|
|
1647
1685
|
async create(input) {
|
|
1648
1686
|
validateCreateInput(input);
|
|
@@ -1722,15 +1760,22 @@ ${note}`;
|
|
|
1722
1760
|
* against; throws on the first unmatched/ambiguous/invalid answer.
|
|
1723
1761
|
*/
|
|
1724
1762
|
async buildQuestionAnswers(input) {
|
|
1725
|
-
const answers = input.customQuestionAnswers;
|
|
1726
|
-
|
|
1763
|
+
const answers = input.customQuestionAnswers ?? [];
|
|
1764
|
+
const requireRequired = input.requireRequiredQuestions ?? false;
|
|
1765
|
+
if (answers.length === 0 && !requireRequired) {
|
|
1727
1766
|
return null;
|
|
1728
1767
|
}
|
|
1729
1768
|
const questions = await this.deps.productService.getCustomQuestions(
|
|
1730
1769
|
input.activityId
|
|
1731
1770
|
);
|
|
1732
|
-
|
|
1733
|
-
|
|
1771
|
+
const resolved = resolveCustomQuestionAnswers(answers, questions, {
|
|
1772
|
+
requireRequired
|
|
1773
|
+
});
|
|
1774
|
+
if (resolved.length === 0) {
|
|
1775
|
+
return null;
|
|
1776
|
+
}
|
|
1777
|
+
return resolved.map((answer) => ({
|
|
1778
|
+
...answer,
|
|
1734
1779
|
refid: randomUUID()
|
|
1735
1780
|
}));
|
|
1736
1781
|
}
|
|
@@ -4113,7 +4158,7 @@ var PeekAccessService = class {
|
|
|
4113
4158
|
|
|
4114
4159
|
// src/internal/cng/endpoints.ts
|
|
4115
4160
|
var CNG_EXTENDABLE_SLUG = "cng_backoffice_api-v1";
|
|
4116
|
-
var PRODUCTS_PATH = "api/v2/
|
|
4161
|
+
var PRODUCTS_PATH = "api/v2/app-registry/products?active=1";
|
|
4117
4162
|
|
|
4118
4163
|
// src/models/cng/product.ts
|
|
4119
4164
|
var ACTIVITY_PRODUCT_TYPE2 = "ACTIVITY";
|
|
@@ -4124,14 +4169,11 @@ function fromProductNodes(nodes) {
|
|
|
4124
4169
|
}
|
|
4125
4170
|
function fromProductNode(node) {
|
|
4126
4171
|
return {
|
|
4127
|
-
productId: node.id
|
|
4172
|
+
productId: node.id == null ? "" : String(node.id),
|
|
4128
4173
|
name: node.name || "",
|
|
4129
|
-
type:
|
|
4130
|
-
color: node.
|
|
4131
|
-
tickets:
|
|
4132
|
-
id: ticket.id,
|
|
4133
|
-
name: ticket.name
|
|
4134
|
-
}))
|
|
4174
|
+
type: ACTIVITY_PRODUCT_TYPE2,
|
|
4175
|
+
color: node.access_control_color_hex || "",
|
|
4176
|
+
tickets: []
|
|
4135
4177
|
};
|
|
4136
4178
|
}
|
|
4137
4179
|
|
|
@@ -4150,15 +4192,13 @@ var CngProductService = class {
|
|
|
4150
4192
|
* ```
|
|
4151
4193
|
*/
|
|
4152
4194
|
async getAllActivities() {
|
|
4153
|
-
const body = await this.client.get(
|
|
4154
|
-
|
|
4155
|
-
);
|
|
4156
|
-
const nodes = Array.isArray(body) ? body : body?.products ?? [];
|
|
4157
|
-
return fromProductNodes(nodes ?? []);
|
|
4195
|
+
const body = await this.client.get(PRODUCTS_PATH);
|
|
4196
|
+
return fromProductNodes(body?.data ?? []);
|
|
4158
4197
|
}
|
|
4159
4198
|
};
|
|
4160
4199
|
|
|
4161
4200
|
// src/internal/cng/rest-client.ts
|
|
4201
|
+
var PERMISSION_SEPARATOR = ": ";
|
|
4162
4202
|
var RestClient = class {
|
|
4163
4203
|
constructor(options) {
|
|
4164
4204
|
this.options = options;
|
|
@@ -4171,6 +4211,7 @@ var RestClient = class {
|
|
|
4171
4211
|
*
|
|
4172
4212
|
* @throws {AdminAccountRequiredError} on HTTP 418
|
|
4173
4213
|
* @throws {RateLimitError} on HTTP 429 after retries are exhausted
|
|
4214
|
+
* @throws {CngPermissionError} on HTTP 403 (app missing a permission)
|
|
4174
4215
|
* @throws {CngApiError} on any other non-2xx response
|
|
4175
4216
|
*/
|
|
4176
4217
|
async get(path) {
|
|
@@ -4184,6 +4225,11 @@ var RestClient = class {
|
|
|
4184
4225
|
path,
|
|
4185
4226
|
async (response) => {
|
|
4186
4227
|
const body = await parseBody(response);
|
|
4228
|
+
if (response.status === FORBIDDEN_STATUS) {
|
|
4229
|
+
const permissions = extractMissingPermissions(body);
|
|
4230
|
+
logger.warn(`Missing permission for ${path} (HTTP 403)`, { url, permissions });
|
|
4231
|
+
throw new CngPermissionError(permissions, body);
|
|
4232
|
+
}
|
|
4187
4233
|
if (!response.ok) {
|
|
4188
4234
|
logger.error(`CNG request failed with HTTP ${response.status}`, { url });
|
|
4189
4235
|
throw new CngApiError(response.status, body);
|
|
@@ -4204,6 +4250,12 @@ var RestClient = class {
|
|
|
4204
4250
|
};
|
|
4205
4251
|
}
|
|
4206
4252
|
};
|
|
4253
|
+
function extractMissingPermissions(body) {
|
|
4254
|
+
if (typeof body !== "object" || body === null) return [];
|
|
4255
|
+
const raw = body.errors?.permission;
|
|
4256
|
+
if (!Array.isArray(raw)) return [];
|
|
4257
|
+
return raw.filter((entry) => typeof entry === "string").map((entry) => entry.split(PERMISSION_SEPARATOR).pop().trim()).filter((permission) => permission.length > 0);
|
|
4258
|
+
}
|
|
4207
4259
|
|
|
4208
4260
|
// src/cng-access-service.ts
|
|
4209
4261
|
var DEFAULT_BASE_URL2 = "https://app-registry.peeklabs.com/installations-api";
|
|
@@ -4548,6 +4600,6 @@ function verifyInstallWebhook(token, secret) {
|
|
|
4548
4600
|
};
|
|
4549
4601
|
}
|
|
4550
4602
|
|
|
4551
|
-
export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, AccountUserService, AcmeAccessService, AcmeApiError, AcmeProductService, AdminAccountRequiredError, AvailabilityService, BookingService, CngAccessService, CngApiError, CngProductService, DailyNoteService, INSTALL_STATUSES, MembershipService, PeekAccessService, PeekGraphQLError, PeekHttpError, PiiAccessDisabledError, PricingService, ProductService, PromoCodeService, RENTAL_PRODUCT_TYPE, RateLimitError, ResellerService, ResourcePoolService, ReviewService, TimeslotService, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
|
|
4603
|
+
export { ACTIVITY_PRODUCT_TYPE, ADD_ON_PRODUCT_TYPE, AccountUserService, AcmeAccessService, AcmeApiError, AcmeProductService, AdminAccountRequiredError, AvailabilityService, BookingService, CngAccessService, CngApiError, CngPermissionError, CngProductService, DailyNoteService, INSTALL_STATUSES, MembershipService, PeekAccessService, PeekGraphQLError, PeekHttpError, PiiAccessDisabledError, PricingService, ProductService, PromoCodeService, RENTAL_PRODUCT_TYPE, RateLimitError, ResellerService, ResourcePoolService, ReviewService, TimeslotService, createAccessServiceForInstall, noopLogger, parseBookingWebhook, parseInstallWebhook, parseWaiverWebhook, verifyInstallWebhook };
|
|
4552
4604
|
//# sourceMappingURL=index.js.map
|
|
4553
4605
|
//# sourceMappingURL=index.js.map
|