@voyant-travel/accommodations 0.105.17

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 (51) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +11 -0
  3. package/dist/booking-engine/handler.d.ts +103 -0
  4. package/dist/booking-engine/handler.d.ts.map +1 -0
  5. package/dist/booking-engine/handler.js +254 -0
  6. package/dist/booking-engine/index.d.ts +8 -0
  7. package/dist/booking-engine/index.d.ts.map +1 -0
  8. package/dist/booking-engine/index.js +7 -0
  9. package/dist/catalog-policy.d.ts +23 -0
  10. package/dist/catalog-policy.d.ts.map +1 -0
  11. package/dist/catalog-policy.js +441 -0
  12. package/dist/content-shape.d.ts +5 -0
  13. package/dist/content-shape.d.ts.map +1 -0
  14. package/dist/content-shape.js +13 -0
  15. package/dist/draft-shape.d.ts +35 -0
  16. package/dist/draft-shape.d.ts.map +1 -0
  17. package/dist/draft-shape.js +84 -0
  18. package/dist/index.d.ts +8 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +7 -0
  21. package/dist/routes-content.d.ts +31 -0
  22. package/dist/routes-content.d.ts.map +1 -0
  23. package/dist/routes-content.js +87 -0
  24. package/dist/schema-bookings.d.ts +582 -0
  25. package/dist/schema-bookings.d.ts.map +1 -0
  26. package/dist/schema-bookings.js +62 -0
  27. package/dist/schema-inventory.d.ts +1361 -0
  28. package/dist/schema-inventory.d.ts.map +1 -0
  29. package/dist/schema-inventory.js +125 -0
  30. package/dist/schema-shared.d.ts +5 -0
  31. package/dist/schema-shared.d.ts.map +1 -0
  32. package/dist/schema-shared.js +24 -0
  33. package/dist/schema-sourced-content.d.ts +254 -0
  34. package/dist/schema-sourced-content.d.ts.map +1 -0
  35. package/dist/schema-sourced-content.js +48 -0
  36. package/dist/schema.d.ts +5 -0
  37. package/dist/schema.d.ts.map +1 -0
  38. package/dist/schema.js +4 -0
  39. package/dist/service-catalog-plane.d.ts +55 -0
  40. package/dist/service-catalog-plane.d.ts.map +1 -0
  41. package/dist/service-catalog-plane.js +202 -0
  42. package/dist/service-content-owned.d.ts +13 -0
  43. package/dist/service-content-owned.d.ts.map +1 -0
  44. package/dist/service-content-owned.js +205 -0
  45. package/dist/service-content-synthesizer.d.ts +43 -0
  46. package/dist/service-content-synthesizer.d.ts.map +1 -0
  47. package/dist/service-content-synthesizer.js +149 -0
  48. package/dist/service-content.d.ts +47 -0
  49. package/dist/service-content.d.ts.map +1 -0
  50. package/dist/service-content.js +304 -0
  51. package/package.json +101 -0
@@ -0,0 +1,441 @@
1
+ /**
2
+ * Catalog plane field policy for `packages/accommodations`.
3
+ *
4
+ * The accommodation vertical's catalog entry is the **room type** — the
5
+ * sellable variant within a property. Properties themselves live in
6
+ * `packages/facilities` and are referenced via `propertyId`.
7
+ *
8
+ * Scope of this file:
9
+ * - The root `room_types` table (from `schema-inventory.ts`).
10
+ * - Provenance + identity fields the catalog plane needs to track.
11
+ *
12
+ * Out of scope for this resale package:
13
+ * - hotel-managed physical room units and their lifecycle.
14
+ * - `rate_plans` — variant pricing axis with its own lifecycle.
15
+ * - `meal_plans` — board-basis variants, structural choice axis.
16
+ * - `room_type_bed_configs` — composite list with managed structural
17
+ * fields under each row.
18
+ */
19
+ import { defineFieldPolicy } from "@voyant-travel/catalog/contract";
20
+ const ACCOMMODATION_FIELD_POLICY = [
21
+ // ── Source pointer / provenance ─────────────────────────────────────────
22
+ {
23
+ path: "source.kind",
24
+ class: "managed",
25
+ merge: "source-only",
26
+ drift: "critical",
27
+ reindex: "facet-affecting",
28
+ snapshot: "on-book",
29
+ query: "indexed-column",
30
+ localized: false,
31
+ visibility: ["staff"],
32
+ editRole: "none",
33
+ overrideFriction: "none",
34
+ sourceFreshness: "sync",
35
+ },
36
+ {
37
+ path: "source.ref",
38
+ class: "managed",
39
+ merge: "source-only",
40
+ drift: "critical",
41
+ reindex: "none",
42
+ snapshot: "on-book",
43
+ query: "indexed-column",
44
+ localized: false,
45
+ visibility: ["staff"],
46
+ editRole: "none",
47
+ overrideFriction: "none",
48
+ sourceFreshness: "sync",
49
+ },
50
+ {
51
+ path: "seller.operator_id",
52
+ class: "managed",
53
+ merge: "source-only",
54
+ drift: "critical",
55
+ reindex: "none",
56
+ snapshot: "on-book",
57
+ query: "indexed-column",
58
+ localized: false,
59
+ visibility: ["staff"],
60
+ editRole: "none",
61
+ overrideFriction: "none",
62
+ sourceFreshness: "static",
63
+ },
64
+ // ── Identity / lifecycle ────────────────────────────────────────────────
65
+ {
66
+ path: "id",
67
+ class: "managed",
68
+ merge: "source-only",
69
+ drift: "critical",
70
+ reindex: "none",
71
+ snapshot: "on-book",
72
+ query: "first-class-table",
73
+ localized: false,
74
+ visibility: ["staff", "customer", "partner"],
75
+ editRole: "none",
76
+ overrideFriction: "none",
77
+ sourceFreshness: "static",
78
+ },
79
+ {
80
+ path: "code",
81
+ class: "managed",
82
+ merge: "source-only",
83
+ drift: "high",
84
+ reindex: "entry",
85
+ snapshot: "on-book",
86
+ query: "indexed-column",
87
+ localized: false,
88
+ visibility: ["staff"],
89
+ editRole: "none",
90
+ overrideFriction: "none",
91
+ sourceFreshness: "sync",
92
+ },
93
+ {
94
+ path: "createdAt",
95
+ class: "managed",
96
+ merge: "source-only",
97
+ drift: "none",
98
+ reindex: "none",
99
+ snapshot: "on-book",
100
+ query: "indexed-column",
101
+ localized: false,
102
+ visibility: ["staff"],
103
+ editRole: "none",
104
+ overrideFriction: "none",
105
+ sourceFreshness: "static",
106
+ },
107
+ {
108
+ path: "updatedAt",
109
+ class: "managed",
110
+ merge: "source-only",
111
+ drift: "none",
112
+ reindex: "none",
113
+ snapshot: "never",
114
+ query: "indexed-column",
115
+ localized: false,
116
+ visibility: ["staff"],
117
+ editRole: "none",
118
+ overrideFriction: "none",
119
+ sourceFreshness: "sync",
120
+ },
121
+ // ── Cross-module reference (the property the room belongs to) ──────────
122
+ {
123
+ path: "propertyId",
124
+ class: "structural",
125
+ merge: "source-only",
126
+ drift: "critical",
127
+ reindex: "facet-affecting",
128
+ snapshot: "on-book",
129
+ query: "indexed-column",
130
+ localized: false,
131
+ visibility: ["staff", "customer", "partner"],
132
+ editRole: "none",
133
+ overrideFriction: "none",
134
+ sourceFreshness: "sync",
135
+ },
136
+ {
137
+ path: "supplierId",
138
+ class: "structural",
139
+ merge: "source-only",
140
+ drift: "high",
141
+ reindex: "facet-affecting",
142
+ snapshot: "on-book",
143
+ query: "indexed-column",
144
+ localized: false,
145
+ visibility: ["staff"],
146
+ editRole: "none",
147
+ overrideFriction: "none",
148
+ sourceFreshness: "sync",
149
+ },
150
+ // ── Merchandisable / marketing ──────────────────────────────────────────
151
+ {
152
+ path: "name",
153
+ class: "merchandisable",
154
+ merge: "replace",
155
+ drift: "medium",
156
+ reindex: "entry-locale",
157
+ snapshot: "on-book",
158
+ query: "indexed-column",
159
+ localized: true,
160
+ visibility: ["staff", "customer", "partner"],
161
+ editRole: "marketing",
162
+ overrideFriction: "none",
163
+ sourceFreshness: "sync",
164
+ },
165
+ {
166
+ path: "description",
167
+ class: "merchandisable",
168
+ merge: "replace",
169
+ drift: "low",
170
+ reindex: "entry-locale",
171
+ snapshot: "on-book",
172
+ query: "blob-only",
173
+ localized: true,
174
+ visibility: ["staff", "customer", "partner"],
175
+ editRole: "marketing",
176
+ overrideFriction: "none",
177
+ sourceFreshness: "sync",
178
+ },
179
+ {
180
+ path: "accessibilityNotes",
181
+ class: "merchandisable",
182
+ merge: "replace",
183
+ drift: "medium",
184
+ reindex: "entry-locale",
185
+ snapshot: "on-book",
186
+ query: "blob-only",
187
+ localized: true,
188
+ visibility: ["staff", "customer", "partner"],
189
+ editRole: "marketing",
190
+ overrideFriction: "confirm",
191
+ sourceFreshness: "sync",
192
+ },
193
+ {
194
+ path: "thumbnailUrl",
195
+ class: "merchandisable",
196
+ merge: "source-only",
197
+ drift: "low",
198
+ reindex: "entry",
199
+ snapshot: "on-book",
200
+ query: "indexed-column",
201
+ localized: false,
202
+ visibility: ["staff", "customer", "partner"],
203
+ editRole: "none",
204
+ overrideFriction: "none",
205
+ sourceFreshness: "sync",
206
+ },
207
+ // ── Structural / facet-affecting ───────────────────────────────────────
208
+ {
209
+ // Supply mechanic — durable, product-agnostic split that drives the
210
+ // search + booking surface: "dynamic" (live-composed, any date, calendar
211
+ // pricing) vs "scheduled" (fixed dated departures with seat allotment).
212
+ // See docs/architecture/catalog-supply-models.md. Accommodation stays are
213
+ // dynamic; the value is shipped by Connect on the search document.
214
+ path: "supplyModel",
215
+ class: "structural",
216
+ merge: "source-only",
217
+ drift: "low",
218
+ reindex: "facet-affecting",
219
+ snapshot: "on-book",
220
+ query: "indexed-column",
221
+ localized: false,
222
+ visibility: ["staff", "customer", "partner"],
223
+ editRole: "none",
224
+ overrideFriction: "none",
225
+ sourceFreshness: "sync",
226
+ },
227
+ {
228
+ path: "inventoryMode",
229
+ class: "structural",
230
+ merge: "source-only",
231
+ drift: "high",
232
+ reindex: "entry",
233
+ snapshot: "on-book",
234
+ query: "indexed-column",
235
+ localized: false,
236
+ visibility: ["staff"],
237
+ editRole: "none",
238
+ overrideFriction: "none",
239
+ sourceFreshness: "sync",
240
+ },
241
+ {
242
+ path: "roomClass",
243
+ class: "structural",
244
+ merge: "source-only",
245
+ drift: "medium",
246
+ reindex: "facet-affecting",
247
+ snapshot: "on-book",
248
+ query: "indexed-column",
249
+ localized: false,
250
+ visibility: ["staff", "customer", "partner"],
251
+ editRole: "ops",
252
+ overrideFriction: "confirm",
253
+ sourceFreshness: "sync",
254
+ },
255
+ {
256
+ path: "active",
257
+ class: "structural",
258
+ merge: "source-only",
259
+ drift: "high",
260
+ reindex: "facet-affecting",
261
+ snapshot: "on-book",
262
+ query: "indexed-column",
263
+ localized: false,
264
+ visibility: ["staff"],
265
+ editRole: "none",
266
+ overrideFriction: "none",
267
+ sourceFreshness: "sync",
268
+ },
269
+ {
270
+ path: "smokingAllowed",
271
+ class: "structural",
272
+ merge: "source-only",
273
+ drift: "medium",
274
+ reindex: "facet-affecting",
275
+ snapshot: "on-book",
276
+ query: "indexed-column",
277
+ localized: false,
278
+ visibility: ["staff", "customer", "partner"],
279
+ editRole: "none",
280
+ overrideFriction: "none",
281
+ sourceFreshness: "sync",
282
+ },
283
+ {
284
+ path: "sortOrder",
285
+ class: "structural",
286
+ merge: "replace",
287
+ drift: "none",
288
+ reindex: "entry",
289
+ snapshot: "never",
290
+ query: "indexed-column",
291
+ localized: false,
292
+ visibility: ["staff"],
293
+ editRole: "ops",
294
+ overrideFriction: "none",
295
+ sourceFreshness: "sync",
296
+ },
297
+ // ── Occupancy / capacity (structural — drives search-side filtering) ──
298
+ {
299
+ path: "maxAdults",
300
+ class: "structural",
301
+ merge: "source-only",
302
+ drift: "medium",
303
+ reindex: "facet-affecting",
304
+ snapshot: "on-book",
305
+ query: "indexed-column",
306
+ localized: false,
307
+ visibility: ["staff", "customer", "partner"],
308
+ editRole: "none",
309
+ overrideFriction: "none",
310
+ sourceFreshness: "sync",
311
+ },
312
+ {
313
+ path: "maxChildren",
314
+ class: "structural",
315
+ merge: "source-only",
316
+ drift: "medium",
317
+ reindex: "facet-affecting",
318
+ snapshot: "on-book",
319
+ query: "indexed-column",
320
+ localized: false,
321
+ visibility: ["staff", "customer", "partner"],
322
+ editRole: "none",
323
+ overrideFriction: "none",
324
+ sourceFreshness: "sync",
325
+ },
326
+ {
327
+ path: "maxInfants",
328
+ class: "structural",
329
+ merge: "source-only",
330
+ drift: "medium",
331
+ reindex: "entry",
332
+ snapshot: "on-book",
333
+ query: "indexed-column",
334
+ localized: false,
335
+ visibility: ["staff", "customer", "partner"],
336
+ editRole: "none",
337
+ overrideFriction: "none",
338
+ sourceFreshness: "sync",
339
+ },
340
+ {
341
+ path: "standardOccupancy",
342
+ class: "structural",
343
+ merge: "source-only",
344
+ drift: "medium",
345
+ reindex: "facet-affecting",
346
+ snapshot: "on-book",
347
+ query: "indexed-column",
348
+ localized: false,
349
+ visibility: ["staff", "customer", "partner"],
350
+ editRole: "none",
351
+ overrideFriction: "none",
352
+ sourceFreshness: "sync",
353
+ },
354
+ {
355
+ path: "maxOccupancy",
356
+ class: "structural",
357
+ merge: "source-only",
358
+ drift: "medium",
359
+ reindex: "facet-affecting",
360
+ snapshot: "on-book",
361
+ query: "indexed-column",
362
+ localized: false,
363
+ visibility: ["staff", "customer", "partner"],
364
+ editRole: "none",
365
+ overrideFriction: "none",
366
+ sourceFreshness: "sync",
367
+ },
368
+ {
369
+ path: "minOccupancy",
370
+ class: "structural",
371
+ merge: "source-only",
372
+ drift: "medium",
373
+ reindex: "entry",
374
+ snapshot: "on-book",
375
+ query: "indexed-column",
376
+ localized: false,
377
+ visibility: ["staff", "customer", "partner"],
378
+ editRole: "none",
379
+ overrideFriction: "none",
380
+ sourceFreshness: "sync",
381
+ },
382
+ // ── Physical attributes ────────────────────────────────────────────────
383
+ {
384
+ path: "bedroomCount",
385
+ class: "structural",
386
+ merge: "source-only",
387
+ drift: "medium",
388
+ reindex: "facet-affecting",
389
+ snapshot: "on-book",
390
+ query: "indexed-column",
391
+ localized: false,
392
+ visibility: ["staff", "customer", "partner"],
393
+ editRole: "none",
394
+ overrideFriction: "none",
395
+ sourceFreshness: "sync",
396
+ },
397
+ {
398
+ path: "bathroomCount",
399
+ class: "structural",
400
+ merge: "source-only",
401
+ drift: "medium",
402
+ reindex: "facet-affecting",
403
+ snapshot: "on-book",
404
+ query: "indexed-column",
405
+ localized: false,
406
+ visibility: ["staff", "customer", "partner"],
407
+ editRole: "none",
408
+ overrideFriction: "none",
409
+ sourceFreshness: "sync",
410
+ },
411
+ {
412
+ path: "areaValue",
413
+ class: "structural",
414
+ merge: "source-only",
415
+ drift: "low",
416
+ reindex: "entry",
417
+ snapshot: "on-book",
418
+ query: "indexed-column",
419
+ localized: false,
420
+ visibility: ["staff", "customer", "partner"],
421
+ editRole: "none",
422
+ overrideFriction: "none",
423
+ sourceFreshness: "sync",
424
+ },
425
+ {
426
+ path: "areaUnit",
427
+ class: "managed",
428
+ merge: "source-only",
429
+ drift: "low",
430
+ reindex: "none",
431
+ snapshot: "on-book",
432
+ query: "blob-only",
433
+ localized: false,
434
+ visibility: ["staff", "customer", "partner"],
435
+ editRole: "none",
436
+ overrideFriction: "none",
437
+ sourceFreshness: "sync",
438
+ },
439
+ ];
440
+ export const accommodationCatalogPolicy = defineFieldPolicy(ACCOMMODATION_FIELD_POLICY);
441
+ export { ACCOMMODATION_FIELD_POLICY };
@@ -0,0 +1,5 @@
1
+ import { type AccommodationContent } from "@voyant-travel/accommodations-contracts/content-shape";
2
+ import { type ContentOverlay, type MergeOverlaysOptions } from "@voyant-travel/catalog";
3
+ export { ACCOMMODATION_CONTENT_SCHEMA_VERSION, type AccommodationAmenity, type AccommodationContent, type AccommodationMealPlan, type AccommodationPolicy, type AccommodationRatePlan, type AccommodationRoomType, accommodationAmenitySchema, accommodationContentSchema, accommodationMealPlanSchema, accommodationPolicySchema, accommodationRatePlanSchema, accommodationRoomTypeSchema, BOARD_BASIS_FROM_SHORT_CODE, BOARD_BASIS_SHORT_CODES, BOARD_BASIS_VALUES, type BoardBasis, type BoardBasisShortCode, boardBasisSchema, type HotelSummary, hotelSummarySchema, validateAccommodationContent, } from "@voyant-travel/accommodations-contracts/content-shape";
4
+ export declare function mergeOverlaysIntoAccommodationContent(payload: AccommodationContent, overlays: ReadonlyArray<ContentOverlay>, options?: Pick<MergeOverlaysOptions, "onOverlayError">): AccommodationContent;
5
+ //# sourceMappingURL=content-shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-shape.d.ts","sourceRoot":"","sources":["../src/content-shape.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,oBAAoB,EAG1B,MAAM,uDAAuD,CAAA;AAC9D,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,oBAAoB,EAE1B,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EACL,oCAAoC,EACpC,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,0BAA0B,EAC1B,0BAA0B,EAC1B,2BAA2B,EAC3B,yBAAyB,EACzB,2BAA2B,EAC3B,2BAA2B,EAC3B,2BAA2B,EAC3B,uBAAuB,EACvB,kBAAkB,EAClB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,gBAAgB,EAChB,KAAK,YAAY,EACjB,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,uDAAuD,CAAA;AAE9D,wBAAgB,qCAAqC,CACnD,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,EAAE,aAAa,CAAC,cAAc,CAAC,EACvC,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,gBAAgB,CAAM,GACzD,oBAAoB,CAStB"}
@@ -0,0 +1,13 @@
1
+ import { accommodationContentSchema, validateAccommodationContent, } from "@voyant-travel/accommodations-contracts/content-shape";
2
+ import { mergeOverlaysIntoContent, } from "@voyant-travel/catalog";
3
+ export { ACCOMMODATION_CONTENT_SCHEMA_VERSION, accommodationAmenitySchema, accommodationContentSchema, accommodationMealPlanSchema, accommodationPolicySchema, accommodationRatePlanSchema, accommodationRoomTypeSchema, BOARD_BASIS_FROM_SHORT_CODE, BOARD_BASIS_SHORT_CODES, BOARD_BASIS_VALUES, boardBasisSchema, hotelSummarySchema, validateAccommodationContent, } from "@voyant-travel/accommodations-contracts/content-shape";
4
+ export function mergeOverlaysIntoAccommodationContent(payload, overlays, options = {}) {
5
+ const merged = mergeOverlaysIntoContent(payload, overlays, {
6
+ validate(p) {
7
+ const r = validateAccommodationContent(p);
8
+ return r.valid ? { valid: true } : { valid: false, reason: r.reason };
9
+ },
10
+ onOverlayError: options.onOverlayError,
11
+ });
12
+ return accommodationContentSchema.parse(merged);
13
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Project a `AccommodationContent` payload into a `BookingDraftShape`.
3
+ *
4
+ * Hotel / room-type bookings need:
5
+ * - Configure: date-range (check-in → check-out) + occupancy.
6
+ * - Accommodation: room selection — the journey's
7
+ * `accommodation.subSteps` rooms variant, populated from
8
+ * `content.room_types[]`.
9
+ * - Add-ons: meal plans + amenities surfaced as upsells (when the
10
+ * supplier prices them as add-ons; otherwise they're informational).
11
+ *
12
+ * Pricing flows through liveResolve at quote time per night /
13
+ * occupancy / rate-plan.
14
+ */
15
+ import { type BookingDraftShape, type PaxBandSpec } from "@voyant-travel/catalog/booking-engine";
16
+ import type { AccommodationContent } from "./content-shape.js";
17
+ export declare const DEFAULT_ACCOMMODATION_PAX_BANDS: ReadonlyArray<PaxBandSpec>;
18
+ export interface BuildAccommodationDraftShapeOptions {
19
+ locale?: string;
20
+ paxBands?: ReadonlyArray<PaxBandSpec>;
21
+ paxBandsAllowedTotal?: {
22
+ min: number;
23
+ max: number;
24
+ };
25
+ /**
26
+ * Default minimum-nights window. Most bedbanks accept 1–30 nights;
27
+ * templates override per supplier when known.
28
+ */
29
+ minNights?: number;
30
+ maxNights?: number;
31
+ /** When true, the wizard allows multiple guests sharing one room. */
32
+ sharedRoomAllowed?: boolean;
33
+ }
34
+ export declare function buildAccommodationDraftShape(content: AccommodationContent, options?: BuildAccommodationDraftShapeOptions): BookingDraftShape;
35
+ //# sourceMappingURL=draft-shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"draft-shape.d.ts","sourceRoot":"","sources":["../src/draft-shape.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,KAAK,iBAAiB,EAItB,KAAK,WAAW,EAIjB,MAAM,uCAAuC,CAAA;AAE9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAE9D,eAAO,MAAM,+BAA+B,EAAE,aAAa,CAAC,WAAW,CAGtE,CAAA;AAED,MAAM,WAAW,mCAAmC;IAClD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAA;IACrC,oBAAoB,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IACnD;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,oBAAoB,EAC7B,OAAO,GAAE,mCAAwC,GAChD,iBAAiB,CAoEnB"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Project a `AccommodationContent` payload into a `BookingDraftShape`.
3
+ *
4
+ * Hotel / room-type bookings need:
5
+ * - Configure: date-range (check-in → check-out) + occupancy.
6
+ * - Accommodation: room selection — the journey's
7
+ * `accommodation.subSteps` rooms variant, populated from
8
+ * `content.room_types[]`.
9
+ * - Add-ons: meal plans + amenities surfaced as upsells (when the
10
+ * supplier prices them as add-ons; otherwise they're informational).
11
+ *
12
+ * Pricing flows through liveResolve at quote time per night /
13
+ * occupancy / rate-plan.
14
+ */
15
+ import { defaultBookingFields, defaultDraftShapeFlags, defaultTravelerFields, paxBandsAllowedTotalFrom, } from "@voyant-travel/catalog/booking-engine";
16
+ export const DEFAULT_ACCOMMODATION_PAX_BANDS = [
17
+ { code: "adult", label: "Adult", minCount: 1, maxCount: 6 },
18
+ { code: "child", label: "Child", minAge: 0, maxAge: 17, minCount: 0, maxCount: 4 },
19
+ ];
20
+ export function buildAccommodationDraftShape(content, options = {}) {
21
+ const paxBands = options.paxBands ?? DEFAULT_ACCOMMODATION_PAX_BANDS;
22
+ const total = options.paxBandsAllowedTotal ?? paxBandsAllowedTotalFrom(paxBands);
23
+ const minNights = options.minNights ?? 1;
24
+ const maxNights = options.maxNights ?? 30;
25
+ const sharedRoomAllowed = options.sharedRoomAllowed ?? true;
26
+ // Project each rate plan once. The journey filters per-room based
27
+ // on `applies_to_room_type_ids` (empty = applies to all rooms).
28
+ const planByRoom = new Map();
29
+ for (const rt of content.room_types) {
30
+ planByRoom.set(rt.id, []);
31
+ }
32
+ for (const plan of content.rate_plans) {
33
+ const rooms = plan.applies_to_room_type_ids.length === 0
34
+ ? content.room_types.map((r) => r.id)
35
+ : plan.applies_to_room_type_ids;
36
+ const planOption = {
37
+ id: plan.id,
38
+ name: plan.name,
39
+ description: plan.description ?? null,
40
+ chargeFrequency: plan.charge_frequency,
41
+ cancellationPolicy: plan.cancellation_policy ?? null,
42
+ inclusions: plan.inclusions,
43
+ };
44
+ for (const roomId of rooms) {
45
+ const list = planByRoom.get(roomId);
46
+ if (list)
47
+ list.push(planOption);
48
+ }
49
+ }
50
+ const roomOptions = content.room_types.map((rt) => ({
51
+ id: rt.id,
52
+ name: rt.name,
53
+ description: rt.description ?? null,
54
+ capacity: rt.max_occupancy ?? rt.max_adults ?? null,
55
+ baseRateHint: null,
56
+ ratePlans: planByRoom.get(rt.id) ?? [],
57
+ }));
58
+ return {
59
+ ...defaultDraftShapeFlags(),
60
+ showsAccommodation: roomOptions.length > 0,
61
+ paxBands,
62
+ paxBandsAllowedTotal: total,
63
+ travelerFields: defaultTravelerFields(),
64
+ bookingFields: defaultBookingFields(),
65
+ configureSubSteps: [
66
+ { kind: "date-range", minNights, maxNights },
67
+ { kind: "occupancy", bands: paxBands },
68
+ ],
69
+ accommodation: roomOptions.length > 0
70
+ ? {
71
+ roomOptions,
72
+ sharedRoomAllowed,
73
+ subSteps: [
74
+ {
75
+ kind: "rooms",
76
+ options: roomOptions,
77
+ sharedRoomAllowed,
78
+ },
79
+ ],
80
+ }
81
+ : undefined,
82
+ paymentIntents: ["hold", "card"],
83
+ };
84
+ }
@@ -0,0 +1,8 @@
1
+ export * from "./booking-engine/index.js";
2
+ export * from "./catalog-policy.js";
3
+ export * from "./content-shape.js";
4
+ export * from "./draft-shape.js";
5
+ export * from "./service-catalog-plane.js";
6
+ export * from "./service-content.js";
7
+ export * from "./service-content-synthesizer.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAA;AACzC,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,sBAAsB,CAAA;AACpC,cAAc,kCAAkC,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export * from "./booking-engine/index.js";
2
+ export * from "./catalog-policy.js";
3
+ export * from "./content-shape.js";
4
+ export * from "./draft-shape.js";
5
+ export * from "./service-catalog-plane.js";
6
+ export * from "./service-content.js";
7
+ export * from "./service-content-synthesizer.js";
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Accommodation content routes — sourced-aware detail endpoint.
3
+ *
4
+ * GET /:id/content
5
+ *
6
+ * Returns lodging detail content for sourced accommodation inventory:
7
+ * cache hit -> cached row + overlay merge; cache miss with rich adapter ->
8
+ * adapter fetch + write-through; cache miss with thin adapter -> synthesizer
9
+ * fallback.
10
+ */
11
+ import type { SourceAdapterRegistry } from "@voyant-travel/catalog/booking-engine";
12
+ import type { AnyDrizzleDb } from "@voyant-travel/db";
13
+ import type { Context } from "hono";
14
+ import { Hono } from "hono";
15
+ export interface AccommodationContentRoutesEnv {
16
+ Variables: {
17
+ db: AnyDrizzleDb;
18
+ };
19
+ }
20
+ export interface CreateAccommodationContentRoutesOptions {
21
+ resolveRegistry: (c: Context) => SourceAdapterRegistry;
22
+ onOverlayError?: (event: {
23
+ field_path: string;
24
+ reason: string;
25
+ }) => void;
26
+ defaultAcceptMachineTranslated?: boolean;
27
+ }
28
+ export declare function createAccommodationContentRoutes(options: CreateAccommodationContentRoutesOptions): Hono<AccommodationContentRoutesEnv>;
29
+ export declare function parseAcceptLanguage(header: string): string[];
30
+ export type AccommodationContentRoutes = ReturnType<typeof createAccommodationContentRoutes>;
31
+ //# sourceMappingURL=routes-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-content.d.ts","sourceRoot":"","sources":["../src/routes-content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AAClF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAI3B,MAAM,WAAW,6BAA6B;IAC5C,SAAS,EAAE;QACT,EAAE,EAAE,YAAY,CAAA;KACjB,CAAA;CACF;AAED,MAAM,WAAW,uCAAuC;IACtD,eAAe,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,qBAAqB,CAAA;IACtD,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;IACxE,8BAA8B,CAAC,EAAE,OAAO,CAAA;CACzC;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,uCAAuC,GAC/C,IAAI,CAAC,6BAA6B,CAAC,CA4DrC;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAqB5D;AAED,MAAM,MAAM,0BAA0B,GAAG,UAAU,CAAC,OAAO,gCAAgC,CAAC,CAAA"}