@voyantjs/promotions 0.90.0 → 0.94.0

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/routes.d.ts CHANGED
@@ -39,9 +39,19 @@ export declare const promotionsRoutes: import("hono/hono-base").HonoBase<Env, {
39
39
  } | {
40
40
  kind: "audiences";
41
41
  audiences: ("staff" | "customer" | "partner" | "supplier")[];
42
+ } | {
43
+ kind: "fare_codes";
44
+ fareCodes: string[];
45
+ } | {
46
+ kind: "cabin_grades";
47
+ cabinGradeCodes: string[];
42
48
  };
43
49
  conditions: {
44
50
  minPax?: number | undefined;
51
+ pastGuestOnly?: boolean | undefined;
52
+ soloTravelerOnly?: boolean | undefined;
53
+ childTravelerOnly?: boolean | undefined;
54
+ familyOnly?: boolean | undefined;
45
55
  };
46
56
  validFrom: string | null;
47
57
  validUntil: string | null;
@@ -88,6 +98,12 @@ export declare const promotionsRoutes: import("hono/hono-base").HonoBase<Env, {
88
98
  } | {
89
99
  kind: "audiences";
90
100
  audiences: ("staff" | "customer" | "partner" | "supplier")[];
101
+ } | {
102
+ kind: "fare_codes";
103
+ fareCodes: string[];
104
+ } | {
105
+ kind: "cabin_grades";
106
+ cabinGradeCodes: string[];
91
107
  };
92
108
  slug: string;
93
109
  currency: string | null;
@@ -101,6 +117,10 @@ export declare const promotionsRoutes: import("hono/hono-base").HonoBase<Env, {
101
117
  validUntil: string | null;
102
118
  conditions: {
103
119
  minPax?: number | undefined;
120
+ pastGuestOnly?: boolean | undefined;
121
+ soloTravelerOnly?: boolean | undefined;
122
+ childTravelerOnly?: boolean | undefined;
123
+ familyOnly?: boolean | undefined;
104
124
  };
105
125
  stackable: boolean;
106
126
  };
@@ -152,6 +172,12 @@ export declare const promotionsRoutes: import("hono/hono-base").HonoBase<Env, {
152
172
  } | {
153
173
  kind: "audiences";
154
174
  audiences: ("staff" | "customer" | "partner" | "supplier")[];
175
+ } | {
176
+ kind: "fare_codes";
177
+ fareCodes: string[];
178
+ } | {
179
+ kind: "cabin_grades";
180
+ cabinGradeCodes: string[];
155
181
  };
156
182
  slug: string;
157
183
  currency: string | null;
@@ -165,6 +191,10 @@ export declare const promotionsRoutes: import("hono/hono-base").HonoBase<Env, {
165
191
  validUntil: string | null;
166
192
  conditions: {
167
193
  minPax?: number | undefined;
194
+ pastGuestOnly?: boolean | undefined;
195
+ soloTravelerOnly?: boolean | undefined;
196
+ childTravelerOnly?: boolean | undefined;
197
+ familyOnly?: boolean | undefined;
168
198
  };
169
199
  stackable: boolean;
170
200
  };
@@ -216,6 +246,12 @@ export declare const promotionsRoutes: import("hono/hono-base").HonoBase<Env, {
216
246
  } | {
217
247
  kind: "audiences";
218
248
  audiences: ("staff" | "customer" | "partner" | "supplier")[];
249
+ } | {
250
+ kind: "fare_codes";
251
+ fareCodes: string[];
252
+ } | {
253
+ kind: "cabin_grades";
254
+ cabinGradeCodes: string[];
219
255
  };
220
256
  slug: string;
221
257
  currency: string | null;
@@ -229,6 +265,10 @@ export declare const promotionsRoutes: import("hono/hono-base").HonoBase<Env, {
229
265
  validUntil: string | null;
230
266
  conditions: {
231
267
  minPax?: number | undefined;
268
+ pastGuestOnly?: boolean | undefined;
269
+ soloTravelerOnly?: boolean | undefined;
270
+ childTravelerOnly?: boolean | undefined;
271
+ familyOnly?: boolean | undefined;
232
272
  };
233
273
  stackable: boolean;
234
274
  };
@@ -280,6 +320,12 @@ export declare const promotionsRoutes: import("hono/hono-base").HonoBase<Env, {
280
320
  } | {
281
321
  kind: "audiences";
282
322
  audiences: ("staff" | "customer" | "partner" | "supplier")[];
323
+ } | {
324
+ kind: "fare_codes";
325
+ fareCodes: string[];
326
+ } | {
327
+ kind: "cabin_grades";
328
+ cabinGradeCodes: string[];
283
329
  };
284
330
  slug: string;
285
331
  currency: string | null;
@@ -293,6 +339,10 @@ export declare const promotionsRoutes: import("hono/hono-base").HonoBase<Env, {
293
339
  validUntil: string | null;
294
340
  conditions: {
295
341
  minPax?: number | undefined;
342
+ pastGuestOnly?: boolean | undefined;
343
+ soloTravelerOnly?: boolean | undefined;
344
+ childTravelerOnly?: boolean | undefined;
345
+ familyOnly?: boolean | undefined;
296
346
  };
297
347
  stackable: boolean;
298
348
  };
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EAAE,KAAK,GAAG,EAAY,MAAM,oBAAoB,CAAA;AAQvD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAgDzB,CAAA;AAEJ,MAAM,MAAM,gBAAgB,GAAG,OAAO,gBAAgB,CAAA"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EAAE,KAAK,GAAG,EAAY,MAAM,oBAAoB,CAAA;AAQvD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAgDzB,CAAA;AAEJ,MAAM,MAAM,gBAAgB,GAAG,OAAO,gBAAgB,CAAA"}
package/dist/schema.d.ts CHANGED
@@ -181,6 +181,12 @@ export declare const promotionalOffers: import("drizzle-orm/pg-core").PgTableWit
181
181
  } | {
182
182
  kind: "audiences";
183
183
  audiences: ("staff" | "customer" | "partner" | "supplier")[];
184
+ } | {
185
+ kind: "fare_codes";
186
+ fareCodes: string[];
187
+ } | {
188
+ kind: "cabin_grades";
189
+ cabinGradeCodes: string[];
184
190
  };
185
191
  driverParam: unknown;
186
192
  notNull: true;
@@ -210,6 +216,12 @@ export declare const promotionalOffers: import("drizzle-orm/pg-core").PgTableWit
210
216
  } | {
211
217
  kind: "audiences";
212
218
  audiences: ("staff" | "customer" | "partner" | "supplier")[];
219
+ } | {
220
+ kind: "fare_codes";
221
+ fareCodes: string[];
222
+ } | {
223
+ kind: "cabin_grades";
224
+ cabinGradeCodes: string[];
213
225
  };
214
226
  }>;
215
227
  conditions: import("drizzle-orm/pg-core").PgColumn<{
@@ -219,6 +231,10 @@ export declare const promotionalOffers: import("drizzle-orm/pg-core").PgTableWit
219
231
  columnType: "PgJsonb";
220
232
  data: {
221
233
  minPax?: number | undefined;
234
+ pastGuestOnly?: boolean | undefined;
235
+ soloTravelerOnly?: boolean | undefined;
236
+ childTravelerOnly?: boolean | undefined;
237
+ familyOnly?: boolean | undefined;
222
238
  };
223
239
  driverParam: unknown;
224
240
  notNull: true;
@@ -233,6 +249,10 @@ export declare const promotionalOffers: import("drizzle-orm/pg-core").PgTableWit
233
249
  }, {}, {
234
250
  $type: {
235
251
  minPax?: number | undefined;
252
+ pastGuestOnly?: boolean | undefined;
253
+ soloTravelerOnly?: boolean | undefined;
254
+ childTravelerOnly?: boolean | undefined;
255
+ familyOnly?: boolean | undefined;
236
256
  };
237
257
  }>;
238
258
  validFrom: import("drizzle-orm/pg-core").PgColumn<{
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAoBH,eAAO,MAAM,gCAAgC,sEAG3C,CAAA;AAEF,MAAM,MAAM,4BAA4B,GACtC,CAAC,OAAO,gCAAgC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;AAE9D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2C7B,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYpC,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmBvC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,iBAAiB,CAAC,YAAY,CAAA;AACpE,MAAM,MAAM,mBAAmB,GAAG,OAAO,iBAAiB,CAAC,YAAY,CAAA;AACvE,MAAM,MAAM,uBAAuB,GAAG,OAAO,wBAAwB,CAAC,YAAY,CAAA;AAClF,MAAM,MAAM,0BAA0B,GAAG,OAAO,wBAAwB,CAAC,YAAY,CAAA;AACrF,MAAM,MAAM,0BAA0B,GAAG,OAAO,2BAA2B,CAAC,YAAY,CAAA;AACxF,MAAM,MAAM,6BAA6B,GAAG,OAAO,2BAA2B,CAAC,YAAY,CAAA;AAE3F;;;;;;;;;GASG;AACH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAc1C,CAAA;AAED,MAAM,MAAM,8BAA8B,GAAG,OAAO,8BAA8B,CAAC,YAAY,CAAA;AAC/F,MAAM,MAAM,iCAAiC,GAAG,OAAO,8BAA8B,CAAC,YAAY,CAAA"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAoBH,eAAO,MAAM,gCAAgC,sEAG3C,CAAA;AAEF,MAAM,MAAM,4BAA4B,GACtC,CAAC,OAAO,gCAAgC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;AAE9D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2C7B,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYpC,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmBvC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,iBAAiB,CAAC,YAAY,CAAA;AACpE,MAAM,MAAM,mBAAmB,GAAG,OAAO,iBAAiB,CAAC,YAAY,CAAA;AACvE,MAAM,MAAM,uBAAuB,GAAG,OAAO,wBAAwB,CAAC,YAAY,CAAA;AAClF,MAAM,MAAM,0BAA0B,GAAG,OAAO,wBAAwB,CAAC,YAAY,CAAA;AACrF,MAAM,MAAM,0BAA0B,GAAG,OAAO,2BAA2B,CAAC,YAAY,CAAA;AACxF,MAAM,MAAM,6BAA6B,GAAG,OAAO,2BAA2B,CAAC,YAAY,CAAA;AAE3F;;;;;;;;;GASG;AACH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAc1C,CAAA;AAED,MAAM,MAAM,8BAA8B,GAAG,OAAO,8BAA8B,CAAC,YAAY,CAAA;AAC/F,MAAM,MAAM,iCAAiC,GAAG,OAAO,8BAA8B,CAAC,YAAY,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"service-catalog-plane-promotions.d.ts","sourceRoot":"","sources":["../src/service-catalog-plane-promotions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,KAAK,EACV,YAAY,EACZ,0BAA0B,EAC3B,MAAM,0CAA0C,CAAA;AAEjD,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAErB,KAAK,gBAAgB,EAEtB,MAAM,wBAAwB,CAAA;AAE/B,MAAM,WAAW,2BAA2B;IAC1C;;;;;;;;;;;;;OAaG;IACH,iBAAiB,CAAC,EAAE,CAClB,EAAE,EAAE,YAAY,EAChB,SAAS,EAAE,MAAM,KACd,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAA;IAErE,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;CACjB;AAED;;;;;GAKG;AACH,iBAAS,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAGzF;AAID,wBAAgB,0CAA0C,CACxD,OAAO,GAAE,2BAAgC,GACxC,0BAA0B,CAiC5B;AAED,iBAAS,eAAe,CACtB,IAAI,EAAE,YAAY,GAAG,IAAI,EACzB,WAAW,EAAE,gBAAgB,GAAG,IAAI,EACpC,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAuB9B;AA8BD,eAAO,MAAM,QAAQ;;;;CAAuD,CAAA;AAE5E,YAAY,EAAE,gBAAgB,EAAE,CAAA"}
1
+ {"version":3,"file":"service-catalog-plane-promotions.d.ts","sourceRoot":"","sources":["../src/service-catalog-plane-promotions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,KAAK,EACV,YAAY,EACZ,0BAA0B,EAC3B,MAAM,0CAA0C,CAAA;AAEjD,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAErB,KAAK,gBAAgB,EAEtB,MAAM,wBAAwB,CAAA;AAE/B,MAAM,WAAW,2BAA2B;IAC1C;;;;;;;;;;;;;OAaG;IACH,iBAAiB,CAAC,EAAE,CAClB,EAAE,EAAE,YAAY,EAChB,SAAS,EAAE,MAAM,KACd,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAA;IAErE,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;CACjB;AAED;;;;;GAKG;AACH,iBAAS,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAGzF;AAID,wBAAgB,0CAA0C,CACxD,OAAO,GAAE,2BAAgC,GACxC,0BAA0B,CAkC5B;AAED,iBAAS,eAAe,CACtB,IAAI,EAAE,YAAY,GAAG,IAAI,EACzB,WAAW,EAAE,gBAAgB,GAAG,IAAI,EACpC,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAuB9B;AA8BD,eAAO,MAAM,QAAQ;;;;CAAuD,CAAA;AAE5E,YAAY,EAAE,gBAAgB,EAAE,CAAA"}
@@ -65,7 +65,7 @@ export function createProductPromotionsProjectionExtension(options = {}) {
65
65
  // pax + code intentionally omitted: catalog plane never knows
66
66
  // these. minPax-conditioned offers land in `result.conditional`.
67
67
  });
68
- const conditional = evaluation.conditional[0] ?? null;
68
+ const conditional = evaluation.conditional.find((offer) => offer.unmet.kind === "min_pax") ?? null;
69
69
  // Surface `originalPriceFromAmountCents` ONLY when an offer applies —
70
70
  // §3.7 keeps the doc lean by leaving it null otherwise.
71
71
  const original = evaluation.best != null ? amountCents : null;
@@ -24,6 +24,16 @@ export interface OfferEvaluationContext {
24
24
  audience: "staff" | "customer" | "partner" | "supplier";
25
25
  market: string;
26
26
  };
27
+ /** Optional booking-line fare code, used by fare-scoped offers. */
28
+ fareCode?: string | null;
29
+ /** Optional cabin grade code, used by cruise cabin-grade-scoped offers. */
30
+ cabinGradeCode?: string | null;
31
+ eligibility?: {
32
+ pastGuest?: boolean;
33
+ soloTraveler?: boolean;
34
+ hasChildTraveler?: boolean;
35
+ family?: boolean;
36
+ };
27
37
  /** Total travelers. Absent at catalog-index time; supplied at checkout. */
28
38
  pax?: number;
29
39
  /** Defaults to `now()` when undefined. */
@@ -64,6 +74,14 @@ export interface ConditionalOffer {
64
74
  unmet: {
65
75
  kind: "min_pax";
66
76
  required: number;
77
+ } | {
78
+ kind: "past_guest";
79
+ } | {
80
+ kind: "solo_traveler";
81
+ } | {
82
+ kind: "child_traveler";
83
+ } | {
84
+ kind: "family";
67
85
  };
68
86
  }
69
87
  /** Outcome of code validation when `ctx.code` is supplied. `null` when ctx.code was not set. */
@@ -77,7 +95,7 @@ export type CodeStatus = null | {
77
95
  kind: "code_not_yet_valid";
78
96
  } | {
79
97
  kind: "code_not_applicable";
80
- reason: "scope" | "min_pax" | "currency";
98
+ reason: "scope" | "min_pax" | "eligibility" | "currency";
81
99
  };
82
100
  export interface EvaluationResult {
83
101
  /** All applied offers (1+ when stacking; 0 when no offer applies). May include a code-gated offer alongside auto offers. */
@@ -1 +1 @@
1
- {"version":3,"file":"service-evaluator.d.ts","sourceRoot":"","sources":["../src/service-evaluator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service-evaluator.d.ts","sourceRoot":"","sources":["../src/service-evaluator.ts"],"names":[],"mappings":"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"}
@@ -86,6 +86,10 @@ function matchesScope(scope, ctx, offerMatchesProduct) {
86
86
  return scope.marketIds.includes(ctx.slice.market);
87
87
  case "audiences":
88
88
  return scope.audiences.includes(ctx.slice.audience);
89
+ case "fare_codes":
90
+ return ctx.fareCode != null && scope.fareCodes.includes(ctx.fareCode);
91
+ case "cabin_grades":
92
+ return ctx.cabinGradeCode != null && scope.cabinGradeCodes.includes(ctx.cabinGradeCode);
89
93
  }
90
94
  }
91
95
  function evaluateConditions(conditions, ctx) {
@@ -97,8 +101,38 @@ function evaluateConditions(conditions, ctx) {
97
101
  return { kind: "excluded", reason: "min_pax" };
98
102
  }
99
103
  }
104
+ if (conditions.pastGuestOnly === true) {
105
+ const result = evaluateEligibilityFlag(ctx.eligibility?.pastGuest, { kind: "past_guest" });
106
+ if (result.kind !== "ok")
107
+ return result;
108
+ }
109
+ if (conditions.soloTravelerOnly === true) {
110
+ const soloTraveler = ctx.eligibility?.soloTraveler ?? (ctx.pax != null ? ctx.pax === 1 : undefined);
111
+ const result = evaluateEligibilityFlag(soloTraveler, { kind: "solo_traveler" });
112
+ if (result.kind !== "ok")
113
+ return result;
114
+ }
115
+ if (conditions.childTravelerOnly === true) {
116
+ const result = evaluateEligibilityFlag(ctx.eligibility?.hasChildTraveler, {
117
+ kind: "child_traveler",
118
+ });
119
+ if (result.kind !== "ok")
120
+ return result;
121
+ }
122
+ if (conditions.familyOnly === true) {
123
+ const result = evaluateEligibilityFlag(ctx.eligibility?.family, { kind: "family" });
124
+ if (result.kind !== "ok")
125
+ return result;
126
+ }
100
127
  return { kind: "ok" };
101
128
  }
129
+ function evaluateEligibilityFlag(value, unmet) {
130
+ if (value === true)
131
+ return { kind: "ok" };
132
+ if (value === false)
133
+ return { kind: "excluded", reason: "eligibility" };
134
+ return { kind: "conditional", unmet };
135
+ }
102
136
  function currencyMatches(offer, ctx) {
103
137
  if (offer.discountType !== "fixed_amount")
104
138
  return true;
@@ -222,7 +256,7 @@ export async function evaluateOffersForProduct(source, ctx) {
222
256
  }
223
257
  if (cond.kind === "excluded") {
224
258
  if (offer === codeOffer)
225
- codeOfferRejection = { kind: "min_pax" };
259
+ codeOfferRejection = { kind: cond.reason };
226
260
  continue;
227
261
  }
228
262
  if (!currencyMatches(offer, ctx)) {
@@ -1 +1 @@
1
- {"version":3,"file":"service-storefront.d.ts","sourceRoot":"","sources":["../src/service-storefront.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,KAAK,EAGV,6BAA6B,EAE7B,wBAAwB,EACxB,0BAA0B,EAE3B,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,KAAK,gBAAgB,EAA+C,MAAM,aAAa,CAAA;AAChG,OAAO,EACL,KAAK,UAAU,EAGhB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAE5D,wBAAgB,mCAAmC,IAAI,wBAAwB,CAoG9E;AAMD,iBAAS,cAAc,CAAC,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,OAAO,GAAG,OAAO,CAenF;AAuBD,iBAAS,eAAe,CACtB,KAAK,EAAE,gBAAgB,EACvB,oBAAoB,EAAE,MAAM,EAAE,GAC7B,0BAA0B,CA+B5B;AAkCD,iBAAS,qBAAqB,CAC5B,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,IAAI,GACR,eAAe,GAAG,qBAAqB,GAAG,IAAI,CAIhD;AAiGD,iBAAS,kBAAkB,CACzB,MAAM,EAAE,UAAU,GACjB,WAAW,CAAC,6BAA6B,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,CAI7D;AA0BD,iBAAS,aAAa,CAAC,KAAK,EAAE;IAC5B,mBAAmB,EAAE,MAAM,EAAE,CAAA;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,cAAc,EAAE,OAAO,CAAA;CACxB,GAAG,6BAA6B,CAAC,UAAU,CAAC,CAc5C;AAED,eAAO,MAAM,QAAQ;;;;;;CAMpB,CAAA"}
1
+ {"version":3,"file":"service-storefront.d.ts","sourceRoot":"","sources":["../src/service-storefront.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,KAAK,EAGV,6BAA6B,EAE7B,wBAAwB,EACxB,0BAA0B,EAE3B,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,KAAK,gBAAgB,EAA+C,MAAM,aAAa,CAAA;AAChG,OAAO,EACL,KAAK,UAAU,EAGhB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAE5D,wBAAgB,mCAAmC,IAAI,wBAAwB,CAoG9E;AAMD,iBAAS,cAAc,CAAC,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,OAAO,GAAG,OAAO,CAmBnF;AAuBD,iBAAS,eAAe,CACtB,KAAK,EAAE,gBAAgB,EACvB,oBAAoB,EAAE,MAAM,EAAE,GAC7B,0BAA0B,CA+B5B;AAkCD,iBAAS,qBAAqB,CAC5B,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,IAAI,GACR,eAAe,GAAG,qBAAqB,GAAG,IAAI,CAIhD;AAiGD,iBAAS,kBAAkB,CACzB,MAAM,EAAE,UAAU,GACjB,WAAW,CAAC,6BAA6B,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,CAI7D;AA0BD,iBAAS,aAAa,CAAC,KAAK,EAAE;IAC5B,mBAAmB,EAAE,MAAM,EAAE,CAAA;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,cAAc,EAAE,OAAO,CAAA;CACxB,GAAG,6BAA6B,CAAC,UAAU,CAAC,CAc5C;AAED,eAAO,MAAM,QAAQ;;;;;;CAMpB,CAAA"}
@@ -120,6 +120,10 @@ function matchesProduct(scope, inLinkTable) {
120
120
  // honored by the catalog projection (PR3) when products are indexed.
121
121
  case "markets":
122
122
  case "audiences":
123
+ // Fare/cabin-grade scopes need booking-line context and are evaluated
124
+ // by the checkout path rather than this product-listing endpoint.
125
+ case "fare_codes":
126
+ case "cabin_grades":
123
127
  return false;
124
128
  }
125
129
  }
package/dist/service.d.ts CHANGED
@@ -39,7 +39,8 @@ export interface OfferMutationRuntime {
39
39
  * `recomputeOfferLinks` and by the event emitter to populate
40
40
  * `affected.productIds`.
41
41
  *
42
- * Returns `null` for slice-shaped scopes (`global`, `markets`, `audiences`)
42
+ * Returns `null` for slice-shaped or checkout-shaped scopes (`global`,
43
+ * `markets`, `audiences`, `fare_codes`, `cabin_grades`)
43
44
  * to signal that the link table should be empty AND that the event payload
44
45
  * should fall back to `affected: { kind: "all" }` — these scopes can match
45
46
  * an unbounded product set and we don't enumerate them at write time
@@ -81,9 +82,19 @@ declare function listOffers(db: PostgresJsDatabase, query: PromotionalOfferListQ
81
82
  } | {
82
83
  kind: "audiences";
83
84
  audiences: ("staff" | "customer" | "partner" | "supplier")[];
85
+ } | {
86
+ kind: "fare_codes";
87
+ fareCodes: string[];
88
+ } | {
89
+ kind: "cabin_grades";
90
+ cabinGradeCodes: string[];
84
91
  };
85
92
  conditions: {
86
93
  minPax?: number | undefined;
94
+ pastGuestOnly?: boolean | undefined;
95
+ soloTravelerOnly?: boolean | undefined;
96
+ childTravelerOnly?: boolean | undefined;
97
+ familyOnly?: boolean | undefined;
87
98
  };
88
99
  validFrom: Date | null;
89
100
  validUntil: Date | null;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAgB9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAIL,KAAK,sBAAsB,EAC5B,MAAM,aAAa,CAAA;AACpB,OAAO,EAEL,KAAK,gBAAgB,EAItB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EACV,sBAAsB,EACtB,yBAAyB,EACzB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,iBAAiB,CAAA;AAExB,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,sBAAsB,CAAA;CAChC;AAUD;;;;;;;;;;GAUG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAyB1B;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,kBAAkB,EACtB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CAAE,CAAC,CAS1C;AA8ED,iBAAe,UAAU,CAAC,EAAE,EAAE,kBAAkB,EAAE,KAAK,EAAE,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EjF;AAUD,iBAAe,YAAY,CAAC,EAAE,EAAE,kBAAkB,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAOhG;AAED,iBAAe,WAAW,CACxB,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,sBAAsB,EAC7B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,gBAAgB,CAAC,CAa3B;AAED,iBAAe,WAAW,CACxB,EAAE,EAAE,kBAAkB,EACtB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,sBAAsB,EAC7B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAsClC;AAED,iBAAe,YAAY,CACzB,EAAE,EAAE,kBAAkB,EACtB,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAgBlC;AAED,iBAAe,WAAW,CACxB,EAAE,EAAE,kBAAkB,EACtB,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAiChC;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;CAS7B,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,OAAO,iBAAiB,CAAA"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAgB9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAIL,KAAK,sBAAsB,EAC5B,MAAM,aAAa,CAAA;AACpB,OAAO,EAEL,KAAK,gBAAgB,EAItB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EACV,sBAAsB,EACtB,yBAAyB,EACzB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,iBAAiB,CAAA;AAExB,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,sBAAsB,CAAA;CAChC;AAUD;;;;;;;;;;;GAWG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CA2B1B;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,kBAAkB,EACtB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;CAAE,CAAC,CAS1C;AA8ED,iBAAe,UAAU,CAAC,EAAE,EAAE,kBAAkB,EAAE,KAAK,EAAE,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EjF;AAUD,iBAAe,YAAY,CAAC,EAAE,EAAE,kBAAkB,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAOhG;AAED,iBAAe,WAAW,CACxB,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,sBAAsB,EAC7B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,gBAAgB,CAAC,CAa3B;AAED,iBAAe,WAAW,CACxB,EAAE,EAAE,kBAAkB,EACtB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,sBAAsB,EAC7B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAsClC;AAED,iBAAe,YAAY,CACzB,EAAE,EAAE,kBAAkB,EACtB,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAgBlC;AAED,iBAAe,WAAW,CACxB,EAAE,EAAE,kBAAkB,EACtB,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAiChC;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;CAS7B,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,OAAO,iBAAiB,CAAA"}
package/dist/service.js CHANGED
@@ -29,7 +29,8 @@ function shouldEmitForUpdate(patch) {
29
29
  * `recomputeOfferLinks` and by the event emitter to populate
30
30
  * `affected.productIds`.
31
31
  *
32
- * Returns `null` for slice-shaped scopes (`global`, `markets`, `audiences`)
32
+ * Returns `null` for slice-shaped or checkout-shaped scopes (`global`,
33
+ * `markets`, `audiences`, `fare_codes`, `cabin_grades`)
33
34
  * to signal that the link table should be empty AND that the event payload
34
35
  * should fall back to `affected: { kind: "all" }` — these scopes can match
35
36
  * an unbounded product set and we don't enumerate them at write time
@@ -60,6 +61,8 @@ export async function resolveScopeProductIds(db, scope) {
60
61
  case "global":
61
62
  case "markets":
62
63
  case "audiences":
64
+ case "fare_codes":
65
+ case "cabin_grades":
63
66
  return null;
64
67
  }
65
68
  }
@@ -31,11 +31,21 @@ export declare const promotionalOfferScopeSchema: z.ZodDiscriminatedUnion<[z.Zod
31
31
  partner: "partner";
32
32
  supplier: "supplier";
33
33
  }>>;
34
+ }, z.core.$strip>, z.ZodObject<{
35
+ kind: z.ZodLiteral<"fare_codes">;
36
+ fareCodes: z.ZodArray<z.ZodString>;
37
+ }, z.core.$strip>, z.ZodObject<{
38
+ kind: z.ZodLiteral<"cabin_grades">;
39
+ cabinGradeCodes: z.ZodArray<z.ZodString>;
34
40
  }, z.core.$strip>], "kind">;
35
41
  export type PromotionalOfferScope = z.infer<typeof promotionalOfferScopeSchema>;
36
42
  export type PromotionalOfferScopeKind = PromotionalOfferScope["kind"];
37
43
  export declare const promotionalOfferConditionsSchema: z.ZodObject<{
38
44
  minPax: z.ZodOptional<z.ZodNumber>;
45
+ pastGuestOnly: z.ZodOptional<z.ZodBoolean>;
46
+ soloTravelerOnly: z.ZodOptional<z.ZodBoolean>;
47
+ childTravelerOnly: z.ZodOptional<z.ZodBoolean>;
48
+ familyOnly: z.ZodOptional<z.ZodBoolean>;
39
49
  }, z.core.$strip>;
40
50
  export type PromotionalOfferConditions = z.infer<typeof promotionalOfferConditionsSchema>;
41
51
  export declare const insertPromotionalOfferSchema: z.ZodObject<{
@@ -71,9 +81,19 @@ export declare const insertPromotionalOfferSchema: z.ZodObject<{
71
81
  partner: "partner";
72
82
  supplier: "supplier";
73
83
  }>>;
84
+ }, z.core.$strip>, z.ZodObject<{
85
+ kind: z.ZodLiteral<"fare_codes">;
86
+ fareCodes: z.ZodArray<z.ZodString>;
87
+ }, z.core.$strip>, z.ZodObject<{
88
+ kind: z.ZodLiteral<"cabin_grades">;
89
+ cabinGradeCodes: z.ZodArray<z.ZodString>;
74
90
  }, z.core.$strip>], "kind">;
75
91
  conditions: z.ZodDefault<z.ZodOptional<z.ZodObject<{
76
92
  minPax: z.ZodOptional<z.ZodNumber>;
93
+ pastGuestOnly: z.ZodOptional<z.ZodBoolean>;
94
+ soloTravelerOnly: z.ZodOptional<z.ZodBoolean>;
95
+ childTravelerOnly: z.ZodOptional<z.ZodBoolean>;
96
+ familyOnly: z.ZodOptional<z.ZodBoolean>;
77
97
  }, z.core.$strip>>>;
78
98
  validFrom: z.ZodOptional<z.ZodNullable<z.ZodCoercedDate<unknown>>>;
79
99
  validUntil: z.ZodOptional<z.ZodNullable<z.ZodCoercedDate<unknown>>>;
@@ -109,6 +129,12 @@ export declare const updatePromotionalOfferSchema: z.ZodObject<{
109
129
  partner: "partner";
110
130
  supplier: "supplier";
111
131
  }>>;
132
+ }, z.core.$strip>, z.ZodObject<{
133
+ kind: z.ZodLiteral<"fare_codes">;
134
+ fareCodes: z.ZodArray<z.ZodString>;
135
+ }, z.core.$strip>, z.ZodObject<{
136
+ kind: z.ZodLiteral<"cabin_grades">;
137
+ cabinGradeCodes: z.ZodArray<z.ZodString>;
112
138
  }, z.core.$strip>], "kind">>;
113
139
  name: z.ZodOptional<z.ZodString>;
114
140
  slug: z.ZodOptional<z.ZodString>;
@@ -118,6 +144,10 @@ export declare const updatePromotionalOfferSchema: z.ZodObject<{
118
144
  currency: z.ZodOptional<z.ZodNullable<z.ZodString>>;
119
145
  conditions: z.ZodDefault<z.ZodOptional<z.ZodObject<{
120
146
  minPax: z.ZodOptional<z.ZodNumber>;
147
+ pastGuestOnly: z.ZodOptional<z.ZodBoolean>;
148
+ soloTravelerOnly: z.ZodOptional<z.ZodBoolean>;
149
+ childTravelerOnly: z.ZodOptional<z.ZodBoolean>;
150
+ familyOnly: z.ZodOptional<z.ZodBoolean>;
121
151
  }, z.core.$strip>>>;
122
152
  validFrom: z.ZodOptional<z.ZodNullable<z.ZodCoercedDate<unknown>>>;
123
153
  validUntil: z.ZodOptional<z.ZodNullable<z.ZodCoercedDate<unknown>>>;
@@ -147,6 +177,8 @@ export declare const promotionalOfferListQuerySchema: z.ZodObject<{
147
177
  global: "global";
148
178
  categories: "categories";
149
179
  audiences: "audiences";
180
+ fare_codes: "fare_codes";
181
+ cabin_grades: "cabin_grades";
150
182
  }>>;
151
183
  validFrom: z.ZodOptional<z.ZodString>;
152
184
  validUntil: z.ZodOptional<z.ZodString>;
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAUvB,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;2BAsBtC,CAAA;AAEF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAC/E,MAAM,MAAM,yBAAyB,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAA;AAOrE,eAAO,MAAM,gCAAgC;;iBAK3C,CAAA;AAEF,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAA;AAqFzF,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAmD,CAAA;AAE5F,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAQxC,CAAA;AAED,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgB1C,CAAA;AAEF,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA;AACtF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA;AACjF,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA;AACtF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA;AACjF,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAA;AACvF,MAAM,MAAM,+BAA+B,GAAG,WAAW,CACvD,yBAAyB,CAAC,iBAAiB,CAAC,CAC7C,CAAA;AACD,MAAM,MAAM,0BAA0B,GAAG,WAAW,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAUvB,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BA8BtC,CAAA;AAEF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAC/E,MAAM,MAAM,yBAAyB,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAA;AAOrE,eAAO,MAAM,gCAAgC;;;;;;iBAa3C,CAAA;AAEF,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAA;AAqFzF,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAmD,CAAA;AAE5F,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAQxC,CAAA;AAED,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyB1C,CAAA;AAEF,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA;AACtF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA;AACjF,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA;AACtF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA;AACjF,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAA;AACvF,MAAM,MAAM,+BAA+B,GAAG,WAAW,CACvD,yBAAyB,CAAC,iBAAiB,CAAC,CAC7C,CAAA;AACD,MAAM,MAAM,0BAA0B,GAAG,WAAW,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC,CAAA"}
@@ -37,6 +37,14 @@ export const promotionalOfferScopeSchema = z.discriminatedUnion("kind", [
37
37
  kind: z.literal("audiences"),
38
38
  audiences: z.array(audienceLiteral).min(1),
39
39
  }),
40
+ z.object({
41
+ kind: z.literal("fare_codes"),
42
+ fareCodes: z.array(z.string().min(1)).min(1),
43
+ }),
44
+ z.object({
45
+ kind: z.literal("cabin_grades"),
46
+ cabinGradeCodes: z.array(z.string().min(1)).min(1),
47
+ }),
40
48
  ]);
41
49
  // ---------- Conditions (§12.1) ----------
42
50
  //
@@ -47,6 +55,14 @@ export const promotionalOfferConditionsSchema = z.object({
47
55
  * conditional offer when pax is unknown; checkout treats below-minimum
48
56
  * as a hard exclusion. */
49
57
  minPax: z.number().int().positive().optional(),
58
+ /** Requires a known past guest / loyalty customer signal. */
59
+ pastGuestOnly: z.boolean().optional(),
60
+ /** Requires a single-traveler party. Falls back to `pax === 1` when pax is known. */
61
+ soloTravelerOnly: z.boolean().optional(),
62
+ /** Requires at least one child traveler in the party. */
63
+ childTravelerOnly: z.boolean().optional(),
64
+ /** Requires the booking party to qualify as a family. */
65
+ familyOnly: z.boolean().optional(),
50
66
  });
51
67
  // ---------- Discount type / value cross-field rule (§11) ----------
52
68
  //
@@ -133,7 +149,16 @@ export const promotionalOfferListQuerySchema = z.object({
133
149
  applicationMode: z.enum(["auto", "code"]).optional(),
134
150
  status: z.enum(["active", "scheduled", "expired", "archived"]).optional(),
135
151
  scopeKind: z
136
- .enum(["global", "products", "categories", "destinations", "markets", "audiences"])
152
+ .enum([
153
+ "global",
154
+ "products",
155
+ "categories",
156
+ "destinations",
157
+ "markets",
158
+ "audiences",
159
+ "fare_codes",
160
+ "cabin_grades",
161
+ ])
137
162
  .optional(),
138
163
  validFrom: z.string().date().optional(),
139
164
  validUntil: z.string().date().optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/promotions",
3
- "version": "0.90.0",
3
+ "version": "0.94.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -69,13 +69,13 @@
69
69
  "drizzle-orm": "^0.45.2",
70
70
  "hono": "^4.12.10",
71
71
  "zod": "^4.3.6",
72
- "@voyantjs/catalog": "0.90.0",
73
- "@voyantjs/core": "0.90.0",
74
- "@voyantjs/db": "0.90.0",
75
- "@voyantjs/hono": "0.90.0",
76
- "@voyantjs/products": "0.90.0",
77
- "@voyantjs/storefront": "0.90.0",
78
- "@voyantjs/workflows": "0.90.0"
72
+ "@voyantjs/catalog": "0.94.0",
73
+ "@voyantjs/core": "0.94.0",
74
+ "@voyantjs/db": "0.94.0",
75
+ "@voyantjs/hono": "0.94.0",
76
+ "@voyantjs/products": "0.94.0",
77
+ "@voyantjs/storefront": "0.94.0",
78
+ "@voyantjs/workflows": "0.94.0"
79
79
  },
80
80
  "devDependencies": {
81
81
  "typescript": "^6.0.2",