@voyant-travel/inventory 0.1.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 (311) hide show
  1. package/LICENSE +201 -0
  2. package/dist/action-ledger-drift.d.ts +29 -0
  3. package/dist/action-ledger-drift.d.ts.map +1 -0
  4. package/dist/action-ledger-drift.js +338 -0
  5. package/dist/action-ledger.d.ts +104 -0
  6. package/dist/action-ledger.d.ts.map +1 -0
  7. package/dist/action-ledger.js +100 -0
  8. package/dist/authoring/builder.d.ts +37 -0
  9. package/dist/authoring/builder.d.ts.map +1 -0
  10. package/dist/authoring/builder.js +248 -0
  11. package/dist/authoring/clone-content.d.ts +38 -0
  12. package/dist/authoring/clone-content.d.ts.map +1 -0
  13. package/dist/authoring/clone-content.js +367 -0
  14. package/dist/authoring/clone-pricing.d.ts +9 -0
  15. package/dist/authoring/clone-pricing.d.ts.map +1 -0
  16. package/dist/authoring/clone-pricing.js +242 -0
  17. package/dist/authoring/clone.d.ts +45 -0
  18. package/dist/authoring/clone.d.ts.map +1 -0
  19. package/dist/authoring/clone.js +142 -0
  20. package/dist/authoring/errors.d.ts +21 -0
  21. package/dist/authoring/errors.d.ts.map +1 -0
  22. package/dist/authoring/errors.js +13 -0
  23. package/dist/authoring/extension.d.ts +248 -0
  24. package/dist/authoring/extension.d.ts.map +1 -0
  25. package/dist/authoring/extension.js +116 -0
  26. package/dist/authoring/index.d.ts +12 -0
  27. package/dist/authoring/index.d.ts.map +1 -0
  28. package/dist/authoring/index.js +11 -0
  29. package/dist/authoring/schema.d.ts +85 -0
  30. package/dist/authoring/schema.d.ts.map +1 -0
  31. package/dist/authoring/schema.js +16 -0
  32. package/dist/authoring/service.d.ts +28 -0
  33. package/dist/authoring/service.d.ts.map +1 -0
  34. package/dist/authoring/service.js +66 -0
  35. package/dist/authoring/spec.d.ts +524 -0
  36. package/dist/authoring/spec.d.ts.map +1 -0
  37. package/dist/authoring/spec.js +167 -0
  38. package/dist/authoring/validate.d.ts +17 -0
  39. package/dist/authoring/validate.d.ts.map +1 -0
  40. package/dist/authoring/validate.js +83 -0
  41. package/dist/authoring.d.ts +2 -0
  42. package/dist/authoring.d.ts.map +1 -0
  43. package/dist/authoring.js +1 -0
  44. package/dist/booking-engine/handler-support.d.ts +91 -0
  45. package/dist/booking-engine/handler-support.d.ts.map +1 -0
  46. package/dist/booking-engine/handler-support.js +355 -0
  47. package/dist/booking-engine/handler.d.ts +404 -0
  48. package/dist/booking-engine/handler.d.ts.map +1 -0
  49. package/dist/booking-engine/handler.js +398 -0
  50. package/dist/booking-engine/index.d.ts +8 -0
  51. package/dist/booking-engine/index.d.ts.map +1 -0
  52. package/dist/booking-engine/index.js +7 -0
  53. package/dist/booking-engine.d.ts +2 -0
  54. package/dist/booking-engine.d.ts.map +1 -0
  55. package/dist/booking-engine.js +1 -0
  56. package/dist/booking-extension.d.ts +278 -0
  57. package/dist/booking-extension.d.ts.map +1 -0
  58. package/dist/booking-extension.js +161 -0
  59. package/dist/catalog-policy-departures.d.ts +52 -0
  60. package/dist/catalog-policy-departures.d.ts.map +1 -0
  61. package/dist/catalog-policy-departures.js +169 -0
  62. package/dist/catalog-policy-destinations.d.ts +43 -0
  63. package/dist/catalog-policy-destinations.d.ts.map +1 -0
  64. package/dist/catalog-policy-destinations.js +165 -0
  65. package/dist/catalog-policy-pricing.d.ts +55 -0
  66. package/dist/catalog-policy-pricing.d.ts.map +1 -0
  67. package/dist/catalog-policy-pricing.js +109 -0
  68. package/dist/catalog-policy-promotions.d.ts +52 -0
  69. package/dist/catalog-policy-promotions.d.ts.map +1 -0
  70. package/dist/catalog-policy-promotions.js +270 -0
  71. package/dist/catalog-policy-taxonomy.d.ts +51 -0
  72. package/dist/catalog-policy-taxonomy.d.ts.map +1 -0
  73. package/dist/catalog-policy-taxonomy.js +191 -0
  74. package/dist/catalog-policy.d.ts +33 -0
  75. package/dist/catalog-policy.d.ts.map +1 -0
  76. package/dist/catalog-policy.js +733 -0
  77. package/dist/content-shape.d.ts +15 -0
  78. package/dist/content-shape.d.ts.map +1 -0
  79. package/dist/content-shape.js +28 -0
  80. package/dist/draft-shape.d.ts +43 -0
  81. package/dist/draft-shape.d.ts.map +1 -0
  82. package/dist/draft-shape.js +48 -0
  83. package/dist/events.d.ts +37 -0
  84. package/dist/events.d.ts.map +1 -0
  85. package/dist/events.js +32 -0
  86. package/dist/extras/catalog-policy.d.ts +30 -0
  87. package/dist/extras/catalog-policy.d.ts.map +1 -0
  88. package/dist/extras/catalog-policy.js +319 -0
  89. package/dist/extras/content-shape.d.ts +5 -0
  90. package/dist/extras/content-shape.d.ts.map +1 -0
  91. package/dist/extras/content-shape.js +13 -0
  92. package/dist/extras/draft-shape.d.ts +34 -0
  93. package/dist/extras/draft-shape.d.ts.map +1 -0
  94. package/dist/extras/draft-shape.js +69 -0
  95. package/dist/extras/routes.d.ts +380 -0
  96. package/dist/extras/routes.d.ts.map +1 -0
  97. package/dist/extras/routes.js +59 -0
  98. package/dist/extras/schema-sourced-content.d.ts +254 -0
  99. package/dist/extras/schema-sourced-content.d.ts.map +1 -0
  100. package/dist/extras/schema-sourced-content.js +45 -0
  101. package/dist/extras/schema.d.ts +628 -0
  102. package/dist/extras/schema.d.ts.map +1 -0
  103. package/dist/extras/schema.js +87 -0
  104. package/dist/extras/service-catalog-plane.d.ts +77 -0
  105. package/dist/extras/service-catalog-plane.d.ts.map +1 -0
  106. package/dist/extras/service-catalog-plane.js +219 -0
  107. package/dist/extras/service-content-synthesizer.d.ts +41 -0
  108. package/dist/extras/service-content-synthesizer.d.ts.map +1 -0
  109. package/dist/extras/service-content-synthesizer.js +138 -0
  110. package/dist/extras/service-content.d.ts +48 -0
  111. package/dist/extras/service-content.d.ts.map +1 -0
  112. package/dist/extras/service-content.js +253 -0
  113. package/dist/extras/service.d.ts +185 -0
  114. package/dist/extras/service.d.ts.map +1 -0
  115. package/dist/extras/service.js +96 -0
  116. package/dist/extras/validation.d.ts +437 -0
  117. package/dist/extras/validation.d.ts.map +1 -0
  118. package/dist/extras/validation.js +149 -0
  119. package/dist/extras.d.ts +267 -0
  120. package/dist/extras.d.ts.map +1 -0
  121. package/dist/extras.js +19 -0
  122. package/dist/index.d.ts +22 -0
  123. package/dist/index.d.ts.map +1 -0
  124. package/dist/index.js +32 -0
  125. package/dist/interface.d.ts +5869 -0
  126. package/dist/interface.d.ts.map +1 -0
  127. package/dist/interface.js +54 -0
  128. package/dist/public-routes.d.ts +2 -0
  129. package/dist/public-routes.d.ts.map +1 -0
  130. package/dist/public-routes.js +1 -0
  131. package/dist/public-validation.d.ts +2 -0
  132. package/dist/public-validation.d.ts.map +1 -0
  133. package/dist/public-validation.js +1 -0
  134. package/dist/read-model.d.ts +25 -0
  135. package/dist/read-model.d.ts.map +1 -0
  136. package/dist/read-model.js +99 -0
  137. package/dist/route-env.d.ts +22 -0
  138. package/dist/route-env.d.ts.map +1 -0
  139. package/dist/route-env.js +1 -0
  140. package/dist/routes-associations.d.ts +164 -0
  141. package/dist/routes-associations.d.ts.map +1 -0
  142. package/dist/routes-associations.js +100 -0
  143. package/dist/routes-catalog.d.ts +436 -0
  144. package/dist/routes-catalog.d.ts.map +1 -0
  145. package/dist/routes-catalog.js +104 -0
  146. package/dist/routes-configuration.d.ts +773 -0
  147. package/dist/routes-configuration.d.ts.map +1 -0
  148. package/dist/routes-configuration.js +364 -0
  149. package/dist/routes-content.d.ts +74 -0
  150. package/dist/routes-content.d.ts.map +1 -0
  151. package/dist/routes-content.js +117 -0
  152. package/dist/routes-core.d.ts +331 -0
  153. package/dist/routes-core.d.ts.map +1 -0
  154. package/dist/routes-core.js +95 -0
  155. package/dist/routes-itinerary.d.ts +759 -0
  156. package/dist/routes-itinerary.d.ts.map +1 -0
  157. package/dist/routes-itinerary.js +387 -0
  158. package/dist/routes-maintenance.d.ts +32 -0
  159. package/dist/routes-maintenance.d.ts.map +1 -0
  160. package/dist/routes-maintenance.js +14 -0
  161. package/dist/routes-media.d.ts +634 -0
  162. package/dist/routes-media.d.ts.map +1 -0
  163. package/dist/routes-media.js +245 -0
  164. package/dist/routes-merchandising.d.ts +1120 -0
  165. package/dist/routes-merchandising.d.ts.map +1 -0
  166. package/dist/routes-merchandising.js +377 -0
  167. package/dist/routes-options.d.ts +363 -0
  168. package/dist/routes-options.d.ts.map +1 -0
  169. package/dist/routes-options.js +173 -0
  170. package/dist/routes-public.d.ts +776 -0
  171. package/dist/routes-public.d.ts.map +1 -0
  172. package/dist/routes-public.js +119 -0
  173. package/dist/routes-translations.d.ts +489 -0
  174. package/dist/routes-translations.d.ts.map +1 -0
  175. package/dist/routes-translations.js +258 -0
  176. package/dist/routes.d.ts +5097 -0
  177. package/dist/routes.d.ts.map +1 -0
  178. package/dist/routes.js +64 -0
  179. package/dist/schema-core.d.ts +1238 -0
  180. package/dist/schema-core.d.ts.map +1 -0
  181. package/dist/schema-core.js +157 -0
  182. package/dist/schema-itinerary.d.ts +1169 -0
  183. package/dist/schema-itinerary.d.ts.map +1 -0
  184. package/dist/schema-itinerary.js +130 -0
  185. package/dist/schema-relations.d.ts +117 -0
  186. package/dist/schema-relations.d.ts.map +1 -0
  187. package/dist/schema-relations.js +192 -0
  188. package/dist/schema-settings.d.ts +1800 -0
  189. package/dist/schema-settings.d.ts.map +1 -0
  190. package/dist/schema-settings.js +220 -0
  191. package/dist/schema-shared.d.ts +15 -0
  192. package/dist/schema-shared.d.ts.map +1 -0
  193. package/dist/schema-shared.js +91 -0
  194. package/dist/schema-sourced-content.d.ts +262 -0
  195. package/dist/schema-sourced-content.d.ts.map +1 -0
  196. package/dist/schema-sourced-content.js +69 -0
  197. package/dist/schema-taxonomy.d.ts +1363 -0
  198. package/dist/schema-taxonomy.d.ts.map +1 -0
  199. package/dist/schema-taxonomy.js +203 -0
  200. package/dist/schema.d.ts +10 -0
  201. package/dist/schema.d.ts.map +1 -0
  202. package/dist/schema.js +9 -0
  203. package/dist/service-aggregates.d.ts +29 -0
  204. package/dist/service-aggregates.d.ts.map +1 -0
  205. package/dist/service-aggregates.js +56 -0
  206. package/dist/service-catalog-plane-destinations.d.ts +30 -0
  207. package/dist/service-catalog-plane-destinations.d.ts.map +1 -0
  208. package/dist/service-catalog-plane-destinations.js +143 -0
  209. package/dist/service-catalog-plane-taxonomy.d.ts +73 -0
  210. package/dist/service-catalog-plane-taxonomy.d.ts.map +1 -0
  211. package/dist/service-catalog-plane-taxonomy.js +242 -0
  212. package/dist/service-catalog-plane.d.ts +179 -0
  213. package/dist/service-catalog-plane.d.ts.map +1 -0
  214. package/dist/service-catalog-plane.js +431 -0
  215. package/dist/service-catalog.d.ts +251 -0
  216. package/dist/service-catalog.d.ts.map +1 -0
  217. package/dist/service-catalog.js +517 -0
  218. package/dist/service-configuration.d.ts +261 -0
  219. package/dist/service-configuration.d.ts.map +1 -0
  220. package/dist/service-configuration.js +343 -0
  221. package/dist/service-content-owned.d.ts +68 -0
  222. package/dist/service-content-owned.d.ts.map +1 -0
  223. package/dist/service-content-owned.js +329 -0
  224. package/dist/service-content-synthesizer.d.ts +90 -0
  225. package/dist/service-content-synthesizer.d.ts.map +1 -0
  226. package/dist/service-content-synthesizer.js +178 -0
  227. package/dist/service-content.d.ts +106 -0
  228. package/dist/service-content.d.ts.map +1 -0
  229. package/dist/service-content.js +388 -0
  230. package/dist/service-core.d.ts +194 -0
  231. package/dist/service-core.d.ts.map +1 -0
  232. package/dist/service-core.js +213 -0
  233. package/dist/service-delivery-formats.d.ts +58 -0
  234. package/dist/service-delivery-formats.d.ts.map +1 -0
  235. package/dist/service-delivery-formats.js +107 -0
  236. package/dist/service-destinations.d.ts +223 -0
  237. package/dist/service-destinations.d.ts.map +1 -0
  238. package/dist/service-destinations.js +310 -0
  239. package/dist/service-itinerary-history.d.ts +457 -0
  240. package/dist/service-itinerary-history.d.ts.map +1 -0
  241. package/dist/service-itinerary-history.js +135 -0
  242. package/dist/service-itinerary.d.ts +1149 -0
  243. package/dist/service-itinerary.d.ts.map +1 -0
  244. package/dist/service-itinerary.js +419 -0
  245. package/dist/service-media.d.ts +272 -0
  246. package/dist/service-media.d.ts.map +1 -0
  247. package/dist/service-media.js +320 -0
  248. package/dist/service-merchandising.d.ts +184 -0
  249. package/dist/service-merchandising.d.ts.map +1 -0
  250. package/dist/service-merchandising.js +181 -0
  251. package/dist/service-option-translations.d.ts +268 -0
  252. package/dist/service-option-translations.d.ts.map +1 -0
  253. package/dist/service-option-translations.js +300 -0
  254. package/dist/service-options.d.ts +181 -0
  255. package/dist/service-options.d.ts.map +1 -0
  256. package/dist/service-options.js +179 -0
  257. package/dist/service-product-destinations.d.ts +37 -0
  258. package/dist/service-product-destinations.d.ts.map +1 -0
  259. package/dist/service-product-destinations.js +94 -0
  260. package/dist/service-public.d.ts +664 -0
  261. package/dist/service-public.d.ts.map +1 -0
  262. package/dist/service-public.js +374 -0
  263. package/dist/service-taxonomy.d.ts +197 -0
  264. package/dist/service-taxonomy.d.ts.map +1 -0
  265. package/dist/service-taxonomy.js +221 -0
  266. package/dist/service.d.ts +3929 -0
  267. package/dist/service.d.ts.map +1 -0
  268. package/dist/service.js +28 -0
  269. package/dist/tasks/brochure-printers.d.ts +31 -0
  270. package/dist/tasks/brochure-printers.d.ts.map +1 -0
  271. package/dist/tasks/brochure-printers.js +149 -0
  272. package/dist/tasks/brochure-templates.d.ts +36 -0
  273. package/dist/tasks/brochure-templates.d.ts.map +1 -0
  274. package/dist/tasks/brochure-templates.js +110 -0
  275. package/dist/tasks/brochures.d.ts +43 -0
  276. package/dist/tasks/brochures.d.ts.map +1 -0
  277. package/dist/tasks/brochures.js +72 -0
  278. package/dist/tasks/generate-pdf.d.ts +8 -0
  279. package/dist/tasks/generate-pdf.d.ts.map +1 -0
  280. package/dist/tasks/generate-pdf.js +106 -0
  281. package/dist/tasks/index.d.ts +5 -0
  282. package/dist/tasks/index.d.ts.map +1 -0
  283. package/dist/tasks/index.js +4 -0
  284. package/dist/tasks/pdf-text.d.ts +2 -0
  285. package/dist/tasks/pdf-text.d.ts.map +1 -0
  286. package/dist/tasks/pdf-text.js +40 -0
  287. package/dist/tasks.d.ts +2 -0
  288. package/dist/tasks.d.ts.map +1 -0
  289. package/dist/tasks.js +1 -0
  290. package/dist/validation-catalog.d.ts +2 -0
  291. package/dist/validation-catalog.d.ts.map +1 -0
  292. package/dist/validation-catalog.js +3 -0
  293. package/dist/validation-config.d.ts +2 -0
  294. package/dist/validation-config.d.ts.map +1 -0
  295. package/dist/validation-config.js +3 -0
  296. package/dist/validation-content.d.ts +2 -0
  297. package/dist/validation-content.d.ts.map +1 -0
  298. package/dist/validation-content.js +3 -0
  299. package/dist/validation-core.d.ts +2 -0
  300. package/dist/validation-core.d.ts.map +1 -0
  301. package/dist/validation-core.js +3 -0
  302. package/dist/validation-public.d.ts +2 -0
  303. package/dist/validation-public.d.ts.map +1 -0
  304. package/dist/validation-public.js +3 -0
  305. package/dist/validation-shared.d.ts +2 -0
  306. package/dist/validation-shared.d.ts.map +1 -0
  307. package/dist/validation-shared.js +3 -0
  308. package/dist/validation.d.ts +2 -0
  309. package/dist/validation.d.ts.map +1 -0
  310. package/dist/validation.js +3 -0
  311. package/package.json +204 -0
@@ -0,0 +1,167 @@
1
+ import { optionPricingModeEnum, optionUnitPricingModeEnum } from "@voyant-travel/commerce";
2
+ import { z } from "zod";
3
+ import { optionUnitTypeEnum, productBookingModeEnum, productCapacityModeEnum, productOptionStatusEnum, productStatusEnum, productVisibilityEnum, serviceTypeEnum, } from "../schema.js";
4
+ /**
5
+ * Normalized, transport-agnostic description of a bookable product graph.
6
+ *
7
+ * Both entry points feed the same builder:
8
+ * - clone — serialize an existing product into a spec, patch the product row.
9
+ * - compose — caller (Max AI agent) supplies the spec directly.
10
+ *
11
+ * Cross-references inside an option (a unit price rule pointing at a sibling
12
+ * unit, a pax tier pointing at a unit) use **local ref keys** (`ref` / `unitRef`),
13
+ * which the builder resolves to freshly-minted ids. For clone, serialize sets
14
+ * each `ref` to the source row id; for compose, the caller picks any unique
15
+ * string. Refs never reach the database.
16
+ *
17
+ * NOTE: `availability_slots` (departures) are intentionally absent — they are
18
+ * date-specific and added separately after the graph exists.
19
+ *
20
+ * Home of this type is under review (here vs `@voyant-travel/products-contracts`).
21
+ */
22
+ const money = z.number().int();
23
+ const jsonRecord = z.record(z.string(), z.unknown());
24
+ export const unitSpecSchema = z.object({
25
+ ref: z.string().min(1),
26
+ name: z.string().min(1).max(255),
27
+ code: z.string().max(255).nullish(),
28
+ description: z.string().nullish(),
29
+ unitType: z.enum(optionUnitTypeEnum.enumValues).default("person"),
30
+ minQuantity: z.number().int().nullish(),
31
+ maxQuantity: z.number().int().nullish(),
32
+ minAge: z.number().int().nullish(),
33
+ maxAge: z.number().int().nullish(),
34
+ occupancyMin: z.number().int().nullish(),
35
+ occupancyMax: z.number().int().nullish(),
36
+ isRequired: z.boolean().default(false),
37
+ isHidden: z.boolean().default(false),
38
+ sortOrder: z.number().int().default(0),
39
+ });
40
+ export const unitTierSpecSchema = z.object({
41
+ minQuantity: z.number().int(),
42
+ maxQuantity: z.number().int().nullish(),
43
+ sellAmountCents: money.nullish(),
44
+ costAmountCents: money.nullish(),
45
+ active: z.boolean().default(true),
46
+ sortOrder: z.number().int().default(0),
47
+ });
48
+ export const unitPriceRuleSpecSchema = z.object({
49
+ /** Resolves to a sibling unit's `ref` within the same option. */
50
+ unitRef: z.string().min(1),
51
+ pricingCategoryId: z.string().nullish(),
52
+ pricingMode: z.enum(optionUnitPricingModeEnum.enumValues).default("per_unit"),
53
+ sellAmountCents: money.nullish(),
54
+ costAmountCents: money.nullish(),
55
+ minQuantity: z.number().int().nullish(),
56
+ maxQuantity: z.number().int().nullish(),
57
+ active: z.boolean().default(true),
58
+ sortOrder: z.number().int().default(0),
59
+ notes: z.string().nullish(),
60
+ metadata: jsonRecord.nullish(),
61
+ tiers: z.array(unitTierSpecSchema).default([]),
62
+ });
63
+ export const optionPriceRuleSpecSchema = z.object({
64
+ /**
65
+ * Price catalog the rule points at. Optional: clone reuses the source rule's
66
+ * catalog; compose resolves the operator default when omitted.
67
+ */
68
+ priceCatalogId: z.string().nullish(),
69
+ priceScheduleId: z.string().nullish(),
70
+ cancellationPolicyId: z.string().nullish(),
71
+ code: z.string().nullish(),
72
+ name: z.string().min(1).max(255),
73
+ description: z.string().nullish(),
74
+ pricingMode: z.enum(optionPricingModeEnum.enumValues).default("per_person"),
75
+ baseSellAmountCents: money.nullish(),
76
+ baseCostAmountCents: money.nullish(),
77
+ minPerBooking: z.number().int().nullish(),
78
+ maxPerBooking: z.number().int().nullish(),
79
+ allPricingCategories: z.boolean().default(true),
80
+ isDefault: z.boolean().default(false),
81
+ active: z.boolean().default(true),
82
+ notes: z.string().nullish(),
83
+ metadata: jsonRecord.nullish(),
84
+ unitPriceRules: z.array(unitPriceRuleSpecSchema).default([]),
85
+ });
86
+ export const optionSpecSchema = z.object({
87
+ ref: z.string().min(1),
88
+ name: z.string().min(1).max(255),
89
+ code: z.string().max(255).nullish(),
90
+ description: z.string().nullish(),
91
+ status: z.enum(productOptionStatusEnum.enumValues).default("draft"),
92
+ isDefault: z.boolean().default(false),
93
+ sortOrder: z.number().int().default(0),
94
+ availableFrom: z.string().nullish(),
95
+ availableTo: z.string().nullish(),
96
+ units: z.array(unitSpecSchema).default([]),
97
+ priceRules: z.array(optionPriceRuleSpecSchema).default([]),
98
+ });
99
+ export const paxPricingTierSpecSchema = z.object({
100
+ /** Optional link to a unit (by `ref`) within the spec. */
101
+ unitRef: z.string().nullish(),
102
+ tierPax: z.number().int(),
103
+ pricePerPaxCents: money,
104
+ promoPricePerPaxCents: money.nullish(),
105
+ effectiveFrom: z.string().nullish(),
106
+ effectiveTo: z.string().nullish(),
107
+ });
108
+ export const dayServiceSpecSchema = z.object({
109
+ supplierServiceId: z.string().nullish(),
110
+ serviceType: z.enum(serviceTypeEnum.enumValues),
111
+ name: z.string().min(1).max(255),
112
+ description: z.string().nullish(),
113
+ countryCode: z.string().nullish(),
114
+ costCurrency: z.string().min(3).max(3),
115
+ costAmountCents: money,
116
+ quantity: z.number().int().default(1),
117
+ sortOrder: z.number().int().nullish(),
118
+ notes: z.string().nullish(),
119
+ });
120
+ export const daySpecSchema = z.object({
121
+ dayNumber: z.number().int(),
122
+ title: z.string().nullish(),
123
+ description: z.string().nullish(),
124
+ location: z.string().nullish(),
125
+ services: z.array(dayServiceSpecSchema).default([]),
126
+ });
127
+ export const itinerarySpecSchema = z.object({
128
+ name: z.string().min(1).max(255),
129
+ isDefault: z.boolean().default(false),
130
+ sortOrder: z.number().int().default(0),
131
+ days: z.array(daySpecSchema).default([]),
132
+ });
133
+ export const productRowSpecSchema = z.object({
134
+ name: z.string().min(1).max(255),
135
+ status: z.enum(productStatusEnum.enumValues).default("draft"),
136
+ description: z.string().nullish(),
137
+ inclusionsHtml: z.string().nullish(),
138
+ exclusionsHtml: z.string().nullish(),
139
+ termsHtml: z.string().nullish(),
140
+ termsShowOnContract: z.boolean().default(false),
141
+ bookingMode: z.enum(productBookingModeEnum.enumValues).default("date"),
142
+ capacityMode: z.enum(productCapacityModeEnum.enumValues).default("limited"),
143
+ timezone: z.string().nullish(),
144
+ defaultLanguageTag: z.string().nullish(),
145
+ visibility: z.enum(productVisibilityEnum.enumValues).default("private"),
146
+ sellCurrency: z.string().min(3).max(3),
147
+ sellAmountCents: money.nullish(),
148
+ costAmountCents: money.nullish(),
149
+ marginPercent: z.number().int().nullish(),
150
+ reservationTimeoutMinutes: z.number().int().nullish(),
151
+ facilityId: z.string().nullish(),
152
+ supplierId: z.string().nullish(),
153
+ startDate: z.string().nullish(),
154
+ endDate: z.string().nullish(),
155
+ pax: z.number().int().nullish(),
156
+ productTypeId: z.string().nullish(),
157
+ contractTemplateId: z.string().nullish(),
158
+ taxClassId: z.string().nullish(),
159
+ customerPaymentPolicy: z.unknown().nullish(),
160
+ tags: z.array(z.string()).default([]),
161
+ });
162
+ export const productGraphSpecSchema = z.object({
163
+ product: productRowSpecSchema,
164
+ options: z.array(optionSpecSchema).default([]),
165
+ paxPricingTiers: z.array(paxPricingTierSpecSchema).default([]),
166
+ itineraries: z.array(itinerarySpecSchema).default([]),
167
+ });
@@ -0,0 +1,17 @@
1
+ import type { AuthoringIssue } from "./errors.js";
2
+ import type { ProductGraphSpec } from "./spec.js";
3
+ /**
4
+ * Category-aware shape validation. Runs before the builder (compose path) so a
5
+ * wrong-shape spec is rejected with descriptive, agent-recoverable issues
6
+ * instead of producing a malformed-but-bookable product.
7
+ *
8
+ * Keyed on `bookingMode` (the structural classifier that exists in the schema
9
+ * today; `supplyModel` is still proposed). See the voyant-travel/platform authoring
10
+ * spec for the canonical per-category rules.
11
+ *
12
+ * Scope: the generic products graph — excursion (`date`/`date_time`), multi-day
13
+ * tour/package (`itinerary`), transfer (`transfer`). Other modes (`stay`,
14
+ * `open`, `other`) pass through leniently in v1.
15
+ */
16
+ export declare function validateProductGraph(spec: ProductGraphSpec): AuthoringIssue[];
17
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/authoring/validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAEjD;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,GAAG,cAAc,EAAE,CAyE7E"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Category-aware shape validation. Runs before the builder (compose path) so a
3
+ * wrong-shape spec is rejected with descriptive, agent-recoverable issues
4
+ * instead of producing a malformed-but-bookable product.
5
+ *
6
+ * Keyed on `bookingMode` (the structural classifier that exists in the schema
7
+ * today; `supplyModel` is still proposed). See the voyant-travel/platform authoring
8
+ * spec for the canonical per-category rules.
9
+ *
10
+ * Scope: the generic products graph — excursion (`date`/`date_time`), multi-day
11
+ * tour/package (`itinerary`), transfer (`transfer`). Other modes (`stay`,
12
+ * `open`, `other`) pass through leniently in v1.
13
+ */
14
+ export function validateProductGraph(spec) {
15
+ const issues = [];
16
+ const mode = spec.product.bookingMode;
17
+ const totalDays = spec.itineraries.reduce((n, i) => n + i.days.length, 0);
18
+ const allUnits = spec.options.flatMap((o) => o.units);
19
+ // Every bookable product needs at least one option with a unit.
20
+ if (spec.options.length === 0) {
21
+ issues.push({
22
+ code: "no_options",
23
+ field: "options",
24
+ message: "Product has no options, so it cannot be booked.",
25
+ fix: "Add at least one option with at least one unit.",
26
+ });
27
+ }
28
+ else if (allUnits.length === 0) {
29
+ issues.push({
30
+ code: "no_units",
31
+ field: "options[].units",
32
+ message: "No option has any units, so there is nothing to price or book.",
33
+ fix: "Add at least one unit (e.g. an 'Adult' person unit) to an option.",
34
+ });
35
+ }
36
+ if (mode === "date" || mode === "date_time") {
37
+ if (totalDays > 1) {
38
+ issues.push({
39
+ code: "excursion_multi_day",
40
+ field: "itineraries",
41
+ message: `A '${mode}' (excursion) product is single-day, but the spec has ${totalDays} itinerary days.`,
42
+ fix: "Use bookingMode 'itinerary' for a multi-day product, or reduce the itinerary to a single day.",
43
+ });
44
+ }
45
+ const roomUnit = allUnits.find((u) => u.unitType === "room");
46
+ if (roomUnit) {
47
+ issues.push({
48
+ code: "excursion_room_unit",
49
+ field: "options[].units[].unitType",
50
+ message: `Excursions price per person, but unit '${roomUnit.name}' has unitType 'room'.`,
51
+ fix: "Set the unit's unitType to 'person', or switch bookingMode to 'stay'/'itinerary' for room-based products.",
52
+ });
53
+ }
54
+ }
55
+ if (mode === "itinerary" && totalDays < 2) {
56
+ issues.push({
57
+ code: "tour_needs_days",
58
+ field: "itineraries",
59
+ message: `A multi-day ('itinerary') product needs at least 2 itinerary days; found ${totalDays}.`,
60
+ fix: "Add itinerary days, or use bookingMode 'date' for a single-day excursion.",
61
+ });
62
+ }
63
+ if (mode === "transfer") {
64
+ if (totalDays > 0) {
65
+ issues.push({
66
+ code: "transfer_no_days",
67
+ field: "itineraries",
68
+ message: `Transfers are point-to-point and take no itinerary days; found ${totalDays}.`,
69
+ fix: "Remove the itinerary days; model the journey via pickup/dropoff pricing instead.",
70
+ });
71
+ }
72
+ const badUnit = allUnits.find((u) => u.unitType !== "vehicle" && u.unitType !== "person");
73
+ if (badUnit) {
74
+ issues.push({
75
+ code: "transfer_unit_type",
76
+ field: "options[].units[].unitType",
77
+ message: `Transfer unit '${badUnit.name}' has unitType '${badUnit.unitType}'; transfers sell per vehicle or per seat.`,
78
+ fix: "Set the unit's unitType to 'vehicle' or 'person'.",
79
+ });
80
+ }
81
+ }
82
+ return issues;
83
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./authoring/index.js";
2
+ //# sourceMappingURL=authoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authoring.d.ts","sourceRoot":"","sources":["../src/authoring.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA"}
@@ -0,0 +1 @@
1
+ export * from "./authoring/index.js";
@@ -0,0 +1,91 @@
1
+ import type { AddonOffer, CommitOwnedRequest, OwnedHandlerContext, ProductVariantOption } from "@voyant-travel/catalog/booking-engine";
2
+ import type { AnyDrizzleDb } from "@voyant-travel/db";
3
+ import { products } from "../schema-core.js";
4
+ import type { BookingCreateBridgeInput, CreateProductsBookingHandlerOptions, DraftLike, ResolvedOptionPrice } from "./handler.js";
5
+ export declare function loadProduct(db: AnyDrizzleDb, productId: string): Promise<typeof products.$inferSelect | undefined>;
6
+ export declare function sumPax(pax: Partial<Record<string, number>> | undefined): number;
7
+ export interface PricedLine {
8
+ kind: "base" | "addon";
9
+ label: string;
10
+ quantity: number;
11
+ unitAmount: number;
12
+ totalAmount: number;
13
+ }
14
+ export interface PricedQuote {
15
+ totalCents: number;
16
+ lines: PricedLine[];
17
+ }
18
+ export interface NormalizedOptionSelection {
19
+ optionId: string;
20
+ optionUnitId?: string;
21
+ optionName?: string;
22
+ optionUnitName?: string;
23
+ quantity: number;
24
+ }
25
+ type DraftOptionSelection = NonNullable<NonNullable<DraftLike["configure"]>["optionSelections"]>[number];
26
+ export declare function normalizeOptionSelections(selections: ReadonlyArray<DraftOptionSelection> | undefined): NormalizedOptionSelection[];
27
+ export declare function priceOptionSelections(input: {
28
+ ctx: OwnedHandlerContext;
29
+ options: CreateProductsBookingHandlerOptions;
30
+ product: typeof products.$inferSelect;
31
+ productOptions: ReadonlyArray<ProductVariantOption>;
32
+ selections: ReadonlyArray<NormalizedOptionSelection>;
33
+ slotDate: string | null;
34
+ }): Promise<PricedQuote>;
35
+ export declare function bookingItemLinesFromOptionSelections(selections: ReadonlyArray<NormalizedOptionSelection>): BookingCreateBridgeInput["itemLines"] | undefined;
36
+ export declare function applyAddonSelections(input: {
37
+ priced: PricedQuote;
38
+ addons: DraftLike["addons"] | undefined;
39
+ addonCatalog: ReadonlyArray<AddonOffer>;
40
+ effectivePax: number;
41
+ }): PricedQuote;
42
+ export declare function bookingExtraLinesFromAddonSelections(input: {
43
+ addons: DraftLike["addons"] | undefined;
44
+ addonCatalog: ReadonlyArray<AddonOffer> | undefined;
45
+ currency: string;
46
+ quantityMultiplier?: number;
47
+ }): BookingCreateBridgeInput["extraLines"] | undefined;
48
+ /**
49
+ * Three-way price computation:
50
+ *
51
+ * 1. **Per-band** (preferred): when `resolvedPrice.unitPrices` matches
52
+ * at least one band with positive count, sum `pax[band] ×
53
+ * unit.sellAmountCents` for each matching band. One breakdown line
54
+ * per band.
55
+ *
56
+ * 2. **Per-booking**: when no per-band match but `baseSellAmountCents`
57
+ * is set, charge a single `base × paxCount` line.
58
+ *
59
+ * 3. **Fallback**: `product.sellAmountCents × paxCount`. Same shape as
60
+ * Phase A behavior, kept for bookings without an option/slot
61
+ * configured yet.
62
+ */
63
+ export declare function priceQuote(input: {
64
+ product: typeof products.$inferSelect;
65
+ resolvedPrice: ResolvedOptionPrice | null;
66
+ pax: Partial<Record<string, number>> | undefined;
67
+ effectivePax: number;
68
+ }): PricedQuote;
69
+ export declare function readInitialStatus(parameters: Record<string, unknown> | undefined): BookingCreateBridgeInput["initialStatus"];
70
+ export declare function extractInternalNotes(party: Record<string, unknown> | undefined): string | undefined;
71
+ export declare function extractBillingParty(party: Record<string, unknown> | undefined): {
72
+ personId?: string | null;
73
+ organizationId?: string | null;
74
+ contactFirstName?: string | null;
75
+ contactLastName?: string | null;
76
+ contactEmail?: string | null;
77
+ contactPhone?: string | null;
78
+ };
79
+ export declare function extractPartyTravelers(party: Record<string, unknown> | undefined): Array<{
80
+ personId?: string | null;
81
+ }>;
82
+ export declare function asRecord(value: unknown): Record<string, unknown> | null;
83
+ export declare function stringValue(value: unknown): string | null;
84
+ export declare function extractTaxLines(pricing: CommitOwnedRequest["pricing"]): BookingCreateBridgeInput["taxLines"];
85
+ export declare function resolveSellAmountCentsOverride(pricing: CommitOwnedRequest["pricing"]): number | null;
86
+ export declare function hasInclusiveTaxLine(breakdown: unknown): boolean;
87
+ export declare function readBreakdownTotal(breakdown: unknown): number | null;
88
+ export declare function asFiniteInteger(value: unknown): number | null;
89
+ export declare function defaultBookingNumber(): string;
90
+ export {};
91
+ //# sourceMappingURL=handler-support.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-support.d.ts","sourceRoot":"","sources":["../../src/booking-engine/handler-support.ts"],"names":[],"mappings":"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"}