@peektravel/app-utilities 0.1.1 → 0.1.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
@@ -922,6 +922,80 @@ declare class ResourcePoolService {
922
922
  getAll(mode?: ResourcePoolMode): Promise<ResourcePool[]>;
923
923
  }
924
924
 
925
+ /**
926
+ * Clean data models for Peek activity reviews.
927
+ */
928
+ /** A guide credited on a review. */
929
+ interface Guide {
930
+ /** Guide id (e.g. `u_y6e4r`). */
931
+ id: string;
932
+ /** Guide display name. */
933
+ name: string;
934
+ }
935
+ /** A single customer review for an activity (product). */
936
+ interface Review {
937
+ /** Review id (e.g. `rvw_359erv`). */
938
+ id: string;
939
+ /** Activity (product) id the review is for. */
940
+ productId: string;
941
+ /** Activity (product) name. */
942
+ productName: string;
943
+ /** Guides credited on the review. May be empty. */
944
+ guides: Guide[];
945
+ /** Customer name. May be null. */
946
+ customerName: string | null;
947
+ /** Customer email. May be null. */
948
+ customerEmail: string | null;
949
+ /** Activity date (`YYYY-MM-DD`), derived from `purchasedFor`. */
950
+ activityDate: string;
951
+ /** Review date (`YYYY-MM-DD`), derived from `reviewedAt`. */
952
+ reviewDate: string;
953
+ /** Star rating, 1–5. */
954
+ rating: number;
955
+ /** Free-text review. May be null. */
956
+ comment: string | null;
957
+ }
958
+
959
+ /**
960
+ * Reads activity reviews from the gateway, which returns them newest-first
961
+ * (descending `reviewedAt`). {@link ReviewService.getReviews} fetches a single
962
+ * page of up to `reviewCount` reviews, skipping the first `reviewOffset` of
963
+ * them via the connection cursor.
964
+ *
965
+ * Obtain an instance via {@link PeekAccessService.getReviewService}.
966
+ */
967
+ declare class ReviewService {
968
+ private readonly client;
969
+ constructor(client: GraphQLClient);
970
+ /**
971
+ * Returns up to `reviewCount` reviews for an activity in **descending order
972
+ * by review date (newest first)**, skipping the `reviewOffset` newest reviews
973
+ * before collecting.
974
+ *
975
+ * The gateway cursor resumes *after* a given absolute offset, so to skip the
976
+ * first `reviewOffset` reviews the request is anchored on the review just
977
+ * before the window. A `reviewOffset` of 0 needs no cursor and is sent
978
+ * without one.
979
+ *
980
+ * @param productId - The activity (product) id to fetch reviews for.
981
+ * @param reviewCount - How many reviews to return (1–50). Default: 50.
982
+ * @param reviewOffset - How many of the newest reviews to skip first
983
+ * (0-based). Default: 0 (start at the newest review).
984
+ *
985
+ * @throws {Error} when `productId` is empty, `reviewCount` is not an integer
986
+ * in 1–50, or `reviewOffset` is not a non-negative integer.
987
+ *
988
+ * @example
989
+ * ```ts
990
+ * const reviews = await peek
991
+ * .getReviewService()
992
+ * .getReviews("87cdf37f-1872-42cb-b0bd-518312624fc1", 25, 50);
993
+ * ```
994
+ */
995
+ getReviews(productId: string, reviewCount?: number, reviewOffset?: number): Promise<Review[]>;
996
+ private validate;
997
+ }
998
+
925
999
  /**
926
1000
  * The clean data model for Peek Pro timeslots and timeslot operations.
927
1001
  */
@@ -1182,6 +1256,7 @@ declare class PeekAccessService {
1182
1256
  private availabilityService?;
1183
1257
  private membershipService?;
1184
1258
  private bookingService?;
1259
+ private reviewService?;
1185
1260
  constructor(config: PeekAccessServiceConfig);
1186
1261
  /**
1187
1262
  * Returns the {@link ProductService} for this install, bound to the shared
@@ -1234,6 +1309,11 @@ declare class PeekAccessService {
1234
1309
  * authenticated transport. The instance is created lazily and reused.
1235
1310
  */
1236
1311
  getBookingService(): BookingService;
1312
+ /**
1313
+ * Returns the {@link ReviewService} for this install, bound to the shared
1314
+ * authenticated transport. The instance is created lazily and reused.
1315
+ */
1316
+ getReviewService(): ReviewService;
1237
1317
  }
1238
1318
 
1239
1319
  /**
@@ -1269,4 +1349,4 @@ declare class PeekGraphQLError extends Error {
1269
1349
  constructor(graphqlErrors: unknown[], message?: string);
1270
1350
  }
1271
1351
 
1272
- export { ADD_ON_PRODUCT_TYPE, type AccountUser, AccountUserService, type AccountUserServiceOptions, 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 CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreatePromoCodeInput, type CreatedBooking, type CreatedPromoCode, type CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type GuideAssignment, type InvoiceLinkResult, type Logger, type MakePaymentInput, type MakePaymentResult, type Membership, type MembershipPurchaseInput, MembershipService, type NoteMode, type Payment, type PaymentSource, PeekAccessService, type PeekAccessServiceConfig, PeekGraphQLError, type Price, type Product, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RateLimitError, type RefundInput, type RefundResult, ResellerService, type Resource, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateTimeslotResult, noopLogger };
1352
+ export { ADD_ON_PRODUCT_TYPE, type AccountUser, AccountUserService, type AccountUserServiceOptions, 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 CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreatePromoCodeInput, type CreatedBooking, type CreatedPromoCode, type CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, type InvoiceLinkResult, type Logger, type MakePaymentInput, type MakePaymentResult, type Membership, type MembershipPurchaseInput, MembershipService, type NoteMode, type Payment, type PaymentSource, PeekAccessService, type PeekAccessServiceConfig, PeekGraphQLError, type Price, type Product, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RateLimitError, type RefundInput, type RefundResult, ResellerService, type Resource, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateTimeslotResult, noopLogger };
package/dist/index.d.ts CHANGED
@@ -922,6 +922,80 @@ declare class ResourcePoolService {
922
922
  getAll(mode?: ResourcePoolMode): Promise<ResourcePool[]>;
923
923
  }
924
924
 
925
+ /**
926
+ * Clean data models for Peek activity reviews.
927
+ */
928
+ /** A guide credited on a review. */
929
+ interface Guide {
930
+ /** Guide id (e.g. `u_y6e4r`). */
931
+ id: string;
932
+ /** Guide display name. */
933
+ name: string;
934
+ }
935
+ /** A single customer review for an activity (product). */
936
+ interface Review {
937
+ /** Review id (e.g. `rvw_359erv`). */
938
+ id: string;
939
+ /** Activity (product) id the review is for. */
940
+ productId: string;
941
+ /** Activity (product) name. */
942
+ productName: string;
943
+ /** Guides credited on the review. May be empty. */
944
+ guides: Guide[];
945
+ /** Customer name. May be null. */
946
+ customerName: string | null;
947
+ /** Customer email. May be null. */
948
+ customerEmail: string | null;
949
+ /** Activity date (`YYYY-MM-DD`), derived from `purchasedFor`. */
950
+ activityDate: string;
951
+ /** Review date (`YYYY-MM-DD`), derived from `reviewedAt`. */
952
+ reviewDate: string;
953
+ /** Star rating, 1–5. */
954
+ rating: number;
955
+ /** Free-text review. May be null. */
956
+ comment: string | null;
957
+ }
958
+
959
+ /**
960
+ * Reads activity reviews from the gateway, which returns them newest-first
961
+ * (descending `reviewedAt`). {@link ReviewService.getReviews} fetches a single
962
+ * page of up to `reviewCount` reviews, skipping the first `reviewOffset` of
963
+ * them via the connection cursor.
964
+ *
965
+ * Obtain an instance via {@link PeekAccessService.getReviewService}.
966
+ */
967
+ declare class ReviewService {
968
+ private readonly client;
969
+ constructor(client: GraphQLClient);
970
+ /**
971
+ * Returns up to `reviewCount` reviews for an activity in **descending order
972
+ * by review date (newest first)**, skipping the `reviewOffset` newest reviews
973
+ * before collecting.
974
+ *
975
+ * The gateway cursor resumes *after* a given absolute offset, so to skip the
976
+ * first `reviewOffset` reviews the request is anchored on the review just
977
+ * before the window. A `reviewOffset` of 0 needs no cursor and is sent
978
+ * without one.
979
+ *
980
+ * @param productId - The activity (product) id to fetch reviews for.
981
+ * @param reviewCount - How many reviews to return (1–50). Default: 50.
982
+ * @param reviewOffset - How many of the newest reviews to skip first
983
+ * (0-based). Default: 0 (start at the newest review).
984
+ *
985
+ * @throws {Error} when `productId` is empty, `reviewCount` is not an integer
986
+ * in 1–50, or `reviewOffset` is not a non-negative integer.
987
+ *
988
+ * @example
989
+ * ```ts
990
+ * const reviews = await peek
991
+ * .getReviewService()
992
+ * .getReviews("87cdf37f-1872-42cb-b0bd-518312624fc1", 25, 50);
993
+ * ```
994
+ */
995
+ getReviews(productId: string, reviewCount?: number, reviewOffset?: number): Promise<Review[]>;
996
+ private validate;
997
+ }
998
+
925
999
  /**
926
1000
  * The clean data model for Peek Pro timeslots and timeslot operations.
927
1001
  */
@@ -1182,6 +1256,7 @@ declare class PeekAccessService {
1182
1256
  private availabilityService?;
1183
1257
  private membershipService?;
1184
1258
  private bookingService?;
1259
+ private reviewService?;
1185
1260
  constructor(config: PeekAccessServiceConfig);
1186
1261
  /**
1187
1262
  * Returns the {@link ProductService} for this install, bound to the shared
@@ -1234,6 +1309,11 @@ declare class PeekAccessService {
1234
1309
  * authenticated transport. The instance is created lazily and reused.
1235
1310
  */
1236
1311
  getBookingService(): BookingService;
1312
+ /**
1313
+ * Returns the {@link ReviewService} for this install, bound to the shared
1314
+ * authenticated transport. The instance is created lazily and reused.
1315
+ */
1316
+ getReviewService(): ReviewService;
1237
1317
  }
1238
1318
 
1239
1319
  /**
@@ -1269,4 +1349,4 @@ declare class PeekGraphQLError extends Error {
1269
1349
  constructor(graphqlErrors: unknown[], message?: string);
1270
1350
  }
1271
1351
 
1272
- export { ADD_ON_PRODUCT_TYPE, type AccountUser, AccountUserService, type AccountUserServiceOptions, 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 CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreatePromoCodeInput, type CreatedBooking, type CreatedPromoCode, type CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type GuideAssignment, type InvoiceLinkResult, type Logger, type MakePaymentInput, type MakePaymentResult, type Membership, type MembershipPurchaseInput, MembershipService, type NoteMode, type Payment, type PaymentSource, PeekAccessService, type PeekAccessServiceConfig, PeekGraphQLError, type Price, type Product, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RateLimitError, type RefundInput, type RefundResult, ResellerService, type Resource, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateTimeslotResult, noopLogger };
1352
+ export { ADD_ON_PRODUCT_TYPE, type AccountUser, AccountUserService, type AccountUserServiceOptions, 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 CreateBookingGuest, type CreateBookingInput, type CreateBookingTicket, type CreatePromoCodeInput, type CreatedBooking, type CreatedPromoCode, type CustomQuestionAnswer, type DailyNote, DailyNoteService, type Duration, type Guest, type GuestMetadata, type Guide, type GuideAssignment, type InvoiceLinkResult, type Logger, type MakePaymentInput, type MakePaymentResult, type Membership, type MembershipPurchaseInput, MembershipService, type NoteMode, type Payment, type PaymentSource, PeekAccessService, type PeekAccessServiceConfig, PeekGraphQLError, type Price, type Product, ProductService, type ProductServiceOptions, type ProductTicket, type PromoCode, type PromoCodeFixedAmount, PromoCodeService, type PromoCodeServiceOptions, type PurchasedMembership, RateLimitError, type RefundInput, type RefundResult, ResellerService, type Resource, type ResourceOptionQuantity, type ResourcePool, type ResourcePoolAccountUser, type ResourcePoolAssignment, type ResourcePoolMode, ResourcePoolService, type Review, ReviewService, type Ticket, type Timeslot, type TimeslotFilter, TimeslotService, type UpdateTimeslotResult, noopLogger };
package/dist/index.js CHANGED
@@ -2129,6 +2129,132 @@ var ResourcePoolService = class {
2129
2129
  }
2130
2130
  };
2131
2131
 
2132
+ // src/internal/reviews/review-converter.ts
2133
+ var ISO_DATE_LENGTH = 10;
2134
+ function toDateOnly(isoDateTime) {
2135
+ return isoDateTime.slice(0, ISO_DATE_LENGTH);
2136
+ }
2137
+ function fromReviewNode(node) {
2138
+ const guides = (node.guides ?? []).map((guide) => ({
2139
+ id: guide.id,
2140
+ name: guide.name
2141
+ }));
2142
+ return {
2143
+ id: node.id,
2144
+ productId: node.activity?.id ?? "",
2145
+ productName: node.activity?.name ?? "",
2146
+ guides,
2147
+ customerName: node.name ?? null,
2148
+ customerEmail: node.email ?? null,
2149
+ activityDate: toDateOnly(node.purchasedFor),
2150
+ reviewDate: toDateOnly(node.reviewedAt),
2151
+ rating: node.rating,
2152
+ comment: node.comment ?? null
2153
+ };
2154
+ }
2155
+
2156
+ // src/internal/reviews/review-cursor.ts
2157
+ function encodeCursor(offset, pageSize) {
2158
+ const start = Math.max(0, offset - pageSize + 1);
2159
+ return Buffer.from(`range:${start}..${offset},${offset}`).toString("base64");
2160
+ }
2161
+
2162
+ // src/internal/reviews/review-queries.ts
2163
+ var REVIEWS_QUERY = `
2164
+ query Reviews($first: Int, $filter: ReviewFilter, $after: String) {
2165
+ reviews(first: $first, filter: $filter, after: $after) {
2166
+ edges {
2167
+ node {
2168
+ activity {
2169
+ id
2170
+ name
2171
+ }
2172
+ guides {
2173
+ id
2174
+ name
2175
+ }
2176
+ id
2177
+ name
2178
+ email
2179
+ rating
2180
+ comment
2181
+ reviewedAt
2182
+ purchasedFor
2183
+ }
2184
+ cursor
2185
+ }
2186
+ }
2187
+ }
2188
+ `;
2189
+ function buildReviewsVariables(params) {
2190
+ return {
2191
+ first: params.first,
2192
+ filter: { activityIds: [params.activityId] },
2193
+ after: params.after
2194
+ };
2195
+ }
2196
+
2197
+ // src/internal/reviews/review-service.ts
2198
+ var DEFAULT_REVIEW_COUNT = 50;
2199
+ var MIN_REVIEW_COUNT = 1;
2200
+ var MAX_REVIEW_COUNT = 50;
2201
+ var ERROR_PRODUCT_ID_REQUIRED = "productId is required";
2202
+ var ERROR_INVALID_REVIEW_COUNT = `reviewCount must be an integer between ${MIN_REVIEW_COUNT} and ${MAX_REVIEW_COUNT}`;
2203
+ var ERROR_INVALID_REVIEW_OFFSET = "reviewOffset must be a non-negative integer";
2204
+ var ReviewService = class {
2205
+ constructor(client) {
2206
+ this.client = client;
2207
+ }
2208
+ client;
2209
+ /**
2210
+ * Returns up to `reviewCount` reviews for an activity in **descending order
2211
+ * by review date (newest first)**, skipping the `reviewOffset` newest reviews
2212
+ * before collecting.
2213
+ *
2214
+ * The gateway cursor resumes *after* a given absolute offset, so to skip the
2215
+ * first `reviewOffset` reviews the request is anchored on the review just
2216
+ * before the window. A `reviewOffset` of 0 needs no cursor and is sent
2217
+ * without one.
2218
+ *
2219
+ * @param productId - The activity (product) id to fetch reviews for.
2220
+ * @param reviewCount - How many reviews to return (1–50). Default: 50.
2221
+ * @param reviewOffset - How many of the newest reviews to skip first
2222
+ * (0-based). Default: 0 (start at the newest review).
2223
+ *
2224
+ * @throws {Error} when `productId` is empty, `reviewCount` is not an integer
2225
+ * in 1–50, or `reviewOffset` is not a non-negative integer.
2226
+ *
2227
+ * @example
2228
+ * ```ts
2229
+ * const reviews = await peek
2230
+ * .getReviewService()
2231
+ * .getReviews("87cdf37f-1872-42cb-b0bd-518312624fc1", 25, 50);
2232
+ * ```
2233
+ */
2234
+ async getReviews(productId, reviewCount = DEFAULT_REVIEW_COUNT, reviewOffset = 0) {
2235
+ this.validate(productId, reviewCount, reviewOffset);
2236
+ const after = reviewOffset > 0 ? encodeCursor(reviewOffset - 1, reviewCount) : null;
2237
+ const body = await this.client.request(
2238
+ SALES_ENDPOINT,
2239
+ REVIEWS_QUERY,
2240
+ buildReviewsVariables({ activityId: productId, first: reviewCount, after })
2241
+ );
2242
+ const edges = body.data?.reviews?.edges ?? [];
2243
+ return edges.map((edge) => fromReviewNode(edge.node));
2244
+ }
2245
+ validate(productId, reviewCount, reviewOffset) {
2246
+ if (!productId) {
2247
+ throw new Error(ERROR_PRODUCT_ID_REQUIRED);
2248
+ }
2249
+ if (!Number.isInteger(reviewCount) || reviewCount < MIN_REVIEW_COUNT || reviewCount > MAX_REVIEW_COUNT) {
2250
+ throw new Error(ERROR_INVALID_REVIEW_COUNT);
2251
+ }
2252
+ if (!Number.isInteger(reviewOffset) || reviewOffset < 0) {
2253
+ throw new Error(ERROR_INVALID_REVIEW_OFFSET);
2254
+ }
2255
+ }
2256
+ };
2257
+
2132
2258
  // src/internal/timeslots/timeslot-converter.ts
2133
2259
  function fromTimeslotNodes(nodes, productId) {
2134
2260
  if (!Array.isArray(nodes) || nodes.length === 0) {
@@ -2776,6 +2902,7 @@ var PeekAccessService = class {
2776
2902
  availabilityService;
2777
2903
  membershipService;
2778
2904
  bookingService;
2905
+ reviewService;
2779
2906
  constructor(config) {
2780
2907
  requireNonEmpty(config.installId, "installId");
2781
2908
  requireNonEmpty(config.jwtSecret, "jwtSecret");
@@ -2912,6 +3039,16 @@ var PeekAccessService = class {
2912
3039
  }
2913
3040
  return this.bookingService;
2914
3041
  }
3042
+ /**
3043
+ * Returns the {@link ReviewService} for this install, bound to the shared
3044
+ * authenticated transport. The instance is created lazily and reused.
3045
+ */
3046
+ getReviewService() {
3047
+ if (!this.reviewService) {
3048
+ this.reviewService = new ReviewService(this.client);
3049
+ }
3050
+ return this.reviewService;
3051
+ }
2915
3052
  };
2916
3053
  function requireNonEmpty(value, name) {
2917
3054
  if (!value) {
@@ -2919,6 +3056,6 @@ function requireNonEmpty(value, name) {
2919
3056
  }
2920
3057
  }
2921
3058
 
2922
- export { ADD_ON_PRODUCT_TYPE, AccountUserService, AdminAccountRequiredError, AvailabilityService, BookingService, DailyNoteService, MembershipService, PeekAccessService, PeekGraphQLError, ProductService, PromoCodeService, RateLimitError, ResellerService, ResourcePoolService, TimeslotService, noopLogger };
3059
+ export { ADD_ON_PRODUCT_TYPE, AccountUserService, AdminAccountRequiredError, AvailabilityService, BookingService, DailyNoteService, MembershipService, PeekAccessService, PeekGraphQLError, ProductService, PromoCodeService, RateLimitError, ResellerService, ResourcePoolService, ReviewService, TimeslotService, noopLogger };
2923
3060
  //# sourceMappingURL=index.js.map
2924
3061
  //# sourceMappingURL=index.js.map