@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 @@
1
+ {"version":3,"file":"routes-configuration.d.ts","sourceRoot":"","sources":["../src/routes-configuration.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AAIzC,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAobnC,CAAA"}
@@ -0,0 +1,364 @@
1
+ import { parseJsonBody, parseQuery } from "@voyant-travel/hono";
2
+ import { Hono } from "hono";
3
+ import { appendProductMutationLedgerEntry, changedMutationFields } from "./action-ledger.js";
4
+ import { productsService } from "./service.js";
5
+ import * as validation from "./validation.js";
6
+ export const productConfigurationRoutes = new Hono()
7
+ // ==========================================================================
8
+ // Product operating configuration
9
+ // ==========================================================================
10
+ .get("/activation-settings", async (c) => {
11
+ const query = parseQuery(c, validation.productActivationSettingListQuerySchema);
12
+ return c.json(await productsService.listActivationSettings(c.get("db"), query));
13
+ })
14
+ .get("/activation-settings/:id", async (c) => {
15
+ const row = await productsService.getActivationSettingById(c.get("db"), c.req.param("id"));
16
+ if (!row) {
17
+ return c.json({ error: "Product activation setting not found" }, 404);
18
+ }
19
+ return c.json({ data: row });
20
+ })
21
+ .post("/:id/activation-settings", async (c) => {
22
+ const productId = c.req.param("id");
23
+ const body = await parseJsonBody(c, validation.insertProductActivationSettingSchema);
24
+ const before = await productsService.getActivationSettingByProductId(c.get("db"), productId);
25
+ const row = await productsService.upsertActivationSetting(c.get("db"), productId, body);
26
+ if (!row) {
27
+ return c.json({ error: "Product not found" }, 404);
28
+ }
29
+ const action = before ? "update" : "create";
30
+ await appendProductMutationLedgerEntry(c, {
31
+ action,
32
+ productId,
33
+ changedFields: changedMutationFields(body, before, row),
34
+ subject: "product activation settings",
35
+ actionName: `product.activation_settings.${action}`,
36
+ routeOrToolName: `products.activation_settings.${action}`,
37
+ });
38
+ return c.json({ data: row }, 201);
39
+ })
40
+ .patch("/activation-settings/:id", async (c) => {
41
+ const id = c.req.param("id");
42
+ const body = await parseJsonBody(c, validation.updateProductActivationSettingSchema);
43
+ const before = await productsService.getActivationSettingById(c.get("db"), id);
44
+ if (!before) {
45
+ return c.json({ error: "Product activation setting not found" }, 404);
46
+ }
47
+ const row = await productsService.updateActivationSetting(c.get("db"), id, body);
48
+ if (!row) {
49
+ return c.json({ error: "Product activation setting not found" }, 404);
50
+ }
51
+ await appendProductMutationLedgerEntry(c, {
52
+ action: "update",
53
+ productId: row.productId,
54
+ changedFields: changedMutationFields(body, before, row),
55
+ subject: "product activation settings",
56
+ actionName: "product.activation_settings.update",
57
+ routeOrToolName: "products.activation_settings.update",
58
+ });
59
+ return c.json({ data: row });
60
+ })
61
+ .delete("/activation-settings/:id", async (c) => {
62
+ const id = c.req.param("id");
63
+ const before = await productsService.getActivationSettingById(c.get("db"), id);
64
+ if (!before) {
65
+ return c.json({ error: "Product activation setting not found" }, 404);
66
+ }
67
+ const row = await productsService.deleteActivationSetting(c.get("db"), id);
68
+ if (!row) {
69
+ return c.json({ error: "Product activation setting not found" }, 404);
70
+ }
71
+ await appendProductMutationLedgerEntry(c, {
72
+ action: "delete",
73
+ productId: before.productId,
74
+ changedFields: [],
75
+ subject: "product activation settings",
76
+ actionName: "product.activation_settings.delete",
77
+ routeOrToolName: "products.activation_settings.delete",
78
+ });
79
+ return c.json({ success: true }, 200);
80
+ })
81
+ .get("/ticket-settings", async (c) => {
82
+ const query = parseQuery(c, validation.productTicketSettingListQuerySchema);
83
+ return c.json(await productsService.listTicketSettings(c.get("db"), query));
84
+ })
85
+ .get("/ticket-settings/:id", async (c) => {
86
+ const row = await productsService.getTicketSettingById(c.get("db"), c.req.param("id"));
87
+ if (!row) {
88
+ return c.json({ error: "Product ticket setting not found" }, 404);
89
+ }
90
+ return c.json({ data: row });
91
+ })
92
+ .post("/:id/ticket-settings", async (c) => {
93
+ const productId = c.req.param("id");
94
+ const body = await parseJsonBody(c, validation.insertProductTicketSettingSchema);
95
+ const before = await productsService.getTicketSettingByProductId(c.get("db"), productId);
96
+ const row = await productsService.upsertTicketSetting(c.get("db"), productId, body);
97
+ if (!row) {
98
+ return c.json({ error: "Product not found" }, 404);
99
+ }
100
+ const action = before ? "update" : "create";
101
+ await appendProductMutationLedgerEntry(c, {
102
+ action,
103
+ productId,
104
+ changedFields: changedMutationFields(body, before, row),
105
+ subject: "product ticket settings",
106
+ actionName: `product.ticket_settings.${action}`,
107
+ routeOrToolName: `products.ticket_settings.${action}`,
108
+ });
109
+ return c.json({ data: row }, 201);
110
+ })
111
+ .patch("/ticket-settings/:id", async (c) => {
112
+ const id = c.req.param("id");
113
+ const body = await parseJsonBody(c, validation.updateProductTicketSettingSchema);
114
+ const before = await productsService.getTicketSettingById(c.get("db"), id);
115
+ if (!before) {
116
+ return c.json({ error: "Product ticket setting not found" }, 404);
117
+ }
118
+ const row = await productsService.updateTicketSetting(c.get("db"), id, body);
119
+ if (!row) {
120
+ return c.json({ error: "Product ticket setting not found" }, 404);
121
+ }
122
+ await appendProductMutationLedgerEntry(c, {
123
+ action: "update",
124
+ productId: row.productId,
125
+ changedFields: changedMutationFields(body, before, row),
126
+ subject: "product ticket settings",
127
+ actionName: "product.ticket_settings.update",
128
+ routeOrToolName: "products.ticket_settings.update",
129
+ });
130
+ return c.json({ data: row });
131
+ })
132
+ .delete("/ticket-settings/:id", async (c) => {
133
+ const id = c.req.param("id");
134
+ const before = await productsService.getTicketSettingById(c.get("db"), id);
135
+ if (!before) {
136
+ return c.json({ error: "Product ticket setting not found" }, 404);
137
+ }
138
+ const row = await productsService.deleteTicketSetting(c.get("db"), id);
139
+ if (!row) {
140
+ return c.json({ error: "Product ticket setting not found" }, 404);
141
+ }
142
+ await appendProductMutationLedgerEntry(c, {
143
+ action: "delete",
144
+ productId: before.productId,
145
+ changedFields: [],
146
+ subject: "product ticket settings",
147
+ actionName: "product.ticket_settings.delete",
148
+ routeOrToolName: "products.ticket_settings.delete",
149
+ });
150
+ return c.json({ success: true }, 200);
151
+ })
152
+ .get("/visibility-settings", async (c) => {
153
+ const query = parseQuery(c, validation.productVisibilitySettingListQuerySchema);
154
+ return c.json(await productsService.listVisibilitySettings(c.get("db"), query));
155
+ })
156
+ .get("/visibility-settings/:id", async (c) => {
157
+ const row = await productsService.getVisibilitySettingById(c.get("db"), c.req.param("id"));
158
+ if (!row) {
159
+ return c.json({ error: "Product visibility setting not found" }, 404);
160
+ }
161
+ return c.json({ data: row });
162
+ })
163
+ .post("/:id/visibility-settings", async (c) => {
164
+ const productId = c.req.param("id");
165
+ const body = await parseJsonBody(c, validation.insertProductVisibilitySettingSchema);
166
+ const before = await productsService.getVisibilitySettingByProductId(c.get("db"), productId);
167
+ const row = await productsService.upsertVisibilitySetting(c.get("db"), productId, body);
168
+ if (!row) {
169
+ return c.json({ error: "Product not found" }, 404);
170
+ }
171
+ const action = before ? "update" : "create";
172
+ await appendProductMutationLedgerEntry(c, {
173
+ action,
174
+ productId,
175
+ changedFields: changedMutationFields(body, before, row),
176
+ subject: "product visibility settings",
177
+ actionName: `product.visibility_settings.${action}`,
178
+ routeOrToolName: `products.visibility_settings.${action}`,
179
+ });
180
+ return c.json({ data: row }, 201);
181
+ })
182
+ .patch("/visibility-settings/:id", async (c) => {
183
+ const id = c.req.param("id");
184
+ const body = await parseJsonBody(c, validation.updateProductVisibilitySettingSchema);
185
+ const before = await productsService.getVisibilitySettingById(c.get("db"), id);
186
+ if (!before) {
187
+ return c.json({ error: "Product visibility setting not found" }, 404);
188
+ }
189
+ const row = await productsService.updateVisibilitySetting(c.get("db"), id, body);
190
+ if (!row) {
191
+ return c.json({ error: "Product visibility setting not found" }, 404);
192
+ }
193
+ await appendProductMutationLedgerEntry(c, {
194
+ action: "update",
195
+ productId: row.productId,
196
+ changedFields: changedMutationFields(body, before, row),
197
+ subject: "product visibility settings",
198
+ actionName: "product.visibility_settings.update",
199
+ routeOrToolName: "products.visibility_settings.update",
200
+ });
201
+ return c.json({ data: row });
202
+ })
203
+ .delete("/visibility-settings/:id", async (c) => {
204
+ const id = c.req.param("id");
205
+ const before = await productsService.getVisibilitySettingById(c.get("db"), id);
206
+ if (!before) {
207
+ return c.json({ error: "Product visibility setting not found" }, 404);
208
+ }
209
+ const row = await productsService.deleteVisibilitySetting(c.get("db"), id);
210
+ if (!row) {
211
+ return c.json({ error: "Product visibility setting not found" }, 404);
212
+ }
213
+ await appendProductMutationLedgerEntry(c, {
214
+ action: "delete",
215
+ productId: before.productId,
216
+ changedFields: [],
217
+ subject: "product visibility settings",
218
+ actionName: "product.visibility_settings.delete",
219
+ routeOrToolName: "products.visibility_settings.delete",
220
+ });
221
+ return c.json({ success: true }, 200);
222
+ })
223
+ .get("/capabilities", async (c) => {
224
+ const query = parseQuery(c, validation.productCapabilityListQuerySchema);
225
+ return c.json(await productsService.listCapabilities(c.get("db"), query));
226
+ })
227
+ .get("/capabilities/:id", async (c) => {
228
+ const row = await productsService.getCapabilityById(c.get("db"), c.req.param("id"));
229
+ if (!row) {
230
+ return c.json({ error: "Product capability not found" }, 404);
231
+ }
232
+ return c.json({ data: row });
233
+ })
234
+ .post("/:id/capabilities", async (c) => {
235
+ const productId = c.req.param("id");
236
+ const body = await parseJsonBody(c, validation.insertProductCapabilitySchema);
237
+ const before = await productsService.getCapabilityByProductAndName(c.get("db"), productId, body.capability);
238
+ const row = await productsService.createCapability(c.get("db"), productId, body);
239
+ if (!row) {
240
+ return c.json({ error: "Product not found" }, 404);
241
+ }
242
+ const action = before ? "update" : "create";
243
+ await appendProductMutationLedgerEntry(c, {
244
+ action,
245
+ productId,
246
+ changedFields: changedMutationFields(body, before, row),
247
+ subject: "product capability",
248
+ actionName: `product.capability.${action}`,
249
+ routeOrToolName: `products.capability.${action}`,
250
+ });
251
+ return c.json({ data: row }, 201);
252
+ })
253
+ .patch("/capabilities/:id", async (c) => {
254
+ const id = c.req.param("id");
255
+ const body = await parseJsonBody(c, validation.updateProductCapabilitySchema);
256
+ const before = await productsService.getCapabilityById(c.get("db"), id);
257
+ if (!before) {
258
+ return c.json({ error: "Product capability not found" }, 404);
259
+ }
260
+ const row = await productsService.updateCapability(c.get("db"), id, body);
261
+ if (!row) {
262
+ return c.json({ error: "Product capability not found" }, 404);
263
+ }
264
+ await appendProductMutationLedgerEntry(c, {
265
+ action: "update",
266
+ productId: row.productId,
267
+ changedFields: changedMutationFields(body, before, row),
268
+ subject: "product capability",
269
+ actionName: "product.capability.update",
270
+ routeOrToolName: "products.capability.update",
271
+ });
272
+ return c.json({ data: row });
273
+ })
274
+ .delete("/capabilities/:id", async (c) => {
275
+ const id = c.req.param("id");
276
+ const before = await productsService.getCapabilityById(c.get("db"), id);
277
+ if (!before) {
278
+ return c.json({ error: "Product capability not found" }, 404);
279
+ }
280
+ const row = await productsService.deleteCapability(c.get("db"), id);
281
+ if (!row) {
282
+ return c.json({ error: "Product capability not found" }, 404);
283
+ }
284
+ await appendProductMutationLedgerEntry(c, {
285
+ action: "delete",
286
+ productId: before.productId,
287
+ changedFields: [],
288
+ subject: "product capability",
289
+ actionName: "product.capability.delete",
290
+ routeOrToolName: "products.capability.delete",
291
+ });
292
+ return c.json({ success: true }, 200);
293
+ })
294
+ .get("/delivery-formats", async (c) => {
295
+ const query = parseQuery(c, validation.productDeliveryFormatListQuerySchema);
296
+ return c.json(await productsService.listDeliveryFormats(c.get("db"), query));
297
+ })
298
+ .get("/delivery-formats/:id", async (c) => {
299
+ const row = await productsService.getDeliveryFormatById(c.get("db"), c.req.param("id"));
300
+ if (!row) {
301
+ return c.json({ error: "Product delivery format not found" }, 404);
302
+ }
303
+ return c.json({ data: row });
304
+ })
305
+ .post("/:id/delivery-formats", async (c) => {
306
+ const productId = c.req.param("id");
307
+ const body = await parseJsonBody(c, validation.insertProductDeliveryFormatSchema);
308
+ const before = await productsService.getDeliveryFormatByProductAndFormat(c.get("db"), productId, body.format);
309
+ const row = await productsService.createDeliveryFormat(c.get("db"), productId, body);
310
+ if (!row) {
311
+ return c.json({ error: "Product not found" }, 404);
312
+ }
313
+ const action = before ? "update" : "create";
314
+ await appendProductMutationLedgerEntry(c, {
315
+ action,
316
+ productId,
317
+ changedFields: changedMutationFields(body, before, row),
318
+ subject: "product delivery format",
319
+ actionName: `product.delivery_format.${action}`,
320
+ routeOrToolName: `products.delivery_format.${action}`,
321
+ });
322
+ return c.json({ data: row }, 201);
323
+ })
324
+ .patch("/delivery-formats/:id", async (c) => {
325
+ const id = c.req.param("id");
326
+ const body = await parseJsonBody(c, validation.updateProductDeliveryFormatSchema);
327
+ const before = await productsService.getDeliveryFormatById(c.get("db"), id);
328
+ if (!before) {
329
+ return c.json({ error: "Product delivery format not found" }, 404);
330
+ }
331
+ const row = await productsService.updateDeliveryFormat(c.get("db"), id, body);
332
+ if (!row) {
333
+ return c.json({ error: "Product delivery format not found" }, 404);
334
+ }
335
+ await appendProductMutationLedgerEntry(c, {
336
+ action: "update",
337
+ productId: row.productId,
338
+ changedFields: changedMutationFields(body, before, row),
339
+ subject: "product delivery format",
340
+ actionName: "product.delivery_format.update",
341
+ routeOrToolName: "products.delivery_format.update",
342
+ });
343
+ return c.json({ data: row });
344
+ })
345
+ .delete("/delivery-formats/:id", async (c) => {
346
+ const id = c.req.param("id");
347
+ const before = await productsService.getDeliveryFormatById(c.get("db"), id);
348
+ if (!before) {
349
+ return c.json({ error: "Product delivery format not found" }, 404);
350
+ }
351
+ const row = await productsService.deleteDeliveryFormat(c.get("db"), id);
352
+ if (!row) {
353
+ return c.json({ error: "Product delivery format not found" }, 404);
354
+ }
355
+ await appendProductMutationLedgerEntry(c, {
356
+ action: "delete",
357
+ productId: before.productId,
358
+ changedFields: [],
359
+ subject: "product delivery format",
360
+ actionName: "product.delivery_format.delete",
361
+ routeOrToolName: "products.delivery_format.delete",
362
+ });
363
+ return c.json({ success: true }, 200);
364
+ });
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Product content routes — unified owned + sourced detail endpoint.
3
+ *
4
+ * GET /:id/content
5
+ *
6
+ * Returns the full `ProductContent` payload for ANY product:
7
+ * - **Sourced**: cache hit → cached row + overlay merge; cache miss
8
+ * with rich adapter → adapter fetch + write-through; cache miss
9
+ * with thin adapter → synthesizer fallback (sourced-content §3.3,
10
+ * §3.4, §3.6).
11
+ * - **Owned**: read from the products module's own tables and
12
+ * project to ProductContent. Overlay merge applies the same way.
13
+ * Marked `source: "owned"` in the response.
14
+ *
15
+ * 404 only when the entity doesn't exist (no sourced-entry row AND
16
+ * no owned product row). The catalog detail sheet calls this on
17
+ * click to enrich the indexed projection with itinerary, media,
18
+ * options, and policies.
19
+ *
20
+ * Templates mount this router under their preferred prefix; the
21
+ * factory takes a `resolveRegistry` callback so the catalog
22
+ * `SourceAdapterRegistry` stays starter-owned (singleton lifetime,
23
+ * adapters carry HTTP clients).
24
+ *
25
+ * See `docs/architecture/catalog-sourced-content.md` §3.3.
26
+ */
27
+ import type { SourceAdapterRegistry } from "@voyant-travel/catalog/booking-engine";
28
+ import type { AnyDrizzleDb } from "@voyant-travel/db";
29
+ import type { Context } from "hono";
30
+ import { Hono } from "hono";
31
+ export interface ProductContentRoutesEnv {
32
+ Variables: {
33
+ db: AnyDrizzleDb;
34
+ };
35
+ }
36
+ export interface CreateProductContentRoutesOptions {
37
+ /**
38
+ * Resolve the catalog `SourceAdapterRegistry` for the current
39
+ * request. Templates typically return a process-local singleton
40
+ * built lazily from env (mirroring the booking-engine registry
41
+ * pattern).
42
+ */
43
+ resolveRegistry: (c: Context) => SourceAdapterRegistry;
44
+ /**
45
+ * Optional sink for overlay-merge diagnostics. When set, called
46
+ * once per overlay that fails to apply. Defaults to silent (the
47
+ * read still succeeds; the bad overlay is skipped).
48
+ */
49
+ onOverlayError?: (event: {
50
+ field_path: string;
51
+ reason: string;
52
+ }) => void;
53
+ /**
54
+ * Optional override for `acceptMachineTranslated`. Defaults to
55
+ * `true` — storefront-friendly. Operator surfaces typically set
56
+ * `false` so ops sees authored content before deciding to override.
57
+ */
58
+ defaultAcceptMachineTranslated?: boolean;
59
+ }
60
+ /**
61
+ * Build the product content router. Returns a Hono instance that
62
+ * exposes a single `GET /:id/content` route. Templates mount it under
63
+ * `/v1/admin/products` or `/v1/public/products` as appropriate.
64
+ */
65
+ export declare function createProductContentRoutes(options: CreateProductContentRoutesOptions): Hono<ProductContentRoutesEnv>;
66
+ /**
67
+ * Parse an `Accept-Language` header into an ordered list of BCP 47
68
+ * tags. Quality factors are honored — higher-q first; ties keep
69
+ * insertion order. Lifted out of the route handler so it's testable
70
+ * in isolation.
71
+ */
72
+ export declare function parseAcceptLanguage(header: string): string[];
73
+ export type ProductContentRoutes = ReturnType<typeof createProductContentRoutes>;
74
+ //# sourceMappingURL=routes-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-content.d.ts","sourceRoot":"","sources":["../src/routes-content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AAClF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAI3B,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE;QACT,EAAE,EAAE,YAAY,CAAA;KACjB,CAAA;CACF;AAED,MAAM,WAAW,iCAAiC;IAChD;;;;;OAKG;IACH,eAAe,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,qBAAqB,CAAA;IACtD;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;IACxE;;;;OAIG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAA;CACzC;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,iCAAiC,GACzC,IAAI,CAAC,uBAAuB,CAAC,CA+D/B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAqB5D;AAED,MAAM,MAAM,oBAAoB,GAAG,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAA"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Product content routes — unified owned + sourced detail endpoint.
3
+ *
4
+ * GET /:id/content
5
+ *
6
+ * Returns the full `ProductContent` payload for ANY product:
7
+ * - **Sourced**: cache hit → cached row + overlay merge; cache miss
8
+ * with rich adapter → adapter fetch + write-through; cache miss
9
+ * with thin adapter → synthesizer fallback (sourced-content §3.3,
10
+ * §3.4, §3.6).
11
+ * - **Owned**: read from the products module's own tables and
12
+ * project to ProductContent. Overlay merge applies the same way.
13
+ * Marked `source: "owned"` in the response.
14
+ *
15
+ * 404 only when the entity doesn't exist (no sourced-entry row AND
16
+ * no owned product row). The catalog detail sheet calls this on
17
+ * click to enrich the indexed projection with itinerary, media,
18
+ * options, and policies.
19
+ *
20
+ * Templates mount this router under their preferred prefix; the
21
+ * factory takes a `resolveRegistry` callback so the catalog
22
+ * `SourceAdapterRegistry` stays starter-owned (singleton lifetime,
23
+ * adapters carry HTTP clients).
24
+ *
25
+ * See `docs/architecture/catalog-sourced-content.md` §3.3.
26
+ */
27
+ import { Hono } from "hono";
28
+ import { getProductContent } from "./service-content.js";
29
+ /**
30
+ * Build the product content router. Returns a Hono instance that
31
+ * exposes a single `GET /:id/content` route. Templates mount it under
32
+ * `/v1/admin/products` or `/v1/public/products` as appropriate.
33
+ */
34
+ export function createProductContentRoutes(options) {
35
+ return new Hono().get("/:id/content", async (c) => {
36
+ const entityId = c.req.param("id");
37
+ const scope = parseScope(c);
38
+ const registry = options.resolveRegistry(c);
39
+ const result = await getProductContent(c.var.db, entityId, scope, {
40
+ registry,
41
+ onOverlayError: options.onOverlayError,
42
+ });
43
+ if (!result) {
44
+ return c.json({
45
+ error: "not_found",
46
+ detail: `Product ${entityId} not found (no owned row + no sourced-entry row).`,
47
+ }, 404);
48
+ }
49
+ return c.json({
50
+ data: {
51
+ content: result.content,
52
+ served_locale: result.resolution.served_locale,
53
+ match_kind: result.resolution.match_kind,
54
+ source: result.source,
55
+ served_stale: result.served_stale,
56
+ synthesized: result.synthesized,
57
+ machine_translated: result.machine_translated,
58
+ },
59
+ });
60
+ });
61
+ function parseScope(c) {
62
+ // Locale priority: explicit query param > Accept-Language header
63
+ // > en-GB fallback. Multiple `?locale=` query params are joined
64
+ // into the preference chain.
65
+ const localeParams = c.req.queries("locale") ?? c.req.queries("locales") ?? [];
66
+ const headerLocale = c.req.header("accept-language");
67
+ const acceptLanguageList = headerLocale ? parseAcceptLanguage(headerLocale) : [];
68
+ const preferredLocales = localeParams.length > 0
69
+ ? localeParams
70
+ : acceptLanguageList.length > 0
71
+ ? acceptLanguageList
72
+ : ["en-GB"];
73
+ const market = c.req.query("market") ?? undefined;
74
+ const currency = c.req.query("currency") ?? undefined;
75
+ const acceptMTQuery = c.req.query("accept_mt");
76
+ const acceptMachineTranslated = acceptMTQuery != null
77
+ ? acceptMTQuery !== "false" && acceptMTQuery !== "0"
78
+ : (options.defaultAcceptMachineTranslated ?? true);
79
+ return {
80
+ preferredLocales,
81
+ market,
82
+ currency,
83
+ acceptMachineTranslated,
84
+ };
85
+ }
86
+ }
87
+ /**
88
+ * Parse an `Accept-Language` header into an ordered list of BCP 47
89
+ * tags. Quality factors are honored — higher-q first; ties keep
90
+ * insertion order. Lifted out of the route handler so it's testable
91
+ * in isolation.
92
+ */
93
+ export function parseAcceptLanguage(header) {
94
+ const parts = header.split(",");
95
+ const ranked = [];
96
+ for (let i = 0; i < parts.length; i += 1) {
97
+ const part = parts[i].trim();
98
+ if (!part)
99
+ continue;
100
+ const [tagRaw, ...params] = part.split(";");
101
+ const tag = tagRaw.trim();
102
+ if (!tag || tag === "*")
103
+ continue;
104
+ let q = 1;
105
+ for (const p of params) {
106
+ const [k, v] = p.split("=").map((s) => s.trim());
107
+ if (k === "q" && v) {
108
+ const parsed = Number.parseFloat(v);
109
+ if (Number.isFinite(parsed))
110
+ q = parsed;
111
+ }
112
+ }
113
+ ranked.push({ tag, q, idx: i });
114
+ }
115
+ ranked.sort((a, b) => b.q - a.q || a.idx - b.idx);
116
+ return ranked.map((r) => r.tag);
117
+ }