@peektravel/app-utilities 0.5.0 → 0.5.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 CHANGED
@@ -2800,6 +2800,7 @@ function fromActivity(activity) {
2800
2800
  name: activity.name,
2801
2801
  type: activity.type,
2802
2802
  color: activity.colorHex || "",
2803
+ currency: activity.currency || "",
2803
2804
  tickets: (activity.resourceOptions ?? []).map((option) => ({
2804
2805
  id: option.id,
2805
2806
  name: option.name
@@ -2818,6 +2819,7 @@ function fromItemOptionNodes(nodes) {
2818
2819
  name: node.item.name,
2819
2820
  type: ADD_ON_PRODUCT_TYPE,
2820
2821
  color: ADD_ON_COLOR,
2822
+ currency: "",
2821
2823
  tickets: []
2822
2824
  };
2823
2825
  grouped.set(itemId, product);
@@ -2837,6 +2839,7 @@ var PRODUCTS_QUERY = `
2837
2839
  deletedAt
2838
2840
  type
2839
2841
  colorHex
2842
+ currency
2840
2843
  resourceOptions {
2841
2844
  id
2842
2845
  name
@@ -3063,6 +3066,325 @@ var PromoCodeService = class {
3063
3066
  }
3064
3067
  };
3065
3068
 
3069
+ // src/internal/peek/pricing/pricing-queries.ts
3070
+ var CREATE_PRICING_ENGINE_MUTATION = `
3071
+ mutation CreatePricingEngine($input: CreatePricingEngineInput!) {
3072
+ createPricingEngine(input: $input) {
3073
+ __typename
3074
+ ... on CreatePricingEngineSuccess {
3075
+ engine {
3076
+ id
3077
+ }
3078
+ }
3079
+ ... on InvalidDataError {
3080
+ message
3081
+ }
3082
+ }
3083
+ }
3084
+ `;
3085
+ var UPDATE_PRICING_ENGINE_MUTATION = `
3086
+ mutation UpdatePricingEngine($input: UpdatePricingEngineInput!) {
3087
+ updatePricingEngine(input: $input) {
3088
+ __typename
3089
+ ... on UpdatePricingEngineSuccess {
3090
+ engine {
3091
+ id
3092
+ name
3093
+ }
3094
+ }
3095
+ ... on InvalidDataError {
3096
+ message
3097
+ }
3098
+ ... on NotFoundError {
3099
+ id
3100
+ message
3101
+ }
3102
+ }
3103
+ }
3104
+ `;
3105
+ var DELETE_PRICING_ENGINE_MUTATION = `
3106
+ mutation DeletePricingEngine($id: ID!) {
3107
+ deletePricingEngine(id: $id) {
3108
+ __typename
3109
+ ... on DeletePricingEngineSuccess {
3110
+ engine {
3111
+ id
3112
+ name
3113
+ }
3114
+ }
3115
+ ... on NotFoundError {
3116
+ id
3117
+ message
3118
+ }
3119
+ }
3120
+ }
3121
+ `;
3122
+ var UPSERT_PRICING_OVERRIDES_MUTATION = `
3123
+ mutation UpsertPricingOverridesActivityContexts($input: UpsertPricingOverridesActivityContextsInput!) {
3124
+ upsertPricingOverridesActivityContexts(input: $input) {
3125
+ __typename
3126
+ ... on UpsertPricingOverridesActivityContextsSuccess {
3127
+ activityContexts {
3128
+ date
3129
+ activity {
3130
+ id
3131
+ name
3132
+ }
3133
+ engine {
3134
+ id
3135
+ name
3136
+ }
3137
+ overrides {
3138
+ order
3139
+ resourceOptions {
3140
+ resourceOption {
3141
+ id
3142
+ name
3143
+ }
3144
+ override {
3145
+ ... on PricingOverridesActivityContextResourceOptionPriceOverride {
3146
+ price {
3147
+ amount
3148
+ currency
3149
+ }
3150
+ }
3151
+ ... on PricingOverridesActivityContextResourceOptionPercentageAdjustmentOverride {
3152
+ percentageAdjustment
3153
+ }
3154
+ }
3155
+ }
3156
+ filters {
3157
+ __typename
3158
+ ... on PricingOverridesActivityContextStartTimeRangeFilter {
3159
+ startTimeRange
3160
+ }
3161
+ ... on PricingOverridesActivityContextSpotsTakenFilter {
3162
+ minSpots
3163
+ maxSpots
3164
+ }
3165
+ }
3166
+ }
3167
+ }
3168
+ }
3169
+ ... on InvalidDataError {
3170
+ message
3171
+ }
3172
+ }
3173
+ }
3174
+ `;
3175
+ var SPOTS_TAKEN_FILTER_TYPENAME = "PricingOverridesActivityContextSpotsTakenFilter";
3176
+ function buildCreateEngineInput(input) {
3177
+ const activityIds = input.activityIds ?? [];
3178
+ return activityIds.length > 0 ? { name: input.name, filters: [{ activityIds }] } : { name: input.name };
3179
+ }
3180
+ function buildUpdateEngineInput(input) {
3181
+ const activityIds = input.activityIds ?? [];
3182
+ return {
3183
+ id: input.engineId,
3184
+ name: input.name,
3185
+ filters: activityIds.length > 0 ? [{ activityIds }] : []
3186
+ };
3187
+ }
3188
+ function buildUpsertInput(input) {
3189
+ return {
3190
+ engineId: input.engineId,
3191
+ dateRange: input.dateRange,
3192
+ activities: input.activities.map((activity) => ({
3193
+ activityId: activity.activityId,
3194
+ overrides: activity.overrides.map((override) => ({
3195
+ order: override.order,
3196
+ resourceOptions: override.resourceOptions.map(
3197
+ (option) => option.mode === "fixed" ? { id: option.id, price: option.price } : { id: option.id, percentageAdjustment: option.percentageAdjustment }
3198
+ ),
3199
+ filters: override.filters
3200
+ }))
3201
+ }))
3202
+ };
3203
+ }
3204
+ function buildClearInput(input) {
3205
+ return {
3206
+ engineId: input.engineId,
3207
+ dateRange: input.dateRange,
3208
+ activities: input.activityIds.map((activityId) => ({
3209
+ activityId,
3210
+ overrides: []
3211
+ }))
3212
+ };
3213
+ }
3214
+
3215
+ // src/internal/peek/pricing/pricing-converter.ts
3216
+ function fromActivityContexts(contexts) {
3217
+ return contexts.map(fromActivityContext);
3218
+ }
3219
+ function fromActivityContext(context) {
3220
+ return {
3221
+ date: context.date,
3222
+ activity: { id: context.activity.id, name: context.activity.name },
3223
+ engine: { id: context.engine.id, name: context.engine.name },
3224
+ overrides: context.overrides.map(fromOverride)
3225
+ };
3226
+ }
3227
+ function fromOverride(override) {
3228
+ return {
3229
+ order: override.order,
3230
+ resourceOptions: override.resourceOptions.map(fromResourceOption),
3231
+ filters: override.filters.map(fromFilter)
3232
+ };
3233
+ }
3234
+ function fromResourceOption(option) {
3235
+ return {
3236
+ resourceOption: {
3237
+ id: option.resourceOption.id,
3238
+ name: option.resourceOption.name
3239
+ },
3240
+ override: fromResolvedOverride(option.override)
3241
+ };
3242
+ }
3243
+ function fromResolvedOverride(override) {
3244
+ return "price" in override ? { mode: "fixed", price: override.price } : { mode: "percentage", percentageAdjustment: override.percentageAdjustment };
3245
+ }
3246
+ function fromFilter(filter) {
3247
+ if (filter.__typename === SPOTS_TAKEN_FILTER_TYPENAME) {
3248
+ const spotsTaken = {};
3249
+ if (filter.minSpots !== null) spotsTaken.minSpots = filter.minSpots;
3250
+ if (filter.maxSpots !== null) spotsTaken.maxSpots = filter.maxSpots;
3251
+ return { spotsTaken };
3252
+ }
3253
+ return { startTimeRange: filter.startTimeRange };
3254
+ }
3255
+
3256
+ // src/internal/peek/pricing/pricing-service.ts
3257
+ var CURRENCY_PATTERN2 = /^[A-Z]{3}$/;
3258
+ var PERCENTAGE_FLOOR = -100;
3259
+ var ERROR_NAME_REQUIRED = "name is required";
3260
+ var ERROR_ENGINE_ID_REQUIRED = "engineId is required";
3261
+ var ERROR_DATE_RANGE_REQUIRED = "dateRange is required";
3262
+ var ERROR_ACTIVITIES_REQUIRED = "activities is required";
3263
+ var ERROR_ACTIVITY_ID_REQUIRED = "activityId is required";
3264
+ var ERROR_TICKET_ID_REQUIRED = "resource-option id is required";
3265
+ var ERROR_CURRENCY_FORMAT = "currency must be 3 uppercase letters";
3266
+ var ERROR_AMOUNT_NUMBER = "price amount must be a valid number";
3267
+ var ERROR_PERCENTAGE_NUMBER = "percentageAdjustment must be a valid number";
3268
+ var ERROR_PERCENTAGE_FLOOR = "percentageAdjustment must be greater than -100";
3269
+ var ERROR_NO_DATA = "pricing mutation returned no data";
3270
+ var PricingService = class {
3271
+ constructor(client) {
3272
+ this.client = client;
3273
+ }
3274
+ client;
3275
+ /**
3276
+ * Creates a pricing engine. Store the returned id and reuse it on every
3277
+ * subsequent override upsert. Throws on an InvalidDataError from Peek.
3278
+ */
3279
+ async createEngine(input) {
3280
+ if (!input.name) throw new Error(ERROR_NAME_REQUIRED);
3281
+ const body = await this.client.request(
3282
+ SALES_ENDPOINT,
3283
+ CREATE_PRICING_ENGINE_MUTATION,
3284
+ { input: buildCreateEngineInput(input) }
3285
+ );
3286
+ const result = body.data?.createPricingEngine;
3287
+ if (!result) throw new Error(ERROR_NO_DATA);
3288
+ if (result.__typename !== "CreatePricingEngineSuccess") {
3289
+ throw new Error(result.message);
3290
+ }
3291
+ return { id: result.engine.id };
3292
+ }
3293
+ /**
3294
+ * Updates a pricing engine's name and/or activity scope. Throws on an
3295
+ * InvalidDataError or NotFoundError from Peek.
3296
+ */
3297
+ async updateEngine(input) {
3298
+ if (!input.engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);
3299
+ if (!input.name) throw new Error(ERROR_NAME_REQUIRED);
3300
+ const body = await this.client.request(
3301
+ SALES_ENDPOINT,
3302
+ UPDATE_PRICING_ENGINE_MUTATION,
3303
+ { input: buildUpdateEngineInput(input) }
3304
+ );
3305
+ const result = body.data?.updatePricingEngine;
3306
+ if (!result) throw new Error(ERROR_NO_DATA);
3307
+ if (result.__typename !== "UpdatePricingEngineSuccess") {
3308
+ throw new Error(result.message);
3309
+ }
3310
+ return { id: result.engine.id, name: result.engine.name };
3311
+ }
3312
+ /**
3313
+ * Deletes a pricing engine. Idempotent — resolves whether the engine existed
3314
+ * or was already gone (Peek's NotFoundError is treated as success).
3315
+ */
3316
+ async deleteEngine(engineId) {
3317
+ if (!engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);
3318
+ await this.client.request(
3319
+ SALES_ENDPOINT,
3320
+ DELETE_PRICING_ENGINE_MUTATION,
3321
+ { id: engineId }
3322
+ );
3323
+ }
3324
+ /**
3325
+ * Upserts pricing overrides for the engine and date range in `input`. Returns
3326
+ * the resolved contexts Peek stored. Throws on an InvalidDataError from Peek.
3327
+ */
3328
+ async upsertOverrides(input) {
3329
+ this.validateUpsertInput(input);
3330
+ return this.sendUpsert(buildUpsertInput(input));
3331
+ }
3332
+ /**
3333
+ * Clears all overrides for the given activities across a date range. This is
3334
+ * an upsert with empty overrides — never clear by omitting an activity.
3335
+ */
3336
+ async clearOverrides(input) {
3337
+ if (!input.engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);
3338
+ if (!input.dateRange) throw new Error(ERROR_DATE_RANGE_REQUIRED);
3339
+ if (!Array.isArray(input.activityIds)) throw new Error(ERROR_ACTIVITIES_REQUIRED);
3340
+ for (const activityId of input.activityIds) {
3341
+ if (!activityId) throw new Error(ERROR_ACTIVITY_ID_REQUIRED);
3342
+ }
3343
+ return this.sendUpsert(buildClearInput(input));
3344
+ }
3345
+ async sendUpsert(rawInput) {
3346
+ const body = await this.client.request(
3347
+ SALES_ENDPOINT,
3348
+ UPSERT_PRICING_OVERRIDES_MUTATION,
3349
+ { input: rawInput }
3350
+ );
3351
+ const result = body.data?.upsertPricingOverridesActivityContexts;
3352
+ if (!result) throw new Error(ERROR_NO_DATA);
3353
+ if (result.__typename !== "UpsertPricingOverridesActivityContextsSuccess") {
3354
+ throw new Error(result.message);
3355
+ }
3356
+ return { activityContexts: fromActivityContexts(result.activityContexts) };
3357
+ }
3358
+ validateUpsertInput(input) {
3359
+ if (!input.engineId) throw new Error(ERROR_ENGINE_ID_REQUIRED);
3360
+ if (!input.dateRange) throw new Error(ERROR_DATE_RANGE_REQUIRED);
3361
+ if (!Array.isArray(input.activities)) throw new Error(ERROR_ACTIVITIES_REQUIRED);
3362
+ for (const activity of input.activities) {
3363
+ if (!activity.activityId) throw new Error(ERROR_ACTIVITY_ID_REQUIRED);
3364
+ for (const override of activity.overrides) {
3365
+ for (const option of override.resourceOptions) {
3366
+ this.validateResourceOption(option);
3367
+ }
3368
+ }
3369
+ }
3370
+ }
3371
+ validateResourceOption(option) {
3372
+ if (!option.id) throw new Error(ERROR_TICKET_ID_REQUIRED);
3373
+ if (option.mode === "fixed") {
3374
+ if (!CURRENCY_PATTERN2.test(option.price.currency)) {
3375
+ throw new Error(ERROR_CURRENCY_FORMAT);
3376
+ }
3377
+ if (Number.isNaN(Number.parseFloat(option.price.amount))) {
3378
+ throw new Error(ERROR_AMOUNT_NUMBER);
3379
+ }
3380
+ return;
3381
+ }
3382
+ const percentage = Number.parseFloat(option.percentageAdjustment);
3383
+ if (Number.isNaN(percentage)) throw new Error(ERROR_PERCENTAGE_NUMBER);
3384
+ if (percentage <= PERCENTAGE_FLOOR) throw new Error(ERROR_PERCENTAGE_FLOOR);
3385
+ }
3386
+ };
3387
+
3066
3388
  // src/logger.ts
3067
3389
  var noopLogger = {
3068
3390
  info() {
@@ -3088,6 +3410,7 @@ var PeekAccessService = class {
3088
3410
  timeslotService;
3089
3411
  resellerService;
3090
3412
  promoCodeService;
3413
+ pricingService;
3091
3414
  dailyNoteService;
3092
3415
  availabilityService;
3093
3416
  membershipService;
@@ -3222,6 +3545,16 @@ var PeekAccessService = class {
3222
3545
  }
3223
3546
  return this.promoCodeService;
3224
3547
  }
3548
+ /**
3549
+ * Returns the {@link PricingService} for this install, bound to the shared
3550
+ * authenticated transport. The instance is created lazily and reused.
3551
+ */
3552
+ getPricingService() {
3553
+ if (!this.pricingService) {
3554
+ this.pricingService = new PricingService(this.client);
3555
+ }
3556
+ return this.pricingService;
3557
+ }
3225
3558
  /**
3226
3559
  * Returns the {@link DailyNoteService} for this install, bound to the shared
3227
3560
  * authenticated transport. The instance is created lazily and reused.
@@ -3342,6 +3675,27 @@ var PeekAccessService = class {
3342
3675
  createPromoCode(input) {
3343
3676
  return this.getPromoCodeService().create(input);
3344
3677
  }
3678
+ // ─── Pricing short-forms ──────────────────────────────────────────────────
3679
+ /** Create a pricing engine. Delegates to {@link PricingService.createEngine}. */
3680
+ createPricingEngine(input) {
3681
+ return this.getPricingService().createEngine(input);
3682
+ }
3683
+ /** Update a pricing engine. Delegates to {@link PricingService.updateEngine}. */
3684
+ updatePricingEngine(input) {
3685
+ return this.getPricingService().updateEngine(input);
3686
+ }
3687
+ /** Delete a pricing engine (idempotent). Delegates to {@link PricingService.deleteEngine}. */
3688
+ deletePricingEngine(engineId) {
3689
+ return this.getPricingService().deleteEngine(engineId);
3690
+ }
3691
+ /** Upsert pricing overrides. Delegates to {@link PricingService.upsertOverrides}. */
3692
+ upsertPricingOverrides(input) {
3693
+ return this.getPricingService().upsertOverrides(input);
3694
+ }
3695
+ /** Clear pricing overrides for a set of activities. Delegates to {@link PricingService.clearOverrides}. */
3696
+ clearPricingOverrides(input) {
3697
+ return this.getPricingService().clearOverrides(input);
3698
+ }
3345
3699
  // ─── Daily-note short-forms ───────────────────────────────────────────────
3346
3700
  /** Today's daily note. Delegates to {@link DailyNoteService.getToday}. */
3347
3701
  getDailyNoteToday() {
@@ -3820,6 +4174,7 @@ exports.MembershipService = MembershipService;
3820
4174
  exports.PeekAccessService = PeekAccessService;
3821
4175
  exports.PeekGraphQLError = PeekGraphQLError;
3822
4176
  exports.PiiAccessDisabledError = PiiAccessDisabledError;
4177
+ exports.PricingService = PricingService;
3823
4178
  exports.ProductService = ProductService;
3824
4179
  exports.PromoCodeService = PromoCodeService;
3825
4180
  exports.RENTAL_PRODUCT_TYPE = RENTAL_PRODUCT_TYPE;