@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,278 @@
1
+ import type { HonoExtension } from "@voyant-travel/hono/module";
2
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
3
+ import { z } from "zod";
4
+ export declare const bookingProductDetails: import("drizzle-orm/pg-core").PgTableWithColumns<{
5
+ name: "booking_product_details";
6
+ schema: undefined;
7
+ columns: {
8
+ bookingId: import("drizzle-orm/pg-core").PgColumn<{
9
+ name: "booking_id";
10
+ tableName: "booking_product_details";
11
+ dataType: "string";
12
+ columnType: "PgText";
13
+ data: string;
14
+ driverParam: string;
15
+ notNull: true;
16
+ hasDefault: false;
17
+ isPrimaryKey: true;
18
+ isAutoincrement: false;
19
+ hasRuntimeDefault: false;
20
+ enumValues: [string, ...string[]];
21
+ baseColumn: never;
22
+ identity: undefined;
23
+ generated: undefined;
24
+ }, {}, {}>;
25
+ productId: import("drizzle-orm/pg-core").PgColumn<{
26
+ name: "product_id";
27
+ tableName: "booking_product_details";
28
+ dataType: "string";
29
+ columnType: "PgText";
30
+ data: string;
31
+ driverParam: string;
32
+ notNull: false;
33
+ hasDefault: false;
34
+ isPrimaryKey: false;
35
+ isAutoincrement: false;
36
+ hasRuntimeDefault: false;
37
+ enumValues: [string, ...string[]];
38
+ baseColumn: never;
39
+ identity: undefined;
40
+ generated: undefined;
41
+ }, {}, {}>;
42
+ optionId: import("drizzle-orm/pg-core").PgColumn<{
43
+ name: "option_id";
44
+ tableName: "booking_product_details";
45
+ dataType: "string";
46
+ columnType: "PgText";
47
+ data: string;
48
+ driverParam: string;
49
+ notNull: false;
50
+ hasDefault: false;
51
+ isPrimaryKey: false;
52
+ isAutoincrement: false;
53
+ hasRuntimeDefault: false;
54
+ enumValues: [string, ...string[]];
55
+ baseColumn: never;
56
+ identity: undefined;
57
+ generated: undefined;
58
+ }, {}, {}>;
59
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
60
+ name: "created_at";
61
+ tableName: "booking_product_details";
62
+ dataType: "date";
63
+ columnType: "PgTimestamp";
64
+ data: Date;
65
+ driverParam: string;
66
+ notNull: true;
67
+ hasDefault: true;
68
+ isPrimaryKey: false;
69
+ isAutoincrement: false;
70
+ hasRuntimeDefault: false;
71
+ enumValues: undefined;
72
+ baseColumn: never;
73
+ identity: undefined;
74
+ generated: undefined;
75
+ }, {}, {}>;
76
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
77
+ name: "updated_at";
78
+ tableName: "booking_product_details";
79
+ dataType: "date";
80
+ columnType: "PgTimestamp";
81
+ data: Date;
82
+ driverParam: string;
83
+ notNull: true;
84
+ hasDefault: true;
85
+ isPrimaryKey: false;
86
+ isAutoincrement: false;
87
+ hasRuntimeDefault: false;
88
+ enumValues: undefined;
89
+ baseColumn: never;
90
+ identity: undefined;
91
+ generated: undefined;
92
+ }, {}, {}>;
93
+ };
94
+ dialect: "pg";
95
+ }>;
96
+ export type BookingProductDetail = typeof bookingProductDetails.$inferSelect;
97
+ export type NewBookingProductDetail = typeof bookingProductDetails.$inferInsert;
98
+ export declare const bookingItemProductDetails: import("drizzle-orm/pg-core").PgTableWithColumns<{
99
+ name: "booking_item_product_details";
100
+ schema: undefined;
101
+ columns: {
102
+ bookingItemId: import("drizzle-orm/pg-core").PgColumn<{
103
+ name: "booking_item_id";
104
+ tableName: "booking_item_product_details";
105
+ dataType: "string";
106
+ columnType: "PgText";
107
+ data: string;
108
+ driverParam: string;
109
+ notNull: true;
110
+ hasDefault: false;
111
+ isPrimaryKey: true;
112
+ isAutoincrement: false;
113
+ hasRuntimeDefault: false;
114
+ enumValues: [string, ...string[]];
115
+ baseColumn: never;
116
+ identity: undefined;
117
+ generated: undefined;
118
+ }, {}, {}>;
119
+ productId: import("drizzle-orm/pg-core").PgColumn<{
120
+ name: "product_id";
121
+ tableName: "booking_item_product_details";
122
+ dataType: "string";
123
+ columnType: "PgText";
124
+ data: string;
125
+ driverParam: string;
126
+ notNull: false;
127
+ hasDefault: false;
128
+ isPrimaryKey: false;
129
+ isAutoincrement: false;
130
+ hasRuntimeDefault: false;
131
+ enumValues: [string, ...string[]];
132
+ baseColumn: never;
133
+ identity: undefined;
134
+ generated: undefined;
135
+ }, {}, {}>;
136
+ optionId: import("drizzle-orm/pg-core").PgColumn<{
137
+ name: "option_id";
138
+ tableName: "booking_item_product_details";
139
+ dataType: "string";
140
+ columnType: "PgText";
141
+ data: string;
142
+ driverParam: string;
143
+ notNull: false;
144
+ hasDefault: false;
145
+ isPrimaryKey: false;
146
+ isAutoincrement: false;
147
+ hasRuntimeDefault: false;
148
+ enumValues: [string, ...string[]];
149
+ baseColumn: never;
150
+ identity: undefined;
151
+ generated: undefined;
152
+ }, {}, {}>;
153
+ unitId: import("drizzle-orm/pg-core").PgColumn<{
154
+ name: "unit_id";
155
+ tableName: "booking_item_product_details";
156
+ dataType: "string";
157
+ columnType: "PgText";
158
+ data: string;
159
+ driverParam: string;
160
+ notNull: false;
161
+ hasDefault: false;
162
+ isPrimaryKey: false;
163
+ isAutoincrement: false;
164
+ hasRuntimeDefault: false;
165
+ enumValues: [string, ...string[]];
166
+ baseColumn: never;
167
+ identity: undefined;
168
+ generated: undefined;
169
+ }, {}, {}>;
170
+ supplierServiceId: import("drizzle-orm/pg-core").PgColumn<{
171
+ name: "supplier_service_id";
172
+ tableName: "booking_item_product_details";
173
+ dataType: "string";
174
+ columnType: "PgText";
175
+ data: string;
176
+ driverParam: string;
177
+ notNull: false;
178
+ hasDefault: false;
179
+ isPrimaryKey: false;
180
+ isAutoincrement: false;
181
+ hasRuntimeDefault: false;
182
+ enumValues: [string, ...string[]];
183
+ baseColumn: never;
184
+ identity: undefined;
185
+ generated: undefined;
186
+ }, {}, {}>;
187
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
188
+ name: "created_at";
189
+ tableName: "booking_item_product_details";
190
+ dataType: "date";
191
+ columnType: "PgTimestamp";
192
+ data: Date;
193
+ driverParam: string;
194
+ notNull: true;
195
+ hasDefault: true;
196
+ isPrimaryKey: false;
197
+ isAutoincrement: false;
198
+ hasRuntimeDefault: false;
199
+ enumValues: undefined;
200
+ baseColumn: never;
201
+ identity: undefined;
202
+ generated: undefined;
203
+ }, {}, {}>;
204
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
205
+ name: "updated_at";
206
+ tableName: "booking_item_product_details";
207
+ dataType: "date";
208
+ columnType: "PgTimestamp";
209
+ data: Date;
210
+ driverParam: string;
211
+ notNull: true;
212
+ hasDefault: true;
213
+ isPrimaryKey: false;
214
+ isAutoincrement: false;
215
+ hasRuntimeDefault: false;
216
+ enumValues: undefined;
217
+ baseColumn: never;
218
+ identity: undefined;
219
+ generated: undefined;
220
+ }, {}, {}>;
221
+ };
222
+ dialect: "pg";
223
+ }>;
224
+ export type BookingItemProductDetail = typeof bookingItemProductDetails.$inferSelect;
225
+ export type NewBookingItemProductDetail = typeof bookingItemProductDetails.$inferInsert;
226
+ declare const bookingProductDetailSchema: z.ZodObject<{
227
+ productId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
228
+ optionId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
229
+ }, z.core.$strip>;
230
+ declare const bookingItemProductDetailSchema: z.ZodObject<{
231
+ productId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
232
+ optionId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
233
+ unitId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
234
+ supplierServiceId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
235
+ }, z.core.$strip>;
236
+ export declare const bookingProductExtensionService: {
237
+ getBookingDetails(db: PostgresJsDatabase, bookingId: string): Promise<{
238
+ bookingId: string;
239
+ productId: string | null;
240
+ optionId: string | null;
241
+ createdAt: Date;
242
+ updatedAt: Date;
243
+ } | null>;
244
+ upsertBookingDetails(db: PostgresJsDatabase, bookingId: string, data: z.infer<typeof bookingProductDetailSchema>): Promise<{
245
+ createdAt: Date;
246
+ updatedAt: Date;
247
+ productId: string | null;
248
+ optionId: string | null;
249
+ bookingId: string;
250
+ } | null>;
251
+ removeBookingDetails(db: PostgresJsDatabase, bookingId: string): Promise<{
252
+ bookingId: string;
253
+ } | null>;
254
+ getItemDetails(db: PostgresJsDatabase, bookingItemId: string): Promise<{
255
+ bookingItemId: string;
256
+ productId: string | null;
257
+ optionId: string | null;
258
+ unitId: string | null;
259
+ supplierServiceId: string | null;
260
+ createdAt: Date;
261
+ updatedAt: Date;
262
+ } | null>;
263
+ upsertItemDetails(db: PostgresJsDatabase, bookingItemId: string, data: z.infer<typeof bookingItemProductDetailSchema>): Promise<{
264
+ createdAt: Date;
265
+ updatedAt: Date;
266
+ productId: string | null;
267
+ optionId: string | null;
268
+ unitId: string | null;
269
+ supplierServiceId: string | null;
270
+ bookingItemId: string;
271
+ } | null>;
272
+ removeItemDetails(db: PostgresJsDatabase, bookingItemId: string): Promise<{
273
+ bookingItemId: string;
274
+ } | null>;
275
+ };
276
+ export declare const productsBookingExtension: HonoExtension;
277
+ export {};
278
+ //# sourceMappingURL=booking-extension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"booking-extension.d.ts","sourceRoot":"","sources":["../src/booking-extension.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAG/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUjC,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG,OAAO,qBAAqB,CAAC,YAAY,CAAA;AAC5E,MAAM,MAAM,uBAAuB,GAAG,OAAO,qBAAqB,CAAC,YAAY,CAAA;AAE/E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBrC,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG,OAAO,yBAAyB,CAAC,YAAY,CAAA;AACpF,MAAM,MAAM,2BAA2B,GAAG,OAAO,yBAAyB,CAAC,YAAY,CAAA;AAIvF,QAAA,MAAM,0BAA0B;;;iBAG9B,CAAA;AAEF,QAAA,MAAM,8BAA8B;;;;;iBAKlC,CAAA;AAIF,eAAO,MAAM,8BAA8B;0BACb,kBAAkB,aAAa,MAAM;;;;;;;6BAU3D,kBAAkB,aACX,MAAM,QACX,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC;;;;;;;6BAqBnB,kBAAkB,aAAa,MAAM;;;uBAQ3C,kBAAkB,iBAAiB,MAAM;;;;;;;;;0BAU5D,kBAAkB,iBACP,MAAM,QACf,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC;;;;;;;;;0BAyB1B,kBAAkB,iBAAiB,MAAM;;;CAOtE,CAAA;AAoFD,eAAO,MAAM,wBAAwB,EAAE,aAGtC,CAAA"}
@@ -0,0 +1,161 @@
1
+ import { parseJsonBody } from "@voyant-travel/hono";
2
+ import { eq } from "drizzle-orm";
3
+ import { index, pgTable, text, timestamp } from "drizzle-orm/pg-core";
4
+ import { Hono } from "hono";
5
+ import { z } from "zod";
6
+ // ---------- schemas ----------
7
+ export const bookingProductDetails = pgTable("booking_product_details", {
8
+ bookingId: text("booking_id").primaryKey(),
9
+ productId: text("product_id"),
10
+ optionId: text("option_id"),
11
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
12
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
13
+ }, (t) => [index("idx_bpd_product").on(t.productId), index("idx_bpd_option").on(t.optionId)]);
14
+ export const bookingItemProductDetails = pgTable("booking_item_product_details", {
15
+ bookingItemId: text("booking_item_id").primaryKey(),
16
+ productId: text("product_id"),
17
+ optionId: text("option_id"),
18
+ unitId: text("unit_id"),
19
+ supplierServiceId: text("supplier_service_id"),
20
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
21
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
22
+ }, (t) => [
23
+ index("idx_bipd_product").on(t.productId),
24
+ index("idx_bipd_option").on(t.optionId),
25
+ index("idx_bipd_unit").on(t.unitId),
26
+ index("idx_bipd_supplier_service").on(t.supplierServiceId),
27
+ ]);
28
+ // ---------- validation ----------
29
+ const bookingProductDetailSchema = z.object({
30
+ productId: z.string().optional().nullable(),
31
+ optionId: z.string().optional().nullable(),
32
+ });
33
+ const bookingItemProductDetailSchema = z.object({
34
+ productId: z.string().optional().nullable(),
35
+ optionId: z.string().optional().nullable(),
36
+ unitId: z.string().optional().nullable(),
37
+ supplierServiceId: z.string().optional().nullable(),
38
+ });
39
+ // ---------- service ----------
40
+ export const bookingProductExtensionService = {
41
+ async getBookingDetails(db, bookingId) {
42
+ const [row] = await db
43
+ .select()
44
+ .from(bookingProductDetails)
45
+ .where(eq(bookingProductDetails.bookingId, bookingId))
46
+ .limit(1);
47
+ return row ?? null;
48
+ },
49
+ async upsertBookingDetails(db, bookingId, data) {
50
+ const [row] = await db
51
+ .insert(bookingProductDetails)
52
+ .values({
53
+ bookingId,
54
+ productId: data.productId ?? null,
55
+ optionId: data.optionId ?? null,
56
+ })
57
+ .onConflictDoUpdate({
58
+ target: bookingProductDetails.bookingId,
59
+ set: {
60
+ productId: data.productId ?? null,
61
+ optionId: data.optionId ?? null,
62
+ updatedAt: new Date(),
63
+ },
64
+ })
65
+ .returning();
66
+ return row ?? null;
67
+ },
68
+ async removeBookingDetails(db, bookingId) {
69
+ const [row] = await db
70
+ .delete(bookingProductDetails)
71
+ .where(eq(bookingProductDetails.bookingId, bookingId))
72
+ .returning({ bookingId: bookingProductDetails.bookingId });
73
+ return row ?? null;
74
+ },
75
+ async getItemDetails(db, bookingItemId) {
76
+ const [row] = await db
77
+ .select()
78
+ .from(bookingItemProductDetails)
79
+ .where(eq(bookingItemProductDetails.bookingItemId, bookingItemId))
80
+ .limit(1);
81
+ return row ?? null;
82
+ },
83
+ async upsertItemDetails(db, bookingItemId, data) {
84
+ const [row] = await db
85
+ .insert(bookingItemProductDetails)
86
+ .values({
87
+ bookingItemId,
88
+ productId: data.productId ?? null,
89
+ optionId: data.optionId ?? null,
90
+ unitId: data.unitId ?? null,
91
+ supplierServiceId: data.supplierServiceId ?? null,
92
+ })
93
+ .onConflictDoUpdate({
94
+ target: bookingItemProductDetails.bookingItemId,
95
+ set: {
96
+ productId: data.productId ?? null,
97
+ optionId: data.optionId ?? null,
98
+ unitId: data.unitId ?? null,
99
+ supplierServiceId: data.supplierServiceId ?? null,
100
+ updatedAt: new Date(),
101
+ },
102
+ })
103
+ .returning();
104
+ return row ?? null;
105
+ },
106
+ async removeItemDetails(db, bookingItemId) {
107
+ const [row] = await db
108
+ .delete(bookingItemProductDetails)
109
+ .where(eq(bookingItemProductDetails.bookingItemId, bookingItemId))
110
+ .returning({ bookingItemId: bookingItemProductDetails.bookingItemId });
111
+ return row ?? null;
112
+ },
113
+ };
114
+ const bookingProductExtensionRoutes = new Hono()
115
+ .get("/:bookingId/product-details", async (c) => {
116
+ const row = await bookingProductExtensionService.getBookingDetails(c.get("db"), c.req.param("bookingId"));
117
+ if (!row) {
118
+ return c.json({ data: null });
119
+ }
120
+ return c.json({ data: row });
121
+ })
122
+ .put("/:bookingId/product-details", async (c) => {
123
+ const data = await parseJsonBody(c, bookingProductDetailSchema);
124
+ const row = await bookingProductExtensionService.upsertBookingDetails(c.get("db"), c.req.param("bookingId"), data);
125
+ return c.json({ data: row });
126
+ })
127
+ .delete("/:bookingId/product-details", async (c) => {
128
+ const row = await bookingProductExtensionService.removeBookingDetails(c.get("db"), c.req.param("bookingId"));
129
+ if (!row) {
130
+ return c.json({ error: "Not found" }, 404);
131
+ }
132
+ return c.json({ success: true });
133
+ })
134
+ .get("/:bookingId/items/:itemId/product-details", async (c) => {
135
+ const row = await bookingProductExtensionService.getItemDetails(c.get("db"), c.req.param("itemId"));
136
+ if (!row) {
137
+ return c.json({ data: null });
138
+ }
139
+ return c.json({ data: row });
140
+ })
141
+ .put("/:bookingId/items/:itemId/product-details", async (c) => {
142
+ const data = await parseJsonBody(c, bookingItemProductDetailSchema);
143
+ const row = await bookingProductExtensionService.upsertItemDetails(c.get("db"), c.req.param("itemId"), data);
144
+ return c.json({ data: row });
145
+ })
146
+ .delete("/:bookingId/items/:itemId/product-details", async (c) => {
147
+ const row = await bookingProductExtensionService.removeItemDetails(c.get("db"), c.req.param("itemId"));
148
+ if (!row) {
149
+ return c.json({ error: "Not found" }, 404);
150
+ }
151
+ return c.json({ success: true });
152
+ });
153
+ // ---------- extension export ----------
154
+ const productsBookingExtensionDef = {
155
+ name: "products-booking",
156
+ module: "bookings",
157
+ };
158
+ export const productsBookingExtension = {
159
+ extension: productsBookingExtensionDef,
160
+ routes: bookingProductExtensionRoutes,
161
+ };
@@ -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 (`nextDepartureDate` 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 "@voyant-travel/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("@voyant-travel/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,iCAAiC,CAAA;AAE1F,QAAA,MAAM,+BAA+B,EAAE,gBAAgB,EAyHtD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,8BAA8B,gDAAqD,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 (`nextDepartureDate` 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 "@voyant-travel/catalog/contract";
45
+ const PRODUCT_DEPARTURES_FIELD_POLICY = [
46
+ // ── Earliest open future departure ──────────────────────────────────────
47
+ // `nextDepartureAt` is the timestamptz for storefront display metadata.
48
+ // `nextDepartureDate` is the slot's local calendar date and backs catalog
49
+ // sort by soonest available.
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 };