@voyant-travel/accommodations 0.105.30 → 0.106.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/dist/booking-engine/index.d.ts +3 -2
- package/dist/booking-engine/index.d.ts.map +1 -1
- package/dist/booking-engine/index.js +3 -2
- package/dist/booking-engine/search-handler.d.ts +94 -0
- package/dist/booking-engine/search-handler.d.ts.map +1 -0
- package/dist/booking-engine/search-handler.js +77 -0
- package/package.json +5 -5
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `@voyant-travel/accommodations/booking-engine` — owned-arm booking
|
|
3
|
-
*
|
|
2
|
+
* `@voyant-travel/accommodations/booking-engine` — owned-arm booking +
|
|
3
|
+
* availability-search handlers for the accommodation vertical.
|
|
4
4
|
*
|
|
5
5
|
* Per `docs/architecture/booking-journey-architecture.md` §6.
|
|
6
6
|
*/
|
|
7
7
|
export { type AccommodationCommitBridge, type AccommodationCommitBridgeInput, type AccommodationCommitBridgeResult, type AccommodationContentLoader, type CreateAccommodationBookingHandlerOptions, createAccommodationBookingHandler, } from "./handler.js";
|
|
8
|
+
export { type AccommodationSearchBridge, type AccommodationSearchBridgeInput, type AccommodationSearchCriteria, type AccommodationSearchMatch, type AccommodationSearchOccupancy, type CreateAccommodationSearchHandlerOptions, createAccommodationOwnedSearchHandler, nightsBetween, } from "./search-handler.js";
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/booking-engine/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,EACnC,KAAK,+BAA+B,EACpC,KAAK,0BAA0B,EAC/B,KAAK,wCAAwC,EAC7C,iCAAiC,GAClC,MAAM,cAAc,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/booking-engine/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,EACnC,KAAK,+BAA+B,EACpC,KAAK,0BAA0B,EAC/B,KAAK,wCAAwC,EAC7C,iCAAiC,GAClC,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,8BAA8B,EACnC,KAAK,2BAA2B,EAChC,KAAK,wBAAwB,EAC7B,KAAK,4BAA4B,EACjC,KAAK,uCAAuC,EAC5C,qCAAqC,EACrC,aAAa,GACd,MAAM,qBAAqB,CAAA"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `@voyant-travel/accommodations/booking-engine` — owned-arm booking
|
|
3
|
-
*
|
|
2
|
+
* `@voyant-travel/accommodations/booking-engine` — owned-arm booking +
|
|
3
|
+
* availability-search handlers for the accommodation vertical.
|
|
4
4
|
*
|
|
5
5
|
* Per `docs/architecture/booking-journey-architecture.md` §6.
|
|
6
6
|
*/
|
|
7
7
|
export { createAccommodationBookingHandler, } from "./handler.js";
|
|
8
|
+
export { createAccommodationOwnedSearchHandler, nightsBetween, } from "./search-handler.js";
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owned-arm availability-search handler for the `accommodation` vertical.
|
|
3
|
+
*
|
|
4
|
+
* The counterpart of `createAccommodationBookingHandler`: it lets owned
|
|
5
|
+
* accommodation inventory participate in the catalog availability fan-out
|
|
6
|
+
* (`fanOutAvailabilitySearch`, RFC #2081/#2093) so owned and sourced supply
|
|
7
|
+
* land in one ranked candidate list.
|
|
8
|
+
*
|
|
9
|
+
* Like the booking handler, this is a thin shell that delegates the actual
|
|
10
|
+
* inventory query to a caller-supplied **bridge**. Owned accommodations have no
|
|
11
|
+
* date-aware rate/availability table in the schema yet, and the location lookup
|
|
12
|
+
* spans the operations (places/facility) schema — both deployment-specific — so
|
|
13
|
+
* the handler owns the vertical-agnostic parts (criteria validation, nights,
|
|
14
|
+
* candidate assembly) and the deployment owns the data access.
|
|
15
|
+
*/
|
|
16
|
+
import type { OwnedAvailabilitySearchHandler, OwnedSearchContext } from "@voyant-travel/catalog";
|
|
17
|
+
import type { AvailabilitySearchRequest } from "@voyant-travel/catalog/adapter/contract";
|
|
18
|
+
/** Occupancy for one requested room. Mirrors the sourced stay-search shape. */
|
|
19
|
+
export interface AccommodationSearchOccupancy {
|
|
20
|
+
adults: number;
|
|
21
|
+
children?: number;
|
|
22
|
+
childrenAges?: number[];
|
|
23
|
+
infants?: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Accommodation-vertical search criteria. The composer/caller shapes
|
|
27
|
+
* `AvailabilitySearchRequest.criteria` into this; `checkIn`/`checkOut`/`rooms`
|
|
28
|
+
* are required.
|
|
29
|
+
*/
|
|
30
|
+
export interface AccommodationSearchCriteria {
|
|
31
|
+
destination?: {
|
|
32
|
+
countryCode?: string;
|
|
33
|
+
region?: string;
|
|
34
|
+
city?: string;
|
|
35
|
+
};
|
|
36
|
+
near?: {
|
|
37
|
+
latitude: number;
|
|
38
|
+
longitude: number;
|
|
39
|
+
radiusKm: number;
|
|
40
|
+
};
|
|
41
|
+
checkIn: string;
|
|
42
|
+
checkOut: string;
|
|
43
|
+
rooms: AccommodationSearchOccupancy[];
|
|
44
|
+
minStars?: number;
|
|
45
|
+
amenities?: string[];
|
|
46
|
+
refundableOnly?: boolean;
|
|
47
|
+
}
|
|
48
|
+
/** Validated criteria + derived context handed to the bridge. */
|
|
49
|
+
export interface AccommodationSearchBridgeInput {
|
|
50
|
+
criteria: AccommodationSearchCriteria;
|
|
51
|
+
/** Nights between check-in and check-out (≥ 1). */
|
|
52
|
+
nights: number;
|
|
53
|
+
scope: AvailabilitySearchRequest["scope"];
|
|
54
|
+
limit?: number;
|
|
55
|
+
cursor?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* One owned room matched + priced for the requested stay. The bridge resolves
|
|
59
|
+
* availability + price from wherever the deployment models owned rates; the
|
|
60
|
+
* handler maps these onto `AvailabilityCandidate`s.
|
|
61
|
+
*/
|
|
62
|
+
export interface AccommodationSearchMatch {
|
|
63
|
+
/** Entity id surfaced to the composer — typically the room type / accommodation id. */
|
|
64
|
+
accommodationId: string;
|
|
65
|
+
roomTypeId: string;
|
|
66
|
+
ratePlanId: string;
|
|
67
|
+
occupancy: AccommodationSearchOccupancy;
|
|
68
|
+
/** Public total stay price across the date range. */
|
|
69
|
+
price: {
|
|
70
|
+
amount: string;
|
|
71
|
+
currency: string;
|
|
72
|
+
};
|
|
73
|
+
/** Stable ref for this match within the search; defaults to a composed key. */
|
|
74
|
+
candidateRef?: string;
|
|
75
|
+
expiresAt?: Date;
|
|
76
|
+
/** Internal-only economics / raw row for reserve. Never serialized publicly. */
|
|
77
|
+
providerData?: Record<string, unknown>;
|
|
78
|
+
}
|
|
79
|
+
export type AccommodationSearchBridge = (ctx: OwnedSearchContext, input: AccommodationSearchBridgeInput) => Promise<{
|
|
80
|
+
matches: AccommodationSearchMatch[];
|
|
81
|
+
nextCursor?: string;
|
|
82
|
+
}>;
|
|
83
|
+
export interface CreateAccommodationSearchHandlerOptions {
|
|
84
|
+
/**
|
|
85
|
+
* Resolves owned accommodation availability for a stay. Wired by the
|
|
86
|
+
* deployment to its owned room/rate query (joins through the operations
|
|
87
|
+
* places/facility schema + the deployment's rate source).
|
|
88
|
+
*/
|
|
89
|
+
searchBridge: AccommodationSearchBridge;
|
|
90
|
+
}
|
|
91
|
+
export declare function createAccommodationOwnedSearchHandler(options: CreateAccommodationSearchHandlerOptions): OwnedAvailabilitySearchHandler;
|
|
92
|
+
/** Whole nights between two ISO dates (UTC), floored to ≥ 1. */
|
|
93
|
+
export declare function nightsBetween(checkIn: string, checkOut: string): number;
|
|
94
|
+
//# sourceMappingURL=search-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-handler.d.ts","sourceRoot":"","sources":["../../src/booking-engine/search-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,8BAA8B,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAChG,OAAO,KAAK,EAEV,yBAAyB,EAE1B,MAAM,yCAAyC,CAAA;AAEhD,+EAA+E;AAC/E,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,2BAA2B;IAC1C,WAAW,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACtE,IAAI,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;IAChE,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,4BAA4B,EAAE,CAAA;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,iEAAiE;AACjE,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,EAAE,2BAA2B,CAAA;IACrC,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,yBAAyB,CAAC,OAAO,CAAC,CAAA;IACzC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,uFAAuF;IACvF,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,4BAA4B,CAAA;IACvC,qDAAqD;IACrD,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3C,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,IAAI,CAAA;IAChB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACvC;AAED,MAAM,MAAM,yBAAyB,GAAG,CACtC,GAAG,EAAE,kBAAkB,EACvB,KAAK,EAAE,8BAA8B,KAClC,OAAO,CAAC;IAAE,OAAO,EAAE,wBAAwB,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAE1E,MAAM,WAAW,uCAAuC;IACtD;;;;OAIG;IACH,YAAY,EAAE,yBAAyB,CAAA;CACxC;AAED,wBAAgB,qCAAqC,CACnD,OAAO,EAAE,uCAAuC,GAC/C,8BAA8B,CAwBhC;AAiBD,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQvE"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owned-arm availability-search handler for the `accommodation` vertical.
|
|
3
|
+
*
|
|
4
|
+
* The counterpart of `createAccommodationBookingHandler`: it lets owned
|
|
5
|
+
* accommodation inventory participate in the catalog availability fan-out
|
|
6
|
+
* (`fanOutAvailabilitySearch`, RFC #2081/#2093) so owned and sourced supply
|
|
7
|
+
* land in one ranked candidate list.
|
|
8
|
+
*
|
|
9
|
+
* Like the booking handler, this is a thin shell that delegates the actual
|
|
10
|
+
* inventory query to a caller-supplied **bridge**. Owned accommodations have no
|
|
11
|
+
* date-aware rate/availability table in the schema yet, and the location lookup
|
|
12
|
+
* spans the operations (places/facility) schema — both deployment-specific — so
|
|
13
|
+
* the handler owns the vertical-agnostic parts (criteria validation, nights,
|
|
14
|
+
* candidate assembly) and the deployment owns the data access.
|
|
15
|
+
*/
|
|
16
|
+
export function createAccommodationOwnedSearchHandler(options) {
|
|
17
|
+
return {
|
|
18
|
+
entityModule: "accommodations",
|
|
19
|
+
async searchAvailability(ctx, request) {
|
|
20
|
+
const criteria = parseAccommodationCriteria(request.criteria);
|
|
21
|
+
const nights = nightsBetween(criteria.checkIn, criteria.checkOut);
|
|
22
|
+
const { matches, nextCursor } = await options.searchBridge(ctx, {
|
|
23
|
+
criteria,
|
|
24
|
+
nights,
|
|
25
|
+
scope: request.scope,
|
|
26
|
+
limit: request.limit,
|
|
27
|
+
cursor: request.cursor,
|
|
28
|
+
});
|
|
29
|
+
const candidates = matches.map((match) => matchToCandidate(match, criteria));
|
|
30
|
+
return {
|
|
31
|
+
candidates,
|
|
32
|
+
status: candidates.length > 0 ? "ok" : "empty",
|
|
33
|
+
next_cursor: nextCursor,
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function parseAccommodationCriteria(criteria) {
|
|
39
|
+
const c = criteria;
|
|
40
|
+
if (typeof c.checkIn !== "string" || typeof c.checkOut !== "string") {
|
|
41
|
+
throw new Error("Accommodation search requires `checkIn` and `checkOut` (ISO dates) in criteria");
|
|
42
|
+
}
|
|
43
|
+
if (!Array.isArray(c.rooms) || c.rooms.length === 0) {
|
|
44
|
+
throw new Error("Accommodation search requires a non-empty `rooms` array in criteria");
|
|
45
|
+
}
|
|
46
|
+
return c;
|
|
47
|
+
}
|
|
48
|
+
/** Whole nights between two ISO dates (UTC), floored to ≥ 1. */
|
|
49
|
+
export function nightsBetween(checkIn, checkOut) {
|
|
50
|
+
const start = Date.parse(checkIn);
|
|
51
|
+
const end = Date.parse(checkOut);
|
|
52
|
+
if (Number.isNaN(start) || Number.isNaN(end)) {
|
|
53
|
+
throw new Error("Accommodation search `checkIn`/`checkOut` must be valid ISO dates");
|
|
54
|
+
}
|
|
55
|
+
const nights = Math.round((end - start) / 86_400_000);
|
|
56
|
+
return nights >= 1 ? nights : 1;
|
|
57
|
+
}
|
|
58
|
+
function matchToCandidate(match, criteria) {
|
|
59
|
+
return {
|
|
60
|
+
candidateRef: match.candidateRef ??
|
|
61
|
+
`${match.accommodationId}:${match.roomTypeId}:${match.ratePlanId}:${criteria.checkIn}:${criteria.checkOut}`,
|
|
62
|
+
entity_module: "accommodations",
|
|
63
|
+
entity_id: match.accommodationId,
|
|
64
|
+
// Enough to re-resolve + reserve the owned stay via the booking handler.
|
|
65
|
+
selection: {
|
|
66
|
+
roomTypeId: match.roomTypeId,
|
|
67
|
+
ratePlanId: match.ratePlanId,
|
|
68
|
+
checkIn: criteria.checkIn,
|
|
69
|
+
checkOut: criteria.checkOut,
|
|
70
|
+
occupancy: match.occupancy,
|
|
71
|
+
},
|
|
72
|
+
// `source` is left for the fan-out to stamp as { kind: "owned", module }.
|
|
73
|
+
price: match.price,
|
|
74
|
+
expiresAt: match.expiresAt,
|
|
75
|
+
providerData: match.providerData,
|
|
76
|
+
};
|
|
77
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyant-travel/accommodations",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.106.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
"hono": "^4.12.10",
|
|
61
61
|
"zod": "^4.3.6",
|
|
62
62
|
"@voyant-travel/accommodations-contracts": "^0.105.3",
|
|
63
|
-
"@voyant-travel/bookings": "^0.
|
|
64
|
-
"@voyant-travel/catalog": "^0.
|
|
65
|
-
"@voyant-travel/
|
|
66
|
-
"@voyant-travel/
|
|
63
|
+
"@voyant-travel/bookings": "^0.133.0",
|
|
64
|
+
"@voyant-travel/catalog": "^0.131.0",
|
|
65
|
+
"@voyant-travel/operations": "^0.2.8",
|
|
66
|
+
"@voyant-travel/db": "^0.109.0"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"drizzle-kit": "^0.31.10",
|