@peektravel/app-utilities 0.9.1 → 0.9.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.d.cts CHANGED
@@ -914,6 +914,16 @@ interface CreateBookingInput {
914
914
  * Default: `false`.
915
915
  */
916
916
  requireRequiredQuestions?: boolean;
917
+ /**
918
+ * When `true`, a `customQuestionAnswers` entry whose `questionIdOrText` is a
919
+ * `cq_…` id is accepted even if that id is **not** among the activity's custom
920
+ * questions — the check that a question id must match the activity's list is
921
+ * skipped, and the answer is sent as-is (as a text answer). Entries given by
922
+ * question **name** are unaffected: they still must match a question, so the
923
+ * activity's questions are fetched only when a by-name answer (or
924
+ * `requireRequiredQuestions`) needs them. Default: `false`.
925
+ */
926
+ acceptAllCustomQuestionIds?: boolean;
917
927
  /** Suppress the customer confirmation email. Default: false. */
918
928
  skipCustomerEmail?: boolean;
919
929
  /** Clone the quote from an existing order. */
@@ -1295,7 +1305,9 @@ declare class BookingService {
1295
1305
  * Resolves the input's custom-question answers into the quote's
1296
1306
  * `questionAnswers` payload (each tagged with a fresh `refid`), or `null` when
1297
1307
  * none were supplied. Fetches the activity's custom questions to validate
1298
- * against; throws on the first unmatched/ambiguous/invalid answer.
1308
+ * against; throws on the first unmatched/ambiguous/invalid answer. When
1309
+ * `acceptAllCustomQuestionIds` is set the fetch is skipped if every answer is
1310
+ * given by id (a by-name answer still needs the list to resolve).
1299
1311
  */
1300
1312
  private buildQuestionAnswers;
1301
1313
  private markCreatedBookingPaid;
@@ -1822,6 +1834,31 @@ interface Review {
1822
1834
  /** Free-text review. May be null. */
1823
1835
  comment: string | null;
1824
1836
  }
1837
+ /**
1838
+ * Aggregate review statistics for a single activity (product), as returned by
1839
+ * {@link ReviewService.getAllReviewSummaries}. Carries no per-review detail or
1840
+ * PII — just the rating distribution and average.
1841
+ */
1842
+ interface ProductReviewSummary {
1843
+ /** Activity (product) id the summary is for. */
1844
+ productId: string;
1845
+ /** Activity (product) name. */
1846
+ productName: string;
1847
+ /** Average star rating as a decimal, or `null` when there are no ratings. */
1848
+ avgRating: number | null;
1849
+ /** Total number of reviews. */
1850
+ countTotal: number;
1851
+ /** Number of 1-star reviews. */
1852
+ countOneStar: number;
1853
+ /** Number of 2-star reviews. */
1854
+ countTwoStar: number;
1855
+ /** Number of 3-star reviews. */
1856
+ countThreeStar: number;
1857
+ /** Number of 4-star reviews. */
1858
+ countFourStar: number;
1859
+ /** Number of 5-star reviews. */
1860
+ countFiveStar: number;
1861
+ }
1825
1862
 
1826
1863
  /**
1827
1864
  * Reads activity reviews from the gateway, which returns them newest-first
@@ -1862,6 +1899,22 @@ declare class ReviewService {
1862
1899
  * ```
1863
1900
  */
1864
1901
  getReviews(productId: string, reviewCount?: number, reviewOffset?: number): Promise<Review[]>;
1902
+ /**
1903
+ * Returns an aggregate review summary for **every** activity — its average
1904
+ * rating and the count of reviews at each star level. This reads the same
1905
+ * activity list as `getAllProducts`; it carries no per-review detail or PII, so
1906
+ * it is unaffected by `fullCustomerAccess`. An activity with no reviews comes
1907
+ * back with a `null` `avgRating` and zero counts.
1908
+ *
1909
+ * @example
1910
+ * ```ts
1911
+ * const summaries = await peek.getReviewService().getAllReviewSummaries();
1912
+ * for (const s of summaries) {
1913
+ * console.log(s.productName, s.avgRating, s.countTotal);
1914
+ * }
1915
+ * ```
1916
+ */
1917
+ getAllReviewSummaries(): Promise<ProductReviewSummary[]>;
1865
1918
  private validate;
1866
1919
  }
1867
1920
 
@@ -2990,4 +3043,4 @@ declare class AcmeApiError extends Error {
2990
3043
  constructor(statusCode: number, body: unknown, message?: string);
2991
3044
  }
2992
3045
 
2993
- 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 };
3046
+ 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, type ProductReviewSummary, 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
@@ -914,6 +914,16 @@ interface CreateBookingInput {
914
914
  * Default: `false`.
915
915
  */
916
916
  requireRequiredQuestions?: boolean;
917
+ /**
918
+ * When `true`, a `customQuestionAnswers` entry whose `questionIdOrText` is a
919
+ * `cq_…` id is accepted even if that id is **not** among the activity's custom
920
+ * questions — the check that a question id must match the activity's list is
921
+ * skipped, and the answer is sent as-is (as a text answer). Entries given by
922
+ * question **name** are unaffected: they still must match a question, so the
923
+ * activity's questions are fetched only when a by-name answer (or
924
+ * `requireRequiredQuestions`) needs them. Default: `false`.
925
+ */
926
+ acceptAllCustomQuestionIds?: boolean;
917
927
  /** Suppress the customer confirmation email. Default: false. */
918
928
  skipCustomerEmail?: boolean;
919
929
  /** Clone the quote from an existing order. */
@@ -1295,7 +1305,9 @@ declare class BookingService {
1295
1305
  * Resolves the input's custom-question answers into the quote's
1296
1306
  * `questionAnswers` payload (each tagged with a fresh `refid`), or `null` when
1297
1307
  * none were supplied. Fetches the activity's custom questions to validate
1298
- * against; throws on the first unmatched/ambiguous/invalid answer.
1308
+ * against; throws on the first unmatched/ambiguous/invalid answer. When
1309
+ * `acceptAllCustomQuestionIds` is set the fetch is skipped if every answer is
1310
+ * given by id (a by-name answer still needs the list to resolve).
1299
1311
  */
1300
1312
  private buildQuestionAnswers;
1301
1313
  private markCreatedBookingPaid;
@@ -1822,6 +1834,31 @@ interface Review {
1822
1834
  /** Free-text review. May be null. */
1823
1835
  comment: string | null;
1824
1836
  }
1837
+ /**
1838
+ * Aggregate review statistics for a single activity (product), as returned by
1839
+ * {@link ReviewService.getAllReviewSummaries}. Carries no per-review detail or
1840
+ * PII — just the rating distribution and average.
1841
+ */
1842
+ interface ProductReviewSummary {
1843
+ /** Activity (product) id the summary is for. */
1844
+ productId: string;
1845
+ /** Activity (product) name. */
1846
+ productName: string;
1847
+ /** Average star rating as a decimal, or `null` when there are no ratings. */
1848
+ avgRating: number | null;
1849
+ /** Total number of reviews. */
1850
+ countTotal: number;
1851
+ /** Number of 1-star reviews. */
1852
+ countOneStar: number;
1853
+ /** Number of 2-star reviews. */
1854
+ countTwoStar: number;
1855
+ /** Number of 3-star reviews. */
1856
+ countThreeStar: number;
1857
+ /** Number of 4-star reviews. */
1858
+ countFourStar: number;
1859
+ /** Number of 5-star reviews. */
1860
+ countFiveStar: number;
1861
+ }
1825
1862
 
1826
1863
  /**
1827
1864
  * Reads activity reviews from the gateway, which returns them newest-first
@@ -1862,6 +1899,22 @@ declare class ReviewService {
1862
1899
  * ```
1863
1900
  */
1864
1901
  getReviews(productId: string, reviewCount?: number, reviewOffset?: number): Promise<Review[]>;
1902
+ /**
1903
+ * Returns an aggregate review summary for **every** activity — its average
1904
+ * rating and the count of reviews at each star level. This reads the same
1905
+ * activity list as `getAllProducts`; it carries no per-review detail or PII, so
1906
+ * it is unaffected by `fullCustomerAccess`. An activity with no reviews comes
1907
+ * back with a `null` `avgRating` and zero counts.
1908
+ *
1909
+ * @example
1910
+ * ```ts
1911
+ * const summaries = await peek.getReviewService().getAllReviewSummaries();
1912
+ * for (const s of summaries) {
1913
+ * console.log(s.productName, s.avgRating, s.countTotal);
1914
+ * }
1915
+ * ```
1916
+ */
1917
+ getAllReviewSummaries(): Promise<ProductReviewSummary[]>;
1865
1918
  private validate;
1866
1919
  }
1867
1920
 
@@ -2990,4 +3043,4 @@ declare class AcmeApiError extends Error {
2990
3043
  constructor(statusCode: number, body: unknown, message?: string);
2991
3044
  }
2992
3045
 
2993
- 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 };
3046
+ 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, type ProductReviewSummary, 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
@@ -1090,6 +1090,9 @@ var QUESTION_TYPE_SELECT_ONE = "SELECT_ONE";
1090
1090
  var QUESTION_TYPE_LOCATION = "LOCATION";
1091
1091
  var QUESTION_ID_REGEX = /^cq_[a-z0-9]+$/;
1092
1092
  var OPTION_ID_REGEX = /^cqao_[a-z0-9]+$/;
1093
+ function isCustomQuestionId(idOrText) {
1094
+ return QUESTION_ID_REGEX.test(idOrText);
1095
+ }
1093
1096
  var CHECKBOX_TRUE = /* @__PURE__ */ new Set(["yes", "true"]);
1094
1097
  var CHECKBOX_VALID = /* @__PURE__ */ new Set(["yes", "no", "true", "false"]);
1095
1098
  var CHECKBOX_TEXT_TRUE = "Yes";
@@ -1107,10 +1110,13 @@ var errMissingRequired = (text, id) => `Custom question "${text}" (${id}) is req
1107
1110
  function normalize(value) {
1108
1111
  return value.toLowerCase().replace(/[^a-z0-9]/g, "");
1109
1112
  }
1110
- function resolveQuestion(idOrText, questions) {
1113
+ function resolveQuestion(idOrText, questions, acceptAllIds) {
1111
1114
  if (QUESTION_ID_REGEX.test(idOrText)) {
1112
1115
  const byId = questions.find((question) => question.id === idOrText);
1113
- if (!byId) throw new Error(errUnknownQuestionId(idOrText));
1116
+ if (!byId) {
1117
+ if (acceptAllIds) return null;
1118
+ throw new Error(errUnknownQuestionId(idOrText));
1119
+ }
1114
1120
  return byId;
1115
1121
  }
1116
1122
  const target = normalize(idOrText);
@@ -1135,8 +1141,11 @@ function resolveOption(value, question) {
1135
1141
  if (matches.length > 1) throw new Error(errAmbiguousOption(value, question.id));
1136
1142
  return matches[0];
1137
1143
  }
1138
- function resolveOne(answer, questions) {
1139
- const question = resolveQuestion(answer.questionIdOrText, questions);
1144
+ function resolveOne(answer, questions, acceptAllIds) {
1145
+ const question = resolveQuestion(answer.questionIdOrText, questions, acceptAllIds);
1146
+ if (!question) {
1147
+ return { questionId: answer.questionIdOrText, questionAnswerText: answer.value };
1148
+ }
1140
1149
  if (question.perGuest) {
1141
1150
  throw new Error(errPerGuestUnsupported(question.id));
1142
1151
  }
@@ -1169,7 +1178,8 @@ function resolveOne(answer, questions) {
1169
1178
  }
1170
1179
  }
1171
1180
  function resolveCustomQuestionAnswers(answers, questions, options) {
1172
- const resolved = answers.map((answer) => resolveOne(answer, questions));
1181
+ const acceptAllIds = options?.acceptAllIds ?? false;
1182
+ const resolved = answers.map((answer) => resolveOne(answer, questions, acceptAllIds));
1173
1183
  if (options?.requireRequired) {
1174
1184
  assertRequiredAnswered(resolved, questions);
1175
1185
  }
@@ -1777,19 +1787,22 @@ ${note}`;
1777
1787
  * Resolves the input's custom-question answers into the quote's
1778
1788
  * `questionAnswers` payload (each tagged with a fresh `refid`), or `null` when
1779
1789
  * none were supplied. Fetches the activity's custom questions to validate
1780
- * against; throws on the first unmatched/ambiguous/invalid answer.
1790
+ * against; throws on the first unmatched/ambiguous/invalid answer. When
1791
+ * `acceptAllCustomQuestionIds` is set the fetch is skipped if every answer is
1792
+ * given by id (a by-name answer still needs the list to resolve).
1781
1793
  */
1782
1794
  async buildQuestionAnswers(input) {
1783
1795
  const answers = input.customQuestionAnswers ?? [];
1784
1796
  const requireRequired = input.requireRequiredQuestions ?? false;
1797
+ const acceptAllIds = input.acceptAllCustomQuestionIds ?? false;
1785
1798
  if (answers.length === 0 && !requireRequired) {
1786
1799
  return null;
1787
1800
  }
1788
- const questions = await this.deps.productService.getCustomQuestions(
1789
- input.activityId
1790
- );
1801
+ const needsQuestions = !acceptAllIds || requireRequired || answers.some((answer) => !isCustomQuestionId(answer.questionIdOrText));
1802
+ const questions = needsQuestions ? await this.deps.productService.getCustomQuestions(input.activityId) : [];
1791
1803
  const resolved = resolveCustomQuestionAnswers(answers, questions, {
1792
- requireRequired
1804
+ requireRequired,
1805
+ acceptAllIds
1793
1806
  });
1794
1807
  if (resolved.length === 0) {
1795
1808
  return null;
@@ -2162,7 +2175,7 @@ async function requestWithRetry(http, url, init, label, onResponse) {
2162
2175
  // src/internal/sdk-headers.ts
2163
2176
  var SDK_HEADER_NAME = "x-peek-sdk";
2164
2177
  var SDK_PLATFORM = "js";
2165
- var SDK_VERSION = "0.9.1";
2178
+ var SDK_VERSION = "0.9.2";
2166
2179
  var SDK_HEADER_VALUE = `${SDK_PLATFORM}-${SDK_VERSION}`;
2167
2180
 
2168
2181
  // src/internal/peek/graphql-client.ts
@@ -2587,6 +2600,23 @@ function fromReviewNode(node) {
2587
2600
  comment: node.comment ?? null
2588
2601
  };
2589
2602
  }
2603
+ function fromActivityReviewSummaryNode(node) {
2604
+ const meta = node.reviewMeta;
2605
+ return {
2606
+ productId: node.id,
2607
+ productName: node.name,
2608
+ avgRating: meta?.avgRating ?? null,
2609
+ countTotal: meta?.count ?? 0,
2610
+ countOneStar: meta?.oneStar ?? 0,
2611
+ countTwoStar: meta?.twoStar ?? 0,
2612
+ countThreeStar: meta?.threeStar ?? 0,
2613
+ countFourStar: meta?.fourStar ?? 0,
2614
+ countFiveStar: meta?.fiveStar ?? 0
2615
+ };
2616
+ }
2617
+ function fromActivityReviewSummaryNodes(nodes) {
2618
+ return nodes.map(fromActivityReviewSummaryNode);
2619
+ }
2590
2620
 
2591
2621
  // src/internal/peek/reviews/review-cursor.ts
2592
2622
  function encodeCursor(offset, pageSize) {
@@ -2622,6 +2652,23 @@ function buildReviewsQuery(fullCustomerAccess) {
2622
2652
  }
2623
2653
  `;
2624
2654
  }
2655
+ var REVIEW_SUMMARIES_QUERY = `
2656
+ query ReviewSummaries {
2657
+ activities {
2658
+ id
2659
+ name
2660
+ reviewMeta {
2661
+ avgRating
2662
+ count
2663
+ fiveStar
2664
+ fourStar
2665
+ threeStar
2666
+ twoStar
2667
+ oneStar
2668
+ }
2669
+ }
2670
+ }
2671
+ `;
2625
2672
  function buildReviewsVariables(params) {
2626
2673
  return {
2627
2674
  first: params.first,
@@ -2681,6 +2728,29 @@ var ReviewService = class {
2681
2728
  const edges = body.data?.reviews?.edges ?? [];
2682
2729
  return edges.map((edge) => fromReviewNode(edge.node));
2683
2730
  }
2731
+ /**
2732
+ * Returns an aggregate review summary for **every** activity — its average
2733
+ * rating and the count of reviews at each star level. This reads the same
2734
+ * activity list as `getAllProducts`; it carries no per-review detail or PII, so
2735
+ * it is unaffected by `fullCustomerAccess`. An activity with no reviews comes
2736
+ * back with a `null` `avgRating` and zero counts.
2737
+ *
2738
+ * @example
2739
+ * ```ts
2740
+ * const summaries = await peek.getReviewService().getAllReviewSummaries();
2741
+ * for (const s of summaries) {
2742
+ * console.log(s.productName, s.avgRating, s.countTotal);
2743
+ * }
2744
+ * ```
2745
+ */
2746
+ async getAllReviewSummaries() {
2747
+ const body = await this.client.request(
2748
+ SALES_ENDPOINT,
2749
+ REVIEW_SUMMARIES_QUERY,
2750
+ {}
2751
+ );
2752
+ return fromActivityReviewSummaryNodes(body.data?.activities ?? []);
2753
+ }
2684
2754
  validate(productId, reviewCount, reviewOffset) {
2685
2755
  if (!productId) {
2686
2756
  throw new Error(ERROR_PRODUCT_ID_REQUIRED);