@voyantjs/products 0.20.0 → 0.21.1

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 (70) 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.map +1 -1
  8. package/dist/catalog-policy.js +15 -1
  9. package/dist/content-shape.d.ts +217 -0
  10. package/dist/content-shape.d.ts.map +1 -0
  11. package/dist/content-shape.js +159 -0
  12. package/dist/draft-shape.d.ts +43 -0
  13. package/dist/draft-shape.d.ts.map +1 -0
  14. package/dist/draft-shape.js +46 -0
  15. package/dist/events.d.ts +37 -0
  16. package/dist/events.d.ts.map +1 -0
  17. package/dist/events.js +32 -0
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1 -0
  21. package/dist/routes-content.d.ts +74 -0
  22. package/dist/routes-content.d.ts.map +1 -0
  23. package/dist/routes-content.js +117 -0
  24. package/dist/routes.d.ts +40 -20
  25. package/dist/routes.d.ts.map +1 -1
  26. package/dist/routes.js +83 -13
  27. package/dist/schema-core.d.ts +240 -1
  28. package/dist/schema-core.d.ts.map +1 -1
  29. package/dist/schema-core.js +49 -0
  30. package/dist/schema-itinerary.d.ts +18 -1
  31. package/dist/schema-itinerary.d.ts.map +1 -1
  32. package/dist/schema-itinerary.js +1 -0
  33. package/dist/schema-settings.d.ts +1 -1
  34. package/dist/schema-sourced-content.d.ts +262 -0
  35. package/dist/schema-sourced-content.d.ts.map +1 -0
  36. package/dist/schema-sourced-content.js +69 -0
  37. package/dist/schema-taxonomy.d.ts +17 -0
  38. package/dist/schema-taxonomy.d.ts.map +1 -1
  39. package/dist/schema-taxonomy.js +13 -0
  40. package/dist/schema.d.ts +1 -0
  41. package/dist/schema.d.ts.map +1 -1
  42. package/dist/schema.js +1 -0
  43. package/dist/service-catalog-plane.d.ts.map +1 -1
  44. package/dist/service-catalog-plane.js +1 -0
  45. package/dist/service-content-owned.d.ts +68 -0
  46. package/dist/service-content-owned.d.ts.map +1 -0
  47. package/dist/service-content-owned.js +224 -0
  48. package/dist/service-content-synthesizer.d.ts +90 -0
  49. package/dist/service-content-synthesizer.d.ts.map +1 -0
  50. package/dist/service-content-synthesizer.js +171 -0
  51. package/dist/service-content.d.ts +106 -0
  52. package/dist/service-content.d.ts.map +1 -0
  53. package/dist/service-content.js +365 -0
  54. package/dist/service.d.ts +76 -22
  55. package/dist/service.d.ts.map +1 -1
  56. package/dist/service.js +4 -0
  57. package/dist/tasks/brochures.d.ts +1 -0
  58. package/dist/tasks/brochures.d.ts.map +1 -1
  59. package/dist/tasks/brochures.js +3 -0
  60. package/dist/validation-catalog.d.ts +4 -4
  61. package/dist/validation-config.d.ts +3 -3
  62. package/dist/validation-content.d.ts +34 -4
  63. package/dist/validation-content.d.ts.map +1 -1
  64. package/dist/validation-content.js +13 -0
  65. package/dist/validation-core.d.ts +53 -3
  66. package/dist/validation-core.d.ts.map +1 -1
  67. package/dist/validation-core.js +16 -0
  68. package/dist/validation-public.d.ts +9 -9
  69. package/dist/validation-shared.d.ts +4 -4
  70. package/package.json +12 -7
@@ -331,7 +331,7 @@ export declare const productDayServices: import("drizzle-orm/pg-core").PgTableWi
331
331
  tableName: "product_day_services";
332
332
  dataType: "string";
333
333
  columnType: "PgEnumColumn";
334
- data: "other" | "transfer" | "accommodation" | "experience" | "guide" | "meal";
334
+ data: "other" | "accommodation" | "transfer" | "experience" | "guide" | "meal";
335
335
  driverParam: string;
336
336
  notNull: true;
337
337
  hasDefault: false;
@@ -377,6 +377,23 @@ export declare const productDayServices: import("drizzle-orm/pg-core").PgTableWi
377
377
  identity: undefined;
378
378
  generated: undefined;
379
379
  }, {}, {}>;
380
+ countryCode: import("drizzle-orm/pg-core").PgColumn<{
381
+ name: "country_code";
382
+ tableName: "product_day_services";
383
+ dataType: "string";
384
+ columnType: "PgText";
385
+ data: string;
386
+ driverParam: string;
387
+ notNull: false;
388
+ hasDefault: false;
389
+ isPrimaryKey: false;
390
+ isAutoincrement: false;
391
+ hasRuntimeDefault: false;
392
+ enumValues: [string, ...string[]];
393
+ baseColumn: never;
394
+ identity: undefined;
395
+ generated: undefined;
396
+ }, {}, {}>;
380
397
  costCurrency: import("drizzle-orm/pg-core").PgColumn<{
381
398
  name: "cost_currency";
382
399
  tableName: "product_day_services";
@@ -1 +1 @@
1
- {"version":3,"file":"schema-itinerary.d.ts","sourceRoot":"","sources":["../src/schema-itinerary.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyB9B,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACrE,MAAM,MAAM,mBAAmB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AAExE,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBvB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AACxD,MAAM,MAAM,aAAa,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AAE3D,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuB9B,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACtE,MAAM,MAAM,oBAAoB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AAEzE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiB3B,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,OAAO,eAAe,CAAC,YAAY,CAAA;AAChE,MAAM,MAAM,iBAAiB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAA;AAEnE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAexB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAC1D,MAAM,MAAM,cAAc,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAE7D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkDxB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAC3D,MAAM,MAAM,eAAe,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA"}
1
+ {"version":3,"file":"schema-itinerary.d.ts","sourceRoot":"","sources":["../src/schema-itinerary.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyB9B,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACrE,MAAM,MAAM,mBAAmB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AAExE,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBvB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AACxD,MAAM,MAAM,aAAa,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AAE3D,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwB9B,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACtE,MAAM,MAAM,oBAAoB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AAEzE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiB3B,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,OAAO,eAAe,CAAC,YAAY,CAAA;AAChE,MAAM,MAAM,iBAAiB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAA;AAEnE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAexB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAC1D,MAAM,MAAM,cAAc,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAE7D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkDxB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAC3D,MAAM,MAAM,eAAe,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA"}
@@ -45,6 +45,7 @@ export const productDayServices = pgTable("product_day_services", {
45
45
  serviceType: serviceTypeEnum("service_type").notNull(),
46
46
  name: text("name").notNull(),
47
47
  description: text("description"),
48
+ countryCode: text("country_code"),
48
49
  costCurrency: text("cost_currency").notNull(),
49
50
  costAmountCents: integer("cost_amount_cents").notNull(),
50
51
  quantity: integer("quantity").notNull().default(1),
@@ -521,7 +521,7 @@ export declare const productCapabilities: import("drizzle-orm/pg-core").PgTableW
521
521
  tableName: "product_capabilities";
522
522
  dataType: "string";
523
523
  columnType: "PgEnumColumn";
524
- data: "on_request" | "private" | "instant_confirmation" | "pickup_available" | "dropoff_available" | "guided" | "shared" | "digital_ticket" | "voucher_required" | "external_inventory" | "multi_day" | "accommodation" | "transport";
524
+ data: "accommodation" | "on_request" | "private" | "instant_confirmation" | "pickup_available" | "dropoff_available" | "guided" | "shared" | "digital_ticket" | "voucher_required" | "external_inventory" | "multi_day" | "transport";
525
525
  driverParam: string;
526
526
  notNull: true;
527
527
  hasDefault: false;
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Products sourced-content cache.
3
+ *
4
+ * One row per sourced product × locale × market. Stores the rich
5
+ * detail-page content the upstream adapter served via `getContent`, plus
6
+ * the SWR metadata the read service needs (TTL, ETag, fetch status,
7
+ * locale fallback bookkeeping).
8
+ *
9
+ * Locale-keyed (per-locale rows, not one JSONB-of-locales) so
10
+ * per-locale TTLs, per-locale fetch failures, "what's missing in ro-RO?"
11
+ * SQL queries, and per-locale invalidation on drift all stay simple.
12
+ *
13
+ * See `docs/architecture/catalog-sourced-content.md` §3.2.
14
+ */
15
+ /**
16
+ * Lifecycle status per cache row. Distinct from sourced-entry lifecycle
17
+ * (which tracks whether the upstream still advertises the entity);
18
+ * `fetch_status` tracks the last cache fetch attempt for one
19
+ * (entity, locale, market) tuple.
20
+ */
21
+ export type ProductsSourcedContentFetchStatus = "ok" | "stale" | "error" | "unsupported";
22
+ /**
23
+ * Sentinel value for the `market` column when an adapter is not
24
+ * market-sensitive. The value `'*'` is the all-markets row; other
25
+ * values are specific markets the adapter served content for.
26
+ */
27
+ export declare const PRODUCTS_CONTENT_MARKET_ANY = "*";
28
+ export declare const productsSourcedContentTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
29
+ name: "products_sourced_content";
30
+ schema: undefined;
31
+ columns: {
32
+ entity_id: import("drizzle-orm/pg-core").PgColumn<{
33
+ name: "entity_id";
34
+ tableName: "products_sourced_content";
35
+ dataType: "string";
36
+ columnType: "PgText";
37
+ data: string;
38
+ driverParam: string;
39
+ notNull: true;
40
+ hasDefault: false;
41
+ isPrimaryKey: false;
42
+ isAutoincrement: false;
43
+ hasRuntimeDefault: false;
44
+ enumValues: [string, ...string[]];
45
+ baseColumn: never;
46
+ identity: undefined;
47
+ generated: undefined;
48
+ }, {}, {}>;
49
+ locale: import("drizzle-orm/pg-core").PgColumn<{
50
+ name: "locale";
51
+ tableName: "products_sourced_content";
52
+ dataType: "string";
53
+ columnType: "PgText";
54
+ data: string;
55
+ driverParam: string;
56
+ notNull: true;
57
+ hasDefault: false;
58
+ isPrimaryKey: false;
59
+ isAutoincrement: false;
60
+ hasRuntimeDefault: false;
61
+ enumValues: [string, ...string[]];
62
+ baseColumn: never;
63
+ identity: undefined;
64
+ generated: undefined;
65
+ }, {}, {}>;
66
+ market: import("drizzle-orm/pg-core").PgColumn<{
67
+ name: "market";
68
+ tableName: "products_sourced_content";
69
+ dataType: "string";
70
+ columnType: "PgText";
71
+ data: string;
72
+ driverParam: string;
73
+ notNull: true;
74
+ hasDefault: true;
75
+ isPrimaryKey: false;
76
+ isAutoincrement: false;
77
+ hasRuntimeDefault: false;
78
+ enumValues: [string, ...string[]];
79
+ baseColumn: never;
80
+ identity: undefined;
81
+ generated: undefined;
82
+ }, {}, {}>;
83
+ payload: import("drizzle-orm/pg-core").PgColumn<{
84
+ name: "payload";
85
+ tableName: "products_sourced_content";
86
+ dataType: "json";
87
+ columnType: "PgJsonb";
88
+ data: Record<string, unknown>;
89
+ driverParam: unknown;
90
+ notNull: true;
91
+ hasDefault: false;
92
+ isPrimaryKey: false;
93
+ isAutoincrement: false;
94
+ hasRuntimeDefault: false;
95
+ enumValues: undefined;
96
+ baseColumn: never;
97
+ identity: undefined;
98
+ generated: undefined;
99
+ }, {}, {
100
+ $type: Record<string, unknown>;
101
+ }>;
102
+ content_schema_version: import("drizzle-orm/pg-core").PgColumn<{
103
+ name: "content_schema_version";
104
+ tableName: "products_sourced_content";
105
+ dataType: "string";
106
+ columnType: "PgText";
107
+ data: string;
108
+ driverParam: string;
109
+ notNull: true;
110
+ hasDefault: false;
111
+ isPrimaryKey: false;
112
+ isAutoincrement: false;
113
+ hasRuntimeDefault: false;
114
+ enumValues: [string, ...string[]];
115
+ baseColumn: never;
116
+ identity: undefined;
117
+ generated: undefined;
118
+ }, {}, {}>;
119
+ returned_locale: import("drizzle-orm/pg-core").PgColumn<{
120
+ name: "returned_locale";
121
+ tableName: "products_sourced_content";
122
+ dataType: "string";
123
+ columnType: "PgText";
124
+ data: string;
125
+ driverParam: string;
126
+ notNull: true;
127
+ hasDefault: false;
128
+ isPrimaryKey: false;
129
+ isAutoincrement: false;
130
+ hasRuntimeDefault: false;
131
+ enumValues: [string, ...string[]];
132
+ baseColumn: never;
133
+ identity: undefined;
134
+ generated: undefined;
135
+ }, {}, {}>;
136
+ machine_translated: import("drizzle-orm/pg-core").PgColumn<{
137
+ name: "machine_translated";
138
+ tableName: "products_sourced_content";
139
+ dataType: "boolean";
140
+ columnType: "PgBoolean";
141
+ data: boolean;
142
+ driverParam: boolean;
143
+ notNull: true;
144
+ hasDefault: true;
145
+ isPrimaryKey: false;
146
+ isAutoincrement: false;
147
+ hasRuntimeDefault: false;
148
+ enumValues: undefined;
149
+ baseColumn: never;
150
+ identity: undefined;
151
+ generated: undefined;
152
+ }, {}, {}>;
153
+ source_updated_at: import("drizzle-orm/pg-core").PgColumn<{
154
+ name: "source_updated_at";
155
+ tableName: "products_sourced_content";
156
+ dataType: "date";
157
+ columnType: "PgTimestamp";
158
+ data: Date;
159
+ driverParam: string;
160
+ notNull: false;
161
+ hasDefault: false;
162
+ isPrimaryKey: false;
163
+ isAutoincrement: false;
164
+ hasRuntimeDefault: false;
165
+ enumValues: undefined;
166
+ baseColumn: never;
167
+ identity: undefined;
168
+ generated: undefined;
169
+ }, {}, {}>;
170
+ fetched_at: import("drizzle-orm/pg-core").PgColumn<{
171
+ name: "fetched_at";
172
+ tableName: "products_sourced_content";
173
+ dataType: "date";
174
+ columnType: "PgTimestamp";
175
+ data: Date;
176
+ driverParam: string;
177
+ notNull: true;
178
+ hasDefault: true;
179
+ isPrimaryKey: false;
180
+ isAutoincrement: false;
181
+ hasRuntimeDefault: false;
182
+ enumValues: undefined;
183
+ baseColumn: never;
184
+ identity: undefined;
185
+ generated: undefined;
186
+ }, {}, {}>;
187
+ fresh_until: import("drizzle-orm/pg-core").PgColumn<{
188
+ name: "fresh_until";
189
+ tableName: "products_sourced_content";
190
+ dataType: "date";
191
+ columnType: "PgTimestamp";
192
+ data: Date;
193
+ driverParam: string;
194
+ notNull: false;
195
+ hasDefault: false;
196
+ isPrimaryKey: false;
197
+ isAutoincrement: false;
198
+ hasRuntimeDefault: false;
199
+ enumValues: undefined;
200
+ baseColumn: never;
201
+ identity: undefined;
202
+ generated: undefined;
203
+ }, {}, {}>;
204
+ etag: import("drizzle-orm/pg-core").PgColumn<{
205
+ name: "etag";
206
+ tableName: "products_sourced_content";
207
+ dataType: "string";
208
+ columnType: "PgText";
209
+ data: string;
210
+ driverParam: string;
211
+ notNull: false;
212
+ hasDefault: false;
213
+ isPrimaryKey: false;
214
+ isAutoincrement: false;
215
+ hasRuntimeDefault: false;
216
+ enumValues: [string, ...string[]];
217
+ baseColumn: never;
218
+ identity: undefined;
219
+ generated: undefined;
220
+ }, {}, {}>;
221
+ fetch_status: import("drizzle-orm/pg-core").PgColumn<{
222
+ name: "fetch_status";
223
+ tableName: "products_sourced_content";
224
+ dataType: "string";
225
+ columnType: "PgText";
226
+ data: ProductsSourcedContentFetchStatus;
227
+ driverParam: string;
228
+ notNull: true;
229
+ hasDefault: true;
230
+ isPrimaryKey: false;
231
+ isAutoincrement: false;
232
+ hasRuntimeDefault: false;
233
+ enumValues: [string, ...string[]];
234
+ baseColumn: never;
235
+ identity: undefined;
236
+ generated: undefined;
237
+ }, {}, {
238
+ $type: ProductsSourcedContentFetchStatus;
239
+ }>;
240
+ fetch_error: import("drizzle-orm/pg-core").PgColumn<{
241
+ name: "fetch_error";
242
+ tableName: "products_sourced_content";
243
+ dataType: "string";
244
+ columnType: "PgText";
245
+ data: string;
246
+ driverParam: string;
247
+ notNull: false;
248
+ hasDefault: false;
249
+ isPrimaryKey: false;
250
+ isAutoincrement: false;
251
+ hasRuntimeDefault: false;
252
+ enumValues: [string, ...string[]];
253
+ baseColumn: never;
254
+ identity: undefined;
255
+ generated: undefined;
256
+ }, {}, {}>;
257
+ };
258
+ dialect: "pg";
259
+ }>;
260
+ export type InsertProductsSourcedContent = typeof productsSourcedContentTable.$inferInsert;
261
+ export type SelectProductsSourcedContent = typeof productsSourcedContentTable.$inferSelect;
262
+ //# sourceMappingURL=schema-sourced-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-sourced-content.d.ts","sourceRoot":"","sources":["../src/schema-sourced-content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;;;;GAKG;AACH,MAAM,MAAM,iCAAiC,GAAG,IAAI,GAAG,OAAO,GAAG,OAAO,GAAG,aAAa,CAAA;AAExF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAA;AAE9C,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0DvC,CAAA;AAED,MAAM,MAAM,4BAA4B,GAAG,OAAO,2BAA2B,CAAC,YAAY,CAAA;AAC1F,MAAM,MAAM,4BAA4B,GAAG,OAAO,2BAA2B,CAAC,YAAY,CAAA"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Products sourced-content cache.
3
+ *
4
+ * One row per sourced product × locale × market. Stores the rich
5
+ * detail-page content the upstream adapter served via `getContent`, plus
6
+ * the SWR metadata the read service needs (TTL, ETag, fetch status,
7
+ * locale fallback bookkeeping).
8
+ *
9
+ * Locale-keyed (per-locale rows, not one JSONB-of-locales) so
10
+ * per-locale TTLs, per-locale fetch failures, "what's missing in ro-RO?"
11
+ * SQL queries, and per-locale invalidation on drift all stay simple.
12
+ *
13
+ * See `docs/architecture/catalog-sourced-content.md` §3.2.
14
+ */
15
+ import { boolean, index, jsonb, pgTable, primaryKey, text, timestamp } from "drizzle-orm/pg-core";
16
+ /**
17
+ * Sentinel value for the `market` column when an adapter is not
18
+ * market-sensitive. The value `'*'` is the all-markets row; other
19
+ * values are specific markets the adapter served content for.
20
+ */
21
+ export const PRODUCTS_CONTENT_MARKET_ANY = "*";
22
+ export const productsSourcedContentTable = pgTable("products_sourced_content", {
23
+ /** TypeID matching the products module — `prod_*`. */
24
+ entity_id: text("entity_id").notNull(),
25
+ /** BCP 47 language tag (e.g. "ro-RO", "en-GB"). */
26
+ locale: text("locale").notNull(),
27
+ /** Market id, or `'*'` for all-markets. */
28
+ market: text("market").notNull().default(PRODUCTS_CONTENT_MARKET_ANY),
29
+ /**
30
+ * Vertical-shaped content payload. Schema-validated against the
31
+ * vertical's Zod validator before write; consumers must validate on
32
+ * read against the recorded `content_schema_version`.
33
+ */
34
+ payload: jsonb("payload").$type().notNull(),
35
+ /** Vertical-managed schema version (e.g. "products/v1"). */
36
+ content_schema_version: text("content_schema_version").notNull(),
37
+ /**
38
+ * The locale the upstream actually served. May differ from
39
+ * `locale` (the request locale) when the upstream did its own
40
+ * fallback. Lets the read path mark `match_kind` accurately even
41
+ * when serving a stale row that originated from upstream-fallback.
42
+ */
43
+ returned_locale: text("returned_locale").notNull(),
44
+ /** True when the upstream marks the payload as machine-translated. */
45
+ machine_translated: boolean("machine_translated").notNull().default(false),
46
+ /** When the upstream itself last modified this content. */
47
+ source_updated_at: timestamp("source_updated_at", { withTimezone: true }),
48
+ /** When this cache row was last written. */
49
+ fetched_at: timestamp("fetched_at", { withTimezone: true }).notNull().defaultNow(),
50
+ /** When the cache considers this row fresh until — SWR boundary. */
51
+ fresh_until: timestamp("fresh_until", { withTimezone: true }),
52
+ /** ETag-style marker for HTTP-cache revalidation on the next pull. */
53
+ etag: text("etag"),
54
+ /** Last fetch outcome. */
55
+ fetch_status: text("fetch_status")
56
+ .$type()
57
+ .notNull()
58
+ .default("ok"),
59
+ /** Error detail when fetch_status === "error". */
60
+ fetch_error: text("fetch_error"),
61
+ }, (table) => [
62
+ primaryKey({ columns: [table.entity_id, table.locale, table.market] }),
63
+ // "What's stale in ro-RO?"
64
+ index("products_sourced_content_locale_fresh_idx").on(table.locale, table.fresh_until),
65
+ // Fallback diagnostics: "what locales did upstream serve for prod_X?"
66
+ index("products_sourced_content_returned_locale_idx").on(table.entity_id, table.returned_locale),
67
+ // Cache flushes on schema bumps: DELETE WHERE schema_version != current.
68
+ index("products_sourced_content_schema_version_idx").on(table.content_schema_version),
69
+ ]);
@@ -285,6 +285,23 @@ export declare const productCategories: import("drizzle-orm/pg-core").PgTableWit
285
285
  identity: undefined;
286
286
  generated: undefined;
287
287
  }, {}, {}>;
288
+ customerPaymentPolicy: import("drizzle-orm/pg-core").PgColumn<{
289
+ name: "customer_payment_policy";
290
+ tableName: "product_categories";
291
+ dataType: "json";
292
+ columnType: "PgJsonb";
293
+ data: unknown;
294
+ driverParam: unknown;
295
+ notNull: false;
296
+ hasDefault: false;
297
+ isPrimaryKey: false;
298
+ isAutoincrement: false;
299
+ hasRuntimeDefault: false;
300
+ enumValues: undefined;
301
+ baseColumn: never;
302
+ identity: undefined;
303
+ generated: undefined;
304
+ }, {}, {}>;
288
305
  metadata: import("drizzle-orm/pg-core").PgColumn<{
289
306
  name: "metadata";
290
307
  tableName: "product_categories";
@@ -1 +1 @@
1
- {"version":3,"file":"schema-taxonomy.d.ts","sourceRoot":"","sources":["../src/schema-taxonomy.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmBxB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAC1D,MAAM,MAAM,cAAc,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAE7D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0B7B,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,OAAO,iBAAiB,CAAC,YAAY,CAAA;AACnE,MAAM,MAAM,kBAAkB,GAAG,OAAO,iBAAiB,CAAC,YAAY,CAAA;AAEtE,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASvB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AACxD,MAAM,MAAM,aAAa,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AAE3D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwBxB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAC1D,MAAM,MAAM,cAAc,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAE7D,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBnC,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG,OAAO,uBAAuB,CAAC,YAAY,CAAA;AAChF,MAAM,MAAM,yBAAyB,GAAG,OAAO,uBAAuB,CAAC,YAAY,CAAA;AAEnF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBnC,CAAA;AAED,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAe9B,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkB/B,CAAA"}
1
+ {"version":3,"file":"schema-taxonomy.d.ts","sourceRoot":"","sources":["../src/schema-taxonomy.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmBxB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAC1D,MAAM,MAAM,cAAc,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAE7D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuC7B,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,OAAO,iBAAiB,CAAC,YAAY,CAAA;AACnE,MAAM,MAAM,kBAAkB,GAAG,OAAO,iBAAiB,CAAC,YAAY,CAAA;AAEtE,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASvB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AACxD,MAAM,MAAM,aAAa,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AAE3D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwBxB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAC1D,MAAM,MAAM,cAAc,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAE7D,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBnC,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG,OAAO,uBAAuB,CAAC,YAAY,CAAA;AAChF,MAAM,MAAM,yBAAyB,GAAG,OAAO,uBAAuB,CAAC,YAAY,CAAA;AAEnF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBnC,CAAA;AAED,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAe9B,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkB/B,CAAA"}
@@ -25,6 +25,19 @@ export const productCategories = pgTable("product_categories", {
25
25
  description: text("description"),
26
26
  sortOrder: integer("sort_order").notNull().default(0),
27
27
  active: boolean("active").notNull().default(true),
28
+ /**
29
+ * Customer-facing payment policy override. When set, bookings
30
+ * for products in this category inherit these terms (unless
31
+ * the listing or booking sets its own override). Shape mirrors
32
+ * `PaymentPolicy` from `@voyantjs/finance`.
33
+ *
34
+ * `null` means "inherit from supplier / operator default".
35
+ *
36
+ * Multi-category products: the cascade picks the FIRST category
37
+ * (ordered by `productCategoryProducts.sortOrder` ascending) that
38
+ * has a non-null policy.
39
+ */
40
+ customerPaymentPolicy: jsonb("customer_payment_policy"),
28
41
  metadata: jsonb("metadata").$type(),
29
42
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
30
43
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
package/dist/schema.d.ts CHANGED
@@ -4,5 +4,6 @@ export * from "./schema-itinerary";
4
4
  export * from "./schema-relations";
5
5
  export * from "./schema-settings";
6
6
  export * from "./schema-shared";
7
+ export { type InsertProductsSourcedContent, PRODUCTS_CONTENT_MARKET_ANY, type ProductsSourcedContentFetchStatus, productsSourcedContentTable, type SelectProductsSourcedContent, } from "./schema-sourced-content";
7
8
  export * from "./schema-taxonomy";
8
9
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AACtF,cAAc,eAAe,CAAA;AAC7B,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,mBAAmB,CAAA"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AACtF,cAAc,eAAe,CAAA;AAC7B,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,EACL,KAAK,4BAA4B,EACjC,2BAA2B,EAC3B,KAAK,iCAAiC,EACtC,2BAA2B,EAC3B,KAAK,4BAA4B,GAClC,MAAM,0BAA0B,CAAA;AACjC,cAAc,mBAAmB,CAAA"}
package/dist/schema.js CHANGED
@@ -4,4 +4,5 @@ export * from "./schema-itinerary";
4
4
  export * from "./schema-relations";
5
5
  export * from "./schema-settings";
6
6
  export * from "./schema-shared";
7
+ export { PRODUCTS_CONTENT_MARKET_ANY, productsSourcedContentTable, } from "./schema-sourced-content";
7
8
  export * from "./schema-taxonomy";
@@ -1 +1 @@
1
- {"version":3,"file":"service-catalog-plane.d.ts","sourceRoot":"","sources":["../src/service-catalog-plane.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAGL,KAAK,oBAAoB,EAEzB,KAAK,eAAe,EACpB,KAAK,eAAe,EAEpB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,aAAa,EAElB,KAAK,UAAU,EAChB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAIhD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAc3C;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,QAAQ,CAAC,YAAY,EACjC,OAAO,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAA;CAAE,GACpC,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAuC9B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,QAAQ,CAAC,YAAY,EAClC,QAAQ,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAA;CAAE,GACrC,UAAU,CAKZ;AAED,8EAA8E;AAC9E,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,gBAAgB,EAAE,MAAM,CAAA;IACxB,qCAAqC;IACrC,KAAK,EAAE,aAAa,CAAA;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,YAAY,EAChB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAS9B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,aAAa,CAAC,OAAO,QAAQ,CAAC,YAAY,CAAC,EACjD,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,YAAY,EAAE,CAAC,CAkBzB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,YAAY,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,qBAAqB,GAAG;IAAE,YAAY,CAAC,EAAE,YAAY,CAAA;CAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC,CASzD;AAMD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE;IACpD,gBAAgB,EAAE,MAAM,CAAA;CACzB,GAAG,eAAe,CAAC,OAAO,QAAQ,CAAC,YAAY,CAAC,CAWhD;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,EAAE,EAAE,YAAY,EAChB,OAAO,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAA;CAAE,GACpC,eAAe,CAQjB;AAED;;GAEG;AACH,YAAY,EACV,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,aAAa,EACb,UAAU,GACX,CAAA"}
1
+ {"version":3,"file":"service-catalog-plane.d.ts","sourceRoot":"","sources":["../src/service-catalog-plane.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAGL,KAAK,oBAAoB,EAEzB,KAAK,eAAe,EACpB,KAAK,eAAe,EAEpB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,aAAa,EAElB,KAAK,UAAU,EAChB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAIhD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAc3C;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,QAAQ,CAAC,YAAY,EACjC,OAAO,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAA;CAAE,GACpC,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAwC9B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,QAAQ,CAAC,YAAY,EAClC,QAAQ,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAA;CAAE,GACrC,UAAU,CAKZ;AAED,8EAA8E;AAC9E,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,gBAAgB,EAAE,MAAM,CAAA;IACxB,qCAAqC;IACrC,KAAK,EAAE,aAAa,CAAA;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,YAAY,EAChB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAS9B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,aAAa,CAAC,OAAO,QAAQ,CAAC,YAAY,CAAC,EACjD,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,YAAY,EAAE,CAAC,CAkBzB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,YAAY,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,qBAAqB,GAAG;IAAE,YAAY,CAAC,EAAE,YAAY,CAAA;CAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC,CASzD;AAMD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE;IACpD,gBAAgB,EAAE,MAAM,CAAA;CACzB,GAAG,eAAe,CAAC,OAAO,QAAQ,CAAC,YAAY,CAAC,CAWhD;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,EAAE,EAAE,YAAY,EAChB,OAAO,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAA;CAAE,GACpC,eAAe,CAQjB;AAED;;GAEG;AACH,YAAY,EACV,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,aAAa,EACb,UAAU,GACX,CAAA"}
@@ -65,6 +65,7 @@ export function productRowToProjection(row, context) {
65
65
  ["activated", row.activated],
66
66
  ["productTypeId", row.productTypeId],
67
67
  ["facilityId", row.facilityId],
68
+ ["supplierId", row.supplierId],
68
69
  ["pax", row.pax],
69
70
  ["startDate", row.startDate],
70
71
  ["endDate", row.endDate],
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Owned-product content builder.
3
+ *
4
+ * Projects an owned product (the products module's own tables) into the
5
+ * vertical-shared `ProductContent` shape so the catalog content service
6
+ * can return rich detail for owned products via the same API that
7
+ * sourced products go through (`getProductContent`).
8
+ *
9
+ * Per sourced-content §3.3: `getProductContent` is the unified read
10
+ * surface for owned + sourced. v1 of service-content.ts only handled
11
+ * sourced (returning null for owned); this helper closes that gap.
12
+ *
13
+ * Locale resolution uses the catalog plane's standard
14
+ * `pickBestCachedLocale` against `product_translations` and
15
+ * `product_option_translations` rows — exact > language-match >
16
+ * fallback-chain > any. Matches the same scoring semantics the sourced
17
+ * cache reads use, so the same `BookingDraft.scope.locale` chain works
18
+ * for both owned and sourced products.
19
+ *
20
+ * The projection reads in parallel:
21
+ * - `products` row → product summary + tags + supplier
22
+ * - `product_translations` → localized name + description per locale
23
+ * - `product_itineraries` + `product_days` → itinerary days (no
24
+ * translation table today; falls back to source)
25
+ * - `product_options` + `product_option_translations` → options +
26
+ * localized labels
27
+ * - `product_media` → hero + gallery
28
+ *
29
+ * Day translations don't exist in the schema yet — when
30
+ * `product_day_translations` lands, this function picks them up the
31
+ * same way.
32
+ */
33
+ import type { ContentLocaleMatchKind } from "@voyantjs/catalog";
34
+ import type { AnyDrizzleDb } from "@voyantjs/db";
35
+ import { type ProductContent } from "./content-shape.js";
36
+ export interface BuildOwnedProductContentOptions {
37
+ /**
38
+ * Ordered locale preference chain — most-preferred first. Same shape
39
+ * the catalog plane's `pickBestCachedLocale` consumes. Pass-through
40
+ * from the caller's `BookingDraft.scope.locale` (storefront /
41
+ * operator UI).
42
+ */
43
+ preferredLocales: ReadonlyArray<string>;
44
+ }
45
+ export interface BuildOwnedProductContentResult {
46
+ /** The owned product projected to ProductContent. */
47
+ content: ProductContent;
48
+ /**
49
+ * The locale we actually served — may differ from
50
+ * `preferredLocales[0]` when a fallback was used. Per-product;
51
+ * options that fell back to a different locale don't override this
52
+ * (storefront UI hints at the product level).
53
+ */
54
+ servedLocale: string;
55
+ /**
56
+ * How well the served locale matched the chain. Surfaces in the UI
57
+ * as a "served in English" hint when content was served in a
58
+ * non-preferred language.
59
+ */
60
+ matchKind: ContentLocaleMatchKind;
61
+ }
62
+ /**
63
+ * Read the owned product + related rows and project to `ProductContent`,
64
+ * resolving translations against the supplied locale-preference chain.
65
+ * Returns null when the product doesn't exist.
66
+ */
67
+ export declare function buildOwnedProductContent(db: AnyDrizzleDb, entityId: string, options: BuildOwnedProductContentOptions): Promise<BuildOwnedProductContentResult | null>;
68
+ //# sourceMappingURL=service-content-owned.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-content-owned.d.ts","sourceRoot":"","sources":["../src/service-content-owned.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAGhD,OAAO,EACL,KAAK,cAAc,EAGpB,MAAM,oBAAoB,CAAA;AAW3B,MAAM,WAAW,+BAA+B;IAC9C;;;;;OAKG;IACH,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACxC;AAED,MAAM,WAAW,8BAA8B;IAC7C,qDAAqD;IACrD,OAAO,EAAE,cAAc,CAAA;IACvB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,SAAS,EAAE,sBAAsB,CAAA;CAClC;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,EAAE,EAAE,YAAY,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,8BAA8B,GAAG,IAAI,CAAC,CAmIhD"}