@peektravel/app-utilities 0.7.4 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +222 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +129 -3
- package/dist/index.d.ts +129 -3
- package/dist/index.js +222 -2
- package/dist/index.js.map +1 -1
- package/llms.txt +19 -2
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -421,6 +421,64 @@ declare const RENTAL_PRODUCT_TYPE = "RENTAL";
|
|
|
421
421
|
*/
|
|
422
422
|
declare const ADD_ON_PRODUCT_TYPE = "ADD-ON";
|
|
423
423
|
|
|
424
|
+
/**
|
|
425
|
+
* The clean, transport-agnostic data model for an activity's custom questions.
|
|
426
|
+
*
|
|
427
|
+
* Custom questions are the operator-configured questions attached to a bookable
|
|
428
|
+
* activity (per-guest waiver-style prompts, free-text inputs, multiple-choice
|
|
429
|
+
* pickers, etc.). This is the shape consumers work with — it is decoupled from
|
|
430
|
+
* the underlying Peek GraphQL `Question`/`ChoiceQuestion` schema, which stays
|
|
431
|
+
* internal.
|
|
432
|
+
*
|
|
433
|
+
* Note: this describes the **question definitions** on an activity, not any
|
|
434
|
+
* customer's answers — so there is no PII here and nothing gated behind
|
|
435
|
+
* `fullCustomerAccess`.
|
|
436
|
+
*/
|
|
437
|
+
/**
|
|
438
|
+
* A single custom question configured on an activity.
|
|
439
|
+
*
|
|
440
|
+
* The ordering and requiredness come from the activity's question
|
|
441
|
+
* configuration; the remaining fields describe the reusable question itself.
|
|
442
|
+
*/
|
|
443
|
+
interface CustomQuestion {
|
|
444
|
+
/** Unique identifier of the question (e.g. `"cq_anq67"`). */
|
|
445
|
+
id: string;
|
|
446
|
+
/** 1-based position of the question within the activity's question list. */
|
|
447
|
+
order: number;
|
|
448
|
+
/** Whether the activity requires an answer to this question. */
|
|
449
|
+
isRequired: boolean;
|
|
450
|
+
/** The question prompt shown to the guest (Peek's `text`). */
|
|
451
|
+
questionText: string;
|
|
452
|
+
/** Helper/hint text shown alongside the prompt, or `null` when none. */
|
|
453
|
+
hintText: string | null;
|
|
454
|
+
/**
|
|
455
|
+
* The question's input type as reported by Peek — e.g. `"CHECK_BOX"`,
|
|
456
|
+
* `"TEXT"`, `"LOCATION"`, `"SELECT_ONE"`. Left as a string so new Peek
|
|
457
|
+
* question types flow through without a package change.
|
|
458
|
+
*/
|
|
459
|
+
questionType: string;
|
|
460
|
+
/** Operator-only label for the question, or `null` when none. */
|
|
461
|
+
internalLabel: string | null;
|
|
462
|
+
/** `true` when the question is answered once per guest rather than per booking. */
|
|
463
|
+
perGuest: boolean;
|
|
464
|
+
/** Pre-filled default answer, or `null` when none. */
|
|
465
|
+
defaultValue: string | null;
|
|
466
|
+
/**
|
|
467
|
+
* Selectable options for choice-style questions (`SELECT_ONE`, `LOCATION`,
|
|
468
|
+
* …). Empty for free-text/checkbox questions that carry no options.
|
|
469
|
+
*/
|
|
470
|
+
options: CustomQuestionOption[];
|
|
471
|
+
}
|
|
472
|
+
/** A single selectable option on a choice-style {@link CustomQuestion}. */
|
|
473
|
+
interface CustomQuestionOption {
|
|
474
|
+
/** Unique identifier of the option (e.g. `"cqao_mwdgvw"`). */
|
|
475
|
+
id: string;
|
|
476
|
+
/** 1-based position of the option within the question's option list. */
|
|
477
|
+
order: number;
|
|
478
|
+
/** The option's display label (Peek's `text`). */
|
|
479
|
+
value: string;
|
|
480
|
+
}
|
|
481
|
+
|
|
424
482
|
/** Tuning options for a {@link ProductService}. */
|
|
425
483
|
interface ProductServiceOptions {
|
|
426
484
|
/** Page size for cursor-paginated item options. Default: 50. */
|
|
@@ -451,6 +509,21 @@ declare class ProductService {
|
|
|
451
509
|
getAllRentals(): Promise<Product[]>;
|
|
452
510
|
/** Returns only add-on products. */
|
|
453
511
|
getAllAddons(): Promise<Product[]>;
|
|
512
|
+
/**
|
|
513
|
+
* Returns every custom question configured on a single activity, in the order
|
|
514
|
+
* Peek reports them. Choice-style questions (`SELECT_ONE`, `LOCATION`, …)
|
|
515
|
+
* carry their selectable {@link CustomQuestion.options}; free-text/checkbox
|
|
516
|
+
* questions return an empty option list.
|
|
517
|
+
*
|
|
518
|
+
* These are question **definitions**, not customer answers — no PII is
|
|
519
|
+
* involved, so the result is unaffected by `fullCustomerAccess`.
|
|
520
|
+
*
|
|
521
|
+
* @param productId The activity's id.
|
|
522
|
+
* @returns The activity's custom questions, or an empty list when the activity
|
|
523
|
+
* has none or is not found.
|
|
524
|
+
* @throws Error when `productId` is missing or blank.
|
|
525
|
+
*/
|
|
526
|
+
getCustomQuestions(productId: string): Promise<CustomQuestion[]>;
|
|
454
527
|
private fetchActivities;
|
|
455
528
|
private fetchAllItemOptionNodes;
|
|
456
529
|
}
|
|
@@ -773,6 +846,34 @@ interface CreateBookingGuest {
|
|
|
773
846
|
optinMarketing?: boolean;
|
|
774
847
|
optinSms?: boolean;
|
|
775
848
|
}
|
|
849
|
+
/**
|
|
850
|
+
* An answer to one of an activity's custom questions, supplied when creating a
|
|
851
|
+
* booking. The question is identified by id **or** text, and the value is
|
|
852
|
+
* resolved against the question's type at create time (see
|
|
853
|
+
* {@link CreateBookingInput.customQuestionAnswers}).
|
|
854
|
+
*/
|
|
855
|
+
interface CustomQuestionAnswerInput {
|
|
856
|
+
/**
|
|
857
|
+
* The question to answer — either its id (`cq_…`) or its question text. Text
|
|
858
|
+
* is matched leniently (lowercased, non-alphanumerics stripped); it must match
|
|
859
|
+
* exactly one question or creation fails.
|
|
860
|
+
*/
|
|
861
|
+
questionIdOrText: string;
|
|
862
|
+
/**
|
|
863
|
+
* The answer. How it is interpreted depends on the question's type:
|
|
864
|
+
* - **checkbox** — `yes`/`no`/`true`/`false` (case-insensitive).
|
|
865
|
+
* - **text** — used verbatim.
|
|
866
|
+
* - **select-one / location** — an option id (`cqao_…`) or the option's label,
|
|
867
|
+
* matched leniently the same way as `questionIdOrText`.
|
|
868
|
+
*
|
|
869
|
+
* For **location** questions you only select the option — Peek holds each
|
|
870
|
+
* option's configured lat/long and applies it, so no coordinates are (or can
|
|
871
|
+
* be) supplied here.
|
|
872
|
+
*
|
|
873
|
+
* Per-guest questions are **not yet supported**: answering one fails creation.
|
|
874
|
+
*/
|
|
875
|
+
value: string;
|
|
876
|
+
}
|
|
776
877
|
/**
|
|
777
878
|
* Input for creating a booking. IDs must already be resolved — the package does
|
|
778
879
|
* not do free-text product/ticket/time matching (that stays in the caller).
|
|
@@ -788,6 +889,21 @@ interface CreateBookingInput {
|
|
|
788
889
|
guest: CreateBookingGuest;
|
|
789
890
|
/** Operator notes to attach. */
|
|
790
891
|
operatorNotes?: string;
|
|
892
|
+
/**
|
|
893
|
+
* Answers to the activity's custom questions. When non-empty, the activity's
|
|
894
|
+
* custom questions are fetched and each answer is validated/resolved before
|
|
895
|
+
* the booking is created — an unmatched question, ambiguous text/option, or
|
|
896
|
+
* invalid checkbox value fails creation before any quote is made.
|
|
897
|
+
*/
|
|
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;
|
|
791
907
|
/** Suppress the customer confirmation email. Default: false. */
|
|
792
908
|
skipCustomerEmail?: boolean;
|
|
793
909
|
/** Clone the quote from an existing order. */
|
|
@@ -1160,10 +1276,18 @@ declare class BookingService {
|
|
|
1160
1276
|
*
|
|
1161
1277
|
* @throws {Error} when `activityId`, `availabilityTimeId`, a ticket
|
|
1162
1278
|
* `resourceOptionId`/positive `quantity`, or the guest `name` is missing; when
|
|
1163
|
-
* `markAsPaid` is set without an `idempotencyKey`;
|
|
1164
|
-
*
|
|
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.
|
|
1165
1282
|
*/
|
|
1166
1283
|
create(input: CreateBookingInput): Promise<CreatedBooking>;
|
|
1284
|
+
/**
|
|
1285
|
+
* Resolves the input's custom-question answers into the quote's
|
|
1286
|
+
* `questionAnswers` payload (each tagged with a fresh `refid`), or `null` when
|
|
1287
|
+
* none were supplied. Fetches the activity's custom questions to validate
|
|
1288
|
+
* against; throws on the first unmatched/ambiguous/invalid answer.
|
|
1289
|
+
*/
|
|
1290
|
+
private buildQuestionAnswers;
|
|
1167
1291
|
private markCreatedBookingPaid;
|
|
1168
1292
|
/** Finds the parent item id of an add-on by matching its option id. */
|
|
1169
1293
|
private resolveParentItemId;
|
|
@@ -2062,6 +2186,8 @@ declare class PeekAccessService {
|
|
|
2062
2186
|
getAllRentals(): Promise<Product[]>;
|
|
2063
2187
|
/** All add-on products. Delegates to {@link ProductService.getAllAddons}. */
|
|
2064
2188
|
getAllAddons(): Promise<Product[]>;
|
|
2189
|
+
/** An activity's custom questions. Delegates to {@link ProductService.getCustomQuestions}. */
|
|
2190
|
+
getCustomQuestions(productId: string): Promise<CustomQuestion[]>;
|
|
2065
2191
|
/** All active account users. Delegates to {@link AccountUserService.getAll}. */
|
|
2066
2192
|
getAllAccountUsers(): Promise<AccountUser[]>;
|
|
2067
2193
|
/** Account user by id, or null. Delegates to {@link AccountUserService.getById}. */
|
|
@@ -2836,4 +2962,4 @@ declare class AcmeApiError extends Error {
|
|
|
2836
2962
|
constructor(statusCode: number, body: unknown, message?: string);
|
|
2837
2963
|
}
|
|
2838
2964
|
|
|
2839
|
-
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, 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 };
|
|
2965
|
+
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -421,6 +421,64 @@ declare const RENTAL_PRODUCT_TYPE = "RENTAL";
|
|
|
421
421
|
*/
|
|
422
422
|
declare const ADD_ON_PRODUCT_TYPE = "ADD-ON";
|
|
423
423
|
|
|
424
|
+
/**
|
|
425
|
+
* The clean, transport-agnostic data model for an activity's custom questions.
|
|
426
|
+
*
|
|
427
|
+
* Custom questions are the operator-configured questions attached to a bookable
|
|
428
|
+
* activity (per-guest waiver-style prompts, free-text inputs, multiple-choice
|
|
429
|
+
* pickers, etc.). This is the shape consumers work with — it is decoupled from
|
|
430
|
+
* the underlying Peek GraphQL `Question`/`ChoiceQuestion` schema, which stays
|
|
431
|
+
* internal.
|
|
432
|
+
*
|
|
433
|
+
* Note: this describes the **question definitions** on an activity, not any
|
|
434
|
+
* customer's answers — so there is no PII here and nothing gated behind
|
|
435
|
+
* `fullCustomerAccess`.
|
|
436
|
+
*/
|
|
437
|
+
/**
|
|
438
|
+
* A single custom question configured on an activity.
|
|
439
|
+
*
|
|
440
|
+
* The ordering and requiredness come from the activity's question
|
|
441
|
+
* configuration; the remaining fields describe the reusable question itself.
|
|
442
|
+
*/
|
|
443
|
+
interface CustomQuestion {
|
|
444
|
+
/** Unique identifier of the question (e.g. `"cq_anq67"`). */
|
|
445
|
+
id: string;
|
|
446
|
+
/** 1-based position of the question within the activity's question list. */
|
|
447
|
+
order: number;
|
|
448
|
+
/** Whether the activity requires an answer to this question. */
|
|
449
|
+
isRequired: boolean;
|
|
450
|
+
/** The question prompt shown to the guest (Peek's `text`). */
|
|
451
|
+
questionText: string;
|
|
452
|
+
/** Helper/hint text shown alongside the prompt, or `null` when none. */
|
|
453
|
+
hintText: string | null;
|
|
454
|
+
/**
|
|
455
|
+
* The question's input type as reported by Peek — e.g. `"CHECK_BOX"`,
|
|
456
|
+
* `"TEXT"`, `"LOCATION"`, `"SELECT_ONE"`. Left as a string so new Peek
|
|
457
|
+
* question types flow through without a package change.
|
|
458
|
+
*/
|
|
459
|
+
questionType: string;
|
|
460
|
+
/** Operator-only label for the question, or `null` when none. */
|
|
461
|
+
internalLabel: string | null;
|
|
462
|
+
/** `true` when the question is answered once per guest rather than per booking. */
|
|
463
|
+
perGuest: boolean;
|
|
464
|
+
/** Pre-filled default answer, or `null` when none. */
|
|
465
|
+
defaultValue: string | null;
|
|
466
|
+
/**
|
|
467
|
+
* Selectable options for choice-style questions (`SELECT_ONE`, `LOCATION`,
|
|
468
|
+
* …). Empty for free-text/checkbox questions that carry no options.
|
|
469
|
+
*/
|
|
470
|
+
options: CustomQuestionOption[];
|
|
471
|
+
}
|
|
472
|
+
/** A single selectable option on a choice-style {@link CustomQuestion}. */
|
|
473
|
+
interface CustomQuestionOption {
|
|
474
|
+
/** Unique identifier of the option (e.g. `"cqao_mwdgvw"`). */
|
|
475
|
+
id: string;
|
|
476
|
+
/** 1-based position of the option within the question's option list. */
|
|
477
|
+
order: number;
|
|
478
|
+
/** The option's display label (Peek's `text`). */
|
|
479
|
+
value: string;
|
|
480
|
+
}
|
|
481
|
+
|
|
424
482
|
/** Tuning options for a {@link ProductService}. */
|
|
425
483
|
interface ProductServiceOptions {
|
|
426
484
|
/** Page size for cursor-paginated item options. Default: 50. */
|
|
@@ -451,6 +509,21 @@ declare class ProductService {
|
|
|
451
509
|
getAllRentals(): Promise<Product[]>;
|
|
452
510
|
/** Returns only add-on products. */
|
|
453
511
|
getAllAddons(): Promise<Product[]>;
|
|
512
|
+
/**
|
|
513
|
+
* Returns every custom question configured on a single activity, in the order
|
|
514
|
+
* Peek reports them. Choice-style questions (`SELECT_ONE`, `LOCATION`, …)
|
|
515
|
+
* carry their selectable {@link CustomQuestion.options}; free-text/checkbox
|
|
516
|
+
* questions return an empty option list.
|
|
517
|
+
*
|
|
518
|
+
* These are question **definitions**, not customer answers — no PII is
|
|
519
|
+
* involved, so the result is unaffected by `fullCustomerAccess`.
|
|
520
|
+
*
|
|
521
|
+
* @param productId The activity's id.
|
|
522
|
+
* @returns The activity's custom questions, or an empty list when the activity
|
|
523
|
+
* has none or is not found.
|
|
524
|
+
* @throws Error when `productId` is missing or blank.
|
|
525
|
+
*/
|
|
526
|
+
getCustomQuestions(productId: string): Promise<CustomQuestion[]>;
|
|
454
527
|
private fetchActivities;
|
|
455
528
|
private fetchAllItemOptionNodes;
|
|
456
529
|
}
|
|
@@ -773,6 +846,34 @@ interface CreateBookingGuest {
|
|
|
773
846
|
optinMarketing?: boolean;
|
|
774
847
|
optinSms?: boolean;
|
|
775
848
|
}
|
|
849
|
+
/**
|
|
850
|
+
* An answer to one of an activity's custom questions, supplied when creating a
|
|
851
|
+
* booking. The question is identified by id **or** text, and the value is
|
|
852
|
+
* resolved against the question's type at create time (see
|
|
853
|
+
* {@link CreateBookingInput.customQuestionAnswers}).
|
|
854
|
+
*/
|
|
855
|
+
interface CustomQuestionAnswerInput {
|
|
856
|
+
/**
|
|
857
|
+
* The question to answer — either its id (`cq_…`) or its question text. Text
|
|
858
|
+
* is matched leniently (lowercased, non-alphanumerics stripped); it must match
|
|
859
|
+
* exactly one question or creation fails.
|
|
860
|
+
*/
|
|
861
|
+
questionIdOrText: string;
|
|
862
|
+
/**
|
|
863
|
+
* The answer. How it is interpreted depends on the question's type:
|
|
864
|
+
* - **checkbox** — `yes`/`no`/`true`/`false` (case-insensitive).
|
|
865
|
+
* - **text** — used verbatim.
|
|
866
|
+
* - **select-one / location** — an option id (`cqao_…`) or the option's label,
|
|
867
|
+
* matched leniently the same way as `questionIdOrText`.
|
|
868
|
+
*
|
|
869
|
+
* For **location** questions you only select the option — Peek holds each
|
|
870
|
+
* option's configured lat/long and applies it, so no coordinates are (or can
|
|
871
|
+
* be) supplied here.
|
|
872
|
+
*
|
|
873
|
+
* Per-guest questions are **not yet supported**: answering one fails creation.
|
|
874
|
+
*/
|
|
875
|
+
value: string;
|
|
876
|
+
}
|
|
776
877
|
/**
|
|
777
878
|
* Input for creating a booking. IDs must already be resolved — the package does
|
|
778
879
|
* not do free-text product/ticket/time matching (that stays in the caller).
|
|
@@ -788,6 +889,21 @@ interface CreateBookingInput {
|
|
|
788
889
|
guest: CreateBookingGuest;
|
|
789
890
|
/** Operator notes to attach. */
|
|
790
891
|
operatorNotes?: string;
|
|
892
|
+
/**
|
|
893
|
+
* Answers to the activity's custom questions. When non-empty, the activity's
|
|
894
|
+
* custom questions are fetched and each answer is validated/resolved before
|
|
895
|
+
* the booking is created — an unmatched question, ambiguous text/option, or
|
|
896
|
+
* invalid checkbox value fails creation before any quote is made.
|
|
897
|
+
*/
|
|
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;
|
|
791
907
|
/** Suppress the customer confirmation email. Default: false. */
|
|
792
908
|
skipCustomerEmail?: boolean;
|
|
793
909
|
/** Clone the quote from an existing order. */
|
|
@@ -1160,10 +1276,18 @@ declare class BookingService {
|
|
|
1160
1276
|
*
|
|
1161
1277
|
* @throws {Error} when `activityId`, `availabilityTimeId`, a ticket
|
|
1162
1278
|
* `resourceOptionId`/positive `quantity`, or the guest `name` is missing; when
|
|
1163
|
-
* `markAsPaid` is set without an `idempotencyKey`;
|
|
1164
|
-
*
|
|
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.
|
|
1165
1282
|
*/
|
|
1166
1283
|
create(input: CreateBookingInput): Promise<CreatedBooking>;
|
|
1284
|
+
/**
|
|
1285
|
+
* Resolves the input's custom-question answers into the quote's
|
|
1286
|
+
* `questionAnswers` payload (each tagged with a fresh `refid`), or `null` when
|
|
1287
|
+
* none were supplied. Fetches the activity's custom questions to validate
|
|
1288
|
+
* against; throws on the first unmatched/ambiguous/invalid answer.
|
|
1289
|
+
*/
|
|
1290
|
+
private buildQuestionAnswers;
|
|
1167
1291
|
private markCreatedBookingPaid;
|
|
1168
1292
|
/** Finds the parent item id of an add-on by matching its option id. */
|
|
1169
1293
|
private resolveParentItemId;
|
|
@@ -2062,6 +2186,8 @@ declare class PeekAccessService {
|
|
|
2062
2186
|
getAllRentals(): Promise<Product[]>;
|
|
2063
2187
|
/** All add-on products. Delegates to {@link ProductService.getAllAddons}. */
|
|
2064
2188
|
getAllAddons(): Promise<Product[]>;
|
|
2189
|
+
/** An activity's custom questions. Delegates to {@link ProductService.getCustomQuestions}. */
|
|
2190
|
+
getCustomQuestions(productId: string): Promise<CustomQuestion[]>;
|
|
2065
2191
|
/** All active account users. Delegates to {@link AccountUserService.getAll}. */
|
|
2066
2192
|
getAllAccountUsers(): Promise<AccountUser[]>;
|
|
2067
2193
|
/** Account user by id, or null. Delegates to {@link AccountUserService.getById}. */
|
|
@@ -2836,4 +2962,4 @@ declare class AcmeApiError extends Error {
|
|
|
2836
2962
|
constructor(statusCode: number, body: unknown, message?: string);
|
|
2837
2963
|
}
|
|
2838
2964
|
|
|
2839
|
-
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, 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 };
|
|
2965
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -1039,6 +1039,107 @@ function toBookingAddon(item) {
|
|
|
1039
1039
|
return { addonId, addonName, total: item.total, addonOptions };
|
|
1040
1040
|
}
|
|
1041
1041
|
|
|
1042
|
+
// src/internal/peek/bookings/custom-question-answer.ts
|
|
1043
|
+
var QUESTION_TYPE_CHECK_BOX = "CHECK_BOX";
|
|
1044
|
+
var QUESTION_TYPE_TEXT = "TEXT";
|
|
1045
|
+
var QUESTION_TYPE_SELECT_ONE = "SELECT_ONE";
|
|
1046
|
+
var QUESTION_TYPE_LOCATION = "LOCATION";
|
|
1047
|
+
var QUESTION_ID_REGEX = /^cq_[a-z0-9]+$/;
|
|
1048
|
+
var OPTION_ID_REGEX = /^cqao_[a-z0-9]+$/;
|
|
1049
|
+
var CHECKBOX_TRUE = /* @__PURE__ */ new Set(["yes", "true"]);
|
|
1050
|
+
var CHECKBOX_VALID = /* @__PURE__ */ new Set(["yes", "no", "true", "false"]);
|
|
1051
|
+
var CHECKBOX_TEXT_TRUE = "Yes";
|
|
1052
|
+
var CHECKBOX_TEXT_FALSE = "No";
|
|
1053
|
+
var errUnknownQuestionId = (v) => `No custom question matches id "${v}" for this activity`;
|
|
1054
|
+
var errNoTextMatch = (v) => `No custom question matches text "${v}" for this activity`;
|
|
1055
|
+
var errAmbiguousText = (v) => `Custom question text "${v}" matches more than one question`;
|
|
1056
|
+
var errPerGuestUnsupported = (id) => `Per-guest custom question "${id}" is not yet supported`;
|
|
1057
|
+
var errUnsupportedType = (type, id) => `Custom question "${id}" has unsupported type "${type}"`;
|
|
1058
|
+
var errInvalidCheckbox = (v, id) => `Checkbox answer for question "${id}" must be yes/no/true/false, got "${v}"`;
|
|
1059
|
+
var errUnknownOptionId = (v, id) => `No option matches id "${v}" for question "${id}"`;
|
|
1060
|
+
var errNoOptionMatch = (v, id) => `No option matches "${v}" for question "${id}"`;
|
|
1061
|
+
var errAmbiguousOption = (v, id) => `Option "${v}" matches more than one option for question "${id}"`;
|
|
1062
|
+
var errMissingRequired = (text, id) => `Custom question "${text}" (${id}) is required but was not answered`;
|
|
1063
|
+
function normalize(value) {
|
|
1064
|
+
return value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1065
|
+
}
|
|
1066
|
+
function resolveQuestion(idOrText, questions) {
|
|
1067
|
+
if (QUESTION_ID_REGEX.test(idOrText)) {
|
|
1068
|
+
const byId = questions.find((question) => question.id === idOrText);
|
|
1069
|
+
if (!byId) throw new Error(errUnknownQuestionId(idOrText));
|
|
1070
|
+
return byId;
|
|
1071
|
+
}
|
|
1072
|
+
const target = normalize(idOrText);
|
|
1073
|
+
const matches = questions.filter(
|
|
1074
|
+
(question) => normalize(question.questionText) === target
|
|
1075
|
+
);
|
|
1076
|
+
if (matches.length === 0) throw new Error(errNoTextMatch(idOrText));
|
|
1077
|
+
if (matches.length > 1) throw new Error(errAmbiguousText(idOrText));
|
|
1078
|
+
return matches[0];
|
|
1079
|
+
}
|
|
1080
|
+
function resolveOption(value, question) {
|
|
1081
|
+
if (OPTION_ID_REGEX.test(value)) {
|
|
1082
|
+
const byId = question.options.find((option) => option.id === value);
|
|
1083
|
+
if (!byId) throw new Error(errUnknownOptionId(value, question.id));
|
|
1084
|
+
return byId;
|
|
1085
|
+
}
|
|
1086
|
+
const target = normalize(value);
|
|
1087
|
+
const matches = question.options.filter(
|
|
1088
|
+
(option) => normalize(option.value) === target
|
|
1089
|
+
);
|
|
1090
|
+
if (matches.length === 0) throw new Error(errNoOptionMatch(value, question.id));
|
|
1091
|
+
if (matches.length > 1) throw new Error(errAmbiguousOption(value, question.id));
|
|
1092
|
+
return matches[0];
|
|
1093
|
+
}
|
|
1094
|
+
function resolveOne(answer, questions) {
|
|
1095
|
+
const question = resolveQuestion(answer.questionIdOrText, questions);
|
|
1096
|
+
if (question.perGuest) {
|
|
1097
|
+
throw new Error(errPerGuestUnsupported(question.id));
|
|
1098
|
+
}
|
|
1099
|
+
switch (question.questionType) {
|
|
1100
|
+
case QUESTION_TYPE_CHECK_BOX: {
|
|
1101
|
+
const normalized = answer.value.trim().toLowerCase();
|
|
1102
|
+
if (!CHECKBOX_VALID.has(normalized)) {
|
|
1103
|
+
throw new Error(errInvalidCheckbox(answer.value, question.id));
|
|
1104
|
+
}
|
|
1105
|
+
const isChecked = CHECKBOX_TRUE.has(normalized);
|
|
1106
|
+
return {
|
|
1107
|
+
questionId: question.id,
|
|
1108
|
+
isChecked,
|
|
1109
|
+
questionAnswerText: isChecked ? CHECKBOX_TEXT_TRUE : CHECKBOX_TEXT_FALSE
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
case QUESTION_TYPE_TEXT:
|
|
1113
|
+
return { questionId: question.id, questionAnswerText: answer.value };
|
|
1114
|
+
case QUESTION_TYPE_SELECT_ONE:
|
|
1115
|
+
case QUESTION_TYPE_LOCATION: {
|
|
1116
|
+
const option = resolveOption(answer.value, question);
|
|
1117
|
+
return {
|
|
1118
|
+
questionId: question.id,
|
|
1119
|
+
questionAnswerOptionId: option.id,
|
|
1120
|
+
questionAnswerText: option.value
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
default:
|
|
1124
|
+
throw new Error(errUnsupportedType(question.questionType, question.id));
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
function resolveCustomQuestionAnswers(answers, questions, options) {
|
|
1128
|
+
const resolved = answers.map((answer) => resolveOne(answer, questions));
|
|
1129
|
+
if (options?.requireRequired) {
|
|
1130
|
+
assertRequiredAnswered(resolved, questions);
|
|
1131
|
+
}
|
|
1132
|
+
return resolved;
|
|
1133
|
+
}
|
|
1134
|
+
function assertRequiredAnswered(resolved, questions) {
|
|
1135
|
+
const answered = new Set(resolved.map((answer) => answer.questionId));
|
|
1136
|
+
for (const question of questions) {
|
|
1137
|
+
if (question.isRequired && !question.perGuest && !answered.has(question.id)) {
|
|
1138
|
+
throw new Error(errMissingRequired(question.questionText, question.id));
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1042
1143
|
// src/internal/peek/bookings/booking-service.ts
|
|
1043
1144
|
var DEFAULT_PAGE_SIZE2 = 50;
|
|
1044
1145
|
var DEFAULT_CANCEL_NOTE = "Canceled";
|
|
@@ -1553,11 +1654,13 @@ ${note}`;
|
|
|
1553
1654
|
*
|
|
1554
1655
|
* @throws {Error} when `activityId`, `availabilityTimeId`, a ticket
|
|
1555
1656
|
* `resourceOptionId`/positive `quantity`, or the guest `name` is missing; when
|
|
1556
|
-
* `markAsPaid` is set without an `idempotencyKey`;
|
|
1557
|
-
*
|
|
1657
|
+
* `markAsPaid` is set without an `idempotencyKey`; when
|
|
1658
|
+
* `requireRequiredQuestions` is set and a required custom question is left
|
|
1659
|
+
* unanswered; or when the quote/order mutations fail.
|
|
1558
1660
|
*/
|
|
1559
1661
|
async create(input) {
|
|
1560
1662
|
validateCreateInput(input);
|
|
1663
|
+
const questionAnswers = await this.buildQuestionAnswers(input);
|
|
1561
1664
|
const tickets = input.tickets.flatMap(
|
|
1562
1665
|
(ticket) => Array.from({ length: ticket.quantity }, () => ({
|
|
1563
1666
|
resourceOptionId: ticket.resourceOptionId,
|
|
@@ -1584,6 +1687,9 @@ ${note}`;
|
|
|
1584
1687
|
if (input.operatorNotes) {
|
|
1585
1688
|
bookingQuote.operatorNotes = input.operatorNotes;
|
|
1586
1689
|
}
|
|
1690
|
+
if (questionAnswers) {
|
|
1691
|
+
bookingQuote.questionAnswers = questionAnswers;
|
|
1692
|
+
}
|
|
1587
1693
|
const quoteInput = { bookingQuotes: [bookingQuote] };
|
|
1588
1694
|
if (input.parentOrderId) {
|
|
1589
1695
|
quoteInput.source = { clonedFromId: input.parentOrderId };
|
|
@@ -1623,6 +1729,32 @@ ${note}`;
|
|
|
1623
1729
|
}
|
|
1624
1730
|
return created;
|
|
1625
1731
|
}
|
|
1732
|
+
/**
|
|
1733
|
+
* Resolves the input's custom-question answers into the quote's
|
|
1734
|
+
* `questionAnswers` payload (each tagged with a fresh `refid`), or `null` when
|
|
1735
|
+
* none were supplied. Fetches the activity's custom questions to validate
|
|
1736
|
+
* against; throws on the first unmatched/ambiguous/invalid answer.
|
|
1737
|
+
*/
|
|
1738
|
+
async buildQuestionAnswers(input) {
|
|
1739
|
+
const answers = input.customQuestionAnswers ?? [];
|
|
1740
|
+
const requireRequired = input.requireRequiredQuestions ?? false;
|
|
1741
|
+
if (answers.length === 0 && !requireRequired) {
|
|
1742
|
+
return null;
|
|
1743
|
+
}
|
|
1744
|
+
const questions = await this.deps.productService.getCustomQuestions(
|
|
1745
|
+
input.activityId
|
|
1746
|
+
);
|
|
1747
|
+
const resolved = resolveCustomQuestionAnswers(answers, questions, {
|
|
1748
|
+
requireRequired
|
|
1749
|
+
});
|
|
1750
|
+
if (resolved.length === 0) {
|
|
1751
|
+
return null;
|
|
1752
|
+
}
|
|
1753
|
+
return resolved.map((answer) => ({
|
|
1754
|
+
...answer,
|
|
1755
|
+
refid: randomUUID()
|
|
1756
|
+
}));
|
|
1757
|
+
}
|
|
1626
1758
|
async markCreatedBookingPaid(booking, input) {
|
|
1627
1759
|
const parsedPartial = input.markAsPaidAmount ? parseFloat(input.markAsPaidAmount) : NaN;
|
|
1628
1760
|
const amount = !Number.isNaN(parsedPartial) && parsedPartial > 0 ? parsedPartial.toFixed(2) : booking.balanceAmount;
|
|
@@ -2935,6 +3067,33 @@ function fromItemOptionNodes(nodes) {
|
|
|
2935
3067
|
return Array.from(grouped.values());
|
|
2936
3068
|
}
|
|
2937
3069
|
|
|
3070
|
+
// src/internal/peek/products/custom-question-converter.ts
|
|
3071
|
+
function fromQuestionConfigurations(configs) {
|
|
3072
|
+
return configs.map(fromQuestionConfiguration);
|
|
3073
|
+
}
|
|
3074
|
+
function fromQuestionConfiguration(config) {
|
|
3075
|
+
const question = config.question;
|
|
3076
|
+
return {
|
|
3077
|
+
id: question.id,
|
|
3078
|
+
order: config.order ?? 0,
|
|
3079
|
+
isRequired: config.isRequired ?? false,
|
|
3080
|
+
questionText: question.text,
|
|
3081
|
+
hintText: question.hint ?? null,
|
|
3082
|
+
questionType: question.questionType,
|
|
3083
|
+
internalLabel: question.internalLabel ?? null,
|
|
3084
|
+
perGuest: question.perGuest ?? false,
|
|
3085
|
+
defaultValue: question.answerDefaultValue ?? null,
|
|
3086
|
+
options: (question.options ?? []).map(fromQuestionOption)
|
|
3087
|
+
};
|
|
3088
|
+
}
|
|
3089
|
+
function fromQuestionOption(option) {
|
|
3090
|
+
return {
|
|
3091
|
+
id: option.id,
|
|
3092
|
+
order: option.order,
|
|
3093
|
+
value: option.text
|
|
3094
|
+
};
|
|
3095
|
+
}
|
|
3096
|
+
|
|
2938
3097
|
// src/internal/peek/products/product-queries.ts
|
|
2939
3098
|
var PRODUCTS_QUERY = `
|
|
2940
3099
|
query Sales {
|
|
@@ -2993,7 +3152,38 @@ var ITEM_OPTIONS_QUERY = `
|
|
|
2993
3152
|
}
|
|
2994
3153
|
`;
|
|
2995
3154
|
|
|
3155
|
+
// src/internal/peek/products/custom-question-queries.ts
|
|
3156
|
+
var CUSTOM_QUESTIONS_QUERY = `
|
|
3157
|
+
query Sales($id: ID!) {
|
|
3158
|
+
activity(id: $id) {
|
|
3159
|
+
id
|
|
3160
|
+
name
|
|
3161
|
+
questionActivityConfigurations {
|
|
3162
|
+
isRequired
|
|
3163
|
+
order
|
|
3164
|
+
question {
|
|
3165
|
+
id
|
|
3166
|
+
questionType
|
|
3167
|
+
text
|
|
3168
|
+
answerDefaultValue
|
|
3169
|
+
hint
|
|
3170
|
+
internalLabel
|
|
3171
|
+
perGuest
|
|
3172
|
+
... on ChoiceQuestion {
|
|
3173
|
+
options {
|
|
3174
|
+
id
|
|
3175
|
+
text
|
|
3176
|
+
order
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
`;
|
|
3184
|
+
|
|
2996
3185
|
// src/internal/peek/products/product-service.ts
|
|
3186
|
+
var ERROR_PRODUCT_ID_REQUIRED2 = "A non-empty product id is required.";
|
|
2997
3187
|
var DEFAULT_ITEM_OPTIONS_PAGE_SIZE = 50;
|
|
2998
3188
|
var ProductService = class {
|
|
2999
3189
|
constructor(client, options = {}) {
|
|
@@ -3038,6 +3228,32 @@ var ProductService = class {
|
|
|
3038
3228
|
const nodes = await this.fetchAllItemOptionNodes();
|
|
3039
3229
|
return fromItemOptionNodes(nodes);
|
|
3040
3230
|
}
|
|
3231
|
+
/**
|
|
3232
|
+
* Returns every custom question configured on a single activity, in the order
|
|
3233
|
+
* Peek reports them. Choice-style questions (`SELECT_ONE`, `LOCATION`, …)
|
|
3234
|
+
* carry their selectable {@link CustomQuestion.options}; free-text/checkbox
|
|
3235
|
+
* questions return an empty option list.
|
|
3236
|
+
*
|
|
3237
|
+
* These are question **definitions**, not customer answers — no PII is
|
|
3238
|
+
* involved, so the result is unaffected by `fullCustomerAccess`.
|
|
3239
|
+
*
|
|
3240
|
+
* @param productId The activity's id.
|
|
3241
|
+
* @returns The activity's custom questions, or an empty list when the activity
|
|
3242
|
+
* has none or is not found.
|
|
3243
|
+
* @throws Error when `productId` is missing or blank.
|
|
3244
|
+
*/
|
|
3245
|
+
async getCustomQuestions(productId) {
|
|
3246
|
+
if (!productId?.trim()) {
|
|
3247
|
+
throw new Error(ERROR_PRODUCT_ID_REQUIRED2);
|
|
3248
|
+
}
|
|
3249
|
+
const body = await this.client.request(
|
|
3250
|
+
SALES_ENDPOINT,
|
|
3251
|
+
CUSTOM_QUESTIONS_QUERY,
|
|
3252
|
+
{ id: productId }
|
|
3253
|
+
);
|
|
3254
|
+
const configs = body.data?.activity?.questionActivityConfigurations ?? [];
|
|
3255
|
+
return fromQuestionConfigurations(configs);
|
|
3256
|
+
}
|
|
3041
3257
|
async fetchActivities() {
|
|
3042
3258
|
const body = await this.client.request(
|
|
3043
3259
|
SALES_ENDPOINT,
|
|
@@ -3751,6 +3967,10 @@ var PeekAccessService = class {
|
|
|
3751
3967
|
getAllAddons() {
|
|
3752
3968
|
return this.getProductService().getAllAddons();
|
|
3753
3969
|
}
|
|
3970
|
+
/** An activity's custom questions. Delegates to {@link ProductService.getCustomQuestions}. */
|
|
3971
|
+
getCustomQuestions(productId) {
|
|
3972
|
+
return this.getProductService().getCustomQuestions(productId);
|
|
3973
|
+
}
|
|
3754
3974
|
// ─── Account-user short-forms ─────────────────────────────────────────────
|
|
3755
3975
|
/** All active account users. Delegates to {@link AccountUserService.getAll}. */
|
|
3756
3976
|
getAllAccountUsers() {
|