@voyantjs/storefront 0.44.0 → 0.46.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.
- package/README.md +74 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/routes-public.d.ts +126 -0
- package/dist/routes-public.d.ts.map +1 -1
- package/dist/routes-public.js +20 -0
- package/dist/service-transport-eligibility.d.ts +10 -0
- package/dist/service-transport-eligibility.d.ts.map +1 -0
- package/dist/service-transport-eligibility.js +198 -0
- package/dist/service.d.ts +14 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +29 -0
- package/dist/transport-eligibility.d.ts +4 -0
- package/dist/transport-eligibility.d.ts.map +1 -0
- package/dist/transport-eligibility.js +2 -0
- package/dist/validation-transport-eligibility.d.ts +314 -0
- package/dist/validation-transport-eligibility.d.ts.map +1 -0
- package/dist/validation-transport-eligibility.js +97 -0
- package/package.json +14 -9
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# @voyantjs/storefront
|
|
2
|
+
|
|
3
|
+
Public storefront routes and service helpers for checkout-adjacent product, departure,
|
|
4
|
+
offer, and eligibility flows.
|
|
5
|
+
|
|
6
|
+
## Transport Eligibility
|
|
7
|
+
|
|
8
|
+
Storefronts can check whether traveler document facts satisfy departure-level
|
|
9
|
+
transport rules before checkout confirmation.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { createStorefrontPublicRoutes } from "@voyantjs/storefront"
|
|
13
|
+
|
|
14
|
+
createStorefrontPublicRoutes({
|
|
15
|
+
transportEligibilityRules: [
|
|
16
|
+
{
|
|
17
|
+
id: "egypt-passport-validity",
|
|
18
|
+
label: "Egypt passport validity",
|
|
19
|
+
productId: "prod_123",
|
|
20
|
+
destinationCountries: ["EG"],
|
|
21
|
+
nationalityCountries: ["RO"],
|
|
22
|
+
requiredDocumentType: "passport",
|
|
23
|
+
minValidityDaysAfterReturn: 180,
|
|
24
|
+
visaRequired: true,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Schemas and the standalone evaluator are exported from
|
|
31
|
+
`@voyantjs/storefront/transport-eligibility`.
|
|
32
|
+
|
|
33
|
+
The public API is available at:
|
|
34
|
+
|
|
35
|
+
- `POST /departures/:departureId/eligibility`
|
|
36
|
+
- `POST /products/:productId/departures/:departureId/eligibility`
|
|
37
|
+
|
|
38
|
+
Request bodies contain only eligibility facts:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"travelStartsOn": "2026-08-01",
|
|
43
|
+
"travelEndsOn": "2026-08-08",
|
|
44
|
+
"travelers": [
|
|
45
|
+
{
|
|
46
|
+
"travelerRef": "traveler_1",
|
|
47
|
+
"nationalityCountry": "RO",
|
|
48
|
+
"dateOfBirth": "1990-01-01",
|
|
49
|
+
"documents": [
|
|
50
|
+
{
|
|
51
|
+
"type": "passport",
|
|
52
|
+
"issuingCountry": "RO",
|
|
53
|
+
"expiresOn": "2027-03-01"
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"hasVisa": true
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Responses return a top-level `eligible` flag plus traveler-specific blocking
|
|
63
|
+
issues and warnings. Supported rule dimensions are product, departure,
|
|
64
|
+
destination country, nationality country, required document type, minimum
|
|
65
|
+
validity after return, age range, visa requirement, minor consent requirement,
|
|
66
|
+
and warning/blocking severity.
|
|
67
|
+
|
|
68
|
+
Do not send or store raw passport numbers through this surface. The route and
|
|
69
|
+
schemas only model document type, issuing country, expiry date, nationality,
|
|
70
|
+
birth date, and boolean evidence such as `hasVisa`.
|
|
71
|
+
|
|
72
|
+
This first slice is API-only. Admin CRUD and operator UI for managing transport
|
|
73
|
+
rules should persist normalized rule objects and can call the same public
|
|
74
|
+
eligibility service once added.
|
package/dist/index.d.ts
CHANGED
|
@@ -5,8 +5,11 @@ export type { StorefrontPublicRoutes } from "./routes-public.js";
|
|
|
5
5
|
export { createStorefrontPublicRoutes } from "./routes-public.js";
|
|
6
6
|
export type { StorefrontOfferResolvers, StorefrontRequestContext, StorefrontServiceOptions, } from "./service.js";
|
|
7
7
|
export { createStorefrontService, resolveStorefrontSettings } from "./service.js";
|
|
8
|
+
export { evaluateStorefrontTransportEligibility } from "./service-transport-eligibility.js";
|
|
8
9
|
export type { StorefrontAppliedOffer, StorefrontDepartureListQuery, StorefrontFormField, StorefrontFormFieldInput, StorefrontOfferApplyInput, StorefrontOfferMutationResult, StorefrontOfferRedeemInput, StorefrontPaymentMethod, StorefrontPaymentMethodCode, StorefrontPaymentMethodInput, StorefrontProductAvailabilitySummaryQuery, StorefrontPromotionalOffer, StorefrontSettings, StorefrontSettingsInput, } from "./validation.js";
|
|
9
10
|
export { storefrontAppliedOfferSchema, storefrontDepartureItinerarySchema, storefrontDepartureListQuerySchema, storefrontDepartureListResponseSchema, storefrontDeparturePricePreviewInputSchema, storefrontDeparturePricePreviewSchema, storefrontDepartureSchema, storefrontFormFieldInputSchema, storefrontFormFieldOptionSchema, storefrontFormFieldSchema, storefrontFormFieldTypeSchema, storefrontOfferApplyInputSchema, storefrontOfferAudienceSchema, storefrontOfferConflictSchema, storefrontOfferMutationReasonSchema, storefrontOfferMutationResponseSchema, storefrontOfferMutationResultSchema, storefrontOfferMutationStatusSchema, storefrontOfferRedeemInputSchema, storefrontPaymentMethodCodeSchema, storefrontPaymentMethodInputSchema, storefrontPaymentMethodSchema, storefrontProductAvailabilitySlotSchema, storefrontProductAvailabilityStateSchema, storefrontProductAvailabilitySummaryQuerySchema, storefrontProductAvailabilitySummaryResponseSchema, storefrontProductAvailabilitySummarySchema, storefrontProductExtensionsQuerySchema, storefrontProductExtensionsResponseSchema, storefrontPromotionalOfferListQuerySchema, storefrontPromotionalOfferListResponseSchema, storefrontPromotionalOfferResponseSchema, storefrontPromotionalOfferSchema, storefrontSettingsInputSchema, storefrontSettingsSchema, } from "./validation.js";
|
|
11
|
+
export type { StorefrontTransportEligibilityInput, StorefrontTransportEligibilityIssue, StorefrontTransportEligibilityResult, StorefrontTransportEligibilityRule, StorefrontTransportEligibilityRuleInput, } from "./validation-transport-eligibility.js";
|
|
12
|
+
export { storefrontRequiredDocumentTypeSchema, storefrontTransportEligibilityDocumentInputSchema, storefrontTransportEligibilityInputSchema, storefrontTransportEligibilityIssueCodeSchema, storefrontTransportEligibilityIssueSchema, storefrontTransportEligibilityResultSchema, storefrontTransportEligibilityRuleSchema, storefrontTransportEligibilitySeveritySchema, storefrontTransportEligibilityTravelerInputSchema, storefrontTransportEligibilityTravelerResultSchema, storefrontTravelDocumentTypeSchema, } from "./validation-transport-eligibility.js";
|
|
10
13
|
export declare const storefrontModule: Module;
|
|
11
14
|
export declare function createStorefrontHonoModule(options?: Parameters<typeof createStorefrontPublicRoutes>[0]): HonoModule;
|
|
12
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAEvD,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAA;AAEjE,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAChE,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAA;AACjE,YAAY,EACV,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAA;AACjF,YAAY,EACV,sBAAsB,EACtB,4BAA4B,EAC5B,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,6BAA6B,EAC7B,0BAA0B,EAC1B,uBAAuB,EACvB,2BAA2B,EAC3B,4BAA4B,EAC5B,yCAAyC,EACzC,0BAA0B,EAC1B,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,4BAA4B,EAC5B,kCAAkC,EAClC,kCAAkC,EAClC,qCAAqC,EACrC,0CAA0C,EAC1C,qCAAqC,EACrC,yBAAyB,EACzB,8BAA8B,EAC9B,+BAA+B,EAC/B,yBAAyB,EACzB,6BAA6B,EAC7B,+BAA+B,EAC/B,6BAA6B,EAC7B,6BAA6B,EAC7B,mCAAmC,EACnC,qCAAqC,EACrC,mCAAmC,EACnC,mCAAmC,EACnC,gCAAgC,EAChC,iCAAiC,EACjC,kCAAkC,EAClC,6BAA6B,EAC7B,uCAAuC,EACvC,wCAAwC,EACxC,+CAA+C,EAC/C,kDAAkD,EAClD,0CAA0C,EAC1C,sCAAsC,EACtC,yCAAyC,EACzC,yCAAyC,EACzC,4CAA4C,EAC5C,wCAAwC,EACxC,gCAAgC,EAChC,6BAA6B,EAC7B,wBAAwB,GACzB,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAEvD,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAA;AAEjE,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAChE,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAA;AACjE,YAAY,EACV,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAA;AACjF,OAAO,EAAE,sCAAsC,EAAE,MAAM,oCAAoC,CAAA;AAC3F,YAAY,EACV,sBAAsB,EACtB,4BAA4B,EAC5B,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,6BAA6B,EAC7B,0BAA0B,EAC1B,uBAAuB,EACvB,2BAA2B,EAC3B,4BAA4B,EAC5B,yCAAyC,EACzC,0BAA0B,EAC1B,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,4BAA4B,EAC5B,kCAAkC,EAClC,kCAAkC,EAClC,qCAAqC,EACrC,0CAA0C,EAC1C,qCAAqC,EACrC,yBAAyB,EACzB,8BAA8B,EAC9B,+BAA+B,EAC/B,yBAAyB,EACzB,6BAA6B,EAC7B,+BAA+B,EAC/B,6BAA6B,EAC7B,6BAA6B,EAC7B,mCAAmC,EACnC,qCAAqC,EACrC,mCAAmC,EACnC,mCAAmC,EACnC,gCAAgC,EAChC,iCAAiC,EACjC,kCAAkC,EAClC,6BAA6B,EAC7B,uCAAuC,EACvC,wCAAwC,EACxC,+CAA+C,EAC/C,kDAAkD,EAClD,0CAA0C,EAC1C,sCAAsC,EACtC,yCAAyC,EACzC,yCAAyC,EACzC,4CAA4C,EAC5C,wCAAwC,EACxC,gCAAgC,EAChC,6BAA6B,EAC7B,wBAAwB,GACzB,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACV,mCAAmC,EACnC,mCAAmC,EACnC,oCAAoC,EACpC,kCAAkC,EAClC,uCAAuC,GACxC,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EACL,oCAAoC,EACpC,iDAAiD,EACjD,yCAAyC,EACzC,6CAA6C,EAC7C,yCAAyC,EACzC,0CAA0C,EAC1C,wCAAwC,EACxC,4CAA4C,EAC5C,iDAAiD,EACjD,kDAAkD,EAClD,kCAAkC,GACnC,MAAM,uCAAuC,CAAA;AAE9C,eAAO,MAAM,gBAAgB,EAAE,MAE9B,CAAA;AAED,wBAAgB,0BAA0B,CACxC,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,4BAA4B,CAAC,CAAC,CAAC,CAAC,GAC3D,UAAU,CAMZ"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createStorefrontPublicRoutes } from "./routes-public.js";
|
|
2
2
|
export { createStorefrontPublicRoutes } from "./routes-public.js";
|
|
3
3
|
export { createStorefrontService, resolveStorefrontSettings } from "./service.js";
|
|
4
|
+
export { evaluateStorefrontTransportEligibility } from "./service-transport-eligibility.js";
|
|
4
5
|
export { storefrontAppliedOfferSchema, storefrontDepartureItinerarySchema, storefrontDepartureListQuerySchema, storefrontDepartureListResponseSchema, storefrontDeparturePricePreviewInputSchema, storefrontDeparturePricePreviewSchema, storefrontDepartureSchema, storefrontFormFieldInputSchema, storefrontFormFieldOptionSchema, storefrontFormFieldSchema, storefrontFormFieldTypeSchema, storefrontOfferApplyInputSchema, storefrontOfferAudienceSchema, storefrontOfferConflictSchema, storefrontOfferMutationReasonSchema, storefrontOfferMutationResponseSchema, storefrontOfferMutationResultSchema, storefrontOfferMutationStatusSchema, storefrontOfferRedeemInputSchema, storefrontPaymentMethodCodeSchema, storefrontPaymentMethodInputSchema, storefrontPaymentMethodSchema, storefrontProductAvailabilitySlotSchema, storefrontProductAvailabilityStateSchema, storefrontProductAvailabilitySummaryQuerySchema, storefrontProductAvailabilitySummaryResponseSchema, storefrontProductAvailabilitySummarySchema, storefrontProductExtensionsQuerySchema, storefrontProductExtensionsResponseSchema, storefrontPromotionalOfferListQuerySchema, storefrontPromotionalOfferListResponseSchema, storefrontPromotionalOfferResponseSchema, storefrontPromotionalOfferSchema, storefrontSettingsInputSchema, storefrontSettingsSchema, } from "./validation.js";
|
|
6
|
+
export { storefrontRequiredDocumentTypeSchema, storefrontTransportEligibilityDocumentInputSchema, storefrontTransportEligibilityInputSchema, storefrontTransportEligibilityIssueCodeSchema, storefrontTransportEligibilityIssueSchema, storefrontTransportEligibilityResultSchema, storefrontTransportEligibilityRuleSchema, storefrontTransportEligibilitySeveritySchema, storefrontTransportEligibilityTravelerInputSchema, storefrontTransportEligibilityTravelerResultSchema, storefrontTravelDocumentTypeSchema, } from "./validation-transport-eligibility.js";
|
|
5
7
|
export const storefrontModule = {
|
|
6
8
|
name: "storefront",
|
|
7
9
|
};
|
package/dist/routes-public.d.ts
CHANGED
|
@@ -243,6 +243,132 @@ export declare function createStorefrontPublicRoutes(options?: StorefrontService
|
|
|
243
243
|
status: 404;
|
|
244
244
|
};
|
|
245
245
|
};
|
|
246
|
+
} & {
|
|
247
|
+
"/departures/:departureId/eligibility": {
|
|
248
|
+
$post: {
|
|
249
|
+
input: {
|
|
250
|
+
param: {
|
|
251
|
+
departureId: string;
|
|
252
|
+
};
|
|
253
|
+
};
|
|
254
|
+
output: {
|
|
255
|
+
data: {
|
|
256
|
+
departureId: string;
|
|
257
|
+
productId: string | null;
|
|
258
|
+
travelStartsOn: string | null;
|
|
259
|
+
travelEndsOn: string | null;
|
|
260
|
+
eligible: boolean;
|
|
261
|
+
blockingIssues: {
|
|
262
|
+
code: "date_of_birth_required" | "document_required" | "document_expiry_required" | "document_validity" | "nationality_required" | "visa_required" | "minor_consent_required" | "travel_dates_required";
|
|
263
|
+
severity: "warning" | "blocking";
|
|
264
|
+
message: string;
|
|
265
|
+
travelerRef: string;
|
|
266
|
+
ruleId: string;
|
|
267
|
+
destinationCountries: string[];
|
|
268
|
+
requiredDocumentType: "passport" | "none" | "id_card" | "passport_or_id_card";
|
|
269
|
+
}[];
|
|
270
|
+
warnings: {
|
|
271
|
+
code: "date_of_birth_required" | "document_required" | "document_expiry_required" | "document_validity" | "nationality_required" | "visa_required" | "minor_consent_required" | "travel_dates_required";
|
|
272
|
+
severity: "warning" | "blocking";
|
|
273
|
+
message: string;
|
|
274
|
+
travelerRef: string;
|
|
275
|
+
ruleId: string;
|
|
276
|
+
destinationCountries: string[];
|
|
277
|
+
requiredDocumentType: "passport" | "none" | "id_card" | "passport_or_id_card";
|
|
278
|
+
}[];
|
|
279
|
+
travelers: {
|
|
280
|
+
travelerRef: string;
|
|
281
|
+
eligible: boolean;
|
|
282
|
+
matchedRuleIds: string[];
|
|
283
|
+
blockingIssues: {
|
|
284
|
+
code: "date_of_birth_required" | "document_required" | "document_expiry_required" | "document_validity" | "nationality_required" | "visa_required" | "minor_consent_required" | "travel_dates_required";
|
|
285
|
+
severity: "warning" | "blocking";
|
|
286
|
+
message: string;
|
|
287
|
+
travelerRef: string;
|
|
288
|
+
ruleId: string;
|
|
289
|
+
destinationCountries: string[];
|
|
290
|
+
requiredDocumentType: "passport" | "none" | "id_card" | "passport_or_id_card";
|
|
291
|
+
}[];
|
|
292
|
+
warnings: {
|
|
293
|
+
code: "date_of_birth_required" | "document_required" | "document_expiry_required" | "document_validity" | "nationality_required" | "visa_required" | "minor_consent_required" | "travel_dates_required";
|
|
294
|
+
severity: "warning" | "blocking";
|
|
295
|
+
message: string;
|
|
296
|
+
travelerRef: string;
|
|
297
|
+
ruleId: string;
|
|
298
|
+
destinationCountries: string[];
|
|
299
|
+
requiredDocumentType: "passport" | "none" | "id_card" | "passport_or_id_card";
|
|
300
|
+
}[];
|
|
301
|
+
}[];
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
outputFormat: "json";
|
|
305
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
306
|
+
};
|
|
307
|
+
};
|
|
308
|
+
} & {
|
|
309
|
+
"/products/:productId/departures/:departureId/eligibility": {
|
|
310
|
+
$post: {
|
|
311
|
+
input: {
|
|
312
|
+
param: {
|
|
313
|
+
departureId: string;
|
|
314
|
+
} & {
|
|
315
|
+
productId: string;
|
|
316
|
+
};
|
|
317
|
+
};
|
|
318
|
+
output: {
|
|
319
|
+
data: {
|
|
320
|
+
departureId: string;
|
|
321
|
+
productId: string | null;
|
|
322
|
+
travelStartsOn: string | null;
|
|
323
|
+
travelEndsOn: string | null;
|
|
324
|
+
eligible: boolean;
|
|
325
|
+
blockingIssues: {
|
|
326
|
+
code: "date_of_birth_required" | "document_required" | "document_expiry_required" | "document_validity" | "nationality_required" | "visa_required" | "minor_consent_required" | "travel_dates_required";
|
|
327
|
+
severity: "warning" | "blocking";
|
|
328
|
+
message: string;
|
|
329
|
+
travelerRef: string;
|
|
330
|
+
ruleId: string;
|
|
331
|
+
destinationCountries: string[];
|
|
332
|
+
requiredDocumentType: "passport" | "none" | "id_card" | "passport_or_id_card";
|
|
333
|
+
}[];
|
|
334
|
+
warnings: {
|
|
335
|
+
code: "date_of_birth_required" | "document_required" | "document_expiry_required" | "document_validity" | "nationality_required" | "visa_required" | "minor_consent_required" | "travel_dates_required";
|
|
336
|
+
severity: "warning" | "blocking";
|
|
337
|
+
message: string;
|
|
338
|
+
travelerRef: string;
|
|
339
|
+
ruleId: string;
|
|
340
|
+
destinationCountries: string[];
|
|
341
|
+
requiredDocumentType: "passport" | "none" | "id_card" | "passport_or_id_card";
|
|
342
|
+
}[];
|
|
343
|
+
travelers: {
|
|
344
|
+
travelerRef: string;
|
|
345
|
+
eligible: boolean;
|
|
346
|
+
matchedRuleIds: string[];
|
|
347
|
+
blockingIssues: {
|
|
348
|
+
code: "date_of_birth_required" | "document_required" | "document_expiry_required" | "document_validity" | "nationality_required" | "visa_required" | "minor_consent_required" | "travel_dates_required";
|
|
349
|
+
severity: "warning" | "blocking";
|
|
350
|
+
message: string;
|
|
351
|
+
travelerRef: string;
|
|
352
|
+
ruleId: string;
|
|
353
|
+
destinationCountries: string[];
|
|
354
|
+
requiredDocumentType: "passport" | "none" | "id_card" | "passport_or_id_card";
|
|
355
|
+
}[];
|
|
356
|
+
warnings: {
|
|
357
|
+
code: "date_of_birth_required" | "document_required" | "document_expiry_required" | "document_validity" | "nationality_required" | "visa_required" | "minor_consent_required" | "travel_dates_required";
|
|
358
|
+
severity: "warning" | "blocking";
|
|
359
|
+
message: string;
|
|
360
|
+
travelerRef: string;
|
|
361
|
+
ruleId: string;
|
|
362
|
+
destinationCountries: string[];
|
|
363
|
+
requiredDocumentType: "passport" | "none" | "id_card" | "passport_or_id_card";
|
|
364
|
+
}[];
|
|
365
|
+
}[];
|
|
366
|
+
};
|
|
367
|
+
};
|
|
368
|
+
outputFormat: "json";
|
|
369
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
370
|
+
};
|
|
371
|
+
};
|
|
246
372
|
} & {
|
|
247
373
|
"/products/:productId/extensions": {
|
|
248
374
|
$get: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes-public.d.ts","sourceRoot":"","sources":["../src/routes-public.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"routes-public.d.ts","sourceRoot":"","sources":["../src/routes-public.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,cAAc,CAAA;AAYrB,KAAK,GAAG,GAAG;IACT,SAAS,EAAE;QACT,EAAE,EAAE,OAAO,CAAA;KACZ,CAAA;CACF,CAAA;AAED,wBAAgB,4BAA4B,CAAC,OAAO,CAAC,EAAE,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAyI9E;AAED,MAAM,MAAM,sBAAsB,GAAG,UAAU,CAAC,OAAO,4BAA4B,CAAC,CAAA"}
|
package/dist/routes-public.js
CHANGED
|
@@ -2,6 +2,7 @@ import { parseJsonBody, parseQuery } from "@voyantjs/hono";
|
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import { createStorefrontService, } from "./service.js";
|
|
4
4
|
import { storefrontDepartureListQuerySchema, storefrontDeparturePricePreviewInputSchema, storefrontOfferApplyInputSchema, storefrontOfferRedeemInputSchema, storefrontProductAvailabilitySummaryQuerySchema, storefrontProductExtensionsQuerySchema, storefrontPromotionalOfferListQuerySchema, } from "./validation.js";
|
|
5
|
+
import { storefrontTransportEligibilityInputSchema } from "./validation-transport-eligibility.js";
|
|
5
6
|
export function createStorefrontPublicRoutes(options) {
|
|
6
7
|
const storefrontService = createStorefrontService(options);
|
|
7
8
|
function getRequestContext(c) {
|
|
@@ -29,6 +30,25 @@ export function createStorefrontPublicRoutes(options) {
|
|
|
29
30
|
return preview
|
|
30
31
|
? c.json({ data: preview })
|
|
31
32
|
: c.json({ error: "Storefront departure not found" }, 404);
|
|
33
|
+
})
|
|
34
|
+
.post("/departures/:departureId/eligibility", async (c) => {
|
|
35
|
+
return c.json({
|
|
36
|
+
data: await storefrontService.checkDepartureTransportEligibility({
|
|
37
|
+
departureId: c.req.param("departureId"),
|
|
38
|
+
body: await parseJsonBody(c, storefrontTransportEligibilityInputSchema),
|
|
39
|
+
context: getRequestContext(c),
|
|
40
|
+
}),
|
|
41
|
+
});
|
|
42
|
+
})
|
|
43
|
+
.post("/products/:productId/departures/:departureId/eligibility", async (c) => {
|
|
44
|
+
return c.json({
|
|
45
|
+
data: await storefrontService.checkDepartureTransportEligibility({
|
|
46
|
+
departureId: c.req.param("departureId"),
|
|
47
|
+
productId: c.req.param("productId"),
|
|
48
|
+
body: await parseJsonBody(c, storefrontTransportEligibilityInputSchema),
|
|
49
|
+
context: getRequestContext(c),
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
32
52
|
})
|
|
33
53
|
.get("/products/:productId/extensions", async (c) => {
|
|
34
54
|
const query = await parseQuery(c, storefrontProductExtensionsQuerySchema);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StorefrontTransportEligibilityInput, StorefrontTransportEligibilityResult, StorefrontTransportEligibilityRuleInput } from "./validation-transport-eligibility.js";
|
|
2
|
+
export declare function evaluateStorefrontTransportEligibility(input: {
|
|
3
|
+
departureId: string;
|
|
4
|
+
productId?: string | null;
|
|
5
|
+
travelStartsOn?: string | null;
|
|
6
|
+
travelEndsOn?: string | null;
|
|
7
|
+
travelers: StorefrontTransportEligibilityInput["travelers"];
|
|
8
|
+
rules: StorefrontTransportEligibilityRuleInput[];
|
|
9
|
+
}): StorefrontTransportEligibilityResult;
|
|
10
|
+
//# sourceMappingURL=service-transport-eligibility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-transport-eligibility.d.ts","sourceRoot":"","sources":["../src/service-transport-eligibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mCAAmC,EAEnC,oCAAoC,EAEpC,uCAAuC,EACxC,MAAM,uCAAuC,CAAA;AAoR9C,wBAAgB,sCAAsC,CAAC,KAAK,EAAE;IAC5D,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,SAAS,EAAE,mCAAmC,CAAC,WAAW,CAAC,CAAA;IAC3D,KAAK,EAAE,uCAAuC,EAAE,CAAA;CACjD,GAAG,oCAAoC,CA0CvC"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { storefrontTransportEligibilityRuleSchema } from "./validation-transport-eligibility.js";
|
|
2
|
+
function parseDate(value) {
|
|
3
|
+
if (!value)
|
|
4
|
+
return null;
|
|
5
|
+
const date = new Date(`${value}T00:00:00.000Z`);
|
|
6
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
7
|
+
}
|
|
8
|
+
function addDays(value, days) {
|
|
9
|
+
const date = parseDate(value);
|
|
10
|
+
if (!date)
|
|
11
|
+
return value;
|
|
12
|
+
date.setUTCDate(date.getUTCDate() + days);
|
|
13
|
+
return date.toISOString().slice(0, 10);
|
|
14
|
+
}
|
|
15
|
+
function getAgeOn(dateOfBirth, onDate) {
|
|
16
|
+
const birth = parseDate(dateOfBirth);
|
|
17
|
+
const reference = parseDate(onDate);
|
|
18
|
+
if (!birth || !reference)
|
|
19
|
+
return null;
|
|
20
|
+
let age = reference.getUTCFullYear() - birth.getUTCFullYear();
|
|
21
|
+
const birthdayThisYear = Date.UTC(reference.getUTCFullYear(), birth.getUTCMonth(), birth.getUTCDate());
|
|
22
|
+
if (reference.getTime() < birthdayThisYear) {
|
|
23
|
+
age -= 1;
|
|
24
|
+
}
|
|
25
|
+
return age;
|
|
26
|
+
}
|
|
27
|
+
function isBeforeDate(left, right) {
|
|
28
|
+
const leftDate = parseDate(left);
|
|
29
|
+
const rightDate = parseDate(right);
|
|
30
|
+
if (!leftDate || !rightDate)
|
|
31
|
+
return false;
|
|
32
|
+
return leftDate.getTime() < rightDate.getTime();
|
|
33
|
+
}
|
|
34
|
+
function findDocuments(traveler, rule) {
|
|
35
|
+
if (rule.requiredDocumentType === "none")
|
|
36
|
+
return [];
|
|
37
|
+
if (rule.requiredDocumentType === "passport_or_id_card") {
|
|
38
|
+
return traveler.documents.filter((document) => document.type === "passport" || document.type === "id_card");
|
|
39
|
+
}
|
|
40
|
+
return traveler.documents.filter((document) => document.type === rule.requiredDocumentType);
|
|
41
|
+
}
|
|
42
|
+
function documentTypeLabel(rule) {
|
|
43
|
+
switch (rule.requiredDocumentType) {
|
|
44
|
+
case "passport_or_id_card":
|
|
45
|
+
return "passport or ID card";
|
|
46
|
+
case "id_card":
|
|
47
|
+
return "ID card";
|
|
48
|
+
case "passport":
|
|
49
|
+
return "passport";
|
|
50
|
+
case "none":
|
|
51
|
+
return "travel document";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function buildIssue(code, traveler, rule, message) {
|
|
55
|
+
return {
|
|
56
|
+
code,
|
|
57
|
+
severity: rule.severity,
|
|
58
|
+
message: rule.message ?? message,
|
|
59
|
+
travelerRef: traveler.travelerRef,
|
|
60
|
+
ruleId: rule.id,
|
|
61
|
+
destinationCountries: rule.destinationCountries,
|
|
62
|
+
requiredDocumentType: rule.requiredDocumentType,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function pushIssue(target, issue) {
|
|
66
|
+
if (issue.severity === "warning") {
|
|
67
|
+
target.warnings.push(issue);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
target.blockingIssues.push(issue);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function appliesToTarget(rule, target) {
|
|
74
|
+
if (rule.productId && rule.productId !== target.productId)
|
|
75
|
+
return false;
|
|
76
|
+
if (rule.departureId && rule.departureId !== target.departureId)
|
|
77
|
+
return false;
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
function appliesToTraveler(rule, traveler, travelStartsOn) {
|
|
81
|
+
if (rule.nationalityCountries.length > 0) {
|
|
82
|
+
if (!traveler.nationalityCountry)
|
|
83
|
+
return "missing_nationality";
|
|
84
|
+
if (!rule.nationalityCountries.includes(traveler.nationalityCountry))
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
if (rule.minAge == null && rule.maxAge == null)
|
|
88
|
+
return true;
|
|
89
|
+
if (!traveler.dateOfBirth || !travelStartsOn)
|
|
90
|
+
return "missing_age_basis";
|
|
91
|
+
const age = getAgeOn(traveler.dateOfBirth, travelStartsOn);
|
|
92
|
+
if (age == null)
|
|
93
|
+
return "missing_age_basis";
|
|
94
|
+
if (rule.minAge != null && age < rule.minAge)
|
|
95
|
+
return false;
|
|
96
|
+
if (rule.maxAge != null && age > rule.maxAge)
|
|
97
|
+
return false;
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
function evaluateTravelerRule(traveler, rule, target) {
|
|
101
|
+
const blockingIssues = [];
|
|
102
|
+
const warnings = [];
|
|
103
|
+
const resultTarget = { blockingIssues, warnings };
|
|
104
|
+
const travelerApplicability = appliesToTraveler(rule, traveler, target.travelStartsOn);
|
|
105
|
+
if (travelerApplicability === false) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
if (travelerApplicability === "missing_nationality") {
|
|
109
|
+
pushIssue(resultTarget, buildIssue("nationality_required", traveler, rule, "Traveler nationality is required to evaluate destination document rules."));
|
|
110
|
+
}
|
|
111
|
+
if (travelerApplicability === "missing_age_basis") {
|
|
112
|
+
pushIssue(resultTarget, buildIssue("date_of_birth_required", traveler, rule, "Traveler date of birth and travel start date are required to evaluate age rules."));
|
|
113
|
+
}
|
|
114
|
+
const documents = findDocuments(traveler, rule);
|
|
115
|
+
if (rule.requiredDocumentType !== "none" && documents.length === 0) {
|
|
116
|
+
pushIssue(resultTarget, buildIssue("document_required", traveler, rule, `Traveler needs a ${documentTypeLabel(rule)} for this destination.`));
|
|
117
|
+
}
|
|
118
|
+
if (rule.minValidityDaysAfterReturn > 0) {
|
|
119
|
+
if (!target.travelEndsOn) {
|
|
120
|
+
pushIssue(resultTarget, buildIssue("travel_dates_required", traveler, rule, "Travel end date is required to evaluate document validity after return."));
|
|
121
|
+
}
|
|
122
|
+
else if (documents.length === 0) {
|
|
123
|
+
// Missing documents are already reported through document_required.
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
const requiredValidUntil = addDays(target.travelEndsOn, rule.minValidityDaysAfterReturn);
|
|
127
|
+
const documentsWithExpiry = documents.filter((document) => typeof document.expiresOn === "string");
|
|
128
|
+
const hasValidDocument = documentsWithExpiry.some((document) => !isBeforeDate(document.expiresOn, requiredValidUntil));
|
|
129
|
+
if (hasValidDocument) {
|
|
130
|
+
// Any acceptable document can satisfy a passport-or-ID-card validity rule.
|
|
131
|
+
}
|
|
132
|
+
else if (documentsWithExpiry.length > 0) {
|
|
133
|
+
pushIssue(resultTarget, buildIssue("document_validity", traveler, rule, `Traveler ${documentTypeLabel(rule)} must be valid until at least ${requiredValidUntil}.`));
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
pushIssue(resultTarget, buildIssue("document_expiry_required", traveler, rule, `Traveler ${documentTypeLabel(rule)} expiry date is required.`));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (rule.visaRequired) {
|
|
141
|
+
const hasVisa = traveler.hasVisa || traveler.documents.some((document) => document.type === "visa");
|
|
142
|
+
if (!hasVisa) {
|
|
143
|
+
pushIssue(resultTarget, buildIssue("visa_required", traveler, rule, "Traveler needs a visa for this destination."));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (rule.minorConsentRequired) {
|
|
147
|
+
const age = traveler.dateOfBirth && target.travelStartsOn
|
|
148
|
+
? getAgeOn(traveler.dateOfBirth, target.travelStartsOn)
|
|
149
|
+
: null;
|
|
150
|
+
const isMinor = age == null ? true : age < 18;
|
|
151
|
+
const hasConsent = traveler.hasMinorConsent ||
|
|
152
|
+
traveler.travelingWithGuardian ||
|
|
153
|
+
traveler.documents.some((document) => document.type === "minor_consent");
|
|
154
|
+
if (isMinor && !hasConsent) {
|
|
155
|
+
pushIssue(resultTarget, buildIssue("minor_consent_required", traveler, rule, "Minor traveler needs guardian travel consent for this departure."));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return { blockingIssues, warnings };
|
|
159
|
+
}
|
|
160
|
+
export function evaluateStorefrontTransportEligibility(input) {
|
|
161
|
+
const travelStartsOn = input.travelStartsOn ?? null;
|
|
162
|
+
const travelEndsOn = input.travelEndsOn ?? null;
|
|
163
|
+
const rules = input.rules
|
|
164
|
+
.map((rule) => storefrontTransportEligibilityRuleSchema.parse(rule))
|
|
165
|
+
.filter((rule) => appliesToTarget(rule, input));
|
|
166
|
+
const travelerResults = input.travelers.map((traveler) => {
|
|
167
|
+
const blockingIssues = [];
|
|
168
|
+
const warnings = [];
|
|
169
|
+
const matchedRuleIds = [];
|
|
170
|
+
for (const rule of rules) {
|
|
171
|
+
const result = evaluateTravelerRule(traveler, rule, { travelStartsOn, travelEndsOn });
|
|
172
|
+
if (!result)
|
|
173
|
+
continue;
|
|
174
|
+
matchedRuleIds.push(rule.id);
|
|
175
|
+
blockingIssues.push(...result.blockingIssues);
|
|
176
|
+
warnings.push(...result.warnings);
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
travelerRef: traveler.travelerRef,
|
|
180
|
+
eligible: blockingIssues.length === 0,
|
|
181
|
+
matchedRuleIds,
|
|
182
|
+
blockingIssues,
|
|
183
|
+
warnings,
|
|
184
|
+
};
|
|
185
|
+
});
|
|
186
|
+
const blockingIssues = travelerResults.flatMap((traveler) => traveler.blockingIssues);
|
|
187
|
+
const warnings = travelerResults.flatMap((traveler) => traveler.warnings);
|
|
188
|
+
return {
|
|
189
|
+
departureId: input.departureId,
|
|
190
|
+
productId: input.productId ?? null,
|
|
191
|
+
travelStartsOn,
|
|
192
|
+
travelEndsOn,
|
|
193
|
+
eligible: blockingIssues.length === 0,
|
|
194
|
+
blockingIssues,
|
|
195
|
+
warnings,
|
|
196
|
+
travelers: travelerResults,
|
|
197
|
+
};
|
|
198
|
+
}
|
package/dist/service.d.ts
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
2
2
|
import { type StorefrontDepartureListQuery, type StorefrontDeparturePricePreviewInput, type StorefrontOfferApplyInput, type StorefrontOfferMutationResult, type StorefrontOfferRedeemInput, type StorefrontProductAvailabilitySummaryQuery, type StorefrontPromotionalOffer, type StorefrontSettings, type StorefrontSettingsInput } from "./validation.js";
|
|
3
|
+
import type { StorefrontTransportEligibilityInput, StorefrontTransportEligibilityResult, StorefrontTransportEligibilityRuleInput } from "./validation-transport-eligibility.js";
|
|
3
4
|
export interface StorefrontServiceOptions {
|
|
4
5
|
settings?: StorefrontSettingsInput;
|
|
5
6
|
resolveSettings?: (context: StorefrontRequestContext) => Promise<StorefrontSettingsInput> | StorefrontSettingsInput;
|
|
6
7
|
offers?: StorefrontOfferResolvers;
|
|
7
8
|
resolveOffers?: (context: StorefrontRequestContext) => Promise<StorefrontOfferResolvers | null | undefined> | StorefrontOfferResolvers | null | undefined;
|
|
9
|
+
transportEligibilityRules?: StorefrontTransportEligibilityRuleInput[];
|
|
10
|
+
resolveTransportEligibilityRules?: (input: {
|
|
11
|
+
departureId: string;
|
|
12
|
+
productId?: string | null;
|
|
13
|
+
travelStartsOn?: string | null;
|
|
14
|
+
travelEndsOn?: string | null;
|
|
15
|
+
} & StorefrontRequestContext) => Promise<StorefrontTransportEligibilityRuleInput[]> | StorefrontTransportEligibilityRuleInput[];
|
|
8
16
|
}
|
|
9
17
|
export interface StorefrontRequestContext {
|
|
10
18
|
db?: PostgresJsDatabase;
|
|
@@ -296,6 +304,12 @@ export declare function createStorefrontService(options?: StorefrontServiceOptio
|
|
|
296
304
|
}[];
|
|
297
305
|
}[];
|
|
298
306
|
} | null>;
|
|
307
|
+
checkDepartureTransportEligibility(input: {
|
|
308
|
+
departureId: string;
|
|
309
|
+
productId?: string | null;
|
|
310
|
+
body: StorefrontTransportEligibilityInput;
|
|
311
|
+
context?: StorefrontRequestContext;
|
|
312
|
+
}): Promise<StorefrontTransportEligibilityResult>;
|
|
299
313
|
listApplicableOffers(input: {
|
|
300
314
|
productId: string;
|
|
301
315
|
departureId?: string;
|
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|
package/dist/service.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getStorefrontDeparture, getStorefrontDepartureItinerary, getStorefrontProductAvailabilitySummary, getStorefrontProductExtensions, listStorefrontProductDepartures, previewStorefrontDeparturePrice, } from "./service-departures.js";
|
|
2
|
+
import { evaluateStorefrontTransportEligibility } from "./service-transport-eligibility.js";
|
|
2
3
|
import { storefrontSettingsInputSchema, storefrontSettingsSchema, } from "./validation.js";
|
|
3
4
|
const defaultPaymentLabels = {
|
|
4
5
|
card: "Card",
|
|
@@ -68,6 +69,11 @@ export function createStorefrontService(options) {
|
|
|
68
69
|
async function resolveOffers(context = {}) {
|
|
69
70
|
return (await options?.resolveOffers?.(context)) ?? options?.offers;
|
|
70
71
|
}
|
|
72
|
+
async function resolveTransportEligibilityRules(input) {
|
|
73
|
+
return ((await options?.resolveTransportEligibilityRules?.(input)) ??
|
|
74
|
+
options?.transportEligibilityRules ??
|
|
75
|
+
[]);
|
|
76
|
+
}
|
|
71
77
|
return {
|
|
72
78
|
getSettings() {
|
|
73
79
|
return settings;
|
|
@@ -91,6 +97,29 @@ export function createStorefrontService(options) {
|
|
|
91
97
|
getDepartureItinerary(db, input) {
|
|
92
98
|
return getStorefrontDepartureItinerary(db, input);
|
|
93
99
|
},
|
|
100
|
+
async checkDepartureTransportEligibility(input) {
|
|
101
|
+
const { context, body, departureId } = input;
|
|
102
|
+
const needsDeparture = context?.db && (!input.productId || !body.travelStartsOn || !body.travelEndsOn);
|
|
103
|
+
const departure = needsDeparture && context?.db ? await getStorefrontDeparture(context.db, departureId) : null;
|
|
104
|
+
const productId = input.productId ?? departure?.productId ?? null;
|
|
105
|
+
const travelStartsOn = body.travelStartsOn ?? departure?.dateLocal ?? departure?.startAt?.slice(0, 10) ?? null;
|
|
106
|
+
const travelEndsOn = body.travelEndsOn ?? departure?.endAt?.slice(0, 10) ?? departure?.dateLocal ?? null;
|
|
107
|
+
const rules = await resolveTransportEligibilityRules({
|
|
108
|
+
...(context ?? {}),
|
|
109
|
+
departureId,
|
|
110
|
+
productId,
|
|
111
|
+
travelStartsOn,
|
|
112
|
+
travelEndsOn,
|
|
113
|
+
});
|
|
114
|
+
return evaluateStorefrontTransportEligibility({
|
|
115
|
+
departureId,
|
|
116
|
+
productId,
|
|
117
|
+
travelStartsOn,
|
|
118
|
+
travelEndsOn,
|
|
119
|
+
travelers: body.travelers,
|
|
120
|
+
rules,
|
|
121
|
+
});
|
|
122
|
+
},
|
|
94
123
|
async listApplicableOffers(input) {
|
|
95
124
|
const { context, ...offerInput } = input;
|
|
96
125
|
const offers = await resolveOffers(context)?.then((resolvers) => resolvers?.listApplicableOffers?.({ ...offerInput, ...(context ?? {}) }));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { evaluateStorefrontTransportEligibility } from "./service-transport-eligibility.js";
|
|
2
|
+
export type { StorefrontTransportEligibilityInput, StorefrontTransportEligibilityIssue, StorefrontTransportEligibilityResult, StorefrontTransportEligibilityRule, StorefrontTransportEligibilityRuleInput, } from "./validation-transport-eligibility.js";
|
|
3
|
+
export { storefrontRequiredDocumentTypeSchema, storefrontTransportEligibilityDocumentInputSchema, storefrontTransportEligibilityInputSchema, storefrontTransportEligibilityIssueCodeSchema, storefrontTransportEligibilityIssueSchema, storefrontTransportEligibilityResultSchema, storefrontTransportEligibilityRuleSchema, storefrontTransportEligibilitySeveritySchema, storefrontTransportEligibilityTravelerInputSchema, storefrontTransportEligibilityTravelerResultSchema, storefrontTravelDocumentTypeSchema, } from "./validation-transport-eligibility.js";
|
|
4
|
+
//# sourceMappingURL=transport-eligibility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-eligibility.d.ts","sourceRoot":"","sources":["../src/transport-eligibility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sCAAsC,EAAE,MAAM,oCAAoC,CAAA;AAC3F,YAAY,EACV,mCAAmC,EACnC,mCAAmC,EACnC,oCAAoC,EACpC,kCAAkC,EAClC,uCAAuC,GACxC,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EACL,oCAAoC,EACpC,iDAAiD,EACjD,yCAAyC,EACzC,6CAA6C,EAC7C,yCAAyC,EACzC,0CAA0C,EAC1C,wCAAwC,EACxC,4CAA4C,EAC5C,iDAAiD,EACjD,kDAAkD,EAClD,kCAAkC,GACnC,MAAM,uCAAuC,CAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { evaluateStorefrontTransportEligibility } from "./service-transport-eligibility.js";
|
|
2
|
+
export { storefrontRequiredDocumentTypeSchema, storefrontTransportEligibilityDocumentInputSchema, storefrontTransportEligibilityInputSchema, storefrontTransportEligibilityIssueCodeSchema, storefrontTransportEligibilityIssueSchema, storefrontTransportEligibilityResultSchema, storefrontTransportEligibilityRuleSchema, storefrontTransportEligibilitySeveritySchema, storefrontTransportEligibilityTravelerInputSchema, storefrontTransportEligibilityTravelerResultSchema, storefrontTravelDocumentTypeSchema, } from "./validation-transport-eligibility.js";
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const storefrontTravelDocumentTypeSchema: z.ZodEnum<{
|
|
3
|
+
passport: "passport";
|
|
4
|
+
visa: "visa";
|
|
5
|
+
other: "other";
|
|
6
|
+
id_card: "id_card";
|
|
7
|
+
residence_permit: "residence_permit";
|
|
8
|
+
minor_consent: "minor_consent";
|
|
9
|
+
}>;
|
|
10
|
+
export declare const storefrontRequiredDocumentTypeSchema: z.ZodEnum<{
|
|
11
|
+
passport: "passport";
|
|
12
|
+
none: "none";
|
|
13
|
+
id_card: "id_card";
|
|
14
|
+
passport_or_id_card: "passport_or_id_card";
|
|
15
|
+
}>;
|
|
16
|
+
export declare const storefrontTransportEligibilitySeveritySchema: z.ZodEnum<{
|
|
17
|
+
warning: "warning";
|
|
18
|
+
blocking: "blocking";
|
|
19
|
+
}>;
|
|
20
|
+
export declare const storefrontTransportEligibilityRuleSchema: z.ZodObject<{
|
|
21
|
+
id: z.ZodString;
|
|
22
|
+
label: z.ZodString;
|
|
23
|
+
productId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
24
|
+
departureId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
25
|
+
destinationCountries: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
26
|
+
nationalityCountries: z.ZodDefault<z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>>;
|
|
27
|
+
requiredDocumentType: z.ZodDefault<z.ZodEnum<{
|
|
28
|
+
passport: "passport";
|
|
29
|
+
none: "none";
|
|
30
|
+
id_card: "id_card";
|
|
31
|
+
passport_or_id_card: "passport_or_id_card";
|
|
32
|
+
}>>;
|
|
33
|
+
minValidityDaysAfterReturn: z.ZodDefault<z.ZodNumber>;
|
|
34
|
+
minAge: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
|
|
35
|
+
maxAge: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
|
|
36
|
+
visaRequired: z.ZodDefault<z.ZodBoolean>;
|
|
37
|
+
minorConsentRequired: z.ZodDefault<z.ZodBoolean>;
|
|
38
|
+
severity: z.ZodDefault<z.ZodEnum<{
|
|
39
|
+
warning: "warning";
|
|
40
|
+
blocking: "blocking";
|
|
41
|
+
}>>;
|
|
42
|
+
message: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
export declare const storefrontTransportEligibilityDocumentInputSchema: z.ZodObject<{
|
|
45
|
+
type: z.ZodEnum<{
|
|
46
|
+
passport: "passport";
|
|
47
|
+
visa: "visa";
|
|
48
|
+
other: "other";
|
|
49
|
+
id_card: "id_card";
|
|
50
|
+
residence_permit: "residence_permit";
|
|
51
|
+
minor_consent: "minor_consent";
|
|
52
|
+
}>;
|
|
53
|
+
issuingCountry: z.ZodNullable<z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>>;
|
|
54
|
+
expiresOn: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
55
|
+
}, z.core.$strip>;
|
|
56
|
+
export declare const storefrontTransportEligibilityTravelerInputSchema: z.ZodObject<{
|
|
57
|
+
travelerRef: z.ZodString;
|
|
58
|
+
nationalityCountry: z.ZodNullable<z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>>;
|
|
59
|
+
dateOfBirth: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
60
|
+
documents: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
61
|
+
type: z.ZodEnum<{
|
|
62
|
+
passport: "passport";
|
|
63
|
+
visa: "visa";
|
|
64
|
+
other: "other";
|
|
65
|
+
id_card: "id_card";
|
|
66
|
+
residence_permit: "residence_permit";
|
|
67
|
+
minor_consent: "minor_consent";
|
|
68
|
+
}>;
|
|
69
|
+
issuingCountry: z.ZodNullable<z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>>;
|
|
70
|
+
expiresOn: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
71
|
+
}, z.core.$strip>>>;
|
|
72
|
+
hasVisa: z.ZodDefault<z.ZodBoolean>;
|
|
73
|
+
travelingWithGuardian: z.ZodDefault<z.ZodBoolean>;
|
|
74
|
+
hasMinorConsent: z.ZodDefault<z.ZodBoolean>;
|
|
75
|
+
}, z.core.$strip>;
|
|
76
|
+
export declare const storefrontTransportEligibilityInputSchema: z.ZodObject<{
|
|
77
|
+
travelStartsOn: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
78
|
+
travelEndsOn: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
79
|
+
travelers: z.ZodArray<z.ZodObject<{
|
|
80
|
+
travelerRef: z.ZodString;
|
|
81
|
+
nationalityCountry: z.ZodNullable<z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>>;
|
|
82
|
+
dateOfBirth: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
83
|
+
documents: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
84
|
+
type: z.ZodEnum<{
|
|
85
|
+
passport: "passport";
|
|
86
|
+
visa: "visa";
|
|
87
|
+
other: "other";
|
|
88
|
+
id_card: "id_card";
|
|
89
|
+
residence_permit: "residence_permit";
|
|
90
|
+
minor_consent: "minor_consent";
|
|
91
|
+
}>;
|
|
92
|
+
issuingCountry: z.ZodNullable<z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>>;
|
|
93
|
+
expiresOn: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
94
|
+
}, z.core.$strip>>>;
|
|
95
|
+
hasVisa: z.ZodDefault<z.ZodBoolean>;
|
|
96
|
+
travelingWithGuardian: z.ZodDefault<z.ZodBoolean>;
|
|
97
|
+
hasMinorConsent: z.ZodDefault<z.ZodBoolean>;
|
|
98
|
+
}, z.core.$strip>>;
|
|
99
|
+
}, z.core.$strip>;
|
|
100
|
+
export declare const storefrontTransportEligibilityIssueCodeSchema: z.ZodEnum<{
|
|
101
|
+
date_of_birth_required: "date_of_birth_required";
|
|
102
|
+
document_required: "document_required";
|
|
103
|
+
document_expiry_required: "document_expiry_required";
|
|
104
|
+
document_validity: "document_validity";
|
|
105
|
+
nationality_required: "nationality_required";
|
|
106
|
+
visa_required: "visa_required";
|
|
107
|
+
minor_consent_required: "minor_consent_required";
|
|
108
|
+
travel_dates_required: "travel_dates_required";
|
|
109
|
+
}>;
|
|
110
|
+
export declare const storefrontTransportEligibilityIssueSchema: z.ZodObject<{
|
|
111
|
+
code: z.ZodEnum<{
|
|
112
|
+
date_of_birth_required: "date_of_birth_required";
|
|
113
|
+
document_required: "document_required";
|
|
114
|
+
document_expiry_required: "document_expiry_required";
|
|
115
|
+
document_validity: "document_validity";
|
|
116
|
+
nationality_required: "nationality_required";
|
|
117
|
+
visa_required: "visa_required";
|
|
118
|
+
minor_consent_required: "minor_consent_required";
|
|
119
|
+
travel_dates_required: "travel_dates_required";
|
|
120
|
+
}>;
|
|
121
|
+
severity: z.ZodEnum<{
|
|
122
|
+
warning: "warning";
|
|
123
|
+
blocking: "blocking";
|
|
124
|
+
}>;
|
|
125
|
+
message: z.ZodString;
|
|
126
|
+
travelerRef: z.ZodString;
|
|
127
|
+
ruleId: z.ZodString;
|
|
128
|
+
destinationCountries: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
129
|
+
requiredDocumentType: z.ZodEnum<{
|
|
130
|
+
passport: "passport";
|
|
131
|
+
none: "none";
|
|
132
|
+
id_card: "id_card";
|
|
133
|
+
passport_or_id_card: "passport_or_id_card";
|
|
134
|
+
}>;
|
|
135
|
+
}, z.core.$strip>;
|
|
136
|
+
export declare const storefrontTransportEligibilityTravelerResultSchema: z.ZodObject<{
|
|
137
|
+
travelerRef: z.ZodString;
|
|
138
|
+
eligible: z.ZodBoolean;
|
|
139
|
+
matchedRuleIds: z.ZodArray<z.ZodString>;
|
|
140
|
+
blockingIssues: z.ZodArray<z.ZodObject<{
|
|
141
|
+
code: z.ZodEnum<{
|
|
142
|
+
date_of_birth_required: "date_of_birth_required";
|
|
143
|
+
document_required: "document_required";
|
|
144
|
+
document_expiry_required: "document_expiry_required";
|
|
145
|
+
document_validity: "document_validity";
|
|
146
|
+
nationality_required: "nationality_required";
|
|
147
|
+
visa_required: "visa_required";
|
|
148
|
+
minor_consent_required: "minor_consent_required";
|
|
149
|
+
travel_dates_required: "travel_dates_required";
|
|
150
|
+
}>;
|
|
151
|
+
severity: z.ZodEnum<{
|
|
152
|
+
warning: "warning";
|
|
153
|
+
blocking: "blocking";
|
|
154
|
+
}>;
|
|
155
|
+
message: z.ZodString;
|
|
156
|
+
travelerRef: z.ZodString;
|
|
157
|
+
ruleId: z.ZodString;
|
|
158
|
+
destinationCountries: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
159
|
+
requiredDocumentType: z.ZodEnum<{
|
|
160
|
+
passport: "passport";
|
|
161
|
+
none: "none";
|
|
162
|
+
id_card: "id_card";
|
|
163
|
+
passport_or_id_card: "passport_or_id_card";
|
|
164
|
+
}>;
|
|
165
|
+
}, z.core.$strip>>;
|
|
166
|
+
warnings: z.ZodArray<z.ZodObject<{
|
|
167
|
+
code: z.ZodEnum<{
|
|
168
|
+
date_of_birth_required: "date_of_birth_required";
|
|
169
|
+
document_required: "document_required";
|
|
170
|
+
document_expiry_required: "document_expiry_required";
|
|
171
|
+
document_validity: "document_validity";
|
|
172
|
+
nationality_required: "nationality_required";
|
|
173
|
+
visa_required: "visa_required";
|
|
174
|
+
minor_consent_required: "minor_consent_required";
|
|
175
|
+
travel_dates_required: "travel_dates_required";
|
|
176
|
+
}>;
|
|
177
|
+
severity: z.ZodEnum<{
|
|
178
|
+
warning: "warning";
|
|
179
|
+
blocking: "blocking";
|
|
180
|
+
}>;
|
|
181
|
+
message: z.ZodString;
|
|
182
|
+
travelerRef: z.ZodString;
|
|
183
|
+
ruleId: z.ZodString;
|
|
184
|
+
destinationCountries: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
185
|
+
requiredDocumentType: z.ZodEnum<{
|
|
186
|
+
passport: "passport";
|
|
187
|
+
none: "none";
|
|
188
|
+
id_card: "id_card";
|
|
189
|
+
passport_or_id_card: "passport_or_id_card";
|
|
190
|
+
}>;
|
|
191
|
+
}, z.core.$strip>>;
|
|
192
|
+
}, z.core.$strip>;
|
|
193
|
+
export declare const storefrontTransportEligibilityResultSchema: z.ZodObject<{
|
|
194
|
+
departureId: z.ZodString;
|
|
195
|
+
productId: z.ZodNullable<z.ZodString>;
|
|
196
|
+
travelStartsOn: z.ZodNullable<z.ZodString>;
|
|
197
|
+
travelEndsOn: z.ZodNullable<z.ZodString>;
|
|
198
|
+
eligible: z.ZodBoolean;
|
|
199
|
+
blockingIssues: z.ZodArray<z.ZodObject<{
|
|
200
|
+
code: z.ZodEnum<{
|
|
201
|
+
date_of_birth_required: "date_of_birth_required";
|
|
202
|
+
document_required: "document_required";
|
|
203
|
+
document_expiry_required: "document_expiry_required";
|
|
204
|
+
document_validity: "document_validity";
|
|
205
|
+
nationality_required: "nationality_required";
|
|
206
|
+
visa_required: "visa_required";
|
|
207
|
+
minor_consent_required: "minor_consent_required";
|
|
208
|
+
travel_dates_required: "travel_dates_required";
|
|
209
|
+
}>;
|
|
210
|
+
severity: z.ZodEnum<{
|
|
211
|
+
warning: "warning";
|
|
212
|
+
blocking: "blocking";
|
|
213
|
+
}>;
|
|
214
|
+
message: z.ZodString;
|
|
215
|
+
travelerRef: z.ZodString;
|
|
216
|
+
ruleId: z.ZodString;
|
|
217
|
+
destinationCountries: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
218
|
+
requiredDocumentType: z.ZodEnum<{
|
|
219
|
+
passport: "passport";
|
|
220
|
+
none: "none";
|
|
221
|
+
id_card: "id_card";
|
|
222
|
+
passport_or_id_card: "passport_or_id_card";
|
|
223
|
+
}>;
|
|
224
|
+
}, z.core.$strip>>;
|
|
225
|
+
warnings: z.ZodArray<z.ZodObject<{
|
|
226
|
+
code: z.ZodEnum<{
|
|
227
|
+
date_of_birth_required: "date_of_birth_required";
|
|
228
|
+
document_required: "document_required";
|
|
229
|
+
document_expiry_required: "document_expiry_required";
|
|
230
|
+
document_validity: "document_validity";
|
|
231
|
+
nationality_required: "nationality_required";
|
|
232
|
+
visa_required: "visa_required";
|
|
233
|
+
minor_consent_required: "minor_consent_required";
|
|
234
|
+
travel_dates_required: "travel_dates_required";
|
|
235
|
+
}>;
|
|
236
|
+
severity: z.ZodEnum<{
|
|
237
|
+
warning: "warning";
|
|
238
|
+
blocking: "blocking";
|
|
239
|
+
}>;
|
|
240
|
+
message: z.ZodString;
|
|
241
|
+
travelerRef: z.ZodString;
|
|
242
|
+
ruleId: z.ZodString;
|
|
243
|
+
destinationCountries: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
244
|
+
requiredDocumentType: z.ZodEnum<{
|
|
245
|
+
passport: "passport";
|
|
246
|
+
none: "none";
|
|
247
|
+
id_card: "id_card";
|
|
248
|
+
passport_or_id_card: "passport_or_id_card";
|
|
249
|
+
}>;
|
|
250
|
+
}, z.core.$strip>>;
|
|
251
|
+
travelers: z.ZodArray<z.ZodObject<{
|
|
252
|
+
travelerRef: z.ZodString;
|
|
253
|
+
eligible: z.ZodBoolean;
|
|
254
|
+
matchedRuleIds: z.ZodArray<z.ZodString>;
|
|
255
|
+
blockingIssues: z.ZodArray<z.ZodObject<{
|
|
256
|
+
code: z.ZodEnum<{
|
|
257
|
+
date_of_birth_required: "date_of_birth_required";
|
|
258
|
+
document_required: "document_required";
|
|
259
|
+
document_expiry_required: "document_expiry_required";
|
|
260
|
+
document_validity: "document_validity";
|
|
261
|
+
nationality_required: "nationality_required";
|
|
262
|
+
visa_required: "visa_required";
|
|
263
|
+
minor_consent_required: "minor_consent_required";
|
|
264
|
+
travel_dates_required: "travel_dates_required";
|
|
265
|
+
}>;
|
|
266
|
+
severity: z.ZodEnum<{
|
|
267
|
+
warning: "warning";
|
|
268
|
+
blocking: "blocking";
|
|
269
|
+
}>;
|
|
270
|
+
message: z.ZodString;
|
|
271
|
+
travelerRef: z.ZodString;
|
|
272
|
+
ruleId: z.ZodString;
|
|
273
|
+
destinationCountries: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
274
|
+
requiredDocumentType: z.ZodEnum<{
|
|
275
|
+
passport: "passport";
|
|
276
|
+
none: "none";
|
|
277
|
+
id_card: "id_card";
|
|
278
|
+
passport_or_id_card: "passport_or_id_card";
|
|
279
|
+
}>;
|
|
280
|
+
}, z.core.$strip>>;
|
|
281
|
+
warnings: z.ZodArray<z.ZodObject<{
|
|
282
|
+
code: z.ZodEnum<{
|
|
283
|
+
date_of_birth_required: "date_of_birth_required";
|
|
284
|
+
document_required: "document_required";
|
|
285
|
+
document_expiry_required: "document_expiry_required";
|
|
286
|
+
document_validity: "document_validity";
|
|
287
|
+
nationality_required: "nationality_required";
|
|
288
|
+
visa_required: "visa_required";
|
|
289
|
+
minor_consent_required: "minor_consent_required";
|
|
290
|
+
travel_dates_required: "travel_dates_required";
|
|
291
|
+
}>;
|
|
292
|
+
severity: z.ZodEnum<{
|
|
293
|
+
warning: "warning";
|
|
294
|
+
blocking: "blocking";
|
|
295
|
+
}>;
|
|
296
|
+
message: z.ZodString;
|
|
297
|
+
travelerRef: z.ZodString;
|
|
298
|
+
ruleId: z.ZodString;
|
|
299
|
+
destinationCountries: z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
300
|
+
requiredDocumentType: z.ZodEnum<{
|
|
301
|
+
passport: "passport";
|
|
302
|
+
none: "none";
|
|
303
|
+
id_card: "id_card";
|
|
304
|
+
passport_or_id_card: "passport_or_id_card";
|
|
305
|
+
}>;
|
|
306
|
+
}, z.core.$strip>>;
|
|
307
|
+
}, z.core.$strip>>;
|
|
308
|
+
}, z.core.$strip>;
|
|
309
|
+
export type StorefrontTransportEligibilityInput = z.infer<typeof storefrontTransportEligibilityInputSchema>;
|
|
310
|
+
export type StorefrontTransportEligibilityRule = z.infer<typeof storefrontTransportEligibilityRuleSchema>;
|
|
311
|
+
export type StorefrontTransportEligibilityRuleInput = z.input<typeof storefrontTransportEligibilityRuleSchema>;
|
|
312
|
+
export type StorefrontTransportEligibilityIssue = z.infer<typeof storefrontTransportEligibilityIssueSchema>;
|
|
313
|
+
export type StorefrontTransportEligibilityResult = z.infer<typeof storefrontTransportEligibilityResultSchema>;
|
|
314
|
+
//# sourceMappingURL=validation-transport-eligibility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-transport-eligibility.d.ts","sourceRoot":"","sources":["../src/validation-transport-eligibility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAQvB,eAAO,MAAM,kCAAkC;;;;;;;EAO7C,CAAA;AAEF,eAAO,MAAM,oCAAoC;;;;;EAK/C,CAAA;AAEF,eAAO,MAAM,4CAA4C;;;EAAkC,CAAA;AAE3F,eAAO,MAAM,wCAAwC;;;;;;;;;;;;;;;;;;;;;;;iBAoBjD,CAAA;AAEJ,eAAO,MAAM,iDAAiD;;;;;;;;;;;iBAI5D,CAAA;AAEF,eAAO,MAAM,iDAAiD;;;;;;;;;;;;;;;;;;;iBAQ5D,CAAA;AAEF,eAAO,MAAM,yCAAyC;;;;;;;;;;;;;;;;;;;;;;;iBAIpD,CAAA;AAEF,eAAO,MAAM,6CAA6C;;;;;;;;;EASxD,CAAA;AAEF,eAAO,MAAM,yCAAyC;;;;;;;;;;;;;;;;;;;;;;;;;iBAQpD,CAAA;AAEF,eAAO,MAAM,kDAAkD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAM7D,CAAA;AAEF,eAAO,MAAM,0CAA0C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASrD,CAAA;AAEF,MAAM,MAAM,mCAAmC,GAAG,CAAC,CAAC,KAAK,CACvD,OAAO,yCAAyC,CACjD,CAAA;AACD,MAAM,MAAM,kCAAkC,GAAG,CAAC,CAAC,KAAK,CACtD,OAAO,wCAAwC,CAChD,CAAA;AACD,MAAM,MAAM,uCAAuC,GAAG,CAAC,CAAC,KAAK,CAC3D,OAAO,wCAAwC,CAChD,CAAA;AACD,MAAM,MAAM,mCAAmC,GAAG,CAAC,CAAC,KAAK,CACvD,OAAO,yCAAyC,CACjD,CAAA;AACD,MAAM,MAAM,oCAAoC,GAAG,CAAC,CAAC,KAAK,CACxD,OAAO,0CAA0C,CAClD,CAAA"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const countryCodeSchema = z
|
|
3
|
+
.string()
|
|
4
|
+
.trim()
|
|
5
|
+
.length(2)
|
|
6
|
+
.transform((value) => value.toUpperCase());
|
|
7
|
+
export const storefrontTravelDocumentTypeSchema = z.enum([
|
|
8
|
+
"passport",
|
|
9
|
+
"id_card",
|
|
10
|
+
"residence_permit",
|
|
11
|
+
"visa",
|
|
12
|
+
"minor_consent",
|
|
13
|
+
"other",
|
|
14
|
+
]);
|
|
15
|
+
export const storefrontRequiredDocumentTypeSchema = z.enum([
|
|
16
|
+
"none",
|
|
17
|
+
"passport",
|
|
18
|
+
"id_card",
|
|
19
|
+
"passport_or_id_card",
|
|
20
|
+
]);
|
|
21
|
+
export const storefrontTransportEligibilitySeveritySchema = z.enum(["blocking", "warning"]);
|
|
22
|
+
export const storefrontTransportEligibilityRuleSchema = z
|
|
23
|
+
.object({
|
|
24
|
+
id: z.string().trim().min(1),
|
|
25
|
+
label: z.string().trim().min(1),
|
|
26
|
+
productId: z.string().trim().min(1).optional().nullable(),
|
|
27
|
+
departureId: z.string().trim().min(1).optional().nullable(),
|
|
28
|
+
destinationCountries: z.array(countryCodeSchema).min(1),
|
|
29
|
+
nationalityCountries: z.array(countryCodeSchema).default([]),
|
|
30
|
+
requiredDocumentType: storefrontRequiredDocumentTypeSchema.default("passport"),
|
|
31
|
+
minValidityDaysAfterReturn: z.number().int().min(0).default(0),
|
|
32
|
+
minAge: z.number().int().min(0).optional().nullable(),
|
|
33
|
+
maxAge: z.number().int().min(0).optional().nullable(),
|
|
34
|
+
visaRequired: z.boolean().default(false),
|
|
35
|
+
minorConsentRequired: z.boolean().default(false),
|
|
36
|
+
severity: storefrontTransportEligibilitySeveritySchema.default("blocking"),
|
|
37
|
+
message: z.string().trim().min(1).optional().nullable(),
|
|
38
|
+
})
|
|
39
|
+
.refine((rule) => rule.minAge == null || rule.maxAge == null || rule.minAge <= rule.maxAge, {
|
|
40
|
+
message: "minAge must be less than or equal to maxAge",
|
|
41
|
+
path: ["maxAge"],
|
|
42
|
+
});
|
|
43
|
+
export const storefrontTransportEligibilityDocumentInputSchema = z.object({
|
|
44
|
+
type: storefrontTravelDocumentTypeSchema,
|
|
45
|
+
issuingCountry: countryCodeSchema.optional().nullable(),
|
|
46
|
+
expiresOn: z.string().date().optional().nullable(),
|
|
47
|
+
});
|
|
48
|
+
export const storefrontTransportEligibilityTravelerInputSchema = z.object({
|
|
49
|
+
travelerRef: z.string().trim().min(1),
|
|
50
|
+
nationalityCountry: countryCodeSchema.optional().nullable(),
|
|
51
|
+
dateOfBirth: z.string().date().optional().nullable(),
|
|
52
|
+
documents: z.array(storefrontTransportEligibilityDocumentInputSchema).default([]),
|
|
53
|
+
hasVisa: z.boolean().default(false),
|
|
54
|
+
travelingWithGuardian: z.boolean().default(false),
|
|
55
|
+
hasMinorConsent: z.boolean().default(false),
|
|
56
|
+
});
|
|
57
|
+
export const storefrontTransportEligibilityInputSchema = z.object({
|
|
58
|
+
travelStartsOn: z.string().date().optional().nullable(),
|
|
59
|
+
travelEndsOn: z.string().date().optional().nullable(),
|
|
60
|
+
travelers: z.array(storefrontTransportEligibilityTravelerInputSchema).min(1),
|
|
61
|
+
});
|
|
62
|
+
export const storefrontTransportEligibilityIssueCodeSchema = z.enum([
|
|
63
|
+
"date_of_birth_required",
|
|
64
|
+
"document_required",
|
|
65
|
+
"document_expiry_required",
|
|
66
|
+
"document_validity",
|
|
67
|
+
"nationality_required",
|
|
68
|
+
"visa_required",
|
|
69
|
+
"minor_consent_required",
|
|
70
|
+
"travel_dates_required",
|
|
71
|
+
]);
|
|
72
|
+
export const storefrontTransportEligibilityIssueSchema = z.object({
|
|
73
|
+
code: storefrontTransportEligibilityIssueCodeSchema,
|
|
74
|
+
severity: storefrontTransportEligibilitySeveritySchema,
|
|
75
|
+
message: z.string(),
|
|
76
|
+
travelerRef: z.string(),
|
|
77
|
+
ruleId: z.string(),
|
|
78
|
+
destinationCountries: z.array(countryCodeSchema),
|
|
79
|
+
requiredDocumentType: storefrontRequiredDocumentTypeSchema,
|
|
80
|
+
});
|
|
81
|
+
export const storefrontTransportEligibilityTravelerResultSchema = z.object({
|
|
82
|
+
travelerRef: z.string(),
|
|
83
|
+
eligible: z.boolean(),
|
|
84
|
+
matchedRuleIds: z.array(z.string()),
|
|
85
|
+
blockingIssues: z.array(storefrontTransportEligibilityIssueSchema),
|
|
86
|
+
warnings: z.array(storefrontTransportEligibilityIssueSchema),
|
|
87
|
+
});
|
|
88
|
+
export const storefrontTransportEligibilityResultSchema = z.object({
|
|
89
|
+
departureId: z.string(),
|
|
90
|
+
productId: z.string().nullable(),
|
|
91
|
+
travelStartsOn: z.string().nullable(),
|
|
92
|
+
travelEndsOn: z.string().nullable(),
|
|
93
|
+
eligible: z.boolean(),
|
|
94
|
+
blockingIssues: z.array(storefrontTransportEligibilityIssueSchema),
|
|
95
|
+
warnings: z.array(storefrontTransportEligibilityIssueSchema),
|
|
96
|
+
travelers: z.array(storefrontTransportEligibilityTravelerResultSchema),
|
|
97
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/storefront",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.46.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
"import": "./dist/service.js",
|
|
20
20
|
"default": "./dist/service.js"
|
|
21
21
|
},
|
|
22
|
+
"./transport-eligibility": {
|
|
23
|
+
"types": "./dist/transport-eligibility.d.ts",
|
|
24
|
+
"import": "./dist/transport-eligibility.js",
|
|
25
|
+
"default": "./dist/transport-eligibility.js"
|
|
26
|
+
},
|
|
22
27
|
"./validation": {
|
|
23
28
|
"types": "./dist/validation.d.ts",
|
|
24
29
|
"import": "./dist/validation.js",
|
|
@@ -29,18 +34,18 @@
|
|
|
29
34
|
"drizzle-orm": "^0.45.2",
|
|
30
35
|
"hono": "^4.12.10",
|
|
31
36
|
"zod": "^4.3.6",
|
|
32
|
-
"@voyantjs/availability": "0.
|
|
33
|
-
"@voyantjs/core": "0.
|
|
34
|
-
"@voyantjs/extras": "0.
|
|
35
|
-
"@voyantjs/hono": "0.
|
|
36
|
-
"@voyantjs/pricing": "0.
|
|
37
|
-
"@voyantjs/products": "0.
|
|
38
|
-
"@voyantjs/sellability": "0.
|
|
37
|
+
"@voyantjs/availability": "0.46.0",
|
|
38
|
+
"@voyantjs/core": "0.46.0",
|
|
39
|
+
"@voyantjs/extras": "0.46.0",
|
|
40
|
+
"@voyantjs/hono": "0.46.0",
|
|
41
|
+
"@voyantjs/pricing": "0.46.0",
|
|
42
|
+
"@voyantjs/products": "0.46.0",
|
|
43
|
+
"@voyantjs/sellability": "0.46.0"
|
|
39
44
|
},
|
|
40
45
|
"devDependencies": {
|
|
41
46
|
"typescript": "^6.0.2",
|
|
42
47
|
"vitest": "^4.1.2",
|
|
43
|
-
"@voyantjs/db": "0.
|
|
48
|
+
"@voyantjs/db": "0.46.0",
|
|
44
49
|
"@voyantjs/voyant-typescript-config": "0.1.0"
|
|
45
50
|
},
|
|
46
51
|
"files": [
|