@voyantjs/products 0.52.2 → 0.52.4

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 (62) hide show
  1. package/dist/action-ledger-drift.d.ts +29 -0
  2. package/dist/action-ledger-drift.d.ts.map +1 -0
  3. package/dist/action-ledger-drift.js +335 -0
  4. package/dist/action-ledger.d.ts +104 -0
  5. package/dist/action-ledger.d.ts.map +1 -0
  6. package/dist/action-ledger.js +100 -0
  7. package/dist/booking-extension.d.ts +3 -3
  8. package/dist/events.d.ts +1 -1
  9. package/dist/events.d.ts.map +1 -1
  10. package/dist/route-env.d.ts +22 -0
  11. package/dist/route-env.d.ts.map +1 -0
  12. package/dist/route-env.js +1 -0
  13. package/dist/routes-associations.d.ts +164 -0
  14. package/dist/routes-associations.d.ts.map +1 -0
  15. package/dist/routes-associations.js +100 -0
  16. package/dist/routes-catalog.d.ts +436 -0
  17. package/dist/routes-catalog.d.ts.map +1 -0
  18. package/dist/routes-catalog.js +104 -0
  19. package/dist/routes-configuration.d.ts +773 -0
  20. package/dist/routes-configuration.d.ts.map +1 -0
  21. package/dist/routes-configuration.js +364 -0
  22. package/dist/routes-core.d.ts +302 -0
  23. package/dist/routes-core.d.ts.map +1 -0
  24. package/dist/routes-core.js +79 -0
  25. package/dist/routes-itinerary.d.ts +614 -0
  26. package/dist/routes-itinerary.d.ts.map +1 -0
  27. package/dist/routes-itinerary.js +309 -0
  28. package/dist/routes-maintenance.d.ts +32 -0
  29. package/dist/routes-maintenance.d.ts.map +1 -0
  30. package/dist/routes-maintenance.js +14 -0
  31. package/dist/routes-media.d.ts +634 -0
  32. package/dist/routes-media.d.ts.map +1 -0
  33. package/dist/routes-media.js +245 -0
  34. package/dist/routes-merchandising.d.ts +1108 -0
  35. package/dist/routes-merchandising.d.ts.map +1 -0
  36. package/dist/routes-merchandising.js +376 -0
  37. package/dist/routes-options.d.ts +363 -0
  38. package/dist/routes-options.d.ts.map +1 -0
  39. package/dist/routes-options.js +173 -0
  40. package/dist/routes-public.d.ts +4 -4
  41. package/dist/routes-translations.d.ts +477 -0
  42. package/dist/routes-translations.d.ts.map +1 -0
  43. package/dist/routes-translations.js +258 -0
  44. package/dist/routes.d.ts +417 -355
  45. package/dist/routes.d.ts.map +1 -1
  46. package/dist/routes.js +21 -1133
  47. package/dist/schema-core.d.ts +3 -3
  48. package/dist/schema-itinerary.d.ts +1 -1
  49. package/dist/schema-settings.d.ts +4 -4
  50. package/dist/service-catalog.d.ts +2 -2
  51. package/dist/service-public.d.ts +4 -4
  52. package/dist/service.d.ts +225 -97
  53. package/dist/service.d.ts.map +1 -1
  54. package/dist/service.js +91 -0
  55. package/dist/tasks/brochures.d.ts +1 -1
  56. package/dist/validation-catalog.d.ts +10 -10
  57. package/dist/validation-config.d.ts +17 -17
  58. package/dist/validation-content.d.ts +26 -26
  59. package/dist/validation-core.d.ts +21 -21
  60. package/dist/validation-public.d.ts +25 -25
  61. package/dist/validation-shared.d.ts +11 -11
  62. package/package.json +13 -7
@@ -0,0 +1,79 @@
1
+ import { parseJsonBody, parseQuery } from "@voyantjs/hono";
2
+ import { Hono } from "hono";
3
+ import { appendProductMutationLedgerEntry, changedProductFields, listProductActionLedger, } from "./action-ledger.js";
4
+ import { emitProductContentChanged } from "./events.js";
5
+ import { productsService } from "./service.js";
6
+ import * as validation from "./validation.js";
7
+ export const productCoreRoutes = new Hono()
8
+ // GET /aggregates — dashboard KPIs (before /:id so the matcher doesn't swallow it)
9
+ .get("/aggregates", async (c) => {
10
+ const query = parseQuery(c, validation.productAggregatesQuerySchema);
11
+ return c.json({ data: await productsService.getProductAggregates(c.get("db"), query) });
12
+ })
13
+ // GET / — List products
14
+ .get("/", async (c) => {
15
+ const query = parseQuery(c, validation.productListQuerySchema);
16
+ return c.json(await productsService.listProducts(c.get("db"), query));
17
+ })
18
+ // POST / — Create product
19
+ .post("/", async (c) => {
20
+ const input = await parseJsonBody(c, validation.insertProductSchema);
21
+ const row = await productsService.createProduct(c.get("db"), input);
22
+ await appendProductMutationLedgerEntry(c, {
23
+ action: "create",
24
+ productId: row.id,
25
+ changedFields: changedProductFields(input, null, row),
26
+ });
27
+ await c.get("eventBus")?.emit("product.created", { id: row.id });
28
+ return c.json({ data: row }, 201);
29
+ })
30
+ // GET /:id — Get single product
31
+ .get("/:id", async (c) => {
32
+ const row = await productsService.getProductById(c.get("db"), c.req.param("id"));
33
+ if (!row) {
34
+ return c.json({ error: "Product not found" }, 404);
35
+ }
36
+ return c.json({ data: row });
37
+ })
38
+ // GET /:id/action-ledger — Product-scoped action timeline
39
+ .get("/:id/action-ledger", listProductActionLedger)
40
+ // PATCH /:id — Update product
41
+ .patch("/:id", async (c) => {
42
+ const productId = c.req.param("id");
43
+ const before = await productsService.getProductById(c.get("db"), productId);
44
+ if (!before) {
45
+ return c.json({ error: "Product not found" }, 404);
46
+ }
47
+ const input = await parseJsonBody(c, validation.updateProductSchema);
48
+ const row = await productsService.updateProduct(c.get("db"), productId, input);
49
+ if (!row) {
50
+ return c.json({ error: "Product not found" }, 404);
51
+ }
52
+ await appendProductMutationLedgerEntry(c, {
53
+ action: "update",
54
+ productId: row.id,
55
+ changedFields: changedProductFields(input, before, row),
56
+ });
57
+ await c.get("eventBus")?.emit("product.updated", { id: row.id });
58
+ await emitProductContentChanged(c.get("eventBus"), { id: row.id, axis: "product" });
59
+ return c.json({ data: row });
60
+ })
61
+ // DELETE /:id — Delete product
62
+ .delete("/:id", async (c) => {
63
+ const productId = c.req.param("id");
64
+ const before = await productsService.getProductById(c.get("db"), productId);
65
+ if (!before) {
66
+ return c.json({ error: "Product not found" }, 404);
67
+ }
68
+ const row = await productsService.deleteProduct(c.get("db"), productId);
69
+ if (!row) {
70
+ return c.json({ error: "Product not found" }, 404);
71
+ }
72
+ await appendProductMutationLedgerEntry(c, {
73
+ action: "delete",
74
+ productId: row.id,
75
+ changedFields: [],
76
+ });
77
+ await c.get("eventBus")?.emit("product.deleted", { id: row.id });
78
+ return c.json({ success: true }, 200);
79
+ });
@@ -0,0 +1,614 @@
1
+ import type { Env } from "./route-env.js";
2
+ export declare const productItineraryRoutes: import("hono/hono-base").HonoBase<Env, {
3
+ "/:id/itineraries": {
4
+ $get: {
5
+ input: {
6
+ param: {
7
+ id: string;
8
+ };
9
+ };
10
+ output: {
11
+ data: {
12
+ id: string;
13
+ productId: string;
14
+ name: string;
15
+ isDefault: boolean;
16
+ sortOrder: number;
17
+ createdAt: string;
18
+ updatedAt: string;
19
+ }[];
20
+ };
21
+ outputFormat: "json";
22
+ status: import("hono/utils/http-status").ContentfulStatusCode;
23
+ };
24
+ };
25
+ } & {
26
+ "/:id/itineraries": {
27
+ $post: {
28
+ input: {
29
+ param: {
30
+ id: string;
31
+ };
32
+ };
33
+ output: {
34
+ error: string;
35
+ };
36
+ outputFormat: "json";
37
+ status: 404;
38
+ } | {
39
+ input: {
40
+ param: {
41
+ id: string;
42
+ };
43
+ };
44
+ output: {
45
+ data: {
46
+ name: string;
47
+ id: string;
48
+ createdAt: string;
49
+ updatedAt: string;
50
+ productId: string;
51
+ isDefault: boolean;
52
+ sortOrder: number;
53
+ };
54
+ };
55
+ outputFormat: "json";
56
+ status: 201;
57
+ };
58
+ };
59
+ } & {
60
+ "/itineraries/:itineraryId": {
61
+ $patch: {
62
+ input: {
63
+ param: {
64
+ itineraryId: string;
65
+ };
66
+ };
67
+ output: {
68
+ error: string;
69
+ };
70
+ outputFormat: "json";
71
+ status: 404;
72
+ } | {
73
+ input: {
74
+ param: {
75
+ itineraryId: string;
76
+ };
77
+ };
78
+ output: {
79
+ data: {
80
+ id: string;
81
+ productId: string;
82
+ name: string;
83
+ isDefault: boolean;
84
+ sortOrder: number;
85
+ createdAt: string;
86
+ updatedAt: string;
87
+ };
88
+ };
89
+ outputFormat: "json";
90
+ status: import("hono/utils/http-status").ContentfulStatusCode;
91
+ };
92
+ };
93
+ } & {
94
+ "/itineraries/:itineraryId": {
95
+ $delete: {
96
+ input: {
97
+ param: {
98
+ itineraryId: string;
99
+ };
100
+ };
101
+ output: {
102
+ error: string;
103
+ };
104
+ outputFormat: "json";
105
+ status: 404;
106
+ } | {
107
+ input: {
108
+ param: {
109
+ itineraryId: string;
110
+ };
111
+ };
112
+ output: {
113
+ success: true;
114
+ };
115
+ outputFormat: "json";
116
+ status: 200;
117
+ };
118
+ };
119
+ } & {
120
+ "/itineraries/:itineraryId/duplicate": {
121
+ $post: {
122
+ input: {
123
+ param: {
124
+ itineraryId: string;
125
+ };
126
+ };
127
+ output: {
128
+ error: string;
129
+ };
130
+ outputFormat: "json";
131
+ status: 404;
132
+ } | {
133
+ input: {
134
+ param: {
135
+ itineraryId: string;
136
+ };
137
+ };
138
+ output: {
139
+ data: {
140
+ name: string;
141
+ id: string;
142
+ createdAt: string;
143
+ updatedAt: string;
144
+ productId: string;
145
+ isDefault: boolean;
146
+ sortOrder: number;
147
+ };
148
+ };
149
+ outputFormat: "json";
150
+ status: 201;
151
+ };
152
+ };
153
+ } & {
154
+ "/:id/itineraries/:itineraryId/days": {
155
+ $get: {
156
+ input: {
157
+ param: {
158
+ id: string;
159
+ } & {
160
+ itineraryId: string;
161
+ };
162
+ };
163
+ output: {
164
+ data: {
165
+ id: string;
166
+ itineraryId: string;
167
+ dayNumber: number;
168
+ title: string | null;
169
+ description: string | null;
170
+ location: string | null;
171
+ createdAt: string;
172
+ updatedAt: string;
173
+ }[];
174
+ };
175
+ outputFormat: "json";
176
+ status: import("hono/utils/http-status").ContentfulStatusCode;
177
+ };
178
+ };
179
+ } & {
180
+ "/:id/itineraries/:itineraryId/days": {
181
+ $post: {
182
+ input: {
183
+ param: {
184
+ id: string;
185
+ } & {
186
+ itineraryId: string;
187
+ };
188
+ };
189
+ output: {
190
+ error: string;
191
+ };
192
+ outputFormat: "json";
193
+ status: 404;
194
+ } | {
195
+ input: {
196
+ param: {
197
+ id: string;
198
+ } & {
199
+ itineraryId: string;
200
+ };
201
+ };
202
+ output: {
203
+ data: {
204
+ id: string;
205
+ description: string | null;
206
+ createdAt: string;
207
+ updatedAt: string;
208
+ itineraryId: string;
209
+ dayNumber: number;
210
+ title: string | null;
211
+ location: string | null;
212
+ };
213
+ };
214
+ outputFormat: "json";
215
+ status: 201;
216
+ };
217
+ };
218
+ } & {
219
+ "/:id/days": {
220
+ $get: {
221
+ input: {
222
+ param: {
223
+ id: string;
224
+ };
225
+ };
226
+ output: {
227
+ data: {
228
+ id: string;
229
+ itineraryId: string;
230
+ dayNumber: number;
231
+ title: string | null;
232
+ description: string | null;
233
+ location: string | null;
234
+ createdAt: string;
235
+ updatedAt: string;
236
+ }[];
237
+ };
238
+ outputFormat: "json";
239
+ status: import("hono/utils/http-status").ContentfulStatusCode;
240
+ };
241
+ };
242
+ } & {
243
+ "/:id/days": {
244
+ $post: {
245
+ input: {
246
+ param: {
247
+ id: string;
248
+ };
249
+ };
250
+ output: {
251
+ error: string;
252
+ };
253
+ outputFormat: "json";
254
+ status: 404;
255
+ } | {
256
+ input: {
257
+ param: {
258
+ id: string;
259
+ };
260
+ };
261
+ output: {
262
+ data: {
263
+ id: string;
264
+ description: string | null;
265
+ createdAt: string;
266
+ updatedAt: string;
267
+ itineraryId: string;
268
+ dayNumber: number;
269
+ title: string | null;
270
+ location: string | null;
271
+ };
272
+ };
273
+ outputFormat: "json";
274
+ status: 201;
275
+ };
276
+ };
277
+ } & {
278
+ "/:id/days/:dayId": {
279
+ $patch: {
280
+ input: {
281
+ param: {
282
+ id: string;
283
+ } & {
284
+ dayId: string;
285
+ };
286
+ };
287
+ output: {
288
+ error: string;
289
+ };
290
+ outputFormat: "json";
291
+ status: 404;
292
+ } | {
293
+ input: {
294
+ param: {
295
+ id: string;
296
+ } & {
297
+ dayId: string;
298
+ };
299
+ };
300
+ output: {
301
+ data: {
302
+ id: string;
303
+ itineraryId: string;
304
+ dayNumber: number;
305
+ title: string | null;
306
+ description: string | null;
307
+ location: string | null;
308
+ createdAt: string;
309
+ updatedAt: string;
310
+ };
311
+ };
312
+ outputFormat: "json";
313
+ status: import("hono/utils/http-status").ContentfulStatusCode;
314
+ };
315
+ };
316
+ } & {
317
+ "/:id/days/:dayId": {
318
+ $delete: {
319
+ input: {
320
+ param: {
321
+ id: string;
322
+ } & {
323
+ dayId: string;
324
+ };
325
+ };
326
+ output: {
327
+ error: string;
328
+ };
329
+ outputFormat: "json";
330
+ status: 404;
331
+ } | {
332
+ input: {
333
+ param: {
334
+ id: string;
335
+ } & {
336
+ dayId: string;
337
+ };
338
+ };
339
+ output: {
340
+ success: true;
341
+ };
342
+ outputFormat: "json";
343
+ status: 200;
344
+ };
345
+ };
346
+ } & {
347
+ "/:id/days/:dayId/services": {
348
+ $get: {
349
+ input: {
350
+ param: {
351
+ id: string;
352
+ } & {
353
+ dayId: string;
354
+ };
355
+ };
356
+ output: {
357
+ data: {
358
+ id: string;
359
+ dayId: string;
360
+ supplierServiceId: string | null;
361
+ serviceType: "other" | "transfer" | "accommodation" | "experience" | "guide" | "meal";
362
+ name: string;
363
+ description: string | null;
364
+ countryCode: string | null;
365
+ costCurrency: string;
366
+ costAmountCents: number;
367
+ quantity: number;
368
+ sortOrder: number | null;
369
+ notes: string | null;
370
+ createdAt: string;
371
+ }[];
372
+ };
373
+ outputFormat: "json";
374
+ status: import("hono/utils/http-status").ContentfulStatusCode;
375
+ };
376
+ };
377
+ } & {
378
+ "/:id/days/:dayId/services": {
379
+ $post: {
380
+ input: {
381
+ param: {
382
+ id: string;
383
+ } & {
384
+ dayId: string;
385
+ };
386
+ };
387
+ output: {
388
+ error: string;
389
+ };
390
+ outputFormat: "json";
391
+ status: 404;
392
+ } | {
393
+ input: {
394
+ param: {
395
+ id: string;
396
+ } & {
397
+ dayId: string;
398
+ };
399
+ };
400
+ output: {
401
+ data: {
402
+ name: string;
403
+ id: string;
404
+ description: string | null;
405
+ createdAt: string;
406
+ costAmountCents: number;
407
+ sortOrder: number | null;
408
+ dayId: string;
409
+ supplierServiceId: string | null;
410
+ serviceType: "other" | "transfer" | "accommodation" | "experience" | "guide" | "meal";
411
+ countryCode: string | null;
412
+ costCurrency: string;
413
+ quantity: number;
414
+ notes: string | null;
415
+ };
416
+ };
417
+ outputFormat: "json";
418
+ status: 201;
419
+ };
420
+ };
421
+ } & {
422
+ "/:id/days/:dayId/services/:serviceId": {
423
+ $patch: {
424
+ input: {
425
+ param: {
426
+ id: string;
427
+ } & {
428
+ dayId: string;
429
+ } & {
430
+ serviceId: string;
431
+ };
432
+ };
433
+ output: {
434
+ error: string;
435
+ };
436
+ outputFormat: "json";
437
+ status: 404;
438
+ } | {
439
+ input: {
440
+ param: {
441
+ id: string;
442
+ } & {
443
+ dayId: string;
444
+ } & {
445
+ serviceId: string;
446
+ };
447
+ };
448
+ output: {
449
+ data: {
450
+ id: string;
451
+ dayId: string;
452
+ supplierServiceId: string | null;
453
+ serviceType: "other" | "transfer" | "accommodation" | "experience" | "guide" | "meal";
454
+ name: string;
455
+ description: string | null;
456
+ countryCode: string | null;
457
+ costCurrency: string;
458
+ costAmountCents: number;
459
+ quantity: number;
460
+ sortOrder: number | null;
461
+ notes: string | null;
462
+ createdAt: string;
463
+ };
464
+ };
465
+ outputFormat: "json";
466
+ status: import("hono/utils/http-status").ContentfulStatusCode;
467
+ };
468
+ };
469
+ } & {
470
+ "/:id/days/:dayId/services/:serviceId": {
471
+ $delete: {
472
+ input: {
473
+ param: {
474
+ id: string;
475
+ } & {
476
+ dayId: string;
477
+ } & {
478
+ serviceId: string;
479
+ };
480
+ };
481
+ output: {
482
+ error: string;
483
+ };
484
+ outputFormat: "json";
485
+ status: 404;
486
+ } | {
487
+ input: {
488
+ param: {
489
+ id: string;
490
+ } & {
491
+ dayId: string;
492
+ } & {
493
+ serviceId: string;
494
+ };
495
+ };
496
+ output: {
497
+ success: true;
498
+ };
499
+ outputFormat: "json";
500
+ status: 200;
501
+ };
502
+ };
503
+ } & {
504
+ "/:id/versions": {
505
+ $get: {
506
+ input: {
507
+ param: {
508
+ id: string;
509
+ };
510
+ };
511
+ output: {
512
+ data: {
513
+ id: string;
514
+ productId: string;
515
+ versionNumber: number;
516
+ snapshot: import("hono/utils/types").JSONValue;
517
+ authorId: string;
518
+ notes: string | null;
519
+ createdAt: string;
520
+ }[];
521
+ };
522
+ outputFormat: "json";
523
+ status: import("hono/utils/http-status").ContentfulStatusCode;
524
+ };
525
+ };
526
+ } & {
527
+ "/:id/versions": {
528
+ $post: {
529
+ input: {
530
+ param: {
531
+ id: string;
532
+ };
533
+ };
534
+ output: {
535
+ error: string;
536
+ };
537
+ outputFormat: "json";
538
+ status: 404;
539
+ } | {
540
+ input: {
541
+ param: {
542
+ id: string;
543
+ };
544
+ };
545
+ output: {
546
+ data: {
547
+ id: string;
548
+ createdAt: string;
549
+ productId: string;
550
+ notes: string | null;
551
+ versionNumber: number;
552
+ snapshot: import("hono/utils/types").JSONValue;
553
+ authorId: string;
554
+ };
555
+ };
556
+ outputFormat: "json";
557
+ status: 201;
558
+ };
559
+ };
560
+ } & {
561
+ "/:id/notes": {
562
+ $get: {
563
+ input: {
564
+ param: {
565
+ id: string;
566
+ };
567
+ };
568
+ output: {
569
+ data: {
570
+ id: string;
571
+ productId: string;
572
+ authorId: string;
573
+ content: string;
574
+ createdAt: string;
575
+ }[];
576
+ };
577
+ outputFormat: "json";
578
+ status: import("hono/utils/http-status").ContentfulStatusCode;
579
+ };
580
+ };
581
+ } & {
582
+ "/:id/notes": {
583
+ $post: {
584
+ input: {
585
+ param: {
586
+ id: string;
587
+ };
588
+ };
589
+ output: {
590
+ error: string;
591
+ };
592
+ outputFormat: "json";
593
+ status: 404;
594
+ } | {
595
+ input: {
596
+ param: {
597
+ id: string;
598
+ };
599
+ };
600
+ output: {
601
+ data: {
602
+ id: string;
603
+ createdAt: string;
604
+ productId: string;
605
+ authorId: string;
606
+ content: string;
607
+ };
608
+ };
609
+ outputFormat: "json";
610
+ status: 201;
611
+ };
612
+ };
613
+ }, "/", "/:id/notes">;
614
+ //# sourceMappingURL=routes-itinerary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-itinerary.d.ts","sourceRoot":"","sources":["../src/routes-itinerary.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AAIzC,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA2X/B,CAAA"}