@voyant-travel/trips 0.112.0 → 0.114.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,63 @@
1
+ import { type CancelEntityResult, type OwnedBookingHandlerRegistry, type QuoteEntityDeps, type QuoteEntityResult, type QuoteResponseV1, type SourceAdapterRegistry } from "@voyant-travel/catalog/booking-engine";
2
+ import type { AnyDrizzleDb } from "@voyant-travel/db";
3
+ import type { CancelComponentInput, CancelComponentResult, CatalogComponentQuoteInput, ComponentCancellationPreview, ComponentCancellationPreviewInput, ComponentCheckoutInput, ComponentCheckoutResult, ReleaseReservedComponentInput, ReleaseReservedComponentResult, ReserveComponentInput, ReserveComponentResult } from "./service-types.js";
4
+ /** Per-request adapter context propagated to the catalog source adapters. */
5
+ export interface CatalogAdapterContext {
6
+ connection_id: string;
7
+ correlation_id: string;
8
+ }
9
+ /** Deployment-specific checkout hand-off for a reserved component. */
10
+ export type StartComponentCheckout = (input: ComponentCheckoutInput) => Promise<ComponentCheckoutResult>;
11
+ /**
12
+ * Deployment-supplied, request-scoped readers + registries for the catalog
13
+ * component adapter. These cross the boundaries trips must not import
14
+ * statically (process-local registries, commerce promotions, the deployment's
15
+ * tax recompute + checkout wiring) and so are injected.
16
+ */
17
+ export interface CatalogComponentAdapterOptions {
18
+ /** The per-request drizzle handle. */
19
+ db: AnyDrizzleDb;
20
+ /** Process-local source-adapter registry (deployment-assembled). */
21
+ registry: SourceAdapterRegistry;
22
+ /** Process-local owned-handler registry (deployment-assembled). */
23
+ ownedHandlers: OwnedBookingHandlerRegistry;
24
+ /**
25
+ * Promotion evaluator for the quote path. Injected because
26
+ * `createCatalogPromotionEvaluator` lives in commerce, which transitively
27
+ * (optionally) depends on quotes → trips.
28
+ */
29
+ evaluatePromotions: QuoteEntityDeps["evaluatePromotions"];
30
+ /**
31
+ * Customer-facing tax recompute applied to a quote result. Injected because
32
+ * the deployment resolves its own tax settings (a deployment reader) and the
33
+ * transform is shared with the catalog-booking route module.
34
+ */
35
+ transformQuoteResult: (result: QuoteEntityResult, entityModule: string, entityId: string, sourceKind: string) => Promise<QuoteEntityResult>;
36
+ /** Builds the per-request adapter context (correlation id, connection id). */
37
+ adapterContext: (connectionId: string | null | undefined) => CatalogAdapterContext;
38
+ /** Deployment-specific checkout hand-off (payment-provider wiring). */
39
+ startCheckout: StartComponentCheckout;
40
+ }
41
+ /** The catalog component orchestration surface produced by the factory. */
42
+ export interface CatalogComponentAdapter {
43
+ quote(input: CatalogComponentQuoteInput): Promise<QuoteResponseV1>;
44
+ reserve(input: ReserveComponentInput): Promise<ReserveComponentResult>;
45
+ release(input: ReleaseReservedComponentInput): Promise<ReleaseReservedComponentResult>;
46
+ previewCancellation(input: ComponentCancellationPreviewInput): Promise<ComponentCancellationPreview>;
47
+ cancel(input: CancelComponentInput): Promise<CancelComponentResult>;
48
+ startCheckout(input: ComponentCheckoutInput): Promise<ComponentCheckoutResult>;
49
+ }
50
+ /**
51
+ * Build the catalog-backed trip-component orchestration bound to a request's
52
+ * db + deployment registries/readers.
53
+ */
54
+ export declare function createCatalogComponentAdapter(options: CatalogComponentAdapterOptions): CatalogComponentAdapter;
55
+ /**
56
+ * Pure catalog-component cancellation preview. Has no db / registry reads —
57
+ * supplier cancellation previews aren't available, so the cancellation result
58
+ * itself is authoritative. Exported standalone so deployments can preview
59
+ * without constructing a request-scoped adapter.
60
+ */
61
+ export declare function previewCancellation(input: ComponentCancellationPreviewInput): Promise<ComponentCancellationPreview>;
62
+ export type { CancelEntityResult };
63
+ //# sourceMappingURL=catalog-component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-component.d.ts","sourceRoot":"","sources":["../src/catalog-component.ts"],"names":[],"mappings":"AAsCA,OAAO,EAKL,KAAK,kBAAkB,EAEvB,KAAK,2BAA2B,EAEhC,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EAGpB,KAAK,qBAAqB,EAC3B,MAAM,uCAAuC,CAAA;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrD,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,0BAA0B,EAC1B,4BAA4B,EAC5B,iCAAiC,EACjC,sBAAsB,EACtB,uBAAuB,EACvB,6BAA6B,EAC7B,8BAA8B,EAC9B,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,oBAAoB,CAAA;AAE3B,6EAA6E;AAC7E,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,sEAAsE;AACtE,MAAM,MAAM,sBAAsB,GAAG,CACnC,KAAK,EAAE,sBAAsB,KAC1B,OAAO,CAAC,uBAAuB,CAAC,CAAA;AAErC;;;;;GAKG;AACH,MAAM,WAAW,8BAA8B;IAC7C,sCAAsC;IACtC,EAAE,EAAE,YAAY,CAAA;IAChB,oEAAoE;IACpE,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,mEAAmE;IACnE,aAAa,EAAE,2BAA2B,CAAA;IAC1C;;;;OAIG;IACH,kBAAkB,EAAE,eAAe,CAAC,oBAAoB,CAAC,CAAA;IACzD;;;;OAIG;IACH,oBAAoB,EAAE,CACpB,MAAM,EAAE,iBAAiB,EACzB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAC/B,8EAA8E;IAC9E,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,KAAK,qBAAqB,CAAA;IAClF,uEAAuE;IACvE,aAAa,EAAE,sBAAsB,CAAA;CACtC;AAED,2EAA2E;AAC3E,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,KAAK,EAAE,0BAA0B,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAClE,OAAO,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAA;IACtE,OAAO,CAAC,KAAK,EAAE,6BAA6B,GAAG,OAAO,CAAC,8BAA8B,CAAC,CAAA;IACtF,mBAAmB,CACjB,KAAK,EAAE,iCAAiC,GACvC,OAAO,CAAC,4BAA4B,CAAC,CAAA;IACxC,MAAM,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACnE,aAAa,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;CAC/E;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,8BAA8B,GACtC,uBAAuB,CAuLzB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,iCAAiC,GACvC,OAAO,CAAC,4BAA4B,CAAC,CA6BvC;AAkJD,YAAY,EAAE,kBAAkB,EAAE,CAAA"}
@@ -0,0 +1,349 @@
1
+ /**
2
+ * Catalog-backed trip-component orchestration — owned by `@voyant-travel/trips`.
3
+ *
4
+ * Trips owns the reserve/checkout flow for catalog-backed components, so the
5
+ * orchestration that turns a `TripComponent` into a catalog booking-engine
6
+ * quote / reservation / cancellation lives here rather than in any deployment:
7
+ * - offer validation (`quote`) + customer-facing tax recompute hand-off,
8
+ * - reserve-with-origin-tracking (stamp the booking's catalog reservation
9
+ * origin so the component → booking link survives),
10
+ * - hold release (compensation) + cancellation preview + cancel,
11
+ * - checkout hand-off.
12
+ *
13
+ * WHY SOME PIECES ARE INJECTED (not imported):
14
+ *
15
+ * Trips depends acyclically on `@voyant-travel/catalog` (booking-engine) and
16
+ * `@voyant-travel/bookings` (origin upsert), so those are imported directly.
17
+ * Three things stay deployment-supplied and are injected via `options`:
18
+ *
19
+ * 1. The `SourceAdapterRegistry` / `OwnedBookingHandlerRegistry` — these are
20
+ * process-local registries assembled from a deployment's installed source
21
+ * adapters + owned vertical handlers. They live in the deployment.
22
+ * 2. The promotion evaluator — `createCatalogPromotionEvaluator` lives in
23
+ * `@voyant-travel/commerce`, and `commerce → quotes → trips` would make a
24
+ * package cycle. So the evaluator is injected.
25
+ * 3. The customer-facing tax recompute (`transformQuoteResult`) — the operator
26
+ * resolves its own tax settings (a deployment reader) and the transform is
27
+ * shared with the catalog-booking route module, so it stays in the
28
+ * deployment and is injected.
29
+ * 4. The checkout starter (`startCatalogCheckout`) — deployment-specific
30
+ * payment-provider wiring.
31
+ *
32
+ * Behaviour is byte-for-byte equivalent to the operator's previous
33
+ * `trips-catalog-runtime.ts`.
34
+ */
35
+ import { toCatalogReservationBookingOriginInput, upsertBookingOrigin, } from "@voyant-travel/bookings";
36
+ import { bookEntity, bookingDraftV1, cancelEntity, quoteEntity, quoteResponseV1, } from "@voyant-travel/catalog/booking-engine";
37
+ import { toBookingDraftV1 } from "./catalog-component-adapter.js";
38
+ /**
39
+ * Build the catalog-backed trip-component orchestration bound to a request's
40
+ * db + deployment registries/readers.
41
+ */
42
+ export function createCatalogComponentAdapter(options) {
43
+ const { db, registry, ownedHandlers, evaluatePromotions, transformQuoteResult, adapterContext } = options;
44
+ async function quote(input) {
45
+ const component = input.component;
46
+ const entityModule = required(component.entityModule, "component.entityModule");
47
+ const entityId = required(component.entityId, "component.entityId");
48
+ const sourceKind = required(component.sourceKind, "component.sourceKind");
49
+ const result = await quoteEntity(db, {
50
+ registry,
51
+ ownedHandlers,
52
+ evaluatePromotions,
53
+ }, {
54
+ entityModule,
55
+ entityId,
56
+ sourceKind,
57
+ sourceConnectionId: component.sourceConnectionId ?? undefined,
58
+ sourceRef: component.sourceRef ?? undefined,
59
+ scope: {
60
+ locale: input.scope.locale ?? "en-GB",
61
+ audience: input.scope.audience ?? "staff",
62
+ market: input.scope.market ?? "default",
63
+ currency: input.scope.currency,
64
+ },
65
+ parameters: engineParametersFromBookingDraft(undefined, input.bookingDraft),
66
+ ttlMs: input.ttlMs,
67
+ adapterContext: adapterContext(component.sourceConnectionId ?? sourceKind),
68
+ });
69
+ const transformed = await transformQuoteResult(result, entityModule, entityId, sourceKind);
70
+ return serializeQuoteResult(transformed);
71
+ }
72
+ async function reserve(input) {
73
+ const component = input.component;
74
+ const quoteId = required(component.catalogQuoteId, "component.catalogQuoteId");
75
+ const bookingDraft = bookingDraftFromComponent(component);
76
+ // The trips can start underlying bookings in draft status. When the
77
+ // operator leaves that option unchecked, the resulting booking lands in
78
+ // `awaiting_payment`. The owned products handler reads this off
79
+ // `request.parameters.initialStatus` and forwards it to the bridge.
80
+ const createAsDraft = readBoolean(input.envelope.constraints?.createAsDraft);
81
+ const initialStatus = createAsDraft ? "draft" : "awaiting_payment";
82
+ const result = await bookEntity(db, {
83
+ registry,
84
+ ownedHandlers,
85
+ }, {
86
+ quoteId,
87
+ party: {
88
+ draft: bookingDraft,
89
+ travelerParty: input.envelope.travelerParty,
90
+ },
91
+ paymentIntent: { type: "hold" },
92
+ parameters: { ...engineParametersFromBookingDraft(undefined, bookingDraft), initialStatus },
93
+ idempotencyKey: componentReserveIdempotencyKey(component.id, quoteId),
94
+ adapterContext: adapterContext(component.sourceConnectionId ?? component.sourceKind),
95
+ });
96
+ if (result.status === "failed") {
97
+ throw new Error("component_reservation_failed");
98
+ }
99
+ const orderRef = result.orderRef || result.snapshotId;
100
+ if (result.bookingId) {
101
+ await upsertBookingOrigin(db, toCatalogReservationBookingOriginInput({
102
+ bookingId: result.bookingId,
103
+ tripEnvelopeId: input.envelope.id,
104
+ tripComponentId: component.id,
105
+ reservationPlanId: input.reservationPlanId,
106
+ catalogPriceResponseId: quoteId,
107
+ catalogSnapshotId: result.snapshotId,
108
+ providerSourceKind: component.sourceKind,
109
+ providerSourceConnectionId: component.sourceConnectionId,
110
+ providerSourceRef: component.sourceRef,
111
+ providerOrderRef: orderRef,
112
+ metadata: {
113
+ entityModule: component.entityModule,
114
+ entityId: component.entityId,
115
+ createAsDraft,
116
+ },
117
+ }));
118
+ }
119
+ return {
120
+ status: bookStatusToComponentStatus(result.status),
121
+ bookingId: result.bookingId,
122
+ orderId: orderRef,
123
+ providerRef: orderRef,
124
+ supplierRef: orderRef,
125
+ warnings: result.status === "held" ? undefined : [`booking_engine_status:${result.status}`],
126
+ };
127
+ }
128
+ async function release(input) {
129
+ const component = input.component;
130
+ if (!component.bookingId || !component.entityModule || !component.entityId) {
131
+ return { released: false, reason: "missing_component_booking_ref" };
132
+ }
133
+ try {
134
+ const result = await cancelEntity(db, { registry }, {
135
+ bookingId: component.bookingId,
136
+ entityModule: component.entityModule,
137
+ entityId: component.entityId,
138
+ reason: "Trips compensation",
139
+ adapterContext: adapterContext(component.sourceConnectionId ?? component.sourceKind),
140
+ });
141
+ return {
142
+ released: result.status === "cancelled",
143
+ reason: result.status === "refused" ? "cancel_refused" : undefined,
144
+ };
145
+ }
146
+ catch (error) {
147
+ return {
148
+ released: false,
149
+ reason: error instanceof Error ? error.message : "release_failed",
150
+ };
151
+ }
152
+ }
153
+ async function cancel(input) {
154
+ const component = input.component;
155
+ if (!component.bookingId || !component.entityModule || !component.entityId) {
156
+ return { status: "refused", reason: "missing_component_booking_ref" };
157
+ }
158
+ const result = await cancelEntity(db, { registry }, {
159
+ bookingId: component.bookingId,
160
+ entityModule: component.entityModule,
161
+ entityId: component.entityId,
162
+ reason: input.reason,
163
+ adapterContext: adapterContext(component.sourceConnectionId ?? component.sourceKind),
164
+ });
165
+ // Catalog adapters can return "pending" when an async cancel was submitted
166
+ // (email/partner-portal/batch) and the inventory hasn't been released yet.
167
+ // The trips's `CancelComponentResult` doesn't model that state;
168
+ // surface it as `refused` with a reason so the trip lands in remediation
169
+ // and the operator follows up out-of-band. `pending_channel` flows through
170
+ // the reason so the UI can show where the request went.
171
+ const status = result.status === "pending" ? "refused" : result.status;
172
+ const reason = result.status === "cancelled"
173
+ ? undefined
174
+ : result.status === "pending"
175
+ ? `cancel_pending${result.pendingChannel ? `:${result.pendingChannel}` : ""}`
176
+ : `cancel_${result.status}`;
177
+ return {
178
+ status,
179
+ refundAmountCents: result.refundAmount,
180
+ refundCurrency: result.refundCurrency,
181
+ reason,
182
+ snapshot: { snapshotId: result.snapshotId },
183
+ };
184
+ }
185
+ function startCheckout(input) {
186
+ return options.startCheckout(input);
187
+ }
188
+ return { quote, reserve, release, previewCancellation, cancel, startCheckout };
189
+ }
190
+ /**
191
+ * Pure catalog-component cancellation preview. Has no db / registry reads —
192
+ * supplier cancellation previews aren't available, so the cancellation result
193
+ * itself is authoritative. Exported standalone so deployments can preview
194
+ * without constructing a request-scoped adapter.
195
+ */
196
+ export function previewCancellation(input) {
197
+ const component = input.component;
198
+ if (!component.bookingId || !component.entityModule || !component.entityId) {
199
+ return Promise.resolve({
200
+ componentId: component.id,
201
+ action: "staff_remediation",
202
+ currentStatus: component.status,
203
+ staffActionRequired: true,
204
+ reason: "missing_component_booking_ref",
205
+ });
206
+ }
207
+ return Promise.resolve({
208
+ componentId: component.id,
209
+ action: "cancel",
210
+ currentStatus: component.status,
211
+ staffActionRequired: false,
212
+ refundAmountCents: 0,
213
+ refundCurrency: component.componentCurrency ?? undefined,
214
+ penaltyAmountCents: 0,
215
+ policySummary: "Supplier cancellation preview is not available; cancellation result is authoritative.",
216
+ snapshot: {
217
+ bookingId: component.bookingId,
218
+ entityModule: component.entityModule,
219
+ entityId: component.entityId,
220
+ sourceKind: component.sourceKind,
221
+ },
222
+ });
223
+ }
224
+ // ── Pure helpers (vertical-agnostic) ────────────────────────────────────────
225
+ function bookingDraftFromComponent(component) {
226
+ const metadata = component.metadata;
227
+ const candidate = metadata.bookingDraftV1 ?? metadata.bookingDraft;
228
+ if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) {
229
+ return bookingDraftV1.parse(candidate);
230
+ }
231
+ return toBookingDraftV1(component);
232
+ }
233
+ function serializeQuoteResult(result) {
234
+ return quoteResponseV1.parse({
235
+ ...result,
236
+ quotedAt: result.quotedAt.toISOString(),
237
+ expiresAt: result.expiresAt.toISOString(),
238
+ pricing: toPricingBreakdownV1(result.pricing),
239
+ });
240
+ }
241
+ function toPricingBreakdownV1(basis) {
242
+ if (!basis)
243
+ return undefined;
244
+ if (basis.breakdown) {
245
+ const breakdown = basis.breakdown;
246
+ if (breakdown.currency && Array.isArray(breakdown.lines) && Array.isArray(breakdown.taxes)) {
247
+ return breakdown;
248
+ }
249
+ }
250
+ const lines = [
251
+ {
252
+ kind: "base",
253
+ label: "Base",
254
+ quantity: 1,
255
+ unitAmount: basis.base_amount,
256
+ totalAmount: basis.base_amount,
257
+ },
258
+ ];
259
+ if (basis.fees > 0) {
260
+ lines.push({ kind: "fee", label: "Fees", unitAmount: basis.fees, totalAmount: basis.fees });
261
+ }
262
+ if (basis.surcharges > 0) {
263
+ lines.push({
264
+ kind: "supplement",
265
+ label: "Surcharges",
266
+ unitAmount: basis.surcharges,
267
+ totalAmount: basis.surcharges,
268
+ });
269
+ }
270
+ const subtotal = basis.base_amount + basis.fees + basis.surcharges;
271
+ return {
272
+ currency: basis.currency,
273
+ lines,
274
+ taxes: basis.taxes > 0
275
+ ? [
276
+ {
277
+ code: "tax",
278
+ label: "Tax",
279
+ rate: 0,
280
+ amount: basis.taxes,
281
+ base: basis.base_amount,
282
+ },
283
+ ]
284
+ : [],
285
+ subtotal,
286
+ taxTotal: basis.taxes,
287
+ total: subtotal + basis.taxes,
288
+ };
289
+ }
290
+ function bookStatusToComponentStatus(status) {
291
+ return status === "held" ? "held" : "booked";
292
+ }
293
+ function componentReserveIdempotencyKey(componentId, quoteId) {
294
+ return `trips:${componentId}:${quoteId}`.slice(0, 128);
295
+ }
296
+ function engineParametersFromBookingDraft(parameters, bookingDraftPayload) {
297
+ const bookingDraft = asRecord(bookingDraftPayload);
298
+ const configure = asRecord(bookingDraft?.configure);
299
+ const departureSlotId = stringValue(configure?.departureSlotId);
300
+ const paxCount = sumBookingDraftPax(configure?.pax);
301
+ const next = {
302
+ ...(parameters ?? {}),
303
+ ...(bookingDraft ? { draft: bookingDraft } : {}),
304
+ };
305
+ if (departureSlotId) {
306
+ if (next.departureSlotId == null)
307
+ next.departureSlotId = departureSlotId;
308
+ if (next.departure_id == null)
309
+ next.departure_id = departureSlotId;
310
+ if (next.slotId == null)
311
+ next.slotId = departureSlotId;
312
+ }
313
+ if (paxCount > 0 && next.paxCount == null) {
314
+ next.paxCount = paxCount;
315
+ }
316
+ const promotionCode = stringValue(bookingDraft?.promotionCode);
317
+ if (promotionCode && next.promotionCode == null) {
318
+ next.promotionCode = promotionCode;
319
+ }
320
+ return next;
321
+ }
322
+ function readBoolean(value) {
323
+ return value === true;
324
+ }
325
+ function asRecord(value) {
326
+ return value && typeof value === "object" && !Array.isArray(value)
327
+ ? value
328
+ : undefined;
329
+ }
330
+ function stringValue(value) {
331
+ return typeof value === "string" && value.length > 0 ? value : null;
332
+ }
333
+ function sumBookingDraftPax(value) {
334
+ const pax = asRecord(value);
335
+ if (!pax)
336
+ return 0;
337
+ let total = 0;
338
+ for (const count of Object.values(pax)) {
339
+ if (typeof count === "number" && Number.isFinite(count) && count > 0) {
340
+ total += count;
341
+ }
342
+ }
343
+ return total;
344
+ }
345
+ function required(value, label) {
346
+ if (!value)
347
+ throw new Error(`${label} is required`);
348
+ return value;
349
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Non-catalog (flight) trip-component orchestration — owned by
3
+ * `@voyant-travel/trips`.
4
+ *
5
+ * Trips owns the reserve/checkout flow for flight placeholder components, so the
6
+ * orchestration that prices a selected flight offer before reserve (detecting
7
+ * price changes / expiry) and books the held flight order lives here:
8
+ * - flight preflight + price-change detection (`validateBeforeReserve`),
9
+ * - passenger-roster building (DOB / contact fallbacks) + billing mapping,
10
+ * - reserve (book the held flight order).
11
+ *
12
+ * WHY THE FLIGHT ADAPTER IS INJECTED (not imported):
13
+ *
14
+ * Trips reads flight *contract types* from `@voyant-travel/flights` (a leaf
15
+ * contract dependency, acyclic), but the concrete adapter
16
+ * (`createDemoFlightAdapter` from `@voyant-travel/plugin-flights-demo`) is
17
+ * deployment-specific provider wiring — which provider, which base URL — so it
18
+ * is injected via `options.adapter` rather than imported. The price/expiry
19
+ * detection, passenger mapping, and billing fallbacks are vertical-agnostic
20
+ * orchestration and live here.
21
+ *
22
+ * Behaviour is byte-for-byte equivalent to the operator's previous
23
+ * `trips-flight-runtime.ts`.
24
+ */
25
+ import type { FlightBookRequest, FlightOffer, FlightOrder } from "@voyant-travel/flights/contract/types";
26
+ import type { ReserveComponentInput, ReserveComponentPreflightResult, ReserveComponentResult } from "./service-types.js";
27
+ /** Per-request adapter context propagated to the flight adapter. */
28
+ export interface FlightAdapterContext {
29
+ connectionId: string;
30
+ correlationId?: string;
31
+ }
32
+ /**
33
+ * The minimal flight-adapter surface the orchestration needs. Injected because
34
+ * the concrete adapter is deployment-specific provider wiring.
35
+ */
36
+ export interface FlightComponentAdapter {
37
+ priceOffer(ctx: FlightAdapterContext, request: {
38
+ offerId: string;
39
+ offer?: FlightOffer;
40
+ }): Promise<{
41
+ offer: FlightOffer;
42
+ valid: boolean;
43
+ invalidReason?: string;
44
+ }>;
45
+ bookFlight(ctx: FlightAdapterContext, request: FlightBookRequest): Promise<{
46
+ order: FlightOrder;
47
+ }>;
48
+ }
49
+ /** Deployment-supplied, request-scoped flight wiring. */
50
+ export interface FlightComponentAdapterOptions {
51
+ /** The deployment-specific flight adapter (provider + base URL). */
52
+ adapter: FlightComponentAdapter;
53
+ /** Per-request adapter context (connection id + correlation id). */
54
+ adapterContext: FlightAdapterContext;
55
+ }
56
+ /** The flight component orchestration surface produced by the factory. */
57
+ export interface FlightComponentAdapterApi {
58
+ validateBeforeReserve(input: ReserveComponentInput): Promise<ReserveComponentPreflightResult | null>;
59
+ reserve(input: ReserveComponentInput): Promise<ReserveComponentResult | null>;
60
+ }
61
+ /**
62
+ * Build the flight (non-catalog) trip-component orchestration bound to a
63
+ * request's flight adapter + adapter context.
64
+ */
65
+ export declare function createFlightComponentAdapter(options: FlightComponentAdapterOptions): FlightComponentAdapterApi;
66
+ //# sourceMappingURL=flight-component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flight-component.d.ts","sourceRoot":"","sources":["../src/flight-component.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,EAEV,iBAAiB,EACjB,WAAW,EACX,WAAW,EAGZ,MAAM,uCAAuC,CAAA;AAG9C,OAAO,KAAK,EACV,qBAAqB,EACrB,+BAA+B,EAC/B,sBAAsB,EACvB,MAAM,oBAAoB,CAAA;AAE3B,oEAAoE;AACpE,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,UAAU,CACR,GAAG,EAAE,oBAAoB,EACzB,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,WAAW,CAAA;KAAE,GAChD,OAAO,CAAC;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC1E,UAAU,CAAC,GAAG,EAAE,oBAAoB,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,WAAW,CAAA;KAAE,CAAC,CAAA;CACnG;AAED,yDAAyD;AACzD,MAAM,WAAW,6BAA6B;IAC5C,oEAAoE;IACpE,OAAO,EAAE,sBAAsB,CAAA;IAC/B,oEAAoE;IACpE,cAAc,EAAE,oBAAoB,CAAA;CACrC;AAED,0EAA0E;AAC1E,MAAM,WAAW,yBAAyB;IACxC,qBAAqB,CACnB,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,+BAA+B,GAAG,IAAI,CAAC,CAAA;IAClD,OAAO,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAA;CAC9E;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,6BAA6B,GACrC,yBAAyB,CAyG3B"}
@@ -0,0 +1,177 @@
1
+ import { formatTripBillingName, readTripBilling, splitTripBillingName } from "./checkout/index.js";
2
+ /**
3
+ * Build the flight (non-catalog) trip-component orchestration bound to a
4
+ * request's flight adapter + adapter context.
5
+ */
6
+ export function createFlightComponentAdapter(options) {
7
+ const { adapter, adapterContext } = options;
8
+ async function validateBeforeReserve(input) {
9
+ if (input.component.kind !== "flight_placeholder")
10
+ return null;
11
+ const flightDraft = asRecord(input.component.metadata)?.flightDraft;
12
+ const draftRecord = asRecord(flightDraft);
13
+ const selectedOffer = draftRecord?.selectedOffer;
14
+ const offerId = stringValue(draftRecord?.offerId) ?? selectedOffer?.offerId;
15
+ if (!selectedOffer || !offerId) {
16
+ return { status: "unavailable", reason: "flight_offer_required" };
17
+ }
18
+ try {
19
+ const priced = await adapter.priceOffer(adapterContext, {
20
+ offerId,
21
+ offer: selectedOffer,
22
+ });
23
+ if (!priced.valid) {
24
+ return {
25
+ status: "unavailable",
26
+ reason: priced.invalidReason ?? "flight_offer_unavailable",
27
+ details: { offerId },
28
+ };
29
+ }
30
+ const previousPricing = asRecord(draftRecord?.pricing);
31
+ const ancillaryAmountCents = numberValue(previousPricing?.ancillaryAmountCents) ?? 0;
32
+ const currentTotalAmountCents = moneyToCents(priced.offer.totalPrice.amount) + ancillaryAmountCents;
33
+ const previousTotalAmountCents = input.component.componentTotalAmountCents ??
34
+ numberValue(previousPricing?.totalAmountCents) ??
35
+ 0;
36
+ const currentCurrency = priced.offer.totalPrice.currency;
37
+ const previousCurrency = input.component.componentCurrency ??
38
+ stringValue(previousPricing?.currency) ??
39
+ currentCurrency;
40
+ if (currentCurrency !== previousCurrency ||
41
+ currentTotalAmountCents !== previousTotalAmountCents) {
42
+ return {
43
+ status: "price_changed",
44
+ reason: "flight_price_changed",
45
+ details: {
46
+ offerId,
47
+ previous: {
48
+ currency: previousCurrency,
49
+ totalAmountCents: previousTotalAmountCents,
50
+ },
51
+ current: {
52
+ currency: currentCurrency,
53
+ totalAmountCents: currentTotalAmountCents,
54
+ },
55
+ },
56
+ };
57
+ }
58
+ return { status: "ok" };
59
+ }
60
+ catch (error) {
61
+ return {
62
+ status: isExpiredOffer(selectedOffer) ? "expired" : "unavailable",
63
+ reason: error instanceof Error ? error.message : "flight_offer_unavailable",
64
+ details: { offerId },
65
+ };
66
+ }
67
+ }
68
+ async function reserve(input) {
69
+ if (input.component.kind !== "flight_placeholder")
70
+ return null;
71
+ const flightDraft = asRecord(input.component.metadata)?.flightDraft;
72
+ const selectedOffer = asRecord(flightDraft)?.selectedOffer;
73
+ if (!selectedOffer?.offerId) {
74
+ throw new Error("flight_offer_required");
75
+ }
76
+ const request = {
77
+ offerId: selectedOffer.offerId,
78
+ offer: selectedOffer,
79
+ passengers: flightPassengersFromTravelerParty(input.envelope.travelerParty),
80
+ contact: flightContactFromTravelerParty(input.envelope.travelerParty),
81
+ paymentIntent: { type: "hold" },
82
+ ancillaries: asRecord(flightDraft)?.ancillaries,
83
+ };
84
+ const response = await adapter.bookFlight(adapterContext, request);
85
+ const order = response.order;
86
+ return {
87
+ status: order.status === "ticketed" ? "booked" : "held",
88
+ orderId: order.orderId,
89
+ providerRef: order.pnr ?? order.orderId,
90
+ supplierRef: order.orderId,
91
+ holdExpiresAt: order.paymentDeadline,
92
+ warnings: order.paymentDeadline ? undefined : ["flight_hold_deadline_missing"],
93
+ };
94
+ }
95
+ return { validateBeforeReserve, reserve };
96
+ }
97
+ // ── Pure helpers (vertical-agnostic) ────────────────────────────────────────
98
+ function moneyToCents(amount) {
99
+ const parsed = Number.parseFloat(amount);
100
+ return Number.isFinite(parsed) ? Math.round(parsed * 100) : 0;
101
+ }
102
+ function isExpiredOffer(offer) {
103
+ const expiresAt = offer.expiresAt ? new Date(offer.expiresAt) : null;
104
+ return Boolean(expiresAt && expiresAt.getTime() <= Date.now());
105
+ }
106
+ function flightPassengersFromTravelerParty(travelerParty) {
107
+ const travelers = Array.isArray(travelerParty.travelers)
108
+ ? travelerParty.travelers
109
+ : [];
110
+ const passengers = travelers.map((traveler, index) => flightPassengerFromTraveler(asRecord(traveler) ?? {}, index));
111
+ if (passengers.length > 0)
112
+ return passengers;
113
+ const billing = readTripBilling(travelerParty);
114
+ const names = splitTripBillingName(formatTripBillingName(billing) ?? "Lead traveler");
115
+ return [
116
+ {
117
+ passengerId: "traveler_1",
118
+ type: "adult",
119
+ firstName: names.firstName,
120
+ lastName: names.lastName,
121
+ dateOfBirth: "1990-01-01",
122
+ ...(billing.contact?.email ? { email: billing.contact.email } : {}),
123
+ ...(billing.contact?.phone ? { phone: billing.contact.phone } : {}),
124
+ },
125
+ ];
126
+ }
127
+ function flightPassengerFromTraveler(traveler, index) {
128
+ const type = passengerTypeFromRole(stringValue(traveler.role));
129
+ return {
130
+ passengerId: stringValue(traveler.localId) || stringValue(traveler.personId) || `traveler_${index + 1}`,
131
+ type,
132
+ firstName: stringValue(traveler.firstName) || fallbackFirstName(type),
133
+ lastName: stringValue(traveler.lastName) || `${index + 1}`,
134
+ dateOfBirth: stringValue(traveler.dateOfBirth) || fallbackDobForPassengerType(type),
135
+ ...(stringValue(traveler.email) ? { email: stringValue(traveler.email) ?? undefined } : {}),
136
+ ...(stringValue(traveler.phone) ? { phone: stringValue(traveler.phone) ?? undefined } : {}),
137
+ };
138
+ }
139
+ function passengerTypeFromRole(role) {
140
+ if (role === "child")
141
+ return "child";
142
+ if (role === "infant")
143
+ return "infant";
144
+ return "adult";
145
+ }
146
+ function fallbackFirstName(type) {
147
+ if (type === "child")
148
+ return "Child";
149
+ if (type === "infant")
150
+ return "Infant";
151
+ return "Adult";
152
+ }
153
+ function fallbackDobForPassengerType(type) {
154
+ if (type === "child")
155
+ return "2016-01-01";
156
+ if (type === "infant")
157
+ return "2025-01-01";
158
+ return "1990-01-01";
159
+ }
160
+ function flightContactFromTravelerParty(travelerParty) {
161
+ const billing = readTripBilling(travelerParty);
162
+ return {
163
+ ...(billing.contact?.email ? { email: billing.contact.email } : {}),
164
+ ...(billing.contact?.phone ? { phone: billing.contact.phone } : {}),
165
+ };
166
+ }
167
+ function asRecord(value) {
168
+ return value && typeof value === "object" && !Array.isArray(value)
169
+ ? value
170
+ : undefined;
171
+ }
172
+ function stringValue(value) {
173
+ return typeof value === "string" && value.length > 0 ? value : null;
174
+ }
175
+ function numberValue(value) {
176
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
177
+ }
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import type { Module } from "@voyant-travel/core";
2
2
  import type { HonoModule } from "@voyant-travel/hono/module";
3
3
  import { type TripsRoutesOptions } from "./routes.js";
4
+ export { type CatalogAdapterContext, type CatalogComponentAdapter, type CatalogComponentAdapterOptions, createCatalogComponentAdapter, previewCancellation, type StartComponentCheckout, } from "./catalog-component.js";
4
5
  export { type CatalogComponentBookingDraftOverrides, isCatalogBackedTripComponent, toBookingDraftV1, } from "./catalog-component-adapter.js";
5
6
  export { CRUISE_EXTENSION_METADATA_KIND, type CruiseExtensionExtra, type CruiseExtensionLifecycle, type CruiseExtensionLinkCommand, type CruiseExtensionLinkInput, type CruiseExtensionPlacement, type CruiseExtensionRepresentation, type CruiseExtensionSelection, type CruiseExtensionTargetKind, createCruiseExtensionComponent, createCruiseExtensionExtra, createCruiseExtensionLinkCommand, cruiseExtensionLinkKey, groupCruiseExtensionLinksByProduct, representCruiseExtensionSelection, } from "./cruise-extension.js";
7
+ export { createFlightComponentAdapter, type FlightAdapterContext, type FlightComponentAdapter, type FlightComponentAdapterApi, type FlightComponentAdapterOptions, } from "./flight-component.js";
6
8
  export type { TripsRoutes, TripsRoutesOptions } from "./routes.js";
7
9
  export { createTripsRoutes } from "./routes.js";
8
10
  export declare const tripsModule: Module;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAE5D,OAAO,EAAqB,KAAK,kBAAkB,EAAe,MAAM,aAAa,CAAA;AAErF,OAAO,EACL,KAAK,qCAAqC,EAC1C,4BAA4B,EAC5B,gBAAgB,GACjB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EACL,8BAA8B,EAC9B,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,8BAA8B,EAC9B,0BAA0B,EAC1B,gCAAgC,EAChC,sBAAsB,EACtB,kCAAkC,EAClC,iCAAiC,GAClC,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAE/C,eAAO,MAAM,WAAW,EAAE,MAEzB,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,UAG7B,CAAA;AAED,MAAM,WAAW,sBAAuB,SAAQ,kBAAkB;IAChE,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B,cAWzE;AAED,YAAY,EACV,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,aAAa,GACd,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EACL,KAAK,4BAA4B,EACjC,qBAAqB,EACrB,4BAA4B,EAC5B,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,cAAc,GACf,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAChF,OAAO,EACL,KAAK,cAAc,EACnB,cAAc,EACd,KAAK,aAAa,EAClB,aAAa,EACb,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,eAAe,EACf,cAAc,EACd,KAAK,gBAAgB,EACrB,aAAa,GACd,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,YAAY,EACV,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,sBAAsB,EACtB,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,4BAA4B,EAC5B,4BAA4B,EAC5B,YAAY,EACZ,2BAA2B,EAC3B,mBAAmB,EACnB,uCAAuC,EACvC,oCAAoC,EACpC,kCAAkC,EAClC,YAAY,EACZ,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,EACvB,cAAc,EACd,sBAAsB,EACtB,aAAa,EACb,6BAA6B,EAC7B,oBAAoB,EACpB,aAAa,GACd,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,gCAAgC,EAChC,+BAA+B,EAC/B,iCAAiC,EACjC,mCAAmC,EACnC,yBAAyB,EACzB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,KAAK,iCAAiC,EACtC,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,8BAA8B,EAC9B,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,8BAA8B,EAC9B,iBAAiB,EACjB,KAAK,2BAA2B,EAChC,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,4BAA4B,EAC5B,KAAK,6BAA6B,EAClC,KAAK,8BAA8B,EACnC,KAAK,qBAAqB,EAC1B,KAAK,+BAA+B,EACpC,KAAK,+BAA+B,EACpC,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,6BAA6B,EAC7B,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,4BAA4B,EACjC,KAAK,kCAAkC,EACvC,KAAK,8BAA8B,EACnC,KAAK,+BAA+B,EACpC,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,IAAI,EACT,KAAK,6BAA6B,EAClC,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,gCAAgC,EACrC,mBAAmB,EACnB,qBAAqB,EACrB,YAAY,GACb,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,+BAA+B,EAC/B,yBAAyB,GAC1B,MAAM,gCAAgC,CAAA;AACvC,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,4BAA4B,EACjC,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,0BAA0B,EAC1B,+BAA+B,EAC/B,iCAAiC,EACjC,6BAA6B,EAC7B,yBAAyB,EACzB,wBAAwB,EACxB,wBAAwB,EACxB,sCAAsC,EACtC,6BAA6B,EAC7B,KAAK,cAAc,EACnB,oBAAoB,EACpB,KAAK,4BAA4B,EACjC,KAAK,cAAc,EACnB,6BAA6B,EAC7B,eAAe,EACf,KAAK,gBAAgB,EACrB,2BAA2B,EAC3B,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,uBAAuB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,4BAA4B,EAC5B,uBAAuB,EACvB,kCAAkC,EAClC,yBAAyB,EACzB,mCAAmC,EACnC,0BAA0B,EAC1B,iCAAiC,EACjC,wBAAwB,EACxB,8BAA8B,EAC9B,0BAA0B,EAC1B,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,6BAA6B,EAC7B,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { createTripsRoutes, tripsRoutes } from "./routes.js";
2
+ export { createCatalogComponentAdapter, previewCancellation, } from "./catalog-component.js";
2
3
  export { isCatalogBackedTripComponent, toBookingDraftV1, } from "./catalog-component-adapter.js";
3
4
  export { CRUISE_EXTENSION_METADATA_KIND, createCruiseExtensionComponent, createCruiseExtensionExtra, createCruiseExtensionLinkCommand, cruiseExtensionLinkKey, groupCruiseExtensionLinksByProduct, representCruiseExtensionSelection, } from "./cruise-extension.js";
5
+ export { createFlightComponentAdapter, } from "./flight-component.js";
4
6
  export { createTripsRoutes } from "./routes.js";
5
7
  export const tripsModule = {
6
8
  name: "trips",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyant-travel/trips",
3
- "version": "0.112.0",
3
+ "version": "0.114.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -39,6 +39,16 @@
39
39
  "import": "./dist/checkout/index.js",
40
40
  "default": "./dist/checkout/index.js"
41
41
  },
42
+ "./catalog-component": {
43
+ "types": "./dist/catalog-component.d.ts",
44
+ "import": "./dist/catalog-component.js",
45
+ "default": "./dist/catalog-component.js"
46
+ },
47
+ "./flight-component": {
48
+ "types": "./dist/flight-component.d.ts",
49
+ "import": "./dist/flight-component.js",
50
+ "default": "./dist/flight-component.js"
51
+ },
42
52
  "./cruise-extension": {
43
53
  "types": "./dist/cruise-extension.d.ts",
44
54
  "import": "./dist/cruise-extension.js",
@@ -60,11 +70,13 @@
60
70
  "drizzle-orm": "^0.45.2",
61
71
  "hono": "^4.12.10",
62
72
  "zod": "^4.3.6",
63
- "@voyant-travel/core": "^0.109.0",
64
- "@voyant-travel/catalog": "^0.119.0",
65
- "@voyant-travel/db": "^0.108.1",
66
- "@voyant-travel/finance": "^0.121.0",
67
- "@voyant-travel/hono": "^0.111.0"
73
+ "@voyant-travel/core": "^0.110.0",
74
+ "@voyant-travel/bookings": "^0.123.0",
75
+ "@voyant-travel/catalog": "^0.121.0",
76
+ "@voyant-travel/db": "^0.108.2",
77
+ "@voyant-travel/finance": "^0.123.0",
78
+ "@voyant-travel/flights": "^0.123.0",
79
+ "@voyant-travel/hono": "^0.112.0"
68
80
  },
69
81
  "devDependencies": {
70
82
  "typescript": "^6.0.2",