@voyantjs/storefront 0.24.1 → 0.24.2

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,303 @@
1
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
2
+ import { type StorefrontDepartureListQuery, type StorefrontDeparturePricePreviewInput, type StorefrontProductAvailabilitySummaryQuery, type StorefrontPromotionalOffer, type StorefrontSettings, type StorefrontSettingsInput } from "./validation.js";
3
+ export interface StorefrontServiceOptions {
4
+ settings?: StorefrontSettingsInput;
5
+ resolveSettings?: (context: StorefrontRequestContext) => Promise<StorefrontSettingsInput> | StorefrontSettingsInput;
6
+ offers?: StorefrontOfferResolvers;
7
+ resolveOffers?: (context: StorefrontRequestContext) => Promise<StorefrontOfferResolvers | null | undefined> | StorefrontOfferResolvers | null | undefined;
8
+ }
9
+ export interface StorefrontRequestContext {
10
+ db?: PostgresJsDatabase;
11
+ env?: unknown;
12
+ context?: unknown;
13
+ }
14
+ export interface StorefrontOfferResolvers {
15
+ listApplicableOffers?: (input: {
16
+ productId: string;
17
+ departureId?: string;
18
+ locale?: string;
19
+ } & StorefrontRequestContext) => Promise<StorefrontPromotionalOffer[]> | StorefrontPromotionalOffer[];
20
+ getOfferBySlug?: (input: {
21
+ slug: string;
22
+ locale?: string;
23
+ } & StorefrontRequestContext) => Promise<StorefrontPromotionalOffer | null> | StorefrontPromotionalOffer | null;
24
+ }
25
+ export declare function resolveStorefrontSettings(input?: StorefrontSettingsInput): StorefrontSettings;
26
+ export declare function createStorefrontService(options?: StorefrontServiceOptions): {
27
+ getSettings(): StorefrontSettings;
28
+ resolveSettings: (context?: StorefrontRequestContext) => Promise<{
29
+ branding: {
30
+ logoUrl: string | null;
31
+ supportedLanguages: string[];
32
+ };
33
+ support: {
34
+ email: string | null;
35
+ phone: string | null;
36
+ };
37
+ legal: {
38
+ termsUrl: string | null;
39
+ privacyUrl: string | null;
40
+ defaultContractTemplateId: string | null;
41
+ };
42
+ forms: {
43
+ billing: {
44
+ fields: {
45
+ key: string;
46
+ label: string;
47
+ type: "date" | "select" | "email" | "text" | "country" | "tel" | "textarea" | "checkbox";
48
+ required: boolean;
49
+ placeholder: string | null;
50
+ description: string | null;
51
+ autocomplete: string | null;
52
+ options: {
53
+ value: string;
54
+ label: string;
55
+ }[];
56
+ }[];
57
+ };
58
+ travelers: {
59
+ fields: {
60
+ key: string;
61
+ label: string;
62
+ type: "date" | "select" | "email" | "text" | "country" | "tel" | "textarea" | "checkbox";
63
+ required: boolean;
64
+ placeholder: string | null;
65
+ description: string | null;
66
+ autocomplete: string | null;
67
+ options: {
68
+ value: string;
69
+ label: string;
70
+ }[];
71
+ }[];
72
+ };
73
+ };
74
+ payment: {
75
+ defaultMethod: "voucher" | "card" | "bank_transfer" | "cash" | "invoice" | null;
76
+ methods: {
77
+ code: "voucher" | "card" | "bank_transfer" | "cash" | "invoice";
78
+ label: string;
79
+ description: string | null;
80
+ enabled: boolean;
81
+ }[];
82
+ };
83
+ }>;
84
+ getDeparture(db: PostgresJsDatabase, departureId: string): Promise<{
85
+ id: string;
86
+ productId: string;
87
+ itineraryId: string;
88
+ optionId: string | null;
89
+ dateLocal: string | null;
90
+ startAt: string | null;
91
+ endAt: string | null;
92
+ timezone: string;
93
+ startTime: {
94
+ id: string;
95
+ label: string | null;
96
+ startTimeLocal: string;
97
+ durationMinutes: number | null;
98
+ } | null;
99
+ meetingPoint: string | null;
100
+ capacity: number | null;
101
+ remaining: number | null;
102
+ departureStatus: "open" | "closed" | "sold_out" | "cancelled" | "on_request";
103
+ nights: number | null;
104
+ days: number | null;
105
+ ratePlans: {
106
+ id: string;
107
+ active: boolean;
108
+ name: string;
109
+ pricingModel: string;
110
+ basePrices: {
111
+ amount: number;
112
+ currencyCode: string;
113
+ }[];
114
+ roomPrices: {
115
+ amount: number;
116
+ currencyCode: string;
117
+ roomType: {
118
+ id: string;
119
+ name: string;
120
+ occupancy: {
121
+ adultsMin: number;
122
+ adultsMax: number;
123
+ childrenMax: number;
124
+ };
125
+ };
126
+ }[];
127
+ }[];
128
+ } | null>;
129
+ listProductDepartures(db: PostgresJsDatabase, productId: string, query: StorefrontDepartureListQuery): Promise<{
130
+ data: {
131
+ id: string;
132
+ productId: string;
133
+ itineraryId: string;
134
+ optionId: string | null;
135
+ dateLocal: string | null;
136
+ startAt: string | null;
137
+ endAt: string | null;
138
+ timezone: string;
139
+ startTime: {
140
+ id: string;
141
+ label: string | null;
142
+ startTimeLocal: string;
143
+ durationMinutes: number | null;
144
+ } | null;
145
+ meetingPoint: string | null;
146
+ capacity: number | null;
147
+ remaining: number | null;
148
+ departureStatus: "open" | "closed" | "sold_out" | "cancelled" | "on_request";
149
+ nights: number | null;
150
+ days: number | null;
151
+ ratePlans: {
152
+ id: string;
153
+ active: boolean;
154
+ name: string;
155
+ pricingModel: string;
156
+ basePrices: {
157
+ amount: number;
158
+ currencyCode: string;
159
+ }[];
160
+ roomPrices: {
161
+ amount: number;
162
+ currencyCode: string;
163
+ roomType: {
164
+ id: string;
165
+ name: string;
166
+ occupancy: {
167
+ adultsMin: number;
168
+ adultsMax: number;
169
+ childrenMax: number;
170
+ };
171
+ };
172
+ }[];
173
+ }[];
174
+ }[];
175
+ total: number;
176
+ limit: number;
177
+ offset: number;
178
+ }>;
179
+ previewDeparturePrice(db: PostgresJsDatabase, departureId: string, input: StorefrontDeparturePricePreviewInput): Promise<{
180
+ departureId: string;
181
+ productId: string;
182
+ optionId: string | null;
183
+ currencyCode: string;
184
+ basePrice: number;
185
+ taxAmount: number;
186
+ total: number;
187
+ notes: string | null;
188
+ lineItems: {
189
+ name: string;
190
+ total: number;
191
+ quantity: number;
192
+ unitPrice: number;
193
+ }[];
194
+ } | null>;
195
+ getProductExtensions(db: PostgresJsDatabase, productId: string, optionId?: string): Promise<{
196
+ extensions: {
197
+ id: string;
198
+ name: string;
199
+ label: string;
200
+ required: boolean;
201
+ selectable: boolean;
202
+ hasOptions: boolean;
203
+ refProductId: string | null;
204
+ thumb: string | null;
205
+ pricePerPerson: number | null;
206
+ currencyCode: string;
207
+ pricingMode: string;
208
+ defaultQuantity: number | null;
209
+ minQuantity: number | null;
210
+ maxQuantity: number | null;
211
+ }[];
212
+ items: {
213
+ id: string;
214
+ name: string;
215
+ label: string;
216
+ required: boolean;
217
+ selectable: boolean;
218
+ hasOptions: boolean;
219
+ refProductId: string | null;
220
+ thumb: string | null;
221
+ pricePerPerson: number | null;
222
+ currencyCode: string;
223
+ pricingMode: string;
224
+ defaultQuantity: number | null;
225
+ minQuantity: number | null;
226
+ maxQuantity: number | null;
227
+ }[];
228
+ details: {
229
+ [k: string]: {
230
+ description: string | null;
231
+ media: {
232
+ url: string;
233
+ alt: string | null;
234
+ }[];
235
+ };
236
+ };
237
+ currencyCode: string;
238
+ }>;
239
+ getProductAvailabilitySummary(db: PostgresJsDatabase, productId: string, query: StorefrontProductAvailabilitySummaryQuery): Promise<{
240
+ productId: string;
241
+ availabilityState: "closed" | "sold_out" | "cancelled" | "past_cutoff" | "too_early" | "unavailable" | "on_request" | "available";
242
+ counts: {
243
+ total: number;
244
+ open: number;
245
+ closed: number;
246
+ soldOut: number;
247
+ cancelled: number;
248
+ onRequest: number;
249
+ pastCutoff: number;
250
+ tooEarly: number;
251
+ available: number;
252
+ };
253
+ departures: {
254
+ id: string;
255
+ productId: string;
256
+ optionId: string | null;
257
+ dateLocal: string | null;
258
+ startAt: string | null;
259
+ endAt: string | null;
260
+ timezone: string;
261
+ status: "open" | "closed" | "sold_out" | "cancelled" | "on_request";
262
+ availabilityState: "closed" | "sold_out" | "cancelled" | "past_cutoff" | "too_early" | "unavailable" | "on_request" | "available";
263
+ capacity: number | null;
264
+ remaining: number | null;
265
+ pastCutoff: boolean;
266
+ tooEarly: boolean;
267
+ }[];
268
+ total: number;
269
+ limit: number;
270
+ offset: number;
271
+ }>;
272
+ getDepartureItinerary(db: PostgresJsDatabase, input: {
273
+ departureId: string;
274
+ productId: string;
275
+ }): Promise<{
276
+ id: string;
277
+ days: {
278
+ id: string;
279
+ title: string;
280
+ description: string | null;
281
+ thumbnail: {
282
+ url: string;
283
+ } | null;
284
+ segments: {
285
+ id: string;
286
+ title: string;
287
+ description: string | null;
288
+ }[];
289
+ }[];
290
+ } | null>;
291
+ listApplicableOffers(input: {
292
+ productId: string;
293
+ departureId?: string;
294
+ locale?: string;
295
+ context?: StorefrontRequestContext;
296
+ }): Promise<StorefrontPromotionalOffer[]>;
297
+ getOfferBySlug(input: {
298
+ slug: string;
299
+ locale?: string;
300
+ context?: StorefrontRequestContext;
301
+ }): Promise<StorefrontPromotionalOffer | null>;
302
+ };
303
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAUjE,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,oCAAoC,EAMzC,KAAK,yCAAyC,EAC9C,KAAK,0BAA0B,EAC/B,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAG7B,MAAM,iBAAiB,CAAA;AAExB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,uBAAuB,CAAA;IAClC,eAAe,CAAC,EAAE,CAChB,OAAO,EAAE,wBAAwB,KAC9B,OAAO,CAAC,uBAAuB,CAAC,GAAG,uBAAuB,CAAA;IAC/D,MAAM,CAAC,EAAE,wBAAwB,CAAA;IACjC,aAAa,CAAC,EAAE,CACd,OAAO,EAAE,wBAAwB,KAE/B,OAAO,CAAC,wBAAwB,GAAG,IAAI,GAAG,SAAS,CAAC,GACpD,wBAAwB,GACxB,IAAI,GACJ,SAAS,CAAA;CACd;AAED,MAAM,WAAW,wBAAwB;IACvC,EAAE,CAAC,EAAE,kBAAkB,CAAA;IACvB,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,wBAAwB;IACvC,oBAAoB,CAAC,EAAE,CACrB,KAAK,EAAE;QACL,SAAS,EAAE,MAAM,CAAA;QACjB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,GAAG,wBAAwB,KACzB,OAAO,CAAC,0BAA0B,EAAE,CAAC,GAAG,0BAA0B,EAAE,CAAA;IACzE,cAAc,CAAC,EAAE,CACf,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,GAAG,wBAAwB,KACzB,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC,GAAG,0BAA0B,GAAG,IAAI,CAAA;CACpF;AAgCD,wBAAgB,yBAAyB,CAAC,KAAK,CAAC,EAAE,uBAAuB,GAAG,kBAAkB,CA8B7F;AAED,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,wBAAwB;mBAgBvD,kBAAkB;gCAbK,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAiB7C,kBAAkB,eAAe,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BAIlD,kBAAkB,aACX,MAAM,SACV,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BAK/B,kBAAkB,eACT,MAAM,SACZ,oCAAoC;;;;;;;;;;;;;;;;6BAIpB,kBAAkB,aAAa,MAAM,aAAa,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCAI3E,kBAAkB,aACX,MAAM,SACV,yCAAyC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BAK5C,kBAAkB,SACf;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;;;;gCAIjB;QAChC,SAAS,EAAE,MAAM,CAAA;QACjB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,OAAO,CAAC,EAAE,wBAAwB,CAAA;KACnC,GAAG,OAAO,CAAC,0BAA0B,EAAE,CAAC;0BAOb;QAC1B,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,OAAO,CAAC,EAAE,wBAAwB,CAAA;KACnC,GAAG,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC;EASjD"}
@@ -0,0 +1,104 @@
1
+ import { getStorefrontDeparture, getStorefrontDepartureItinerary, getStorefrontProductAvailabilitySummary, getStorefrontProductExtensions, listStorefrontProductDepartures, previewStorefrontDeparturePrice, } from "./service-departures.js";
2
+ import { storefrontSettingsInputSchema, storefrontSettingsSchema, } from "./validation.js";
3
+ const defaultPaymentLabels = {
4
+ card: "Card",
5
+ bank_transfer: "Bank transfer",
6
+ cash: "Cash",
7
+ voucher: "Voucher",
8
+ invoice: "Invoice",
9
+ };
10
+ function normalizeField(field) {
11
+ return {
12
+ key: field.key,
13
+ label: field.label,
14
+ type: field.type,
15
+ required: field.required,
16
+ placeholder: field.placeholder ?? null,
17
+ description: field.description ?? null,
18
+ autocomplete: field.autocomplete ?? null,
19
+ options: field.options,
20
+ };
21
+ }
22
+ function normalizePaymentMethod(method) {
23
+ return {
24
+ code: method.code,
25
+ label: method.label ?? defaultPaymentLabels[method.code],
26
+ description: method.description ?? null,
27
+ enabled: method.enabled,
28
+ };
29
+ }
30
+ export function resolveStorefrontSettings(input) {
31
+ const parsed = storefrontSettingsInputSchema.parse(input ?? {});
32
+ return storefrontSettingsSchema.parse({
33
+ branding: {
34
+ logoUrl: parsed.branding?.logoUrl ?? null,
35
+ supportedLanguages: parsed.branding?.supportedLanguages ?? [],
36
+ },
37
+ support: {
38
+ email: parsed.support?.email ?? null,
39
+ phone: parsed.support?.phone ?? null,
40
+ },
41
+ legal: {
42
+ termsUrl: parsed.legal?.termsUrl ?? null,
43
+ privacyUrl: parsed.legal?.privacyUrl ?? null,
44
+ defaultContractTemplateId: parsed.legal?.defaultContractTemplateId ?? null,
45
+ },
46
+ forms: {
47
+ billing: {
48
+ fields: (parsed.forms?.billing?.fields ?? []).map(normalizeField),
49
+ },
50
+ travelers: {
51
+ fields: (parsed.forms?.travelers?.fields ?? []).map(normalizeField),
52
+ },
53
+ },
54
+ payment: {
55
+ defaultMethod: parsed.payment?.defaultMethod ?? null,
56
+ methods: (parsed.payment?.methods ?? []).map(normalizePaymentMethod),
57
+ },
58
+ });
59
+ }
60
+ export function createStorefrontService(options) {
61
+ const settings = resolveStorefrontSettings(options?.settings);
62
+ async function resolveSettings(context = {}) {
63
+ if (!options?.resolveSettings) {
64
+ return settings;
65
+ }
66
+ return resolveStorefrontSettings(await options.resolveSettings(context));
67
+ }
68
+ async function resolveOffers(context = {}) {
69
+ return (await options?.resolveOffers?.(context)) ?? options?.offers;
70
+ }
71
+ return {
72
+ getSettings() {
73
+ return settings;
74
+ },
75
+ resolveSettings,
76
+ getDeparture(db, departureId) {
77
+ return getStorefrontDeparture(db, departureId);
78
+ },
79
+ listProductDepartures(db, productId, query) {
80
+ return listStorefrontProductDepartures(db, productId, query);
81
+ },
82
+ previewDeparturePrice(db, departureId, input) {
83
+ return previewStorefrontDeparturePrice(db, departureId, input);
84
+ },
85
+ getProductExtensions(db, productId, optionId) {
86
+ return getStorefrontProductExtensions(db, productId, optionId);
87
+ },
88
+ getProductAvailabilitySummary(db, productId, query) {
89
+ return getStorefrontProductAvailabilitySummary(db, productId, query);
90
+ },
91
+ getDepartureItinerary(db, input) {
92
+ return getStorefrontDepartureItinerary(db, input);
93
+ },
94
+ async listApplicableOffers(input) {
95
+ const { context, ...offerInput } = input;
96
+ const offers = await resolveOffers(context)?.then((resolvers) => resolvers?.listApplicableOffers?.({ ...offerInput, ...(context ?? {}) }));
97
+ return offers ?? [];
98
+ },
99
+ async getOfferBySlug(input) {
100
+ const { context, ...offerInput } = input;
101
+ return ((await resolveOffers(context)?.then((resolvers) => resolvers?.getOfferBySlug?.({ ...offerInput, ...(context ?? {}) }))) ?? null);
102
+ },
103
+ };
104
+ }