@voyantjs/products 0.28.3 → 0.29.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.
Files changed (43) hide show
  1. package/dist/booking-engine/handler.d.ts +8 -0
  2. package/dist/booking-engine/handler.d.ts.map +1 -1
  3. package/dist/booking-engine/handler.js +38 -0
  4. package/dist/catalog-policy-departures.d.ts +52 -0
  5. package/dist/catalog-policy-departures.d.ts.map +1 -0
  6. package/dist/catalog-policy-departures.js +169 -0
  7. package/dist/catalog-policy-destinations.d.ts +41 -0
  8. package/dist/catalog-policy-destinations.d.ts.map +1 -0
  9. package/dist/catalog-policy-destinations.js +121 -0
  10. package/dist/catalog-policy-pricing.d.ts +55 -0
  11. package/dist/catalog-policy-pricing.d.ts.map +1 -0
  12. package/dist/catalog-policy-pricing.js +109 -0
  13. package/dist/catalog-policy-promotions.d.ts +52 -0
  14. package/dist/catalog-policy-promotions.d.ts.map +1 -0
  15. package/dist/catalog-policy-promotions.js +270 -0
  16. package/dist/catalog-policy-taxonomy.d.ts +51 -0
  17. package/dist/catalog-policy-taxonomy.d.ts.map +1 -0
  18. package/dist/catalog-policy-taxonomy.js +191 -0
  19. package/dist/events.d.ts +1 -1
  20. package/dist/events.d.ts.map +1 -1
  21. package/dist/routes.d.ts +254 -19
  22. package/dist/routes.d.ts.map +1 -1
  23. package/dist/routes.js +73 -5
  24. package/dist/schema-taxonomy.d.ts +287 -0
  25. package/dist/schema-taxonomy.d.ts.map +1 -1
  26. package/dist/schema-taxonomy.js +47 -0
  27. package/dist/service-catalog-plane-destinations.d.ts +30 -0
  28. package/dist/service-catalog-plane-destinations.d.ts.map +1 -0
  29. package/dist/service-catalog-plane-destinations.js +119 -0
  30. package/dist/service-catalog-plane-taxonomy.d.ts +73 -0
  31. package/dist/service-catalog-plane-taxonomy.d.ts.map +1 -0
  32. package/dist/service-catalog-plane-taxonomy.js +242 -0
  33. package/dist/service-catalog-plane.d.ts +46 -1
  34. package/dist/service-catalog-plane.d.ts.map +1 -1
  35. package/dist/service-catalog-plane.js +42 -6
  36. package/dist/service.d.ts +98 -19
  37. package/dist/service.d.ts.map +1 -1
  38. package/dist/service.js +142 -1
  39. package/dist/tasks/brochures.d.ts +1 -1
  40. package/dist/validation-content.d.ts +38 -0
  41. package/dist/validation-content.d.ts.map +1 -1
  42. package/dist/validation-content.js +29 -0
  43. package/package.json +77 -7
@@ -38,6 +38,14 @@ export interface QuickCreateBridgeInput {
38
38
  personId?: string | null;
39
39
  organizationId?: string | null;
40
40
  internalNotes?: string | null;
41
+ /**
42
+ * Override the seed sellAmountCents the booking lands at. The owned
43
+ * commit passes this when the catalog booking-engine's promotion hook
44
+ * has discounted the quote — without it, customers would be charged
45
+ * the product's list price even with a successful promotion. Per
46
+ * docs/architecture/promotions-architecture.md §7.1.
47
+ */
48
+ sellAmountCentsOverride?: number | null;
41
49
  travelers?: Array<{
42
50
  firstName: string;
43
51
  lastName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/booking-engine/handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/booking-engine/handler.ts"],"names":[],"mappings":"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"}
@@ -233,6 +233,13 @@ export function createProductsBookingHandler(options) {
233
233
  ? t.band
234
234
  : "adult",
235
235
  }));
236
+ // Promotion-discounted quotes: thread the discounted customer-
237
+ // facing amount into the booking's seed sellAmountCents so
238
+ // checkout / payment see the quoted amount, not the product list
239
+ // price. Inclusive-tax quotes rewrite `base_amount` to net
240
+ // subtotal during tax recompute, so derive the override from the
241
+ // gross breakdown total when an included tax line is present.
242
+ const sellAmountCentsOverride = resolveSellAmountCentsOverride(request.pricing);
236
243
  const bridge = await options.quickCreate({
237
244
  productId: product.id,
238
245
  bookingNumber: generateNumber(),
@@ -240,6 +247,7 @@ export function createProductsBookingHandler(options) {
240
247
  organizationId: extractOrganizationId(request.party),
241
248
  internalNotes: extractInternalNotes(request.party),
242
249
  travelers: travelers.length > 0 ? travelers : undefined,
250
+ sellAmountCentsOverride,
243
251
  taxLines: extractTaxLines(request.pricing),
244
252
  });
245
253
  if (bridge.status !== "ok" || !bridge.bookingId) {
@@ -406,6 +414,36 @@ function extractTaxLines(pricing) {
406
414
  }
407
415
  return lines.length ? lines : undefined;
408
416
  }
417
+ function resolveSellAmountCentsOverride(pricing) {
418
+ if (!pricing)
419
+ return null;
420
+ const breakdown = pricing.breakdown;
421
+ if (hasInclusiveTaxLine(breakdown)) {
422
+ const total = readBreakdownTotal(breakdown);
423
+ if (total != null)
424
+ return total;
425
+ }
426
+ return pricing.base_amount != null ? Math.round(pricing.base_amount) : null;
427
+ }
428
+ function hasInclusiveTaxLine(breakdown) {
429
+ if (!breakdown || typeof breakdown !== "object" || Array.isArray(breakdown))
430
+ return false;
431
+ const taxes = breakdown.taxes;
432
+ if (!Array.isArray(taxes))
433
+ return false;
434
+ return taxes.some((tax) => {
435
+ if (!tax || typeof tax !== "object" || Array.isArray(tax))
436
+ return false;
437
+ const row = tax;
438
+ return row.includedInPrice === true || row.scope === "included";
439
+ });
440
+ }
441
+ function readBreakdownTotal(breakdown) {
442
+ if (!breakdown || typeof breakdown !== "object" || Array.isArray(breakdown))
443
+ return null;
444
+ const total = breakdown.total;
445
+ return typeof total === "number" && Number.isFinite(total) ? Math.round(total) : null;
446
+ }
409
447
  function asFiniteInteger(value) {
410
448
  if (typeof value !== "number" || !Number.isFinite(value))
411
449
  return null;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Catalog plane field policy for product → departures denormalization.
3
+ *
4
+ * These fields don't live on the `products` table — they're aggregated
5
+ * from `availability_slots` (filtered to `status = 'open'` and future
6
+ * `startsAt`) at index time and projected onto the product search
7
+ * document. See `docs/architecture/catalog-architecture.md` §5.4.
8
+ *
9
+ * Storefront product cards filter and display by departure surface:
10
+ * - "departing in May" (filter: `departureMonths[]` includes "2026-05")
11
+ * - "available this weekend" (filter: `departureDates[]` overlap)
12
+ * - "available now" (filter: `hasUpcomingDeparture:true`)
13
+ * - sort by next departure (`nextDepartureAt` asc)
14
+ * - show capacity badge (`availableUnitsTotal`)
15
+ *
16
+ * Wire this policy into the products registry by composing with
17
+ * `productCatalogPolicy`:
18
+ *
19
+ * const registry = createFieldPolicyRegistry([
20
+ * ...productCatalogPolicy,
21
+ * ...productDeparturesCatalogPolicy,
22
+ * ])
23
+ *
24
+ * and wire `createProductDeparturesProjectionExtension` into
25
+ * `createProductDocumentBuilder` so the values land in the doc.
26
+ *
27
+ * Reindex semantics: every aggregation depends on `now()` — the same
28
+ * product reindexed an hour later will produce slightly different
29
+ * documents because the future window slides. Operators rely on the
30
+ * channel-push reconciler + scheduled refresh to keep these fields warm
31
+ * without storming the indexer on each tick. Per architecture §5.4,
32
+ * `reindex: "facet-affecting"` is the right tier — these fields drive
33
+ * facets but aren't on the merchandisable hot path.
34
+ *
35
+ * Out of scope here:
36
+ * - Sold-out / cancelled / closed slots. The projection only counts
37
+ * `status = 'open'` so storefront filters never surface unavailable
38
+ * departures. A "show sold-out" toggle is a query-time concern.
39
+ * - Per-option splits. Today's projection rolls up to the product;
40
+ * per-option faceting is a follow-up if storefronts need it.
41
+ * - Duration buckets (nights/days). Slots carry these but products
42
+ * with mixed-duration slots can't be summarized in one number.
43
+ */
44
+ import { type FieldPolicyInput } from "@voyantjs/catalog/contract";
45
+ declare const PRODUCT_DEPARTURES_FIELD_POLICY: FieldPolicyInput[];
46
+ /**
47
+ * Resolved departures policy. Compose with `productCatalogPolicy` when
48
+ * building the products registry.
49
+ */
50
+ export declare const productDeparturesCatalogPolicy: import("@voyantjs/catalog").FieldPolicy[];
51
+ export { PRODUCT_DEPARTURES_FIELD_POLICY };
52
+ //# sourceMappingURL=catalog-policy-departures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-policy-departures.d.ts","sourceRoot":"","sources":["../src/catalog-policy-departures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAErF,QAAA,MAAM,+BAA+B,EAAE,gBAAgB,EAyHtD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,8BAA8B,2CAAqD,CAAA;AAEhG,OAAO,EAAE,+BAA+B,EAAE,CAAA"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Catalog plane field policy for product → departures denormalization.
3
+ *
4
+ * These fields don't live on the `products` table — they're aggregated
5
+ * from `availability_slots` (filtered to `status = 'open'` and future
6
+ * `startsAt`) at index time and projected onto the product search
7
+ * document. See `docs/architecture/catalog-architecture.md` §5.4.
8
+ *
9
+ * Storefront product cards filter and display by departure surface:
10
+ * - "departing in May" (filter: `departureMonths[]` includes "2026-05")
11
+ * - "available this weekend" (filter: `departureDates[]` overlap)
12
+ * - "available now" (filter: `hasUpcomingDeparture:true`)
13
+ * - sort by next departure (`nextDepartureAt` asc)
14
+ * - show capacity badge (`availableUnitsTotal`)
15
+ *
16
+ * Wire this policy into the products registry by composing with
17
+ * `productCatalogPolicy`:
18
+ *
19
+ * const registry = createFieldPolicyRegistry([
20
+ * ...productCatalogPolicy,
21
+ * ...productDeparturesCatalogPolicy,
22
+ * ])
23
+ *
24
+ * and wire `createProductDeparturesProjectionExtension` into
25
+ * `createProductDocumentBuilder` so the values land in the doc.
26
+ *
27
+ * Reindex semantics: every aggregation depends on `now()` — the same
28
+ * product reindexed an hour later will produce slightly different
29
+ * documents because the future window slides. Operators rely on the
30
+ * channel-push reconciler + scheduled refresh to keep these fields warm
31
+ * without storming the indexer on each tick. Per architecture §5.4,
32
+ * `reindex: "facet-affecting"` is the right tier — these fields drive
33
+ * facets but aren't on the merchandisable hot path.
34
+ *
35
+ * Out of scope here:
36
+ * - Sold-out / cancelled / closed slots. The projection only counts
37
+ * `status = 'open'` so storefront filters never surface unavailable
38
+ * departures. A "show sold-out" toggle is a query-time concern.
39
+ * - Per-option splits. Today's projection rolls up to the product;
40
+ * per-option faceting is a follow-up if storefronts need it.
41
+ * - Duration buckets (nights/days). Slots carry these but products
42
+ * with mixed-duration slots can't be summarized in one number.
43
+ */
44
+ import { defineFieldPolicy } from "@voyantjs/catalog/contract";
45
+ const PRODUCT_DEPARTURES_FIELD_POLICY = [
46
+ // ── Earliest open future departure ──────────────────────────────────────
47
+ // `nextDepartureAt` is the timestamptz for sort order (catalog sort by
48
+ // soonest available). `nextDepartureDate` is the same departure expressed
49
+ // as the slot's local calendar date — what the storefront card renders.
50
+ {
51
+ path: "nextDepartureAt",
52
+ class: "structural",
53
+ merge: "source-only",
54
+ drift: "low",
55
+ reindex: "facet-affecting",
56
+ snapshot: "on-book",
57
+ query: "indexed-column",
58
+ localized: false,
59
+ visibility: ["staff", "customer", "partner"],
60
+ editRole: "none",
61
+ overrideFriction: "none",
62
+ sourceFreshness: "sync",
63
+ },
64
+ {
65
+ path: "nextDepartureDate",
66
+ class: "structural",
67
+ merge: "source-only",
68
+ drift: "low",
69
+ reindex: "facet-affecting",
70
+ snapshot: "on-book",
71
+ query: "indexed-column",
72
+ localized: false,
73
+ visibility: ["staff", "customer", "partner"],
74
+ editRole: "none",
75
+ overrideFriction: "none",
76
+ sourceFreshness: "sync",
77
+ },
78
+ // ── Existence + count facets ─────────────────────────────────────────────
79
+ // `hasUpcomingDeparture` is the cheap "available now" filter. The count
80
+ // lets storefront sort by "lots of options available" without exposing
81
+ // the date list to the query layer.
82
+ {
83
+ path: "hasUpcomingDeparture",
84
+ class: "structural",
85
+ merge: "source-only",
86
+ drift: "low",
87
+ reindex: "facet-affecting",
88
+ snapshot: "on-book",
89
+ query: "indexed-column",
90
+ localized: false,
91
+ visibility: ["staff", "customer", "partner"],
92
+ editRole: "none",
93
+ overrideFriction: "none",
94
+ sourceFreshness: "sync",
95
+ },
96
+ {
97
+ path: "upcomingDepartureCount",
98
+ class: "structural",
99
+ merge: "source-only",
100
+ drift: "low",
101
+ reindex: "facet-affecting",
102
+ snapshot: "on-book",
103
+ query: "indexed-column",
104
+ localized: false,
105
+ visibility: ["staff", "customer", "partner"],
106
+ editRole: "none",
107
+ overrideFriction: "none",
108
+ sourceFreshness: "sync",
109
+ },
110
+ // ── Calendar-bucket facets ──────────────────────────────────────────────
111
+ // `departureDates[]` powers fine-grained "this weekend" / "next week"
112
+ // filters; capped at 180 days of distinct calendar dates so document
113
+ // size stays bounded for daily-slot products. `departureMonths[]` is
114
+ // the longer-tail facet — 24 months of "YYYY-MM" tokens covers an
115
+ // operator's typical forward-published inventory horizon.
116
+ {
117
+ path: "departureDates[]",
118
+ class: "structural",
119
+ merge: "source-only",
120
+ drift: "low",
121
+ reindex: "facet-affecting",
122
+ snapshot: "on-book",
123
+ query: "indexed-column",
124
+ localized: false,
125
+ visibility: ["staff", "customer", "partner"],
126
+ editRole: "none",
127
+ overrideFriction: "none",
128
+ sourceFreshness: "sync",
129
+ },
130
+ {
131
+ path: "departureMonths[]",
132
+ class: "structural",
133
+ merge: "source-only",
134
+ drift: "low",
135
+ reindex: "facet-affecting",
136
+ snapshot: "on-book",
137
+ query: "indexed-column",
138
+ localized: false,
139
+ visibility: ["staff", "customer", "partner"],
140
+ editRole: "none",
141
+ overrideFriction: "none",
142
+ sourceFreshness: "sync",
143
+ },
144
+ // ── Capacity ────────────────────────────────────────────────────────────
145
+ // Sum of `remaining_pax` across upcoming open slots. `null` when ANY
146
+ // counted slot is unlimited — unbounded capacity can't be summarized in
147
+ // a number, and emitting a partial sum would mislead the storefront
148
+ // ("3 seats left" when one slot is actually unlimited).
149
+ {
150
+ path: "availableUnitsTotal",
151
+ class: "structural",
152
+ merge: "source-only",
153
+ drift: "low",
154
+ reindex: "facet-affecting",
155
+ snapshot: "on-book",
156
+ query: "indexed-column",
157
+ localized: false,
158
+ visibility: ["staff", "customer", "partner"],
159
+ editRole: "none",
160
+ overrideFriction: "none",
161
+ sourceFreshness: "sync",
162
+ },
163
+ ];
164
+ /**
165
+ * Resolved departures policy. Compose with `productCatalogPolicy` when
166
+ * building the products registry.
167
+ */
168
+ export const productDeparturesCatalogPolicy = defineFieldPolicy(PRODUCT_DEPARTURES_FIELD_POLICY);
169
+ export { PRODUCT_DEPARTURES_FIELD_POLICY };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Catalog plane field policy for product → destination denormalization.
3
+ *
4
+ * These fields don't live on the `products` table — they're joined from
5
+ * `product_destinations` → `destinations` (+ `destination_translations` for
6
+ * locale-aware names) at index time and projected onto the product search
7
+ * document. See `docs/architecture/catalog-architecture.md` §5.4 — the
8
+ * search index is the canonical place for cross-entity denormalization.
9
+ *
10
+ * Storefront product cards filter and display by destinations:
11
+ * - "trips to Italy" (filter: `countries[]` includes "Italy")
12
+ * - "trips in Rome" (filter: `cities[]` includes "Rome")
13
+ * - "Mediterranean cruises" (filter: `regions[]` includes "Mediterranean")
14
+ *
15
+ * Wire this policy into the products registry by composing with
16
+ * `productCatalogPolicy`:
17
+ *
18
+ * const registry = createFieldPolicyRegistry([
19
+ * ...productCatalogPolicy,
20
+ * ...productDestinationsCatalogPolicy,
21
+ * ])
22
+ *
23
+ * and wire `createProductDestinationsProjectionExtension` into
24
+ * `createProductDocumentBuilder` so the values land in the doc.
25
+ *
26
+ * Out of scope here:
27
+ * - Coordinates / geopoints. The `destinations` table has no coordinate
28
+ * columns; product geolocation lives on `product_locations` and will
29
+ * ship as its own policy in a follow-up PR.
30
+ * - Slug fields per locale. Destinations have one canonical slug today;
31
+ * locale-specific slugs are a follow-up if marketing needs them.
32
+ */
33
+ import { type FieldPolicyInput } from "@voyantjs/catalog/contract";
34
+ declare const PRODUCT_DESTINATIONS_FIELD_POLICY: FieldPolicyInput[];
35
+ /**
36
+ * Resolved destinations policy. Compose with `productCatalogPolicy` when
37
+ * building the products registry.
38
+ */
39
+ export declare const productDestinationsCatalogPolicy: import("@voyantjs/catalog").FieldPolicy[];
40
+ export { PRODUCT_DESTINATIONS_FIELD_POLICY };
41
+ //# sourceMappingURL=catalog-policy-destinations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-policy-destinations.d.ts","sourceRoot":"","sources":["../src/catalog-policy-destinations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAErF,QAAA,MAAM,iCAAiC,EAAE,gBAAgB,EAmFxD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,gCAAgC,2CAAuD,CAAA;AAEpG,OAAO,EAAE,iCAAiC,EAAE,CAAA"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Catalog plane field policy for product → destination denormalization.
3
+ *
4
+ * These fields don't live on the `products` table — they're joined from
5
+ * `product_destinations` → `destinations` (+ `destination_translations` for
6
+ * locale-aware names) at index time and projected onto the product search
7
+ * document. See `docs/architecture/catalog-architecture.md` §5.4 — the
8
+ * search index is the canonical place for cross-entity denormalization.
9
+ *
10
+ * Storefront product cards filter and display by destinations:
11
+ * - "trips to Italy" (filter: `countries[]` includes "Italy")
12
+ * - "trips in Rome" (filter: `cities[]` includes "Rome")
13
+ * - "Mediterranean cruises" (filter: `regions[]` includes "Mediterranean")
14
+ *
15
+ * Wire this policy into the products registry by composing with
16
+ * `productCatalogPolicy`:
17
+ *
18
+ * const registry = createFieldPolicyRegistry([
19
+ * ...productCatalogPolicy,
20
+ * ...productDestinationsCatalogPolicy,
21
+ * ])
22
+ *
23
+ * and wire `createProductDestinationsProjectionExtension` into
24
+ * `createProductDocumentBuilder` so the values land in the doc.
25
+ *
26
+ * Out of scope here:
27
+ * - Coordinates / geopoints. The `destinations` table has no coordinate
28
+ * columns; product geolocation lives on `product_locations` and will
29
+ * ship as its own policy in a follow-up PR.
30
+ * - Slug fields per locale. Destinations have one canonical slug today;
31
+ * locale-specific slugs are a follow-up if marketing needs them.
32
+ */
33
+ import { defineFieldPolicy } from "@voyantjs/catalog/contract";
34
+ const PRODUCT_DESTINATIONS_FIELD_POLICY = [
35
+ // ── Locale-aware destination labels ──────────────────────────────────────
36
+ // Sourced from `destination_translations` (falls back to `destinations.slug`
37
+ // when no translation exists for the slice's locale). One array entry per
38
+ // linked destination of the matching `destination_type`.
39
+ {
40
+ path: "regions[]",
41
+ class: "structural",
42
+ merge: "source-only",
43
+ drift: "low",
44
+ reindex: "entry-locale",
45
+ snapshot: "on-book",
46
+ query: "indexed-column",
47
+ localized: true,
48
+ visibility: ["staff", "customer", "partner"],
49
+ editRole: "none",
50
+ overrideFriction: "none",
51
+ sourceFreshness: "sync",
52
+ },
53
+ {
54
+ path: "countries[]",
55
+ class: "structural",
56
+ merge: "source-only",
57
+ drift: "low",
58
+ reindex: "entry-locale",
59
+ snapshot: "on-book",
60
+ query: "indexed-column",
61
+ localized: true,
62
+ visibility: ["staff", "customer", "partner"],
63
+ editRole: "none",
64
+ overrideFriction: "none",
65
+ sourceFreshness: "sync",
66
+ },
67
+ {
68
+ path: "cities[]",
69
+ class: "structural",
70
+ merge: "source-only",
71
+ drift: "low",
72
+ reindex: "entry-locale",
73
+ snapshot: "on-book",
74
+ query: "indexed-column",
75
+ localized: true,
76
+ visibility: ["staff", "customer", "partner"],
77
+ editRole: "none",
78
+ overrideFriction: "none",
79
+ sourceFreshness: "sync",
80
+ },
81
+ // ── Slugs (locale-stable) ────────────────────────────────────────────────
82
+ // Used for category-page links — operators want stable URLs that don't
83
+ // shift when translations are edited. One entry per linked destination.
84
+ {
85
+ path: "destinationSlugs[]",
86
+ class: "structural",
87
+ merge: "source-only",
88
+ drift: "low",
89
+ reindex: "facet-affecting",
90
+ snapshot: "on-book",
91
+ query: "indexed-column",
92
+ localized: false,
93
+ visibility: ["staff", "customer", "partner"],
94
+ editRole: "none",
95
+ overrideFriction: "none",
96
+ sourceFreshness: "sync",
97
+ },
98
+ // ── Destination IDs ──────────────────────────────────────────────────────
99
+ // Useful for filtering by exact destination match (e.g. landing pages
100
+ // pinned to a destination ID rather than a slug).
101
+ {
102
+ path: "destinationIds[]",
103
+ class: "structural",
104
+ merge: "source-only",
105
+ drift: "low",
106
+ reindex: "facet-affecting",
107
+ snapshot: "on-book",
108
+ query: "indexed-column",
109
+ localized: false,
110
+ visibility: ["staff", "customer", "partner"],
111
+ editRole: "none",
112
+ overrideFriction: "none",
113
+ sourceFreshness: "sync",
114
+ },
115
+ ];
116
+ /**
117
+ * Resolved destinations policy. Compose with `productCatalogPolicy` when
118
+ * building the products registry.
119
+ */
120
+ export const productDestinationsCatalogPolicy = defineFieldPolicy(PRODUCT_DESTINATIONS_FIELD_POLICY);
121
+ export { PRODUCT_DESTINATIONS_FIELD_POLICY };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Catalog plane field policy for product → pricing denormalization.
3
+ *
4
+ * Aggregates a "price from" value across the product's configured
5
+ * default-rule prices so storefront cards can render `from $X` without
6
+ * fanning out to per-option pricing on every render. See
7
+ * `docs/architecture/catalog-architecture.md` §5.4.
8
+ *
9
+ * Storefront product cards filter and display by:
10
+ * - "trips under $1000" (filter: `priceFromAmountCents` <= 100000)
11
+ * - badge "from $X" (display: `priceFromAmountCents` + `priceFromCurrency`)
12
+ * - sort by price ascending (`priceFromAmountCents` asc)
13
+ *
14
+ * Wire this policy into the products registry by composing with
15
+ * `productCatalogPolicy`:
16
+ *
17
+ * const registry = createFieldPolicyRegistry([
18
+ * ...productCatalogPolicy,
19
+ * ...productPricingCatalogPolicy,
20
+ * ])
21
+ *
22
+ * and wire `createProductPricingProjectionExtension` (from
23
+ * `@voyantjs/pricing/service-catalog-plane-pricing`) into
24
+ * `createProductDocumentBuilder` so the values land in the doc.
25
+ *
26
+ * Why a separate field instead of reusing the existing `sellAmountCents`
27
+ * from `productCatalogPolicy`: that path projects the product-row
28
+ * configured default verbatim. Multi-option products often leave
29
+ * `products.sellAmountCents` null and put the real prices on options —
30
+ * this projection MINs across both, giving storefront a value that's
31
+ * always meaningful even for the option-driven case.
32
+ *
33
+ * Out of scope here (deferred):
34
+ * - Schedule-aware rule resolution. The kernel reads `isDefault=true`
35
+ * rule prices only — it does NOT walk seasonal schedules, per-
36
+ * departure overrides, or per-unit occupancy tiers. A "true cheapest
37
+ * bookable price right now" projection requires per-slice rule
38
+ * evaluation with a moving "now" date and is a follow-up.
39
+ * - Per-audience / per-market currency conversion. The currency we
40
+ * emit is `products.sellCurrency`; multi-catalog operators using
41
+ * mixed currencies for the same product will see prices clipped
42
+ * to the rules matching that currency.
43
+ * - `pricing.changed` event surface. Today, edits to option-price
44
+ * rules don't fire any event, so the bridge can only reindex on
45
+ * `product.updated`. Tracked separately.
46
+ */
47
+ import { type FieldPolicyInput } from "@voyantjs/catalog/contract";
48
+ declare const PRODUCT_PRICING_FIELD_POLICY: FieldPolicyInput[];
49
+ /**
50
+ * Resolved pricing policy. Compose with `productCatalogPolicy` when
51
+ * building the products registry.
52
+ */
53
+ export declare const productPricingCatalogPolicy: import("@voyantjs/catalog").FieldPolicy[];
54
+ export { PRODUCT_PRICING_FIELD_POLICY };
55
+ //# sourceMappingURL=catalog-policy-pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-policy-pricing.d.ts","sourceRoot":"","sources":["../src/catalog-policy-pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAErF,QAAA,MAAM,4BAA4B,EAAE,gBAAgB,EAuDnD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,2BAA2B,2CAAkD,CAAA;AAE1F,OAAO,EAAE,4BAA4B,EAAE,CAAA"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Catalog plane field policy for product → pricing denormalization.
3
+ *
4
+ * Aggregates a "price from" value across the product's configured
5
+ * default-rule prices so storefront cards can render `from $X` without
6
+ * fanning out to per-option pricing on every render. See
7
+ * `docs/architecture/catalog-architecture.md` §5.4.
8
+ *
9
+ * Storefront product cards filter and display by:
10
+ * - "trips under $1000" (filter: `priceFromAmountCents` <= 100000)
11
+ * - badge "from $X" (display: `priceFromAmountCents` + `priceFromCurrency`)
12
+ * - sort by price ascending (`priceFromAmountCents` asc)
13
+ *
14
+ * Wire this policy into the products registry by composing with
15
+ * `productCatalogPolicy`:
16
+ *
17
+ * const registry = createFieldPolicyRegistry([
18
+ * ...productCatalogPolicy,
19
+ * ...productPricingCatalogPolicy,
20
+ * ])
21
+ *
22
+ * and wire `createProductPricingProjectionExtension` (from
23
+ * `@voyantjs/pricing/service-catalog-plane-pricing`) into
24
+ * `createProductDocumentBuilder` so the values land in the doc.
25
+ *
26
+ * Why a separate field instead of reusing the existing `sellAmountCents`
27
+ * from `productCatalogPolicy`: that path projects the product-row
28
+ * configured default verbatim. Multi-option products often leave
29
+ * `products.sellAmountCents` null and put the real prices on options —
30
+ * this projection MINs across both, giving storefront a value that's
31
+ * always meaningful even for the option-driven case.
32
+ *
33
+ * Out of scope here (deferred):
34
+ * - Schedule-aware rule resolution. The kernel reads `isDefault=true`
35
+ * rule prices only — it does NOT walk seasonal schedules, per-
36
+ * departure overrides, or per-unit occupancy tiers. A "true cheapest
37
+ * bookable price right now" projection requires per-slice rule
38
+ * evaluation with a moving "now" date and is a follow-up.
39
+ * - Per-audience / per-market currency conversion. The currency we
40
+ * emit is `products.sellCurrency`; multi-catalog operators using
41
+ * mixed currencies for the same product will see prices clipped
42
+ * to the rules matching that currency.
43
+ * - `pricing.changed` event surface. Today, edits to option-price
44
+ * rules don't fire any event, so the bridge can only reindex on
45
+ * `product.updated`. Tracked separately.
46
+ */
47
+ import { defineFieldPolicy } from "@voyantjs/catalog/contract";
48
+ const PRODUCT_PRICING_FIELD_POLICY = [
49
+ // ── Aggregated "price from" amount ───────────────────────────────────────
50
+ // MIN across `products.sellAmountCents` and the active default
51
+ // `optionPriceRules.baseSellAmountCents` (plus option-unit-rule MINs for
52
+ // per-unit-priced options). `null` when no source has a non-null amount.
53
+ {
54
+ path: "priceFromAmountCents",
55
+ class: "structural",
56
+ merge: "source-only",
57
+ drift: "low",
58
+ reindex: "facet-affecting",
59
+ snapshot: "on-book",
60
+ query: "indexed-column",
61
+ localized: false,
62
+ visibility: ["staff", "customer", "partner"],
63
+ editRole: "none",
64
+ overrideFriction: "none",
65
+ sourceFreshness: "sync",
66
+ },
67
+ // ── Currency for the projected amount ────────────────────────────────────
68
+ // `products.sellCurrency`. Stays consistent across all rule sources for
69
+ // the projected product because we filter rule rows to ones matching
70
+ // this currency before MIN'ing.
71
+ {
72
+ path: "priceFromCurrency",
73
+ class: "structural",
74
+ merge: "source-only",
75
+ drift: "low",
76
+ reindex: "facet-affecting",
77
+ snapshot: "on-book",
78
+ query: "indexed-column",
79
+ localized: false,
80
+ visibility: ["staff", "customer", "partner"],
81
+ editRole: "none",
82
+ overrideFriction: "none",
83
+ sourceFreshness: "sync",
84
+ },
85
+ // ── Existence flag ───────────────────────────────────────────────────────
86
+ // `false` when neither the product row nor any active default rule has a
87
+ // configured price. Storefront filters use this for "show only priced
88
+ // products" and to suppress an empty `from` badge.
89
+ {
90
+ path: "hasPricing",
91
+ class: "structural",
92
+ merge: "source-only",
93
+ drift: "low",
94
+ reindex: "facet-affecting",
95
+ snapshot: "on-book",
96
+ query: "indexed-column",
97
+ localized: false,
98
+ visibility: ["staff", "customer", "partner"],
99
+ editRole: "none",
100
+ overrideFriction: "none",
101
+ sourceFreshness: "sync",
102
+ },
103
+ ];
104
+ /**
105
+ * Resolved pricing policy. Compose with `productCatalogPolicy` when
106
+ * building the products registry.
107
+ */
108
+ export const productPricingCatalogPolicy = defineFieldPolicy(PRODUCT_PRICING_FIELD_POLICY);
109
+ export { PRODUCT_PRICING_FIELD_POLICY };