@voyantjs/products 0.19.0 → 0.21.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 (72) hide show
  1. package/dist/booking-engine/handler.d.ts +203 -0
  2. package/dist/booking-engine/handler.d.ts.map +1 -0
  3. package/dist/booking-engine/handler.js +330 -0
  4. package/dist/booking-engine/index.d.ts +8 -0
  5. package/dist/booking-engine/index.d.ts.map +1 -0
  6. package/dist/booking-engine/index.js +7 -0
  7. package/dist/catalog-policy.d.ts +33 -0
  8. package/dist/catalog-policy.d.ts.map +1 -0
  9. package/dist/catalog-policy.js +421 -0
  10. package/dist/content-shape.d.ts +217 -0
  11. package/dist/content-shape.d.ts.map +1 -0
  12. package/dist/content-shape.js +159 -0
  13. package/dist/draft-shape.d.ts +43 -0
  14. package/dist/draft-shape.d.ts.map +1 -0
  15. package/dist/draft-shape.js +46 -0
  16. package/dist/events.d.ts +37 -0
  17. package/dist/events.d.ts.map +1 -0
  18. package/dist/events.js +32 -0
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +1 -0
  22. package/dist/routes-content.d.ts +74 -0
  23. package/dist/routes-content.d.ts.map +1 -0
  24. package/dist/routes-content.js +117 -0
  25. package/dist/routes.d.ts +47 -26
  26. package/dist/routes.d.ts.map +1 -1
  27. package/dist/routes.js +88 -16
  28. package/dist/schema-core.d.ts +240 -1
  29. package/dist/schema-core.d.ts.map +1 -1
  30. package/dist/schema-core.js +49 -0
  31. package/dist/schema-itinerary.d.ts +18 -1
  32. package/dist/schema-itinerary.d.ts.map +1 -1
  33. package/dist/schema-itinerary.js +1 -0
  34. package/dist/schema-settings.d.ts +1 -1
  35. package/dist/schema-sourced-content.d.ts +262 -0
  36. package/dist/schema-sourced-content.d.ts.map +1 -0
  37. package/dist/schema-sourced-content.js +69 -0
  38. package/dist/schema-taxonomy.d.ts +17 -0
  39. package/dist/schema-taxonomy.d.ts.map +1 -1
  40. package/dist/schema-taxonomy.js +13 -0
  41. package/dist/schema.d.ts +1 -0
  42. package/dist/schema.d.ts.map +1 -1
  43. package/dist/schema.js +1 -0
  44. package/dist/service-catalog-plane.d.ts +129 -0
  45. package/dist/service-catalog-plane.d.ts.map +1 -0
  46. package/dist/service-catalog-plane.js +212 -0
  47. package/dist/service-content-owned.d.ts +68 -0
  48. package/dist/service-content-owned.d.ts.map +1 -0
  49. package/dist/service-content-owned.js +224 -0
  50. package/dist/service-content-synthesizer.d.ts +90 -0
  51. package/dist/service-content-synthesizer.d.ts.map +1 -0
  52. package/dist/service-content-synthesizer.js +171 -0
  53. package/dist/service-content.d.ts +106 -0
  54. package/dist/service-content.d.ts.map +1 -0
  55. package/dist/service-content.js +365 -0
  56. package/dist/service.d.ts +82 -28
  57. package/dist/service.d.ts.map +1 -1
  58. package/dist/service.js +4 -0
  59. package/dist/tasks/brochures.d.ts +2 -1
  60. package/dist/tasks/brochures.d.ts.map +1 -1
  61. package/dist/tasks/brochures.js +3 -0
  62. package/dist/validation-catalog.d.ts +4 -4
  63. package/dist/validation-config.d.ts +3 -3
  64. package/dist/validation-content.d.ts +34 -4
  65. package/dist/validation-content.d.ts.map +1 -1
  66. package/dist/validation-content.js +13 -0
  67. package/dist/validation-core.d.ts +53 -3
  68. package/dist/validation-core.d.ts.map +1 -1
  69. package/dist/validation-core.js +16 -0
  70. package/dist/validation-public.d.ts +9 -9
  71. package/dist/validation-shared.d.ts +4 -4
  72. package/package.json +12 -6
package/dist/routes.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { parseJsonBody, parseQuery, RequestValidationError, requireUserId } from "@voyantjs/hono";
2
2
  import { Hono } from "hono";
3
3
  import { z } from "zod";
4
+ import { emitProductContentChanged } from "./events.js";
4
5
  import { productsService } from "./service.js";
5
6
  import { destinationListQuerySchema, destinationTranslationListQuerySchema, duplicateItinerarySchema, insertDaySchema, insertDayServiceSchema, insertDestinationSchema, insertDestinationTranslationSchema, insertItinerarySchema, insertOptionUnitSchema, insertOptionUnitTranslationSchema, insertProductActivationSettingSchema, insertProductCapabilitySchema, insertProductCategorySchema, insertProductDeliveryFormatSchema, insertProductDestinationSchema, insertProductFaqSchema, insertProductFeatureSchema, insertProductLocationSchema, insertProductMediaSchema, insertProductNoteSchema, insertProductOptionSchema, insertProductOptionTranslationSchema, insertProductSchema, insertProductTagSchema, insertProductTicketSettingSchema, insertProductTranslationSchema, insertProductTypeSchema, insertProductVisibilitySettingSchema, insertVersionSchema, optionUnitListQuerySchema, optionUnitTranslationListQuerySchema, productActivationSettingListQuerySchema, productAggregatesQuerySchema, productCapabilityListQuerySchema, productCategoryListQuerySchema, productDeliveryFormatListQuerySchema, productDestinationListQuerySchema, productFaqListQuerySchema, productFeatureListQuerySchema, productListQuerySchema, productLocationListQuerySchema, productMediaListQuerySchema, productOptionListQuerySchema, productOptionTranslationListQuerySchema, productTagListQuerySchema, productTicketSettingListQuerySchema, productTranslationListQuerySchema, productTypeListQuerySchema, productVisibilitySettingListQuerySchema, reorderProductMediaSchema, updateDaySchema, updateDayServiceSchema, updateDestinationSchema, updateDestinationTranslationSchema, updateItinerarySchema, updateOptionUnitSchema, updateOptionUnitTranslationSchema, updateProductActivationSettingSchema, updateProductCapabilitySchema, updateProductCategorySchema, updateProductDeliveryFormatSchema, updateProductFaqSchema, updateProductFeatureSchema, updateProductLocationSchema, updateProductMediaSchema, updateProductOptionSchema, updateProductOptionTranslationSchema, updateProductSchema, updateProductTagSchema, updateProductTicketSettingSchema, updateProductTranslationSchema, updateProductTypeSchema, updateProductVisibilitySettingSchema, upsertProductBrochureSchema, } from "./validation.js";
6
7
  // ==========================================================================
@@ -19,9 +20,9 @@ export const productRoutes = new Hono()
19
20
  })
20
21
  // POST / — Create product
21
22
  .post("/", async (c) => {
22
- return c.json({
23
- data: await productsService.createProduct(c.get("db"), await parseJsonBody(c, insertProductSchema)),
24
- }, 201);
23
+ const row = await productsService.createProduct(c.get("db"), await parseJsonBody(c, insertProductSchema));
24
+ await c.get("eventBus")?.emit("product.created", { id: row.id });
25
+ return c.json({ data: row }, 201);
25
26
  })
26
27
  // ==========================================================================
27
28
  // Product operating configuration
@@ -198,10 +199,12 @@ export const productRoutes = new Hono()
198
199
  return c.json({ data: row });
199
200
  })
200
201
  .post("/:id/features", async (c) => {
201
- const row = await productsService.createFeature(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertProductFeatureSchema));
202
+ const productId = c.req.param("id");
203
+ const row = await productsService.createFeature(c.get("db"), productId, await parseJsonBody(c, insertProductFeatureSchema));
202
204
  if (!row) {
203
205
  return c.json({ error: "Product not found" }, 404);
204
206
  }
207
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "feature" });
205
208
  return c.json({ data: row }, 201);
206
209
  })
207
210
  .patch("/features/:id", async (c) => {
@@ -209,6 +212,9 @@ export const productRoutes = new Hono()
209
212
  if (!row) {
210
213
  return c.json({ error: "Product feature not found" }, 404);
211
214
  }
215
+ if (row.productId) {
216
+ await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "feature" });
217
+ }
212
218
  return c.json({ data: row });
213
219
  })
214
220
  .delete("/features/:id", async (c) => {
@@ -216,6 +222,9 @@ export const productRoutes = new Hono()
216
222
  if (!row) {
217
223
  return c.json({ error: "Product feature not found" }, 404);
218
224
  }
225
+ if ("productId" in row && typeof row.productId === "string") {
226
+ await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "feature" });
227
+ }
219
228
  return c.json({ success: true }, 200);
220
229
  })
221
230
  .get("/faqs", async (c) => {
@@ -230,10 +239,12 @@ export const productRoutes = new Hono()
230
239
  return c.json({ data: row });
231
240
  })
232
241
  .post("/:id/faqs", async (c) => {
233
- const row = await productsService.createFaq(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertProductFaqSchema));
242
+ const productId = c.req.param("id");
243
+ const row = await productsService.createFaq(c.get("db"), productId, await parseJsonBody(c, insertProductFaqSchema));
234
244
  if (!row) {
235
245
  return c.json({ error: "Product not found" }, 404);
236
246
  }
247
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "faq" });
237
248
  return c.json({ data: row }, 201);
238
249
  })
239
250
  .patch("/faqs/:id", async (c) => {
@@ -241,6 +252,9 @@ export const productRoutes = new Hono()
241
252
  if (!row) {
242
253
  return c.json({ error: "Product FAQ not found" }, 404);
243
254
  }
255
+ if (row.productId) {
256
+ await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "faq" });
257
+ }
244
258
  return c.json({ data: row });
245
259
  })
246
260
  .delete("/faqs/:id", async (c) => {
@@ -248,6 +262,9 @@ export const productRoutes = new Hono()
248
262
  if (!row) {
249
263
  return c.json({ error: "Product FAQ not found" }, 404);
250
264
  }
265
+ if ("productId" in row && typeof row.productId === "string") {
266
+ await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "faq" });
267
+ }
251
268
  return c.json({ success: true }, 200);
252
269
  })
253
270
  .get("/locations", async (c) => {
@@ -262,10 +279,12 @@ export const productRoutes = new Hono()
262
279
  return c.json({ data: row });
263
280
  })
264
281
  .post("/:id/locations", async (c) => {
265
- const row = await productsService.createLocation(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertProductLocationSchema));
282
+ const productId = c.req.param("id");
283
+ const row = await productsService.createLocation(c.get("db"), productId, await parseJsonBody(c, insertProductLocationSchema));
266
284
  if (!row) {
267
285
  return c.json({ error: "Product not found" }, 404);
268
286
  }
287
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "location" });
269
288
  return c.json({ data: row }, 201);
270
289
  })
271
290
  .patch("/locations/:id", async (c) => {
@@ -273,6 +292,9 @@ export const productRoutes = new Hono()
273
292
  if (!row) {
274
293
  return c.json({ error: "Product location not found" }, 404);
275
294
  }
295
+ if (row.productId) {
296
+ await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "location" });
297
+ }
276
298
  return c.json({ data: row });
277
299
  })
278
300
  .delete("/locations/:id", async (c) => {
@@ -280,6 +302,9 @@ export const productRoutes = new Hono()
280
302
  if (!row) {
281
303
  return c.json({ error: "Product location not found" }, 404);
282
304
  }
305
+ if ("productId" in row && typeof row.productId === "string") {
306
+ await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "location" });
307
+ }
283
308
  return c.json({ success: true }, 200);
284
309
  })
285
310
  .get("/destinations", async (c) => {
@@ -341,17 +366,21 @@ export const productRoutes = new Hono()
341
366
  return c.json(await productsService.listProductDestinations(c.get("db"), query));
342
367
  })
343
368
  .post("/:id/destinations", async (c) => {
344
- const row = await productsService.assignProductDestination(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertProductDestinationSchema));
369
+ const productId = c.req.param("id");
370
+ const row = await productsService.assignProductDestination(c.get("db"), productId, await parseJsonBody(c, insertProductDestinationSchema));
345
371
  if (!row) {
346
372
  return c.json({ error: "Product or destination not found" }, 404);
347
373
  }
374
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "destination" });
348
375
  return c.json({ data: row }, 201);
349
376
  })
350
377
  .delete("/:id/destinations/:destinationId", async (c) => {
351
- const row = await productsService.removeProductDestination(c.get("db"), c.req.param("id"), c.req.param("destinationId"));
378
+ const productId = c.req.param("id");
379
+ const row = await productsService.removeProductDestination(c.get("db"), productId, c.req.param("destinationId"));
352
380
  if (!row) {
353
381
  return c.json({ error: "Product destination link not found" }, 404);
354
382
  }
383
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "destination" });
355
384
  return c.json({ success: true }, 200);
356
385
  })
357
386
  // ==========================================================================
@@ -372,10 +401,12 @@ export const productRoutes = new Hono()
372
401
  })
373
402
  // POST /:id/options — Create option for product
374
403
  .post("/:id/options", async (c) => {
375
- const row = await productsService.createOption(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertProductOptionSchema));
404
+ const productId = c.req.param("id");
405
+ const row = await productsService.createOption(c.get("db"), productId, await parseJsonBody(c, insertProductOptionSchema));
376
406
  if (!row) {
377
407
  return c.json({ error: "Product not found" }, 404);
378
408
  }
409
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "option" });
379
410
  return c.json({ data: row }, 201);
380
411
  })
381
412
  // PATCH /options/:optionId — Update option
@@ -384,6 +415,9 @@ export const productRoutes = new Hono()
384
415
  if (!row) {
385
416
  return c.json({ error: "Product option not found" }, 404);
386
417
  }
418
+ if (row.productId) {
419
+ await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "option" });
420
+ }
387
421
  return c.json({ data: row });
388
422
  })
389
423
  // DELETE /options/:optionId — Delete option
@@ -392,6 +426,9 @@ export const productRoutes = new Hono()
392
426
  if (!row) {
393
427
  return c.json({ error: "Product option not found" }, 404);
394
428
  }
429
+ if ("productId" in row && typeof row.productId === "string") {
430
+ await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "option" });
431
+ }
395
432
  return c.json({ success: true }, 200);
396
433
  })
397
434
  // ==========================================================================
@@ -449,10 +486,12 @@ export const productRoutes = new Hono()
449
486
  return c.json({ data: row });
450
487
  })
451
488
  .post("/:id/translations", async (c) => {
452
- const row = await productsService.createProductTranslation(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertProductTranslationSchema));
489
+ const productId = c.req.param("id");
490
+ const row = await productsService.createProductTranslation(c.get("db"), productId, await parseJsonBody(c, insertProductTranslationSchema));
453
491
  if (!row) {
454
492
  return c.json({ error: "Product not found" }, 404);
455
493
  }
494
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "translation" });
456
495
  return c.json({ data: row }, 201);
457
496
  })
458
497
  .patch("/translations/:translationId", async (c) => {
@@ -460,6 +499,12 @@ export const productRoutes = new Hono()
460
499
  if (!row) {
461
500
  return c.json({ error: "Product translation not found" }, 404);
462
501
  }
502
+ if (row.productId) {
503
+ await emitProductContentChanged(c.get("eventBus"), {
504
+ id: row.productId,
505
+ axis: "translation",
506
+ });
507
+ }
463
508
  return c.json({ data: row });
464
509
  })
465
510
  .delete("/translations/:translationId", async (c) => {
@@ -467,6 +512,12 @@ export const productRoutes = new Hono()
467
512
  if (!row) {
468
513
  return c.json({ error: "Product translation not found" }, 404);
469
514
  }
515
+ if ("productId" in row && typeof row.productId === "string") {
516
+ await emitProductContentChanged(c.get("eventBus"), {
517
+ id: row.productId,
518
+ axis: "translation",
519
+ });
520
+ }
470
521
  return c.json({ success: true }, 200);
471
522
  })
472
523
  .get("/option-translations", async (c) => {
@@ -729,6 +780,8 @@ export const productRoutes = new Hono()
729
780
  if (!row) {
730
781
  return c.json({ error: "Product not found" }, 404);
731
782
  }
783
+ await c.get("eventBus")?.emit("product.updated", { id: row.id });
784
+ await emitProductContentChanged(c.get("eventBus"), { id: row.id, axis: "product" });
732
785
  return c.json({ data: row });
733
786
  })
734
787
  // DELETE /:id — Delete product
@@ -737,6 +790,7 @@ export const productRoutes = new Hono()
737
790
  if (!row) {
738
791
  return c.json({ error: "Product not found" }, 404);
739
792
  }
793
+ await c.get("eventBus")?.emit("product.deleted", { id: row.id });
740
794
  return c.json({ success: true }, 200);
741
795
  })
742
796
  // ==========================================================================
@@ -795,26 +849,32 @@ export const productRoutes = new Hono()
795
849
  })
796
850
  // POST /:id/days — Add day to product
797
851
  .post("/:id/days", async (c) => {
798
- const row = await productsService.createDay(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertDaySchema));
852
+ const productId = c.req.param("id");
853
+ const row = await productsService.createDay(c.get("db"), productId, await parseJsonBody(c, insertDaySchema));
799
854
  if (!row) {
800
855
  return c.json({ error: "Product not found" }, 404);
801
856
  }
857
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
802
858
  return c.json({ data: row }, 201);
803
859
  })
804
860
  // PATCH /:id/days/:dayId — Update day
805
861
  .patch("/:id/days/:dayId", async (c) => {
862
+ const productId = c.req.param("id");
806
863
  const row = await productsService.updateDay(c.get("db"), c.req.param("dayId"), await parseJsonBody(c, updateDaySchema));
807
864
  if (!row) {
808
865
  return c.json({ error: "Day not found" }, 404);
809
866
  }
867
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
810
868
  return c.json({ data: row });
811
869
  })
812
870
  // DELETE /:id/days/:dayId — Delete day
813
871
  .delete("/:id/days/:dayId", async (c) => {
872
+ const productId = c.req.param("id");
814
873
  const row = await productsService.deleteDay(c.get("db"), c.req.param("dayId"));
815
874
  if (!row) {
816
875
  return c.json({ error: "Day not found" }, 404);
817
876
  }
877
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
818
878
  return c.json({ success: true }, 200);
819
879
  })
820
880
  // ==========================================================================
@@ -828,26 +888,32 @@ export const productRoutes = new Hono()
828
888
  })
829
889
  // POST /:id/days/:dayId/services — Add service to day
830
890
  .post("/:id/days/:dayId/services", async (c) => {
831
- const row = await productsService.createDayService(c.get("db"), c.req.param("id"), c.req.param("dayId"), await parseJsonBody(c, insertDayServiceSchema));
891
+ const productId = c.req.param("id");
892
+ const row = await productsService.createDayService(c.get("db"), productId, c.req.param("dayId"), await parseJsonBody(c, insertDayServiceSchema));
832
893
  if (!row) {
833
894
  return c.json({ error: "Day not found" }, 404);
834
895
  }
896
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
835
897
  return c.json({ data: row }, 201);
836
898
  })
837
899
  // PATCH /:id/days/:dayId/services/:serviceId — Update service
838
900
  .patch("/:id/days/:dayId/services/:serviceId", async (c) => {
839
- const row = await productsService.updateDayService(c.get("db"), c.req.param("id"), c.req.param("serviceId"), await parseJsonBody(c, updateDayServiceSchema));
901
+ const productId = c.req.param("id");
902
+ const row = await productsService.updateDayService(c.get("db"), productId, c.req.param("serviceId"), await parseJsonBody(c, updateDayServiceSchema));
840
903
  if (!row) {
841
904
  return c.json({ error: "Service not found" }, 404);
842
905
  }
906
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
843
907
  return c.json({ data: row });
844
908
  })
845
909
  // DELETE /:id/days/:dayId/services/:serviceId — Delete service
846
910
  .delete("/:id/days/:dayId/services/:serviceId", async (c) => {
847
- const row = await productsService.deleteDayService(c.get("db"), c.req.param("id"), c.req.param("serviceId"));
911
+ const productId = c.req.param("id");
912
+ const row = await productsService.deleteDayService(c.get("db"), productId, c.req.param("serviceId"));
848
913
  if (!row) {
849
914
  return c.json({ error: "Service not found" }, 404);
850
915
  }
916
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
851
917
  return c.json({ success: true }, 200);
852
918
  })
853
919
  // ==========================================================================
@@ -950,16 +1016,20 @@ export const productRoutes = new Hono()
950
1016
  })
951
1017
  // POST /:id/media — Create media for product
952
1018
  .post("/:id/media", async (c) => {
953
- const row = await productsService.createMedia(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertProductMediaSchema));
1019
+ const productId = c.req.param("id");
1020
+ const row = await productsService.createMedia(c.get("db"), productId, await parseJsonBody(c, insertProductMediaSchema));
954
1021
  if (!row) {
955
1022
  return c.json({ error: "Product not found or invalid dayId" }, 404);
956
1023
  }
1024
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "media" });
957
1025
  return c.json({ data: row }, 201);
958
1026
  })
959
1027
  // POST /:id/media/reorder — Batch reorder media
960
1028
  .post("/:id/media/reorder", async (c) => {
1029
+ const productId = c.req.param("id");
961
1030
  const data = await parseJsonBody(c, reorderProductMediaSchema);
962
1031
  const results = await productsService.reorderMedia(c.get("db"), data);
1032
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "media" });
963
1033
  return c.json({ data: results });
964
1034
  })
965
1035
  // GET /:id/days/:dayId/media — List day media
@@ -972,14 +1042,16 @@ export const productRoutes = new Hono()
972
1042
  })
973
1043
  // POST /:id/days/:dayId/media — Create day media
974
1044
  .post("/:id/days/:dayId/media", async (c) => {
1045
+ const productId = c.req.param("id");
975
1046
  const body = await parseJsonBody(c, insertProductMediaSchema);
976
- const row = await productsService.createMedia(c.get("db"), c.req.param("id"), {
1047
+ const row = await productsService.createMedia(c.get("db"), productId, {
977
1048
  ...body,
978
1049
  dayId: c.req.param("dayId"),
979
1050
  });
980
1051
  if (!row) {
981
1052
  return c.json({ error: "Product or day not found" }, 404);
982
1053
  }
1054
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "media" });
983
1055
  return c.json({ data: row }, 201);
984
1056
  })
985
1057
  // ==========================================================================
@@ -257,6 +257,23 @@ export declare const products: import("drizzle-orm/pg-core").PgTableWithColumns<
257
257
  identity: undefined;
258
258
  generated: undefined;
259
259
  }, {}, {}>;
260
+ supplierId: import("drizzle-orm/pg-core").PgColumn<{
261
+ name: "supplier_id";
262
+ tableName: "products";
263
+ dataType: "string";
264
+ columnType: "PgText";
265
+ data: string;
266
+ driverParam: string;
267
+ notNull: false;
268
+ hasDefault: false;
269
+ isPrimaryKey: false;
270
+ isAutoincrement: false;
271
+ hasRuntimeDefault: false;
272
+ enumValues: [string, ...string[]];
273
+ baseColumn: never;
274
+ identity: undefined;
275
+ generated: undefined;
276
+ }, {}, {}>;
260
277
  startDate: import("drizzle-orm/pg-core").PgColumn<{
261
278
  name: "start_date";
262
279
  tableName: "products";
@@ -325,6 +342,40 @@ export declare const products: import("drizzle-orm/pg-core").PgTableWithColumns<
325
342
  identity: undefined;
326
343
  generated: undefined;
327
344
  }, {}, {}>;
345
+ taxClassId: import("drizzle-orm/pg-core").PgColumn<{
346
+ name: "tax_class_id";
347
+ tableName: "products";
348
+ dataType: "string";
349
+ columnType: "PgText";
350
+ data: string;
351
+ driverParam: string;
352
+ notNull: false;
353
+ hasDefault: false;
354
+ isPrimaryKey: false;
355
+ isAutoincrement: false;
356
+ hasRuntimeDefault: false;
357
+ enumValues: [string, ...string[]];
358
+ baseColumn: never;
359
+ identity: undefined;
360
+ generated: undefined;
361
+ }, {}, {}>;
362
+ customerPaymentPolicy: import("drizzle-orm/pg-core").PgColumn<{
363
+ name: "customer_payment_policy";
364
+ tableName: "products";
365
+ dataType: "json";
366
+ columnType: "PgJsonb";
367
+ data: unknown;
368
+ driverParam: unknown;
369
+ notNull: false;
370
+ hasDefault: false;
371
+ isPrimaryKey: false;
372
+ isAutoincrement: false;
373
+ hasRuntimeDefault: false;
374
+ enumValues: undefined;
375
+ baseColumn: never;
376
+ identity: undefined;
377
+ generated: undefined;
378
+ }, {}, {}>;
328
379
  tags: import("drizzle-orm/pg-core").PgColumn<{
329
380
  name: "tags";
330
381
  tableName: "products";
@@ -690,7 +741,7 @@ export declare const optionUnits: import("drizzle-orm/pg-core").PgTableWithColum
690
741
  tableName: "option_units";
691
742
  dataType: "string";
692
743
  columnType: "PgEnumColumn";
693
- data: "service" | "other" | "person" | "group" | "room" | "vehicle";
744
+ data: "service" | "other" | "group" | "person" | "room" | "vehicle";
694
745
  driverParam: string;
695
746
  notNull: true;
696
747
  hasDefault: true;
@@ -894,4 +945,192 @@ export declare const optionUnits: import("drizzle-orm/pg-core").PgTableWithColum
894
945
  }>;
895
946
  export type OptionUnit = typeof optionUnits.$inferSelect;
896
947
  export type NewOptionUnit = typeof optionUnits.$inferInsert;
948
+ /**
949
+ * Per-product per-occupancy rate tiers for non-cruise verticals.
950
+ * Cruises keep the specialized `cruise_prices` table; everyone else
951
+ * uses this. Per booking-journey-architecture §9.
952
+ *
953
+ * `tier_pax` is the occupancy count the rate applies to (1-supp, 2-default,
954
+ * 3-share, 4). Falls back to `option_unit_tiers` (quantity-based, not
955
+ * occupancy-based) when no occupancy tier exists.
956
+ */
957
+ export declare const productPaxPricingTiers: import("drizzle-orm/pg-core").PgTableWithColumns<{
958
+ name: "product_pax_pricing_tiers";
959
+ schema: undefined;
960
+ columns: {
961
+ id: import("drizzle-orm/pg-core").PgColumn<{
962
+ name: string;
963
+ tableName: "product_pax_pricing_tiers";
964
+ dataType: "string";
965
+ columnType: "PgText";
966
+ data: string;
967
+ driverParam: string;
968
+ notNull: true;
969
+ hasDefault: true;
970
+ isPrimaryKey: true;
971
+ isAutoincrement: false;
972
+ hasRuntimeDefault: true;
973
+ enumValues: [string, ...string[]];
974
+ baseColumn: never;
975
+ identity: undefined;
976
+ generated: undefined;
977
+ }, {}, {}>;
978
+ productId: import("drizzle-orm/pg-core").PgColumn<{
979
+ name: string;
980
+ tableName: "product_pax_pricing_tiers";
981
+ dataType: "string";
982
+ columnType: "PgText";
983
+ data: string;
984
+ driverParam: string;
985
+ notNull: true;
986
+ hasDefault: false;
987
+ isPrimaryKey: false;
988
+ isAutoincrement: false;
989
+ hasRuntimeDefault: false;
990
+ enumValues: [string, ...string[]];
991
+ baseColumn: never;
992
+ identity: undefined;
993
+ generated: undefined;
994
+ }, {}, {}>;
995
+ optionUnitId: import("drizzle-orm/pg-core").PgColumn<{
996
+ name: string;
997
+ tableName: "product_pax_pricing_tiers";
998
+ dataType: "string";
999
+ columnType: "PgText";
1000
+ data: string;
1001
+ driverParam: string;
1002
+ notNull: false;
1003
+ hasDefault: false;
1004
+ isPrimaryKey: false;
1005
+ isAutoincrement: false;
1006
+ hasRuntimeDefault: false;
1007
+ enumValues: [string, ...string[]];
1008
+ baseColumn: never;
1009
+ identity: undefined;
1010
+ generated: undefined;
1011
+ }, {}, {}>;
1012
+ tierPax: import("drizzle-orm/pg-core").PgColumn<{
1013
+ name: "tier_pax";
1014
+ tableName: "product_pax_pricing_tiers";
1015
+ dataType: "number";
1016
+ columnType: "PgInteger";
1017
+ data: number;
1018
+ driverParam: string | number;
1019
+ notNull: true;
1020
+ hasDefault: false;
1021
+ isPrimaryKey: false;
1022
+ isAutoincrement: false;
1023
+ hasRuntimeDefault: false;
1024
+ enumValues: undefined;
1025
+ baseColumn: never;
1026
+ identity: undefined;
1027
+ generated: undefined;
1028
+ }, {}, {}>;
1029
+ pricePerPaxCents: import("drizzle-orm/pg-core").PgColumn<{
1030
+ name: "price_per_pax_cents";
1031
+ tableName: "product_pax_pricing_tiers";
1032
+ dataType: "number";
1033
+ columnType: "PgInteger";
1034
+ data: number;
1035
+ driverParam: string | number;
1036
+ notNull: true;
1037
+ hasDefault: false;
1038
+ isPrimaryKey: false;
1039
+ isAutoincrement: false;
1040
+ hasRuntimeDefault: false;
1041
+ enumValues: undefined;
1042
+ baseColumn: never;
1043
+ identity: undefined;
1044
+ generated: undefined;
1045
+ }, {}, {}>;
1046
+ promoPricePerPaxCents: import("drizzle-orm/pg-core").PgColumn<{
1047
+ name: "promo_price_per_pax_cents";
1048
+ tableName: "product_pax_pricing_tiers";
1049
+ dataType: "number";
1050
+ columnType: "PgInteger";
1051
+ data: number;
1052
+ driverParam: string | number;
1053
+ notNull: false;
1054
+ hasDefault: false;
1055
+ isPrimaryKey: false;
1056
+ isAutoincrement: false;
1057
+ hasRuntimeDefault: false;
1058
+ enumValues: undefined;
1059
+ baseColumn: never;
1060
+ identity: undefined;
1061
+ generated: undefined;
1062
+ }, {}, {}>;
1063
+ effectiveFrom: import("drizzle-orm/pg-core").PgColumn<{
1064
+ name: "effective_from";
1065
+ tableName: "product_pax_pricing_tiers";
1066
+ dataType: "string";
1067
+ columnType: "PgDateString";
1068
+ data: string;
1069
+ driverParam: string;
1070
+ notNull: false;
1071
+ hasDefault: false;
1072
+ isPrimaryKey: false;
1073
+ isAutoincrement: false;
1074
+ hasRuntimeDefault: false;
1075
+ enumValues: undefined;
1076
+ baseColumn: never;
1077
+ identity: undefined;
1078
+ generated: undefined;
1079
+ }, {}, {}>;
1080
+ effectiveTo: import("drizzle-orm/pg-core").PgColumn<{
1081
+ name: "effective_to";
1082
+ tableName: "product_pax_pricing_tiers";
1083
+ dataType: "string";
1084
+ columnType: "PgDateString";
1085
+ data: string;
1086
+ driverParam: string;
1087
+ notNull: false;
1088
+ hasDefault: false;
1089
+ isPrimaryKey: false;
1090
+ isAutoincrement: false;
1091
+ hasRuntimeDefault: false;
1092
+ enumValues: undefined;
1093
+ baseColumn: never;
1094
+ identity: undefined;
1095
+ generated: undefined;
1096
+ }, {}, {}>;
1097
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
1098
+ name: "created_at";
1099
+ tableName: "product_pax_pricing_tiers";
1100
+ dataType: "date";
1101
+ columnType: "PgTimestamp";
1102
+ data: Date;
1103
+ driverParam: string;
1104
+ notNull: true;
1105
+ hasDefault: true;
1106
+ isPrimaryKey: false;
1107
+ isAutoincrement: false;
1108
+ hasRuntimeDefault: false;
1109
+ enumValues: undefined;
1110
+ baseColumn: never;
1111
+ identity: undefined;
1112
+ generated: undefined;
1113
+ }, {}, {}>;
1114
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
1115
+ name: "updated_at";
1116
+ tableName: "product_pax_pricing_tiers";
1117
+ dataType: "date";
1118
+ columnType: "PgTimestamp";
1119
+ data: Date;
1120
+ driverParam: string;
1121
+ notNull: true;
1122
+ hasDefault: true;
1123
+ isPrimaryKey: false;
1124
+ isAutoincrement: false;
1125
+ hasRuntimeDefault: false;
1126
+ enumValues: undefined;
1127
+ baseColumn: never;
1128
+ identity: undefined;
1129
+ generated: undefined;
1130
+ }, {}, {}>;
1131
+ };
1132
+ dialect: "pg";
1133
+ }>;
1134
+ export type ProductPaxPricingTier = typeof productPaxPricingTiers.$inferSelect;
1135
+ export type NewProductPaxPricingTier = typeof productPaxPricingTiers.$inferInsert;
897
1136
  //# sourceMappingURL=schema-core.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-core.d.ts","sourceRoot":"","sources":["../src/schema-core.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4CpB,CAAA;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAClD,MAAM,MAAM,UAAU,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAErD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyB1B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,cAAc,CAAC,YAAY,CAAA;AAC9D,MAAM,MAAM,gBAAgB,GAAG,OAAO,cAAc,CAAC,YAAY,CAAA;AAEjE,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BvB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AACxD,MAAM,MAAM,aAAa,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA"}
1
+ {"version":3,"file":"schema-core.d.ts","sourceRoot":"","sources":["../src/schema-core.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgEpB,CAAA;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAClD,MAAM,MAAM,UAAU,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAErD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyB1B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,cAAc,CAAC,YAAY,CAAA;AAC9D,MAAM,MAAM,gBAAgB,GAAG,OAAO,cAAc,CAAC,YAAY,CAAA;AAEjE,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BvB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AACxD,MAAM,MAAM,aAAa,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AAE3D;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuBlC,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,OAAO,sBAAsB,CAAC,YAAY,CAAA;AAC9E,MAAM,MAAM,wBAAwB,GAAG,OAAO,sBAAsB,CAAC,YAAY,CAAA"}