@voyantjs/products 0.52.1 → 0.52.3

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 (73) 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/catalog-policy.d.ts.map +1 -1
  9. package/dist/catalog-policy.js +18 -0
  10. package/dist/content-shape.d.ts +2 -0
  11. package/dist/content-shape.d.ts.map +1 -1
  12. package/dist/content-shape.js +2 -0
  13. package/dist/events.d.ts +1 -1
  14. package/dist/events.d.ts.map +1 -1
  15. package/dist/route-env.d.ts +22 -0
  16. package/dist/route-env.d.ts.map +1 -0
  17. package/dist/route-env.js +1 -0
  18. package/dist/routes-associations.d.ts +164 -0
  19. package/dist/routes-associations.d.ts.map +1 -0
  20. package/dist/routes-associations.js +100 -0
  21. package/dist/routes-catalog.d.ts +436 -0
  22. package/dist/routes-catalog.d.ts.map +1 -0
  23. package/dist/routes-catalog.js +104 -0
  24. package/dist/routes-configuration.d.ts +773 -0
  25. package/dist/routes-configuration.d.ts.map +1 -0
  26. package/dist/routes-configuration.js +364 -0
  27. package/dist/routes-core.d.ts +302 -0
  28. package/dist/routes-core.d.ts.map +1 -0
  29. package/dist/routes-core.js +79 -0
  30. package/dist/routes-itinerary.d.ts +614 -0
  31. package/dist/routes-itinerary.d.ts.map +1 -0
  32. package/dist/routes-itinerary.js +309 -0
  33. package/dist/routes-maintenance.d.ts +32 -0
  34. package/dist/routes-maintenance.d.ts.map +1 -0
  35. package/dist/routes-maintenance.js +14 -0
  36. package/dist/routes-media.d.ts +634 -0
  37. package/dist/routes-media.d.ts.map +1 -0
  38. package/dist/routes-media.js +245 -0
  39. package/dist/routes-merchandising.d.ts +1108 -0
  40. package/dist/routes-merchandising.d.ts.map +1 -0
  41. package/dist/routes-merchandising.js +376 -0
  42. package/dist/routes-options.d.ts +363 -0
  43. package/dist/routes-options.d.ts.map +1 -0
  44. package/dist/routes-options.js +173 -0
  45. package/dist/routes-public.d.ts +4 -4
  46. package/dist/routes-translations.d.ts +477 -0
  47. package/dist/routes-translations.d.ts.map +1 -0
  48. package/dist/routes-translations.js +258 -0
  49. package/dist/routes.d.ts +417 -355
  50. package/dist/routes.d.ts.map +1 -1
  51. package/dist/routes.js +21 -1133
  52. package/dist/schema-core.d.ts +3 -3
  53. package/dist/schema-itinerary.d.ts +1 -1
  54. package/dist/schema-settings.d.ts +4 -4
  55. package/dist/service-catalog-plane.d.ts.map +1 -1
  56. package/dist/service-catalog-plane.js +48 -1
  57. package/dist/service-catalog.d.ts +2 -2
  58. package/dist/service-content-owned.d.ts.map +1 -1
  59. package/dist/service-content-owned.js +98 -4
  60. package/dist/service-public.d.ts +4 -4
  61. package/dist/service.d.ts +225 -97
  62. package/dist/service.d.ts.map +1 -1
  63. package/dist/service.js +91 -0
  64. package/dist/tasks/brochures.d.ts +1 -1
  65. package/dist/validation-catalog.d.ts +10 -10
  66. package/dist/validation-config.d.ts +17 -17
  67. package/dist/validation-content.d.ts +26 -26
  68. package/dist/validation-core.d.ts +46 -46
  69. package/dist/validation-core.d.ts.map +1 -1
  70. package/dist/validation-core.js +17 -1
  71. package/dist/validation-public.d.ts +25 -25
  72. package/dist/validation-shared.d.ts +11 -11
  73. package/package.json +13 -7
@@ -0,0 +1,309 @@
1
+ import { parseJsonBody, RequestValidationError, requireUserId } from "@voyantjs/hono";
2
+ import { Hono } from "hono";
3
+ import { appendProductMutationLedgerEntry, changedMutationFields } 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 productItineraryRoutes = new Hono()
8
+ // ==========================================================================
9
+ // Itineraries
10
+ // ==========================================================================
11
+ .get("/:id/itineraries", async (c) => {
12
+ return c.json({ data: await productsService.listItineraries(c.get("db"), c.req.param("id")) });
13
+ })
14
+ .post("/:id/itineraries", async (c) => {
15
+ const productId = c.req.param("id");
16
+ const body = await parseJsonBody(c, validation.insertItinerarySchema);
17
+ const row = await productsService.createItinerary(c.get("db"), productId, body);
18
+ if (!row) {
19
+ return c.json({ error: "Product not found" }, 404);
20
+ }
21
+ await appendProductMutationLedgerEntry(c, {
22
+ action: "create",
23
+ productId,
24
+ changedFields: changedMutationFields(body, null, row),
25
+ subject: "product itinerary",
26
+ actionName: "product.itinerary.create",
27
+ routeOrToolName: "products.itinerary.create",
28
+ });
29
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "itinerary" });
30
+ return c.json({ data: row }, 201);
31
+ })
32
+ .patch("/itineraries/:itineraryId", async (c) => {
33
+ const itineraryId = c.req.param("itineraryId");
34
+ const body = await parseJsonBody(c, validation.updateItinerarySchema);
35
+ const before = await productsService.getItineraryById(c.get("db"), itineraryId);
36
+ if (!before) {
37
+ return c.json({ error: "Itinerary not found" }, 404);
38
+ }
39
+ const row = await productsService.updateItinerary(c.get("db"), itineraryId, body);
40
+ if (!row) {
41
+ return c.json({ error: "Itinerary not found" }, 404);
42
+ }
43
+ await appendProductMutationLedgerEntry(c, {
44
+ action: "update",
45
+ productId: row.productId,
46
+ changedFields: changedMutationFields(body, before, row),
47
+ subject: "product itinerary",
48
+ actionName: "product.itinerary.update",
49
+ routeOrToolName: "products.itinerary.update",
50
+ });
51
+ await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "itinerary" });
52
+ return c.json({ data: row });
53
+ })
54
+ .delete("/itineraries/:itineraryId", async (c) => {
55
+ const itineraryId = c.req.param("itineraryId");
56
+ const before = await productsService.getItineraryById(c.get("db"), itineraryId);
57
+ if (!before) {
58
+ return c.json({ error: "Itinerary not found" }, 404);
59
+ }
60
+ const row = await productsService.deleteItinerary(c.get("db"), itineraryId);
61
+ if (!row) {
62
+ return c.json({ error: "Itinerary not found" }, 404);
63
+ }
64
+ await appendProductMutationLedgerEntry(c, {
65
+ action: "delete",
66
+ productId: before.productId,
67
+ changedFields: [],
68
+ subject: "product itinerary",
69
+ actionName: "product.itinerary.delete",
70
+ routeOrToolName: "products.itinerary.delete",
71
+ });
72
+ await emitProductContentChanged(c.get("eventBus"), { id: before.productId, axis: "itinerary" });
73
+ return c.json({ success: true }, 200);
74
+ })
75
+ .post("/itineraries/:itineraryId/duplicate", async (c) => {
76
+ const itineraryId = c.req.param("itineraryId");
77
+ const body = await parseJsonBody(c, validation.duplicateItinerarySchema);
78
+ const source = await productsService.getItineraryById(c.get("db"), itineraryId);
79
+ if (!source) {
80
+ return c.json({ error: "Itinerary not found" }, 404);
81
+ }
82
+ const row = await productsService.duplicateItinerary(c.get("db"), itineraryId, body);
83
+ if (!row) {
84
+ return c.json({ error: "Itinerary not found" }, 404);
85
+ }
86
+ await appendProductMutationLedgerEntry(c, {
87
+ action: "duplicate",
88
+ productId: source.productId,
89
+ changedFields: changedMutationFields(body, null, row),
90
+ subject: "product itinerary",
91
+ actionName: "product.itinerary.duplicate",
92
+ routeOrToolName: "products.itinerary.duplicate",
93
+ });
94
+ await emitProductContentChanged(c.get("eventBus"), {
95
+ id: source.productId,
96
+ axis: "itinerary",
97
+ });
98
+ return c.json({ data: row }, 201);
99
+ })
100
+ // ==========================================================================
101
+ // Days
102
+ // ==========================================================================
103
+ .get("/:id/itineraries/:itineraryId/days", async (c) => {
104
+ return c.json({
105
+ data: await productsService.listItineraryDays(c.get("db"), c.req.param("itineraryId")),
106
+ });
107
+ })
108
+ .post("/:id/itineraries/:itineraryId/days", async (c) => {
109
+ const productId = c.req.param("id");
110
+ const body = await parseJsonBody(c, validation.insertDaySchema);
111
+ const row = await productsService.createItineraryDay(c.get("db"), productId, c.req.param("itineraryId"), body);
112
+ if (!row) {
113
+ return c.json({ error: "Itinerary not found" }, 404);
114
+ }
115
+ await appendProductMutationLedgerEntry(c, {
116
+ action: "create",
117
+ productId,
118
+ changedFields: changedMutationFields(body, null, row),
119
+ subject: "product itinerary day",
120
+ actionName: "product.day.create",
121
+ routeOrToolName: "products.day.create",
122
+ });
123
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
124
+ return c.json({ data: row }, 201);
125
+ })
126
+ // GET /:id/days — List days for product
127
+ .get("/:id/days", async (c) => {
128
+ return c.json({ data: await productsService.listDays(c.get("db"), c.req.param("id")) });
129
+ })
130
+ // POST /:id/days — Add day to product
131
+ .post("/:id/days", async (c) => {
132
+ const productId = c.req.param("id");
133
+ const body = await parseJsonBody(c, validation.insertDaySchema);
134
+ const row = await productsService.createDay(c.get("db"), productId, body);
135
+ if (!row) {
136
+ return c.json({ error: "Product not found" }, 404);
137
+ }
138
+ await appendProductMutationLedgerEntry(c, {
139
+ action: "create",
140
+ productId,
141
+ changedFields: changedMutationFields(body, null, row),
142
+ subject: "product itinerary day",
143
+ actionName: "product.day.create",
144
+ routeOrToolName: "products.day.create",
145
+ });
146
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
147
+ return c.json({ data: row }, 201);
148
+ })
149
+ // PATCH /:id/days/:dayId — Update day
150
+ .patch("/:id/days/:dayId", async (c) => {
151
+ const productId = c.req.param("id");
152
+ const dayId = c.req.param("dayId");
153
+ const body = await parseJsonBody(c, validation.updateDaySchema);
154
+ const before = await productsService.getDayForProductMutation(c.get("db"), dayId);
155
+ if (!before || before.productId !== productId) {
156
+ return c.json({ error: "Day not found" }, 404);
157
+ }
158
+ const row = await productsService.updateDay(c.get("db"), dayId, body);
159
+ if (!row) {
160
+ return c.json({ error: "Day not found" }, 404);
161
+ }
162
+ await appendProductMutationLedgerEntry(c, {
163
+ action: "update",
164
+ productId: before.productId,
165
+ changedFields: changedMutationFields(body, before, row),
166
+ subject: "product itinerary day",
167
+ actionName: "product.day.update",
168
+ routeOrToolName: "products.day.update",
169
+ });
170
+ await emitProductContentChanged(c.get("eventBus"), { id: before.productId, axis: "day" });
171
+ return c.json({ data: row });
172
+ })
173
+ // DELETE /:id/days/:dayId — Delete day
174
+ .delete("/:id/days/:dayId", async (c) => {
175
+ const productId = c.req.param("id");
176
+ const dayId = c.req.param("dayId");
177
+ const before = await productsService.getDayForProductMutation(c.get("db"), dayId);
178
+ if (!before || before.productId !== productId) {
179
+ return c.json({ error: "Day not found" }, 404);
180
+ }
181
+ const row = await productsService.deleteDay(c.get("db"), dayId);
182
+ if (!row) {
183
+ return c.json({ error: "Day not found" }, 404);
184
+ }
185
+ await appendProductMutationLedgerEntry(c, {
186
+ action: "delete",
187
+ productId: before.productId,
188
+ changedFields: [],
189
+ subject: "product itinerary day",
190
+ actionName: "product.day.delete",
191
+ routeOrToolName: "products.day.delete",
192
+ });
193
+ await emitProductContentChanged(c.get("eventBus"), { id: before.productId, axis: "day" });
194
+ return c.json({ success: true }, 200);
195
+ })
196
+ // ==========================================================================
197
+ // Day Services
198
+ // ==========================================================================
199
+ // GET /:id/days/:dayId/services — List services for a day
200
+ .get("/:id/days/:dayId/services", async (c) => {
201
+ return c.json({
202
+ data: await productsService.listDayServices(c.get("db"), c.req.param("dayId")),
203
+ });
204
+ })
205
+ // POST /:id/days/:dayId/services — Add service to day
206
+ .post("/:id/days/:dayId/services", async (c) => {
207
+ const productId = c.req.param("id");
208
+ const body = await parseJsonBody(c, validation.insertDayServiceSchema);
209
+ const row = await productsService.createDayService(c.get("db"), productId, c.req.param("dayId"), body);
210
+ if (!row) {
211
+ return c.json({ error: "Day not found" }, 404);
212
+ }
213
+ await appendProductMutationLedgerEntry(c, {
214
+ action: "create",
215
+ productId,
216
+ changedFields: changedMutationFields(body, null, row),
217
+ subject: "product day service",
218
+ actionName: "product.day_service.create",
219
+ routeOrToolName: "products.day_service.create",
220
+ });
221
+ await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
222
+ return c.json({ data: row }, 201);
223
+ })
224
+ // PATCH /:id/days/:dayId/services/:serviceId — Update service
225
+ .patch("/:id/days/:dayId/services/:serviceId", async (c) => {
226
+ const productId = c.req.param("id");
227
+ const serviceId = c.req.param("serviceId");
228
+ const body = await parseJsonBody(c, validation.updateDayServiceSchema);
229
+ const before = await productsService.getDayServiceForProductMutation(c.get("db"), serviceId);
230
+ if (!before || before.productId !== productId) {
231
+ return c.json({ error: "Service not found" }, 404);
232
+ }
233
+ const row = await productsService.updateDayService(c.get("db"), productId, serviceId, body);
234
+ if (!row) {
235
+ return c.json({ error: "Service not found" }, 404);
236
+ }
237
+ await appendProductMutationLedgerEntry(c, {
238
+ action: "update",
239
+ productId: before.productId,
240
+ changedFields: changedMutationFields(body, before, row),
241
+ subject: "product day service",
242
+ actionName: "product.day_service.update",
243
+ routeOrToolName: "products.day_service.update",
244
+ });
245
+ await emitProductContentChanged(c.get("eventBus"), { id: before.productId, axis: "day" });
246
+ return c.json({ data: row });
247
+ })
248
+ // DELETE /:id/days/:dayId/services/:serviceId — Delete service
249
+ .delete("/:id/days/:dayId/services/:serviceId", async (c) => {
250
+ const productId = c.req.param("id");
251
+ const serviceId = c.req.param("serviceId");
252
+ const before = await productsService.getDayServiceForProductMutation(c.get("db"), serviceId);
253
+ if (!before || before.productId !== productId) {
254
+ return c.json({ error: "Service not found" }, 404);
255
+ }
256
+ const row = await productsService.deleteDayService(c.get("db"), productId, serviceId);
257
+ if (!row) {
258
+ return c.json({ error: "Service not found" }, 404);
259
+ }
260
+ await appendProductMutationLedgerEntry(c, {
261
+ action: "delete",
262
+ productId: before.productId,
263
+ changedFields: [],
264
+ subject: "product day service",
265
+ actionName: "product.day_service.delete",
266
+ routeOrToolName: "products.day_service.delete",
267
+ });
268
+ await emitProductContentChanged(c.get("eventBus"), { id: before.productId, axis: "day" });
269
+ return c.json({ success: true }, 200);
270
+ })
271
+ // ==========================================================================
272
+ // Versions
273
+ // ==========================================================================
274
+ // GET /:id/versions — List versions for product
275
+ .get("/:id/versions", async (c) => {
276
+ return c.json({ data: await productsService.listVersions(c.get("db"), c.req.param("id")) });
277
+ })
278
+ // POST /:id/versions — Create version snapshot
279
+ .post("/:id/versions", async (c) => {
280
+ const userId = requireUserId(c);
281
+ const row = await productsService.createVersion(c.get("db"), c.req.param("id"), userId, await parseJsonBody(c, validation.insertVersionSchema, {
282
+ invalidJsonMessage: "Invalid JSON body",
283
+ }).catch((error) => {
284
+ if (error instanceof RequestValidationError && error.message === "Invalid JSON body") {
285
+ return {};
286
+ }
287
+ throw error;
288
+ }));
289
+ if (!row) {
290
+ return c.json({ error: "Product not found" }, 404);
291
+ }
292
+ return c.json({ data: row }, 201);
293
+ })
294
+ // ==========================================================================
295
+ // Notes
296
+ // ==========================================================================
297
+ // GET /:id/notes — List notes for product
298
+ .get("/:id/notes", async (c) => {
299
+ return c.json({ data: await productsService.listNotes(c.get("db"), c.req.param("id")) });
300
+ })
301
+ // POST /:id/notes — Add note to product
302
+ .post("/:id/notes", async (c) => {
303
+ const userId = requireUserId(c);
304
+ const row = await productsService.createNote(c.get("db"), c.req.param("id"), userId, await parseJsonBody(c, validation.insertProductNoteSchema));
305
+ if (!row) {
306
+ return c.json({ error: "Product not found" }, 404);
307
+ }
308
+ return c.json({ data: row }, 201);
309
+ });
@@ -0,0 +1,32 @@
1
+ import type { Env } from "./route-env.js";
2
+ export declare const productMaintenanceRoutes: import("hono/hono-base").HonoBase<Env, {
3
+ "/:id/recalculate": {
4
+ $post: {
5
+ input: {
6
+ param: {
7
+ id: string;
8
+ };
9
+ };
10
+ output: {
11
+ error: string;
12
+ };
13
+ outputFormat: "json";
14
+ status: 404;
15
+ } | {
16
+ input: {
17
+ param: {
18
+ id: string;
19
+ };
20
+ };
21
+ output: {
22
+ data: {
23
+ costAmountCents: number;
24
+ marginPercent: number;
25
+ };
26
+ };
27
+ outputFormat: "json";
28
+ status: import("hono/utils/http-status").ContentfulStatusCode;
29
+ };
30
+ };
31
+ }, "/", "/:id/recalculate">;
32
+ //# sourceMappingURL=routes-maintenance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-maintenance.d.ts","sourceRoot":"","sources":["../src/routes-maintenance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AAGzC,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAcjC,CAAA"}
@@ -0,0 +1,14 @@
1
+ import { Hono } from "hono";
2
+ import { productsService } from "./service.js";
3
+ export const productMaintenanceRoutes = new Hono()
4
+ // ==========================================================================
5
+ // Recalculate
6
+ // ==========================================================================
7
+ // POST /:id/recalculate — Recalculate product cost and margin
8
+ .post("/:id/recalculate", async (c) => {
9
+ const result = await productsService.recalculate(c.get("db"), c.req.param("id"));
10
+ if (!result) {
11
+ return c.json({ error: "Product not found" }, 404);
12
+ }
13
+ return c.json({ data: result });
14
+ });