@voyant-travel/storefront 0.120.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 (126) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +231 -0
  3. package/dist/booking-intents.d.ts +42 -0
  4. package/dist/booking-intents.d.ts.map +1 -0
  5. package/dist/booking-intents.js +83 -0
  6. package/dist/customer-portal/index.d.ts +16 -0
  7. package/dist/customer-portal/index.d.ts.map +1 -0
  8. package/dist/customer-portal/index.js +23 -0
  9. package/dist/customer-portal/route-runtime.d.ts +16 -0
  10. package/dist/customer-portal/route-runtime.d.ts.map +1 -0
  11. package/dist/customer-portal/route-runtime.js +27 -0
  12. package/dist/customer-portal/routes-public.d.ts +1936 -0
  13. package/dist/customer-portal/routes-public.d.ts.map +1 -0
  14. package/dist/customer-portal/routes-public.js +165 -0
  15. package/dist/customer-portal/routes.d.ts +43 -0
  16. package/dist/customer-portal/routes.d.ts.map +1 -0
  17. package/dist/customer-portal/routes.js +17 -0
  18. package/dist/customer-portal/service-public-impl.d.ts +138 -0
  19. package/dist/customer-portal/service-public-impl.d.ts.map +1 -0
  20. package/dist/customer-portal/service-public-impl.js +1808 -0
  21. package/dist/customer-portal/service-public.d.ts +2 -0
  22. package/dist/customer-portal/service-public.d.ts.map +1 -0
  23. package/dist/customer-portal/service-public.js +1 -0
  24. package/dist/customer-portal/validation-public/bookings.d.ts +551 -0
  25. package/dist/customer-portal/validation-public/bookings.d.ts.map +1 -0
  26. package/dist/customer-portal/validation-public/bookings.js +132 -0
  27. package/dist/customer-portal/validation-public/common.d.ts +162 -0
  28. package/dist/customer-portal/validation-public/common.d.ts.map +1 -0
  29. package/dist/customer-portal/validation-public/common.js +139 -0
  30. package/dist/customer-portal/validation-public/profile.d.ts +749 -0
  31. package/dist/customer-portal/validation-public/profile.d.ts.map +1 -0
  32. package/dist/customer-portal/validation-public/profile.js +308 -0
  33. package/dist/customer-portal/validation-public.d.ts +3 -0
  34. package/dist/customer-portal/validation-public.d.ts.map +1 -0
  35. package/dist/customer-portal/validation-public.js +2 -0
  36. package/dist/guest-booking-guard.d.ts +24 -0
  37. package/dist/guest-booking-guard.d.ts.map +1 -0
  38. package/dist/guest-booking-guard.js +55 -0
  39. package/dist/index.d.ts +23 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +41 -0
  42. package/dist/product-extra-ref.d.ts +238 -0
  43. package/dist/product-extra-ref.d.ts.map +1 -0
  44. package/dist/product-extra-ref.js +22 -0
  45. package/dist/routes-admin.d.ts +220 -0
  46. package/dist/routes-admin.d.ts.map +1 -0
  47. package/dist/routes-admin.js +28 -0
  48. package/dist/routes-public.d.ts +1475 -0
  49. package/dist/routes-public.d.ts.map +1 -0
  50. package/dist/routes-public.js +362 -0
  51. package/dist/service-booking-session-bootstrap.d.ts +227 -0
  52. package/dist/service-booking-session-bootstrap.d.ts.map +1 -0
  53. package/dist/service-booking-session-bootstrap.js +287 -0
  54. package/dist/service-boundary-resource-sql.d.ts +18 -0
  55. package/dist/service-boundary-resource-sql.d.ts.map +1 -0
  56. package/dist/service-boundary-resource-sql.js +73 -0
  57. package/dist/service-boundary-sql.d.ts +103 -0
  58. package/dist/service-boundary-sql.d.ts.map +1 -0
  59. package/dist/service-boundary-sql.js +307 -0
  60. package/dist/service-departures-core.d.ts +41 -0
  61. package/dist/service-departures-core.d.ts.map +1 -0
  62. package/dist/service-departures-core.js +92 -0
  63. package/dist/service-departures-extensions.d.ts +46 -0
  64. package/dist/service-departures-extensions.d.ts.map +1 -0
  65. package/dist/service-departures-extensions.js +81 -0
  66. package/dist/service-departures-offers.d.ts +220 -0
  67. package/dist/service-departures-offers.d.ts.map +1 -0
  68. package/dist/service-departures-offers.js +177 -0
  69. package/dist/service-departures-price-preview.d.ts +306 -0
  70. package/dist/service-departures-price-preview.d.ts.map +1 -0
  71. package/dist/service-departures-price-preview.js +383 -0
  72. package/dist/service-departures-pricing-context.d.ts +115 -0
  73. package/dist/service-departures-pricing-context.d.ts.map +1 -0
  74. package/dist/service-departures-pricing-context.js +237 -0
  75. package/dist/service-departures-pricing.d.ts +5 -0
  76. package/dist/service-departures-pricing.d.ts.map +1 -0
  77. package/dist/service-departures-pricing.js +4 -0
  78. package/dist/service-departures.d.ts +192 -0
  79. package/dist/service-departures.d.ts.map +1 -0
  80. package/dist/service-departures.js +213 -0
  81. package/dist/service-intake.d.ts +130 -0
  82. package/dist/service-intake.d.ts.map +1 -0
  83. package/dist/service-intake.js +274 -0
  84. package/dist/service-transport-eligibility.d.ts +10 -0
  85. package/dist/service-transport-eligibility.d.ts.map +1 -0
  86. package/dist/service-transport-eligibility.js +198 -0
  87. package/dist/service.d.ts +1062 -0
  88. package/dist/service.d.ts.map +1 -0
  89. package/dist/service.js +332 -0
  90. package/dist/transport-eligibility.d.ts +4 -0
  91. package/dist/transport-eligibility.d.ts.map +1 -0
  92. package/dist/transport-eligibility.js +2 -0
  93. package/dist/validation/departures.d.ts +1669 -0
  94. package/dist/validation/departures.d.ts.map +1 -0
  95. package/dist/validation/departures.js +397 -0
  96. package/dist/validation/intake.d.ts +147 -0
  97. package/dist/validation/intake.d.ts.map +1 -0
  98. package/dist/validation/intake.js +69 -0
  99. package/dist/validation/offers.d.ts +340 -0
  100. package/dist/validation/offers.d.ts.map +1 -0
  101. package/dist/validation/offers.js +117 -0
  102. package/dist/validation-settings.d.ts +609 -0
  103. package/dist/validation-settings.d.ts.map +1 -0
  104. package/dist/validation-settings.js +235 -0
  105. package/dist/validation-transport-eligibility.d.ts +314 -0
  106. package/dist/validation-transport-eligibility.d.ts.map +1 -0
  107. package/dist/validation-transport-eligibility.js +97 -0
  108. package/dist/validation.d.ts +6 -0
  109. package/dist/validation.d.ts.map +1 -0
  110. package/dist/validation.js +4 -0
  111. package/dist/verification/index.d.ts +12 -0
  112. package/dist/verification/index.d.ts.map +1 -0
  113. package/dist/verification/index.js +18 -0
  114. package/dist/verification/routes-public.d.ts +121 -0
  115. package/dist/verification/routes-public.d.ts.map +1 -0
  116. package/dist/verification/routes-public.js +125 -0
  117. package/dist/verification/schema.d.ts +273 -0
  118. package/dist/verification/schema.d.ts.map +1 -0
  119. package/dist/verification/schema.js +50 -0
  120. package/dist/verification/service.d.ts +114 -0
  121. package/dist/verification/service.d.ts.map +1 -0
  122. package/dist/verification/service.js +283 -0
  123. package/dist/verification/validation.d.ts +98 -0
  124. package/dist/verification/validation.d.ts.map +1 -0
  125. package/dist/verification/validation.js +54 -0
  126. package/package.json +148 -0
@@ -0,0 +1,1062 @@
1
+ import type { EventBus } from "@voyant-travel/core";
2
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
3
+ import { type StorefrontBookingSessionBootstrapOptions } from "./service-booking-session-bootstrap.js";
4
+ import { type StorefrontCustomerSignalCreatedEvent, type StorefrontIntakeGuard, type StorefrontIntakeOptions, type StorefrontIntakePersistence, type StorefrontIntakePersistenceResolver, type StorefrontIntakePerson, type StorefrontIntakeSignal } from "./service-intake.js";
5
+ import { type StorefrontBookingSessionBootstrapInput, type StorefrontDepartureListQuery, type StorefrontDeparturePricePreviewInput, type StorefrontLeadIntakeInput, type StorefrontNewsletterSubscribeInput, type StorefrontOfferApplyInput, type StorefrontOfferMutationResult, type StorefrontOfferRedeemInput, type StorefrontProductAvailabilitySummaryQuery, type StorefrontPromotionalOffer, type StorefrontSettings, type StorefrontSettingsInput, type StorefrontSettingsPatchInput } from "./validation.js";
6
+ import type { StorefrontTransportEligibilityInput, StorefrontTransportEligibilityResult, StorefrontTransportEligibilityRuleInput } from "./validation-transport-eligibility.js";
7
+ export interface StorefrontServiceOptions {
8
+ /**
9
+ * Enables the async booking-bootstrap mode (queued write pipeline,
10
+ * RFC voyant#1687 §3.2). When set, `createStorefrontHonoModule`'s
11
+ * bootstrap registers the intent handler on the app bus AND the
12
+ * public bootstrap route honors `?async=1` / `Prefer: respond-async`.
13
+ * When omitted, async-mode requests fall back to the SYNC path — an
14
+ * intent with no registered handler would otherwise 202 and then
15
+ * stale-fail, which is strictly worse than just doing the work.
16
+ */
17
+ bookingIntents?: {
18
+ resolveDb: (bindings: Record<string, unknown>) => unknown;
19
+ };
20
+ settings?: StorefrontSettingsInput;
21
+ resolveSettings?: (context: StorefrontRequestContext) => Promise<StorefrontSettingsInput> | StorefrontSettingsInput;
22
+ updateSettings?: (input: StorefrontSettings, context: StorefrontRequestContext) => Promise<StorefrontSettingsInput | StorefrontSettings> | StorefrontSettingsInput | StorefrontSettings;
23
+ offers?: StorefrontOfferResolvers;
24
+ resolveOffers?: (context: StorefrontRequestContext) => Promise<StorefrontOfferResolvers | null | undefined> | StorefrontOfferResolvers | null | undefined;
25
+ transportEligibilityRules?: StorefrontTransportEligibilityRuleInput[];
26
+ resolveTransportEligibilityRules?: (input: {
27
+ departureId: string;
28
+ productId?: string | null;
29
+ travelStartsOn?: string | null;
30
+ travelEndsOn?: string | null;
31
+ } & StorefrontRequestContext) => Promise<StorefrontTransportEligibilityRuleInput[]> | StorefrontTransportEligibilityRuleInput[];
32
+ intake?: StorefrontIntakeOptions;
33
+ bookingSessionBootstrap?: StorefrontBookingSessionBootstrapOptions;
34
+ }
35
+ export interface StorefrontRequestContext {
36
+ db?: PostgresJsDatabase;
37
+ eventBus?: EventBus;
38
+ env?: unknown;
39
+ context?: unknown;
40
+ }
41
+ export interface StorefrontOfferResolvers {
42
+ listApplicableOffers?: (input: {
43
+ productId: string;
44
+ departureId?: string;
45
+ locale?: string;
46
+ } & StorefrontRequestContext) => Promise<StorefrontPromotionalOffer[]> | StorefrontPromotionalOffer[];
47
+ getOfferBySlug?: (input: {
48
+ slug: string;
49
+ locale?: string;
50
+ } & StorefrontRequestContext) => Promise<StorefrontPromotionalOffer | null> | StorefrontPromotionalOffer | null;
51
+ applyOffer?: (input: {
52
+ slug: string;
53
+ body: StorefrontOfferApplyInput;
54
+ } & StorefrontRequestContext) => Promise<StorefrontOfferMutationResult> | StorefrontOfferMutationResult;
55
+ redeemOffer?: (input: {
56
+ body: StorefrontOfferRedeemInput;
57
+ } & StorefrontRequestContext) => Promise<StorefrontOfferMutationResult> | StorefrontOfferMutationResult;
58
+ }
59
+ export declare function resolveStorefrontSettings(input?: StorefrontSettingsInput): StorefrontSettings;
60
+ export declare function mergeStorefrontSettingsPatch(current: StorefrontSettings, patch: StorefrontSettingsPatchInput): StorefrontSettings;
61
+ export declare function createStorefrontService(options?: StorefrontServiceOptions): {
62
+ getSettings(): StorefrontSettings;
63
+ resolveSettings: (context?: StorefrontRequestContext) => Promise<{
64
+ branding: {
65
+ logoUrl: string | null;
66
+ faviconUrl: string | null;
67
+ brandMarkUrl: string | null;
68
+ primaryColor: string | null;
69
+ accentColor: string | null;
70
+ supportedLanguages: string[];
71
+ };
72
+ support: {
73
+ email: string | null;
74
+ phone: string | null;
75
+ links: {
76
+ label: string;
77
+ url: string;
78
+ }[];
79
+ };
80
+ legal: {
81
+ termsUrl: string | null;
82
+ privacyUrl: string | null;
83
+ cancellationUrl: string | null;
84
+ defaultContractTemplateId: string | null;
85
+ };
86
+ localization: {
87
+ defaultLocale: string | null;
88
+ currencyDisplay: "symbol" | "name" | "code";
89
+ };
90
+ forms: {
91
+ billing: {
92
+ fields: {
93
+ key: string;
94
+ label: string;
95
+ type: "date" | "select" | "text" | "email" | "textarea" | "country" | "tel" | "checkbox";
96
+ required: boolean;
97
+ placeholder: string | null;
98
+ description: string | null;
99
+ autocomplete: string | null;
100
+ options: {
101
+ value: string;
102
+ label: string;
103
+ }[];
104
+ }[];
105
+ };
106
+ travelers: {
107
+ fields: {
108
+ key: string;
109
+ label: string;
110
+ type: "date" | "select" | "text" | "email" | "textarea" | "country" | "tel" | "checkbox";
111
+ required: boolean;
112
+ placeholder: string | null;
113
+ description: string | null;
114
+ autocomplete: string | null;
115
+ options: {
116
+ value: string;
117
+ label: string;
118
+ }[];
119
+ }[];
120
+ };
121
+ };
122
+ payment: {
123
+ defaultMethod: "voucher" | "bank_transfer" | "cash" | "invoice" | "card" | null;
124
+ methods: {
125
+ code: "voucher" | "bank_transfer" | "cash" | "invoice" | "card";
126
+ label: string;
127
+ description: string | null;
128
+ enabled: boolean;
129
+ }[];
130
+ structure: "split" | "full";
131
+ schedule: {
132
+ percent: number;
133
+ dueInDays: number;
134
+ dueCondition: "after_booking" | "before_departure";
135
+ }[];
136
+ defaultSchedule: {
137
+ depositPercent: number | null;
138
+ balanceDueDaysBeforeDeparture: number | null;
139
+ } | null;
140
+ bankTransfer: {
141
+ dueDays: number | null;
142
+ account: {
143
+ provider: string | null;
144
+ currency: string | null;
145
+ iban: string;
146
+ beneficiary: string;
147
+ bank: string;
148
+ } | null;
149
+ accountHolder: string | null;
150
+ bankName: string | null;
151
+ iban: string | null;
152
+ bic: string | null;
153
+ paymentReference: string | null;
154
+ instructions: string | null;
155
+ } | null;
156
+ };
157
+ }>;
158
+ updateSettings: (patch: StorefrontSettingsPatchInput, context?: StorefrontRequestContext) => Promise<{
159
+ branding: {
160
+ logoUrl: string | null;
161
+ faviconUrl: string | null;
162
+ brandMarkUrl: string | null;
163
+ primaryColor: string | null;
164
+ accentColor: string | null;
165
+ supportedLanguages: string[];
166
+ };
167
+ support: {
168
+ email: string | null;
169
+ phone: string | null;
170
+ links: {
171
+ label: string;
172
+ url: string;
173
+ }[];
174
+ };
175
+ legal: {
176
+ termsUrl: string | null;
177
+ privacyUrl: string | null;
178
+ cancellationUrl: string | null;
179
+ defaultContractTemplateId: string | null;
180
+ };
181
+ localization: {
182
+ defaultLocale: string | null;
183
+ currencyDisplay: "symbol" | "name" | "code";
184
+ };
185
+ forms: {
186
+ billing: {
187
+ fields: {
188
+ key: string;
189
+ label: string;
190
+ type: "date" | "select" | "text" | "email" | "textarea" | "country" | "tel" | "checkbox";
191
+ required: boolean;
192
+ placeholder: string | null;
193
+ description: string | null;
194
+ autocomplete: string | null;
195
+ options: {
196
+ value: string;
197
+ label: string;
198
+ }[];
199
+ }[];
200
+ };
201
+ travelers: {
202
+ fields: {
203
+ key: string;
204
+ label: string;
205
+ type: "date" | "select" | "text" | "email" | "textarea" | "country" | "tel" | "checkbox";
206
+ required: boolean;
207
+ placeholder: string | null;
208
+ description: string | null;
209
+ autocomplete: string | null;
210
+ options: {
211
+ value: string;
212
+ label: string;
213
+ }[];
214
+ }[];
215
+ };
216
+ };
217
+ payment: {
218
+ defaultMethod: "voucher" | "bank_transfer" | "cash" | "invoice" | "card" | null;
219
+ methods: {
220
+ code: "voucher" | "bank_transfer" | "cash" | "invoice" | "card";
221
+ label: string;
222
+ description: string | null;
223
+ enabled: boolean;
224
+ }[];
225
+ structure: "split" | "full";
226
+ schedule: {
227
+ percent: number;
228
+ dueInDays: number;
229
+ dueCondition: "after_booking" | "before_departure";
230
+ }[];
231
+ defaultSchedule: {
232
+ depositPercent: number | null;
233
+ balanceDueDaysBeforeDeparture: number | null;
234
+ } | null;
235
+ bankTransfer: {
236
+ dueDays: number | null;
237
+ account: {
238
+ provider: string | null;
239
+ currency: string | null;
240
+ iban: string;
241
+ beneficiary: string;
242
+ bank: string;
243
+ } | null;
244
+ accountHolder: string | null;
245
+ bankName: string | null;
246
+ iban: string | null;
247
+ bic: string | null;
248
+ paymentReference: string | null;
249
+ instructions: string | null;
250
+ } | null;
251
+ };
252
+ } | null>;
253
+ getDeparture(db: PostgresJsDatabase, departureId: string): Promise<{
254
+ id: string;
255
+ productId: string;
256
+ itineraryId: string;
257
+ optionId: string | null;
258
+ dateLocal: string | null;
259
+ startAt: string | null;
260
+ endAt: string | null;
261
+ timezone: string;
262
+ startTime: {
263
+ id: string;
264
+ label: string | null;
265
+ startTimeLocal: string;
266
+ durationMinutes: number | null;
267
+ } | null;
268
+ meetingPoint: string | null;
269
+ capacity: number | null;
270
+ remaining: number | null;
271
+ departureStatus: "on_request" | import("./service-boundary-sql.js").StorefrontSlotStatus;
272
+ nights: number | null;
273
+ days: number | null;
274
+ ratePlans: {
275
+ id: string;
276
+ active: boolean;
277
+ name: string;
278
+ pricingModel: string;
279
+ basePrices: {
280
+ amount: number;
281
+ currencyCode: string;
282
+ }[];
283
+ roomPrices: {
284
+ amount: number;
285
+ currencyCode: string;
286
+ roomType: {
287
+ id: string;
288
+ name: string;
289
+ occupancy: {
290
+ adultsMin: number;
291
+ adultsMax: number;
292
+ childrenMax: number;
293
+ };
294
+ };
295
+ }[];
296
+ }[];
297
+ resourceManifest: {
298
+ kinds: {
299
+ capacity: number;
300
+ assigned: number;
301
+ available: number;
302
+ kind: string;
303
+ }[];
304
+ resources: {
305
+ id: string;
306
+ kind: string;
307
+ label: string | null;
308
+ refType: string | null;
309
+ refId: string | null;
310
+ capacity: number;
311
+ assigned: number;
312
+ available: number;
313
+ parentId: string | null;
314
+ flags: Record<string, unknown>;
315
+ }[];
316
+ } | null;
317
+ } | null>;
318
+ listProductDepartures(db: PostgresJsDatabase, productId: string, query: StorefrontDepartureListQuery): Promise<{
319
+ data: {
320
+ id: string;
321
+ productId: string;
322
+ itineraryId: string;
323
+ optionId: string | null;
324
+ dateLocal: string | null;
325
+ startAt: string | null;
326
+ endAt: string | null;
327
+ timezone: string;
328
+ startTime: {
329
+ id: string;
330
+ label: string | null;
331
+ startTimeLocal: string;
332
+ durationMinutes: number | null;
333
+ } | null;
334
+ meetingPoint: string | null;
335
+ capacity: number | null;
336
+ remaining: number | null;
337
+ departureStatus: "on_request" | import("./service-boundary-sql.js").StorefrontSlotStatus;
338
+ nights: number | null;
339
+ days: number | null;
340
+ ratePlans: {
341
+ id: string;
342
+ active: boolean;
343
+ name: string;
344
+ pricingModel: string;
345
+ basePrices: {
346
+ amount: number;
347
+ currencyCode: string;
348
+ }[];
349
+ roomPrices: {
350
+ amount: number;
351
+ currencyCode: string;
352
+ roomType: {
353
+ id: string;
354
+ name: string;
355
+ occupancy: {
356
+ adultsMin: number;
357
+ adultsMax: number;
358
+ childrenMax: number;
359
+ };
360
+ };
361
+ }[];
362
+ }[];
363
+ resourceManifest: {
364
+ kinds: {
365
+ capacity: number;
366
+ assigned: number;
367
+ available: number;
368
+ kind: string;
369
+ }[];
370
+ resources: {
371
+ id: string;
372
+ kind: string;
373
+ label: string | null;
374
+ refType: string | null;
375
+ refId: string | null;
376
+ capacity: number;
377
+ assigned: number;
378
+ available: number;
379
+ parentId: string | null;
380
+ flags: Record<string, unknown>;
381
+ }[];
382
+ } | null;
383
+ }[];
384
+ total: number;
385
+ limit: number;
386
+ offset: number;
387
+ }>;
388
+ previewDeparturePrice(db: PostgresJsDatabase, departureId: string, input: StorefrontDeparturePricePreviewInput, context?: StorefrontRequestContext): Promise<{
389
+ departureId: string;
390
+ productId: string;
391
+ optionId: string | null;
392
+ currencyCode: string;
393
+ basePrice: number;
394
+ taxAmount: number;
395
+ total: number;
396
+ notes: string | null;
397
+ lineItems: {
398
+ name: string;
399
+ total: number;
400
+ quantity: number;
401
+ unitPrice: number;
402
+ }[];
403
+ allocation: {
404
+ slot: {
405
+ id: string;
406
+ productId: string;
407
+ optionId: string | null;
408
+ dateLocal: string | null;
409
+ startAt: string | null;
410
+ endAt: string | null;
411
+ timezone: string;
412
+ status: "on_request" | import("./service-boundary-sql.js").StorefrontSlotStatus;
413
+ availabilityState: import("./service-departures-core.js").StorefrontProductAvailabilityState;
414
+ capacity: number | null;
415
+ remaining: number | null;
416
+ pastCutoff: boolean;
417
+ tooEarly: boolean;
418
+ resourceManifest: {
419
+ kinds: {
420
+ capacity: number;
421
+ assigned: number;
422
+ available: number;
423
+ kind: string;
424
+ }[];
425
+ resources: {
426
+ id: string;
427
+ kind: string;
428
+ label: string | null;
429
+ refType: string | null;
430
+ refId: string | null;
431
+ capacity: number;
432
+ assigned: number;
433
+ available: number;
434
+ parentId: string | null;
435
+ flags: Record<string, unknown>;
436
+ }[];
437
+ } | null;
438
+ };
439
+ pax: {
440
+ adults: number;
441
+ children: number;
442
+ infants: number;
443
+ total: number;
444
+ };
445
+ requestedUnits: {
446
+ unitId: string | null;
447
+ requestRef: string | null;
448
+ name: string;
449
+ unitType: string | null;
450
+ quantity: number;
451
+ pricingMode: string | null;
452
+ unitPrice: number;
453
+ total: number;
454
+ currencyCode: string;
455
+ tierId: string | null;
456
+ }[];
457
+ rooms: {
458
+ unitId: string;
459
+ name: string;
460
+ occupancy: number;
461
+ quantity: number;
462
+ pax: number;
463
+ pricingMode: string | null;
464
+ unitPrice: number;
465
+ total: number;
466
+ currencyCode: string;
467
+ tierId: string | null;
468
+ }[];
469
+ };
470
+ units: {
471
+ unitId: string | null;
472
+ requestRef: string | null;
473
+ name: string;
474
+ unitType: string | null;
475
+ quantity: number;
476
+ pricingMode: string | null;
477
+ unitPrice: number;
478
+ total: number;
479
+ currencyCode: string;
480
+ tierId: string | null;
481
+ }[];
482
+ rooms: {
483
+ unitId: string;
484
+ name: string;
485
+ occupancy: number;
486
+ quantity: number;
487
+ pax: number;
488
+ pricingMode: string | null;
489
+ unitPrice: number;
490
+ total: number;
491
+ currencyCode: string;
492
+ tierId: string | null;
493
+ }[];
494
+ extras: {
495
+ extraId: string;
496
+ name: string;
497
+ required: boolean;
498
+ selectable: boolean;
499
+ selected: boolean;
500
+ pricingMode: string;
501
+ quantity: number;
502
+ unitPrice: number;
503
+ total: number;
504
+ currencyCode: string;
505
+ }[];
506
+ offers: {
507
+ available: {
508
+ offer: {
509
+ id: string;
510
+ name: string;
511
+ slug: string | null;
512
+ description: string | null;
513
+ discountType: "percentage" | "fixed_amount";
514
+ discountValue: string;
515
+ currency: string | null;
516
+ applicableProductIds: string[];
517
+ applicableDepartureIds: string[];
518
+ validFrom: string | null;
519
+ validTo: string | null;
520
+ minTravelers: number | null;
521
+ imageMobileUrl: string | null;
522
+ imageDesktopUrl: string | null;
523
+ stackable: boolean;
524
+ createdAt: string;
525
+ updatedAt: string;
526
+ };
527
+ status: string;
528
+ reason: string | null;
529
+ selected: boolean;
530
+ discountAppliedCents: number;
531
+ discountedPriceCents: number;
532
+ }[];
533
+ requested: ({
534
+ kind: "slug";
535
+ value: string;
536
+ result: {
537
+ status: "applied" | "not_applicable" | "invalid" | "conflict";
538
+ reason: "currency" | "scope" | "booking_mismatch" | "conflict" | "offer_not_found" | "offer_expired" | "offer_not_yet_valid" | "code_not_found" | "code_required" | "code_expired" | "code_not_yet_valid" | "min_pax" | "eligibility" | "no_discount" | "session_mismatch" | null;
539
+ offer: {
540
+ id: string;
541
+ name: string;
542
+ slug: string | null;
543
+ description: string | null;
544
+ discountType: "percentage" | "fixed_amount";
545
+ discountValue: string;
546
+ currency: string | null;
547
+ applicableProductIds: string[];
548
+ applicableDepartureIds: string[];
549
+ validFrom: string | null;
550
+ validTo: string | null;
551
+ minTravelers: number | null;
552
+ imageMobileUrl: string | null;
553
+ imageDesktopUrl: string | null;
554
+ stackable: boolean;
555
+ createdAt: string;
556
+ updatedAt: string;
557
+ } | null;
558
+ target: {
559
+ bookingId: string | null;
560
+ sessionId: string | null;
561
+ productId: string;
562
+ departureId: string | null;
563
+ };
564
+ pricing: {
565
+ basePriceCents: number;
566
+ currency: string;
567
+ discountAppliedCents: number;
568
+ discountedPriceCents: number;
569
+ };
570
+ appliedOffers: {
571
+ offerId: string;
572
+ offerName: string;
573
+ discountAppliedCents: number;
574
+ discountedPriceCents: number;
575
+ currency: string;
576
+ discountKind: "percentage" | "fixed_amount";
577
+ discountPercent: number | null;
578
+ discountAmountCents: number | null;
579
+ appliedCode: string | null;
580
+ stackable: boolean;
581
+ }[];
582
+ conflict: {
583
+ policy: "best_discount_wins" | "stackable_compose";
584
+ autoAppliedOfferIds: string[];
585
+ manualOfferId: string | null;
586
+ selectedOfferIds: string[];
587
+ message: string;
588
+ } | null;
589
+ } | null;
590
+ } | {
591
+ kind: "code";
592
+ value: string;
593
+ result: {
594
+ status: "applied" | "not_applicable" | "invalid" | "conflict";
595
+ reason: "currency" | "scope" | "booking_mismatch" | "conflict" | "offer_not_found" | "offer_expired" | "offer_not_yet_valid" | "code_not_found" | "code_required" | "code_expired" | "code_not_yet_valid" | "min_pax" | "eligibility" | "no_discount" | "session_mismatch" | null;
596
+ offer: {
597
+ id: string;
598
+ name: string;
599
+ slug: string | null;
600
+ description: string | null;
601
+ discountType: "percentage" | "fixed_amount";
602
+ discountValue: string;
603
+ currency: string | null;
604
+ applicableProductIds: string[];
605
+ applicableDepartureIds: string[];
606
+ validFrom: string | null;
607
+ validTo: string | null;
608
+ minTravelers: number | null;
609
+ imageMobileUrl: string | null;
610
+ imageDesktopUrl: string | null;
611
+ stackable: boolean;
612
+ createdAt: string;
613
+ updatedAt: string;
614
+ } | null;
615
+ target: {
616
+ bookingId: string | null;
617
+ sessionId: string | null;
618
+ productId: string;
619
+ departureId: string | null;
620
+ };
621
+ pricing: {
622
+ basePriceCents: number;
623
+ currency: string;
624
+ discountAppliedCents: number;
625
+ discountedPriceCents: number;
626
+ };
627
+ appliedOffers: {
628
+ offerId: string;
629
+ offerName: string;
630
+ discountAppliedCents: number;
631
+ discountedPriceCents: number;
632
+ currency: string;
633
+ discountKind: "percentage" | "fixed_amount";
634
+ discountPercent: number | null;
635
+ discountAmountCents: number | null;
636
+ appliedCode: string | null;
637
+ stackable: boolean;
638
+ }[];
639
+ conflict: {
640
+ policy: "best_discount_wins" | "stackable_compose";
641
+ autoAppliedOfferIds: string[];
642
+ manualOfferId: string | null;
643
+ selectedOfferIds: string[];
644
+ message: string;
645
+ } | null;
646
+ } | null;
647
+ })[];
648
+ applied: {
649
+ offerId: string;
650
+ offerName: string;
651
+ discountAppliedCents: number;
652
+ discountedPriceCents: number;
653
+ currency: string;
654
+ discountKind: "percentage" | "fixed_amount";
655
+ discountPercent: number | null;
656
+ discountAmountCents: number | null;
657
+ appliedCode: string | null;
658
+ stackable: boolean;
659
+ }[];
660
+ conflict: {
661
+ policy: "best_discount_wins" | "stackable_compose";
662
+ autoAppliedOfferIds: string[];
663
+ manualOfferId: string | null;
664
+ selectedOfferIds: string[];
665
+ message: string;
666
+ } | {
667
+ policy: string;
668
+ autoAppliedOfferIds: string[];
669
+ manualOfferId: null;
670
+ selectedOfferIds: string[];
671
+ message: string;
672
+ } | null;
673
+ discountTotal: number;
674
+ discountTotalCents: number;
675
+ totalAfterDiscount: number;
676
+ currencyCode: string;
677
+ };
678
+ totals: {
679
+ currencyCode: string;
680
+ base: number;
681
+ extras: number;
682
+ subtotal: number;
683
+ discount: number;
684
+ tax: number;
685
+ total: number;
686
+ perPerson: number;
687
+ perBooking: number;
688
+ };
689
+ } | null>;
690
+ getProductExtensions(db: PostgresJsDatabase, productId: string, optionId?: string): Promise<{
691
+ extensions: {
692
+ id: string;
693
+ name: string;
694
+ label: string;
695
+ required: boolean;
696
+ selectable: boolean;
697
+ hasOptions: boolean;
698
+ refProductId: string | null;
699
+ thumb: string | null;
700
+ pricePerPerson: number | null;
701
+ currencyCode: string;
702
+ pricingMode: string;
703
+ defaultQuantity: number | null;
704
+ minQuantity: number | null;
705
+ maxQuantity: number | null;
706
+ }[];
707
+ items: {
708
+ id: string;
709
+ name: string;
710
+ label: string;
711
+ required: boolean;
712
+ selectable: boolean;
713
+ hasOptions: boolean;
714
+ refProductId: string | null;
715
+ thumb: string | null;
716
+ pricePerPerson: number | null;
717
+ currencyCode: string;
718
+ pricingMode: string;
719
+ defaultQuantity: number | null;
720
+ minQuantity: number | null;
721
+ maxQuantity: number | null;
722
+ }[];
723
+ details: {
724
+ [k: string]: {
725
+ description: string | null;
726
+ media: {
727
+ url: string;
728
+ alt: string | null;
729
+ }[];
730
+ };
731
+ };
732
+ currencyCode: string;
733
+ }>;
734
+ getProductAvailabilitySummary(db: PostgresJsDatabase, productId: string, query: StorefrontProductAvailabilitySummaryQuery): Promise<{
735
+ productId: string;
736
+ availabilityState: import("./service-departures-core.js").StorefrontProductAvailabilityState;
737
+ counts: {
738
+ total: number;
739
+ open: number;
740
+ closed: number;
741
+ soldOut: number;
742
+ cancelled: number;
743
+ onRequest: number;
744
+ pastCutoff: number;
745
+ tooEarly: number;
746
+ available: number;
747
+ };
748
+ departures: {
749
+ id: string;
750
+ productId: string;
751
+ optionId: string | null;
752
+ dateLocal: string | null;
753
+ startAt: string | null;
754
+ endAt: string | null;
755
+ timezone: string;
756
+ status: "on_request" | import("./service-boundary-sql.js").StorefrontSlotStatus;
757
+ availabilityState: import("./service-departures-core.js").StorefrontProductAvailabilityState;
758
+ capacity: number | null;
759
+ remaining: number | null;
760
+ pastCutoff: boolean;
761
+ tooEarly: boolean;
762
+ }[];
763
+ total: number;
764
+ limit: number;
765
+ offset: number;
766
+ }>;
767
+ getDepartureItinerary(db: PostgresJsDatabase, input: {
768
+ departureId: string;
769
+ productId: string;
770
+ }): Promise<{
771
+ id: string;
772
+ itineraryId: string;
773
+ days: {
774
+ id: string;
775
+ title: string;
776
+ description: string | null;
777
+ thumbnail: {
778
+ url: string;
779
+ } | null;
780
+ segments: {
781
+ id: string;
782
+ title: string;
783
+ description: string | null;
784
+ }[];
785
+ }[];
786
+ } | null>;
787
+ checkDepartureTransportEligibility(input: {
788
+ departureId: string;
789
+ productId?: string | null;
790
+ body: StorefrontTransportEligibilityInput;
791
+ context?: StorefrontRequestContext;
792
+ }): Promise<StorefrontTransportEligibilityResult>;
793
+ bootstrapBookingSession(context: StorefrontRequestContext & {
794
+ db: PostgresJsDatabase;
795
+ }, input: StorefrontBookingSessionBootstrapInput, userId?: string): Promise<{
796
+ status: Exclude<string, "ok">;
797
+ } | {
798
+ status: "stale_quote";
799
+ repricing: {
800
+ originalQuote: {
801
+ currencyCode: string;
802
+ totalSellAmountCents: number;
803
+ quotedAt?: string | null | undefined;
804
+ expiresAt?: string | null | undefined;
805
+ };
806
+ current: {
807
+ sessionId: string;
808
+ catalogId: string | null;
809
+ currencyCode: string;
810
+ totalSellAmountCents: number;
811
+ items: {
812
+ inputIndex: number;
813
+ itemId: string;
814
+ title: string;
815
+ productId: string | null;
816
+ optionId: string | null;
817
+ optionUnitId: string | null;
818
+ optionUnitName: string | null;
819
+ optionUnitType: string | null;
820
+ pricingCategoryId: string | null;
821
+ quantity: number;
822
+ pricingMode: string;
823
+ unitSellAmountCents: number | null;
824
+ totalSellAmountCents: number | null;
825
+ warnings: string[];
826
+ }[];
827
+ warnings: never[];
828
+ appliedToSession: boolean;
829
+ };
830
+ deltaAmountCents: number;
831
+ staleQuote: boolean;
832
+ };
833
+ bootstrap?: undefined;
834
+ } | {
835
+ status: "ok";
836
+ bootstrap: {
837
+ session: {
838
+ sessionId: string;
839
+ bookingNumber: string;
840
+ status: "draft" | "confirmed" | "cancelled" | "on_hold" | "awaiting_payment" | "in_progress" | "completed" | "expired";
841
+ externalBookingRef: string | null;
842
+ communicationLanguage: string | null;
843
+ sellCurrency: string;
844
+ sellAmountCents: number | null;
845
+ startDate: string | null;
846
+ endDate: string | null;
847
+ pax: number | null;
848
+ holdExpiresAt: string | null;
849
+ confirmedAt: string | null;
850
+ expiredAt: string | null;
851
+ cancelledAt: string | null;
852
+ completedAt: string | null;
853
+ travelers: {
854
+ id: string;
855
+ participantType: "other" | "traveler" | "occupant";
856
+ travelerCategory: "other" | "adult" | "child" | "infant" | "senior" | null;
857
+ firstName: string;
858
+ lastName: string;
859
+ email: string | null;
860
+ phone: string | null;
861
+ preferredLanguage: string | null;
862
+ specialRequests: string | null;
863
+ isPrimary: boolean;
864
+ notes: string | null;
865
+ }[];
866
+ items: {
867
+ id: string;
868
+ title: string;
869
+ description: string | null;
870
+ itemType: "service" | "unit" | "other" | "extra" | "fee" | "tax" | "discount" | "adjustment" | "accommodation" | "transport";
871
+ status: "draft" | "confirmed" | "cancelled" | "fulfilled" | "on_hold" | "expired";
872
+ serviceDate: string | null;
873
+ startsAt: string | null;
874
+ endsAt: string | null;
875
+ quantity: number;
876
+ sellCurrency: string;
877
+ unitSellAmountCents: number | null;
878
+ totalSellAmountCents: number | null;
879
+ costCurrency: string | null;
880
+ unitCostAmountCents: number | null;
881
+ totalCostAmountCents: number | null;
882
+ notes: string | null;
883
+ productId: string | null;
884
+ optionId: string | null;
885
+ optionUnitId: string | null;
886
+ pricingCategoryId: string | null;
887
+ travelerLinks: {
888
+ id: string;
889
+ travelerId: string;
890
+ role: string;
891
+ isPrimary: boolean;
892
+ }[];
893
+ }[];
894
+ allocations: {
895
+ id: string;
896
+ bookingItemId: string;
897
+ productId: string | null;
898
+ optionId: string | null;
899
+ optionUnitId: string | null;
900
+ pricingCategoryId: string | null;
901
+ availabilitySlotId: string | null;
902
+ quantity: number;
903
+ allocationType: "unit" | "pickup" | "resource";
904
+ status: "confirmed" | "cancelled" | "fulfilled" | "expired" | "held" | "released";
905
+ holdExpiresAt: string | null;
906
+ confirmedAt: string | null;
907
+ releasedAt: string | null;
908
+ }[];
909
+ checklist: {
910
+ hasTravelers: boolean;
911
+ hasPrimaryTraveler: boolean;
912
+ hasItems: boolean;
913
+ hasAllocations: boolean;
914
+ readyForConfirmation: boolean;
915
+ };
916
+ state: {
917
+ sessionId: string;
918
+ stateKey: "wizard";
919
+ currentStep: string | null;
920
+ completedSteps: string[];
921
+ payload: Record<string, unknown>;
922
+ version: number;
923
+ createdAt: string;
924
+ updatedAt: string;
925
+ } | null;
926
+ };
927
+ paymentPlan: {
928
+ source: "storefront_default";
929
+ depositKind: import("@voyant-travel/finance").DepositKind;
930
+ depositPercent: number | null;
931
+ depositAmountCents: number | null;
932
+ requiresFullPayment: boolean;
933
+ };
934
+ paymentSchedule: {
935
+ id: string;
936
+ scheduleType: "other" | "deposit" | "installment" | "balance" | "hold";
937
+ status: "pending" | "cancelled" | "waived" | "expired" | "paid" | "due";
938
+ dueDate: string;
939
+ currency: string;
940
+ amountCents: number;
941
+ notes: string | null;
942
+ }[];
943
+ repricing: {
944
+ originalQuote: {
945
+ currencyCode: string;
946
+ totalSellAmountCents: number;
947
+ quotedAt?: string | null | undefined;
948
+ expiresAt?: string | null | undefined;
949
+ };
950
+ current: {
951
+ sessionId: string;
952
+ items: {
953
+ itemId: string;
954
+ title: string;
955
+ productId: string | null;
956
+ optionId: string | null;
957
+ optionUnitId: string | null;
958
+ optionUnitName: string | null;
959
+ optionUnitType: string | null;
960
+ pricingCategoryId: string | null;
961
+ quantity: number;
962
+ pricingMode: string;
963
+ unitSellAmountCents: number | null;
964
+ totalSellAmountCents: number | null;
965
+ warnings: string[];
966
+ }[];
967
+ catalogId: string | null;
968
+ currencyCode: string;
969
+ totalSellAmountCents: number;
970
+ warnings: never[];
971
+ appliedToSession: boolean;
972
+ };
973
+ deltaAmountCents: number;
974
+ staleQuote: boolean;
975
+ };
976
+ availability: {
977
+ departureId: string;
978
+ slotId: string;
979
+ productId: string;
980
+ optionId: string | null;
981
+ dateLocal: string | Date;
982
+ startsAt: string | null;
983
+ endsAt: string | null;
984
+ timezone: string;
985
+ status: import("./service-boundary-sql.js").StorefrontSlotStatus;
986
+ capacity: number | null;
987
+ remaining: number | null;
988
+ };
989
+ allocation: {
990
+ id: string;
991
+ bookingItemId: string;
992
+ productId: string | null;
993
+ optionId: string | null;
994
+ optionUnitId: string | null;
995
+ pricingCategoryId: string | null;
996
+ availabilitySlotId: string | null;
997
+ quantity: number;
998
+ allocationType: "unit" | "pickup" | "resource";
999
+ status: "confirmed" | "cancelled" | "fulfilled" | "expired" | "held" | "released";
1000
+ holdExpiresAt: string | null;
1001
+ confirmedAt: string | null;
1002
+ releasedAt: string | null;
1003
+ }[];
1004
+ currency: string;
1005
+ };
1006
+ repricing?: undefined;
1007
+ }>;
1008
+ listApplicableOffers(input: {
1009
+ productId: string;
1010
+ departureId?: string;
1011
+ locale?: string;
1012
+ context?: StorefrontRequestContext;
1013
+ }): Promise<StorefrontPromotionalOffer[]>;
1014
+ getOfferBySlug(input: {
1015
+ slug: string;
1016
+ locale?: string;
1017
+ context?: StorefrontRequestContext;
1018
+ }): Promise<StorefrontPromotionalOffer | null>;
1019
+ applyOffer(input: {
1020
+ slug: string;
1021
+ body: StorefrontOfferApplyInput;
1022
+ context?: StorefrontRequestContext;
1023
+ }): Promise<StorefrontOfferMutationResult | null>;
1024
+ redeemOffer(input: {
1025
+ body: StorefrontOfferRedeemInput;
1026
+ context?: StorefrontRequestContext;
1027
+ }): Promise<StorefrontOfferMutationResult | null>;
1028
+ checkIntakeGuard: (input: {
1029
+ kind: "lead";
1030
+ body: StorefrontLeadIntakeInput;
1031
+ context: StorefrontRequestContext;
1032
+ } | {
1033
+ kind: "newsletter";
1034
+ body: StorefrontNewsletterSubscribeInput;
1035
+ context: StorefrontRequestContext;
1036
+ }) => Promise<import("./service-intake.js").StorefrontIntakeGuardDecision | undefined>;
1037
+ createLead(input: {
1038
+ body: StorefrontLeadIntakeInput;
1039
+ context: StorefrontRequestContext;
1040
+ }): Promise<{
1041
+ id: string;
1042
+ personId: string;
1043
+ kind: "notify" | "wishlist" | "inquiry" | "request_offer" | "referral";
1044
+ source: "admin" | "phone" | "booking" | "form" | "website" | "abandoned_cart";
1045
+ status: "expired" | "lost" | "new" | "contacted" | "qualified" | "converted";
1046
+ duplicate: boolean;
1047
+ }>;
1048
+ subscribeNewsletter(input: {
1049
+ body: StorefrontNewsletterSubscribeInput;
1050
+ context: StorefrontRequestContext;
1051
+ }): Promise<{
1052
+ id: string;
1053
+ personId: string;
1054
+ kind: "notify" | "wishlist" | "inquiry" | "request_offer" | "referral";
1055
+ source: "admin" | "phone" | "booking" | "form" | "website" | "abandoned_cart";
1056
+ status: "expired" | "lost" | "new" | "contacted" | "qualified" | "converted";
1057
+ duplicate: boolean;
1058
+ doubleOptIn: "requested" | "not_configured";
1059
+ }>;
1060
+ };
1061
+ export type { StorefrontCustomerSignalCreatedEvent, StorefrontIntakeGuard, StorefrontIntakeOptions, StorefrontIntakePersistence, StorefrontIntakePersistenceResolver, StorefrontIntakePerson, StorefrontIntakeSignal, };
1062
+ //# sourceMappingURL=service.d.ts.map