@voyant-travel/cruises 0.118.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.
- package/LICENSE +201 -0
- package/README.md +50 -0
- package/dist/adapters/connect-compat.d.ts +20 -0
- package/dist/adapters/connect-compat.d.ts.map +1 -0
- package/dist/adapters/connect-compat.js +71 -0
- package/dist/adapters/contract-fixture.d.ts +32 -0
- package/dist/adapters/contract-fixture.d.ts.map +1 -0
- package/dist/adapters/contract-fixture.js +152 -0
- package/dist/adapters/index.d.ts +331 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +16 -0
- package/dist/adapters/memoize.d.ts +28 -0
- package/dist/adapters/memoize.d.ts.map +1 -0
- package/dist/adapters/memoize.js +131 -0
- package/dist/adapters/mock.d.ts +44 -0
- package/dist/adapters/mock.d.ts.map +1 -0
- package/dist/adapters/mock.js +192 -0
- package/dist/adapters/registry.d.ts +26 -0
- package/dist/adapters/registry.d.ts.map +1 -0
- package/dist/adapters/registry.js +42 -0
- package/dist/adapters/source-adapter-shim.d.ts +80 -0
- package/dist/adapters/source-adapter-shim.d.ts.map +1 -0
- package/dist/adapters/source-adapter-shim.js +390 -0
- package/dist/booking-engine/handler.d.ts +108 -0
- package/dist/booking-engine/handler.d.ts.map +1 -0
- package/dist/booking-engine/handler.js +225 -0
- package/dist/booking-engine/index.d.ts +9 -0
- package/dist/booking-engine/index.d.ts.map +1 -0
- package/dist/booking-engine/index.js +8 -0
- package/dist/booking-extension.d.ts +1179 -0
- package/dist/booking-extension.d.ts.map +1 -0
- package/dist/booking-extension.js +342 -0
- package/dist/cabin-features.d.ts +8 -0
- package/dist/cabin-features.d.ts.map +1 -0
- package/dist/cabin-features.js +7 -0
- package/dist/catalog-policy-cabins.d.ts +18 -0
- package/dist/catalog-policy-cabins.d.ts.map +1 -0
- package/dist/catalog-policy-cabins.js +96 -0
- package/dist/catalog-policy-core.d.ts +3 -0
- package/dist/catalog-policy-core.d.ts.map +1 -0
- package/dist/catalog-policy-core.js +247 -0
- package/dist/catalog-policy-structure.d.ts +3 -0
- package/dist/catalog-policy-structure.d.ts.map +1 -0
- package/dist/catalog-policy-structure.js +387 -0
- package/dist/catalog-policy.d.ts +15 -0
- package/dist/catalog-policy.d.ts.map +1 -0
- package/dist/catalog-policy.js +19 -0
- package/dist/content-shape.d.ts +5 -0
- package/dist/content-shape.d.ts.map +1 -0
- package/dist/content-shape.js +13 -0
- package/dist/draft-shape.d.ts +59 -0
- package/dist/draft-shape.d.ts.map +1 -0
- package/dist/draft-shape.js +98 -0
- package/dist/events.d.ts +21 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +21 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -0
- package/dist/lib/key.d.ts +41 -0
- package/dist/lib/key.d.ts.map +1 -0
- package/dist/lib/key.js +100 -0
- package/dist/routes-booking-payloads.d.ts +133 -0
- package/dist/routes-booking-payloads.d.ts.map +1 -0
- package/dist/routes-booking-payloads.js +142 -0
- package/dist/routes-content.d.ts +53 -0
- package/dist/routes-content.d.ts.map +1 -0
- package/dist/routes-content.js +158 -0
- package/dist/routes-core.d.ts +4 -0
- package/dist/routes-core.d.ts.map +1 -0
- package/dist/routes-core.js +68 -0
- package/dist/routes-detail.d.ts +4 -0
- package/dist/routes-detail.d.ts.map +1 -0
- package/dist/routes-detail.js +261 -0
- package/dist/routes-env.d.ts +13 -0
- package/dist/routes-env.d.ts.map +1 -0
- package/dist/routes-env.js +1 -0
- package/dist/routes-keying.d.ts +28 -0
- package/dist/routes-keying.d.ts.map +1 -0
- package/dist/routes-keying.js +70 -0
- package/dist/routes-public.d.ts +911 -0
- package/dist/routes-public.d.ts.map +1 -0
- package/dist/routes-public.js +252 -0
- package/dist/routes-sailings-prices.d.ts +4 -0
- package/dist/routes-sailings-prices.d.ts.map +1 -0
- package/dist/routes-sailings-prices.js +278 -0
- package/dist/routes-search-index.d.ts +4 -0
- package/dist/routes-search-index.d.ts.map +1 -0
- package/dist/routes-search-index.js +25 -0
- package/dist/routes-ships.d.ts +4 -0
- package/dist/routes-ships.d.ts.map +1 -0
- package/dist/routes-ships.js +147 -0
- package/dist/routes-voyage-groups.d.ts +4 -0
- package/dist/routes-voyage-groups.d.ts.map +1 -0
- package/dist/routes-voyage-groups.js +85 -0
- package/dist/routes.d.ts +5 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +14 -0
- package/dist/schema-cabins.d.ts +1098 -0
- package/dist/schema-cabins.d.ts.map +1 -0
- package/dist/schema-cabins.js +105 -0
- package/dist/schema-content.d.ts +577 -0
- package/dist/schema-content.d.ts.map +1 -0
- package/dist/schema-content.js +63 -0
- package/dist/schema-core.d.ts +1790 -0
- package/dist/schema-core.d.ts.map +1 -0
- package/dist/schema-core.js +171 -0
- package/dist/schema-itinerary.d.ts +556 -0
- package/dist/schema-itinerary.d.ts.map +1 -0
- package/dist/schema-itinerary.js +50 -0
- package/dist/schema-pricing.d.ts +633 -0
- package/dist/schema-pricing.d.ts.map +1 -0
- package/dist/schema-pricing.js +73 -0
- package/dist/schema-search.d.ts +611 -0
- package/dist/schema-search.d.ts.map +1 -0
- package/dist/schema-search.js +64 -0
- package/dist/schema-shared.d.ts +23 -0
- package/dist/schema-shared.d.ts.map +1 -0
- package/dist/schema-shared.js +107 -0
- package/dist/schema-sourced-content.d.ts +247 -0
- package/dist/schema-sourced-content.d.ts.map +1 -0
- package/dist/schema-sourced-content.js +38 -0
- package/dist/schema.d.ts +10 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +9 -0
- package/dist/service-booking-helpers.d.ts +12 -0
- package/dist/service-booking-helpers.d.ts.map +1 -0
- package/dist/service-booking-helpers.js +94 -0
- package/dist/service-booking-types.d.ts +101 -0
- package/dist/service-booking-types.d.ts.map +1 -0
- package/dist/service-booking-types.js +1 -0
- package/dist/service-bookings.d.ts +46 -0
- package/dist/service-bookings.d.ts.map +1 -0
- package/dist/service-bookings.js +420 -0
- package/dist/service-catalog-plane-cabins.d.ts +24 -0
- package/dist/service-catalog-plane-cabins.d.ts.map +1 -0
- package/dist/service-catalog-plane-cabins.js +90 -0
- package/dist/service-catalog-plane.d.ts +74 -0
- package/dist/service-catalog-plane.d.ts.map +1 -0
- package/dist/service-catalog-plane.js +194 -0
- package/dist/service-content-synthesizer.d.ts +42 -0
- package/dist/service-content-synthesizer.d.ts.map +1 -0
- package/dist/service-content-synthesizer.js +144 -0
- package/dist/service-content.d.ts +74 -0
- package/dist/service-content.d.ts.map +1 -0
- package/dist/service-content.js +315 -0
- package/dist/service-core.d.ts +134 -0
- package/dist/service-core.d.ts.map +1 -0
- package/dist/service-core.js +257 -0
- package/dist/service-detach.d.ts +18 -0
- package/dist/service-detach.d.ts.map +1 -0
- package/dist/service-detach.js +199 -0
- package/dist/service-enrichment.d.ts +11 -0
- package/dist/service-enrichment.d.ts.map +1 -0
- package/dist/service-enrichment.js +47 -0
- package/dist/service-external-refresh.d.ts +39 -0
- package/dist/service-external-refresh.d.ts.map +1 -0
- package/dist/service-external-refresh.js +47 -0
- package/dist/service-itinerary.d.ts +22 -0
- package/dist/service-itinerary.d.ts.map +1 -0
- package/dist/service-itinerary.js +34 -0
- package/dist/service-prices.d.ts +46 -0
- package/dist/service-prices.d.ts.map +1 -0
- package/dist/service-prices.js +89 -0
- package/dist/service-pricing.d.ts +97 -0
- package/dist/service-pricing.d.ts.map +1 -0
- package/dist/service-pricing.js +198 -0
- package/dist/service-sailings.d.ts +48 -0
- package/dist/service-sailings.d.ts.map +1 -0
- package/dist/service-sailings.js +145 -0
- package/dist/service-search-types.d.ts +54 -0
- package/dist/service-search-types.d.ts.map +1 -0
- package/dist/service-search-types.js +1 -0
- package/dist/service-search.d.ts +65 -0
- package/dist/service-search.d.ts.map +1 -0
- package/dist/service-search.js +467 -0
- package/dist/service-shared.d.ts +22 -0
- package/dist/service-shared.d.ts.map +1 -0
- package/dist/service-shared.js +22 -0
- package/dist/service-ships.d.ts +47 -0
- package/dist/service-ships.d.ts.map +1 -0
- package/dist/service-ships.js +156 -0
- package/dist/service.d.ts +255 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +12 -0
- package/dist/validation-cabins.d.ts +267 -0
- package/dist/validation-cabins.d.ts.map +1 -0
- package/dist/validation-cabins.js +77 -0
- package/dist/validation-content.d.ts +123 -0
- package/dist/validation-content.d.ts.map +1 -0
- package/dist/validation-content.js +40 -0
- package/dist/validation-core.d.ts +393 -0
- package/dist/validation-core.d.ts.map +1 -0
- package/dist/validation-core.js +162 -0
- package/dist/validation-itinerary.d.ts +123 -0
- package/dist/validation-itinerary.d.ts.map +1 -0
- package/dist/validation-itinerary.js +47 -0
- package/dist/validation-pricing.d.ts +137 -0
- package/dist/validation-pricing.d.ts.map +1 -0
- package/dist/validation-pricing.js +49 -0
- package/dist/validation-search.d.ts +118 -0
- package/dist/validation-search.d.ts.map +1 -0
- package/dist/validation-search.js +60 -0
- package/dist/validation-shared.d.ts +123 -0
- package/dist/validation-shared.d.ts.map +1 -0
- package/dist/validation-shared.js +103 -0
- package/dist/validation.d.ts +8 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +7 -0
- package/package.json +146 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory CruiseAdapter for tests and templates that need a working
|
|
3
|
+
* external source without a real upstream.
|
|
4
|
+
*
|
|
5
|
+
* Seed it via the `add*` methods; queries against the registered data work
|
|
6
|
+
* exactly like a real adapter would. Booking commits return synthesized
|
|
7
|
+
* confirmation refs and increment a per-instance counter.
|
|
8
|
+
*/
|
|
9
|
+
function refKey(ref) {
|
|
10
|
+
return JSON.stringify(sortValue(ref));
|
|
11
|
+
}
|
|
12
|
+
function sortValue(value) {
|
|
13
|
+
if (Array.isArray(value))
|
|
14
|
+
return value.map(sortValue);
|
|
15
|
+
if (!value || typeof value !== "object")
|
|
16
|
+
return value;
|
|
17
|
+
const out = {};
|
|
18
|
+
for (const key of Object.keys(value).sort()) {
|
|
19
|
+
out[key] = sortValue(value[key]);
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
export class MockCruiseAdapter {
|
|
24
|
+
name;
|
|
25
|
+
version;
|
|
26
|
+
cruisesByRef = new Map();
|
|
27
|
+
shipsByRef = new Map();
|
|
28
|
+
bookingResults = new Map();
|
|
29
|
+
// Telemetry — useful for assertions in tests.
|
|
30
|
+
callCount = 0;
|
|
31
|
+
bookingCount = 0;
|
|
32
|
+
failEveryNthCall;
|
|
33
|
+
constructor(options = {}) {
|
|
34
|
+
this.name = options.name ?? "mock";
|
|
35
|
+
this.version = options.version ?? "1.0.0";
|
|
36
|
+
this.failEveryNthCall = options.failEveryNthCall ?? 0;
|
|
37
|
+
}
|
|
38
|
+
// ---------- seeders ----------
|
|
39
|
+
addCruise(cruise, sailings = []) {
|
|
40
|
+
const key = refKey(cruise.sourceRef);
|
|
41
|
+
this.cruisesByRef.set(key, {
|
|
42
|
+
cruise,
|
|
43
|
+
sailings: [...sailings],
|
|
44
|
+
itinerariesBySailing: new Map(),
|
|
45
|
+
pricingBySailing: new Map(),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
addSailing(cruiseRef, sailing) {
|
|
49
|
+
const seeded = this.cruisesByRef.get(refKey(cruiseRef));
|
|
50
|
+
if (!seeded)
|
|
51
|
+
throw new Error(`MockCruiseAdapter: cruise ${cruiseRef.externalId} not seeded`);
|
|
52
|
+
seeded.sailings.push(sailing);
|
|
53
|
+
}
|
|
54
|
+
addShip(ship) {
|
|
55
|
+
this.shipsByRef.set(refKey(ship.sourceRef), ship);
|
|
56
|
+
}
|
|
57
|
+
setSailingPricing(sailingRef, prices) {
|
|
58
|
+
for (const seeded of this.cruisesByRef.values()) {
|
|
59
|
+
const match = seeded.sailings.find((s) => refKey(s.sourceRef) === refKey(sailingRef));
|
|
60
|
+
if (match) {
|
|
61
|
+
seeded.pricingBySailing.set(refKey(sailingRef), prices);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
throw new Error(`MockCruiseAdapter: sailing ${sailingRef.externalId} not seeded`);
|
|
66
|
+
}
|
|
67
|
+
setSailingItinerary(sailingRef, days) {
|
|
68
|
+
for (const seeded of this.cruisesByRef.values()) {
|
|
69
|
+
const match = seeded.sailings.find((s) => refKey(s.sourceRef) === refKey(sailingRef));
|
|
70
|
+
if (match) {
|
|
71
|
+
seeded.itinerariesBySailing.set(refKey(sailingRef), days);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`MockCruiseAdapter: sailing ${sailingRef.externalId} not seeded`);
|
|
76
|
+
}
|
|
77
|
+
/** Pre-program a specific booking response for the next createBooking that matches. */
|
|
78
|
+
setBookingResult(sailingRef, cabinCategoryRef, result) {
|
|
79
|
+
this.bookingResults.set(`${refKey(sailingRef)}::${refKey(cabinCategoryRef)}`, result);
|
|
80
|
+
}
|
|
81
|
+
// ---------- contract implementation ----------
|
|
82
|
+
tickAndCheck() {
|
|
83
|
+
this.callCount++;
|
|
84
|
+
if (this.failEveryNthCall > 0 && this.callCount % this.failEveryNthCall === 0) {
|
|
85
|
+
throw new Error(`MockCruiseAdapter forced failure on call #${this.callCount}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async listEntries(options = {}) {
|
|
89
|
+
this.tickAndCheck();
|
|
90
|
+
const limit = options.limit ?? 50;
|
|
91
|
+
const all = [];
|
|
92
|
+
for (const seeded of this.cruisesByRef.values()) {
|
|
93
|
+
const c = seeded.cruise;
|
|
94
|
+
const earliest = seeded.sailings
|
|
95
|
+
.map((s) => s.departureDate)
|
|
96
|
+
.sort()
|
|
97
|
+
.at(0) ?? null;
|
|
98
|
+
all.push({
|
|
99
|
+
sourceRef: c.sourceRef,
|
|
100
|
+
name: c.name,
|
|
101
|
+
slug: c.slug,
|
|
102
|
+
cruiseType: c.cruiseType,
|
|
103
|
+
lineName: c.lineName,
|
|
104
|
+
nights: c.nights,
|
|
105
|
+
earliestDeparture: earliest,
|
|
106
|
+
heroImageUrl: c.heroImageUrl ?? null,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return { entries: all.slice(0, limit) };
|
|
110
|
+
}
|
|
111
|
+
async *searchProjection(options = {}) {
|
|
112
|
+
this.tickAndCheck();
|
|
113
|
+
void options;
|
|
114
|
+
for (const seeded of this.cruisesByRef.values()) {
|
|
115
|
+
const c = seeded.cruise;
|
|
116
|
+
const earliest = seeded.sailings
|
|
117
|
+
.map((s) => s.departureDate)
|
|
118
|
+
.sort()
|
|
119
|
+
.at(0) ?? null;
|
|
120
|
+
const latest = seeded.sailings
|
|
121
|
+
.map((s) => s.departureDate)
|
|
122
|
+
.sort()
|
|
123
|
+
.at(-1) ?? null;
|
|
124
|
+
yield {
|
|
125
|
+
sourceRef: c.sourceRef,
|
|
126
|
+
slug: c.slug,
|
|
127
|
+
name: c.name,
|
|
128
|
+
cruiseType: c.cruiseType,
|
|
129
|
+
lineName: c.lineName,
|
|
130
|
+
shipName: this.shipsByRef.get(refKey(c.defaultShipRef ?? c.sourceRef))?.name ?? c.lineName,
|
|
131
|
+
nights: c.nights,
|
|
132
|
+
embarkPortName: c.embarkPortName ?? null,
|
|
133
|
+
disembarkPortName: c.disembarkPortName ?? null,
|
|
134
|
+
regions: c.regions,
|
|
135
|
+
themes: c.themes,
|
|
136
|
+
earliestDeparture: earliest,
|
|
137
|
+
latestDeparture: latest,
|
|
138
|
+
heroImageUrl: c.heroImageUrl ?? null,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async fetchCruise(ref) {
|
|
143
|
+
this.tickAndCheck();
|
|
144
|
+
return this.cruisesByRef.get(refKey(ref))?.cruise ?? null;
|
|
145
|
+
}
|
|
146
|
+
async fetchSailing(ref) {
|
|
147
|
+
this.tickAndCheck();
|
|
148
|
+
for (const seeded of this.cruisesByRef.values()) {
|
|
149
|
+
const match = seeded.sailings.find((s) => refKey(s.sourceRef) === refKey(ref));
|
|
150
|
+
if (match)
|
|
151
|
+
return match;
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
async fetchSailingPricing(ref) {
|
|
156
|
+
this.tickAndCheck();
|
|
157
|
+
for (const seeded of this.cruisesByRef.values()) {
|
|
158
|
+
const prices = seeded.pricingBySailing.get(refKey(ref));
|
|
159
|
+
if (prices)
|
|
160
|
+
return prices;
|
|
161
|
+
}
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
async fetchSailingItinerary(ref) {
|
|
165
|
+
this.tickAndCheck();
|
|
166
|
+
for (const seeded of this.cruisesByRef.values()) {
|
|
167
|
+
const days = seeded.itinerariesBySailing.get(refKey(ref));
|
|
168
|
+
if (days)
|
|
169
|
+
return days;
|
|
170
|
+
}
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
async fetchShip(ref) {
|
|
174
|
+
this.tickAndCheck();
|
|
175
|
+
return this.shipsByRef.get(refKey(ref)) ?? null;
|
|
176
|
+
}
|
|
177
|
+
async listSailingsForCruise(cruiseRef) {
|
|
178
|
+
this.tickAndCheck();
|
|
179
|
+
return this.cruisesByRef.get(refKey(cruiseRef))?.sailings ?? [];
|
|
180
|
+
}
|
|
181
|
+
async createBooking(input) {
|
|
182
|
+
this.tickAndCheck();
|
|
183
|
+
this.bookingCount++;
|
|
184
|
+
const programmed = this.bookingResults.get(`${refKey(input.sailingRef)}::${refKey(input.cabinCategoryRef)}`);
|
|
185
|
+
if (programmed)
|
|
186
|
+
return programmed;
|
|
187
|
+
return {
|
|
188
|
+
connectorBookingRef: `MOCK-${this.bookingCount.toString().padStart(6, "0")}`,
|
|
189
|
+
connectorStatus: "confirmed",
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-local registry of cruise adapters.
|
|
3
|
+
*
|
|
4
|
+
* Templates register adapters at app startup:
|
|
5
|
+
*
|
|
6
|
+
* import { registerCruiseAdapter } from "@voyant-travel/cruises/adapters"
|
|
7
|
+
* import { createCruiseAdapter } from "external-cruise-adapter"
|
|
8
|
+
*
|
|
9
|
+
* registerCruiseAdapter(createCruiseAdapter({ token: env.CRUISE_ADAPTER_TOKEN }))
|
|
10
|
+
*
|
|
11
|
+
* The route layer resolves an adapter by `sourceProvider` (the prefix in the
|
|
12
|
+
* unified key `<provider>:<ref>`) before dispatching detail reads, refresh,
|
|
13
|
+
* detach, or the external booking commit.
|
|
14
|
+
*
|
|
15
|
+
* The registry is intentionally a plain Map. There's no per-tenant scoping —
|
|
16
|
+
* each Voyant deployment is single-tenant. Tests can reset state via
|
|
17
|
+
* `clearCruiseAdapters()`.
|
|
18
|
+
*/
|
|
19
|
+
import type { CruiseAdapter } from "./index.js";
|
|
20
|
+
export declare function registerCruiseAdapter(adapter: CruiseAdapter): void;
|
|
21
|
+
export declare function unregisterCruiseAdapter(name: string): boolean;
|
|
22
|
+
export declare function clearCruiseAdapters(): void;
|
|
23
|
+
export declare function resolveCruiseAdapter(name: string): CruiseAdapter | undefined;
|
|
24
|
+
export declare function listCruiseAdapters(): CruiseAdapter[];
|
|
25
|
+
export declare function hasCruiseAdapter(name: string): boolean;
|
|
26
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/adapters/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAI/C,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAQlE;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAE5E;AAED,wBAAgB,kBAAkB,IAAI,aAAa,EAAE,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-local registry of cruise adapters.
|
|
3
|
+
*
|
|
4
|
+
* Templates register adapters at app startup:
|
|
5
|
+
*
|
|
6
|
+
* import { registerCruiseAdapter } from "@voyant-travel/cruises/adapters"
|
|
7
|
+
* import { createCruiseAdapter } from "external-cruise-adapter"
|
|
8
|
+
*
|
|
9
|
+
* registerCruiseAdapter(createCruiseAdapter({ token: env.CRUISE_ADAPTER_TOKEN }))
|
|
10
|
+
*
|
|
11
|
+
* The route layer resolves an adapter by `sourceProvider` (the prefix in the
|
|
12
|
+
* unified key `<provider>:<ref>`) before dispatching detail reads, refresh,
|
|
13
|
+
* detach, or the external booking commit.
|
|
14
|
+
*
|
|
15
|
+
* The registry is intentionally a plain Map. There's no per-tenant scoping —
|
|
16
|
+
* each Voyant deployment is single-tenant. Tests can reset state via
|
|
17
|
+
* `clearCruiseAdapters()`.
|
|
18
|
+
*/
|
|
19
|
+
const adapters = new Map();
|
|
20
|
+
export function registerCruiseAdapter(adapter) {
|
|
21
|
+
if (!adapter.name)
|
|
22
|
+
throw new Error("Adapter must have a non-empty name");
|
|
23
|
+
if (adapters.has(adapter.name)) {
|
|
24
|
+
throw new Error(`Cruise adapter '${adapter.name}' is already registered; call unregisterCruiseAdapter first if you intend to replace it`);
|
|
25
|
+
}
|
|
26
|
+
adapters.set(adapter.name, adapter);
|
|
27
|
+
}
|
|
28
|
+
export function unregisterCruiseAdapter(name) {
|
|
29
|
+
return adapters.delete(name);
|
|
30
|
+
}
|
|
31
|
+
export function clearCruiseAdapters() {
|
|
32
|
+
adapters.clear();
|
|
33
|
+
}
|
|
34
|
+
export function resolveCruiseAdapter(name) {
|
|
35
|
+
return adapters.get(name);
|
|
36
|
+
}
|
|
37
|
+
export function listCruiseAdapters() {
|
|
38
|
+
return Array.from(adapters.values());
|
|
39
|
+
}
|
|
40
|
+
export function hasCruiseAdapter(name) {
|
|
41
|
+
return adapters.has(name);
|
|
42
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapt a vertical-shaped `CruiseAdapter` (with its multi-method
|
|
3
|
+
* `fetchCruise / fetchSailing / fetchShip / fetchSailingItinerary`
|
|
4
|
+
* surface) into a catalog-plane `SourceAdapter` so the cruises module
|
|
5
|
+
* can participate in:
|
|
6
|
+
*
|
|
7
|
+
* - The catalog plane's discovery / projection-capture pipeline
|
|
8
|
+
* (`sync.ts` writes a `catalog_sourced_entries` row per emitted
|
|
9
|
+
* projection), enabling the durable thin-content synthesizer
|
|
10
|
+
* fallback for cruises (sourced-content §2.5, §3.6).
|
|
11
|
+
* - The `getCruiseContent` SWR machinery (sourced-content §3.4) —
|
|
12
|
+
* the shim's `getContent` composes the cruise adapter's per-aspect
|
|
13
|
+
* fetches into one `CruiseContent` payload.
|
|
14
|
+
* - The catalog plane's snapshot content capture (sourced-content
|
|
15
|
+
* §5.1) — `bookEntity` calls this `getContent` at commit time.
|
|
16
|
+
*
|
|
17
|
+
* Per the doc's Phase E note: the cruise adapter retains its internal
|
|
18
|
+
* multi-call composition; only the public catalog surface narrows.
|
|
19
|
+
*
|
|
20
|
+
* Templates wire the shim by registering it into the catalog
|
|
21
|
+
* `SourceAdapterRegistry` AT PROCESS START, alongside the cruise
|
|
22
|
+
* adapter's own per-vertical registration. Both registrations are
|
|
23
|
+
* cheap — they share the same underlying `CruiseAdapter` instance.
|
|
24
|
+
*/
|
|
25
|
+
import type { SourceAdapter } from "@voyant-travel/catalog";
|
|
26
|
+
import { type CruiseContent } from "../content-shape.js";
|
|
27
|
+
import type { CruiseAdapter, ExternalItineraryDay, SourceRef } from "./index.js";
|
|
28
|
+
export interface CruiseSourceAdapterShimOptions {
|
|
29
|
+
/**
|
|
30
|
+
* The `source_kind` reported on every projection emitted by the
|
|
31
|
+
* shim. Defaults to `"cruise:" + adapter.name` so multiple cruise
|
|
32
|
+
* adapters (different agencies) coexist in the catalog registry
|
|
33
|
+
* without colliding on `source_kind`.
|
|
34
|
+
*/
|
|
35
|
+
sourceKind?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Optional translator from `SourceRef` → catalog-side `entity_id`.
|
|
38
|
+
* Catalog `entity_id` is the Voyant-side TypeID; this shim produces
|
|
39
|
+
* one synthetically by hashing the upstream ref so discovery is
|
|
40
|
+
* idempotent. Templates can override when they have an external-id
|
|
41
|
+
* → typeid mapping in their own DB.
|
|
42
|
+
*
|
|
43
|
+
* The default produces stable ids that round-trip across re-syncs:
|
|
44
|
+
* `crus_${slug-of-externalId}`. The catalog plane uses the entity_id
|
|
45
|
+
* as its primary key into `catalog_sourced_entries`, so stability is
|
|
46
|
+
* load-bearing — drift on the id maps to a new entity.
|
|
47
|
+
*/
|
|
48
|
+
buildEntityId?: (sourceRef: SourceRef) => string;
|
|
49
|
+
/**
|
|
50
|
+
* Pagination batch size for `discover`. Defaults to 200 — large
|
|
51
|
+
* enough to amortize HTTP overhead, small enough to cap memory.
|
|
52
|
+
*/
|
|
53
|
+
pageSize?: number;
|
|
54
|
+
/**
|
|
55
|
+
* BCP 47 locales the cruise adapter can serve content in. Reported
|
|
56
|
+
* via `capabilities.supportedContentLocales`. Defaults to undefined
|
|
57
|
+
* (unknown — caller probes per-call).
|
|
58
|
+
*/
|
|
59
|
+
supportedContentLocales?: ReadonlyArray<string>;
|
|
60
|
+
/**
|
|
61
|
+
* When false, declares `supportsContentFetch: false` so the catalog
|
|
62
|
+
* plane skips `getContent` and falls through to the per-vertical
|
|
63
|
+
* thin-content synthesizer (sourced-content §3.6). Defaults to
|
|
64
|
+
* true — the shim composes a real `CruiseContent` payload from the
|
|
65
|
+
* cruise adapter's per-aspect fetches.
|
|
66
|
+
*/
|
|
67
|
+
supportsContentFetch?: boolean;
|
|
68
|
+
}
|
|
69
|
+
export interface CruiseSourceAdapterShim extends SourceAdapter {
|
|
70
|
+
/** The wrapped vertical adapter — exposed for diagnostics / tests. */
|
|
71
|
+
readonly cruiseAdapter: CruiseAdapter;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Wrap a `CruiseAdapter` as a catalog `SourceAdapter`. The wrapped
|
|
75
|
+
* adapter is shared by reference — its internal state (HTTP clients,
|
|
76
|
+
* caches, credentials) is not duplicated.
|
|
77
|
+
*/
|
|
78
|
+
export declare function cruiseAdapterToSourceAdapter(cruiseAdapter: CruiseAdapter, options?: CruiseSourceAdapterShimOptions): CruiseSourceAdapterShim;
|
|
79
|
+
export declare function cruiseItineraryStopFrom(day: ExternalItineraryDay, date?: string | null): CruiseContent["itinerary_stops"][number];
|
|
80
|
+
//# sourceMappingURL=source-adapter-shim.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-adapter-shim.d.ts","sourceRoot":"","sources":["../../src/adapters/source-adapter-shim.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAcV,aAAa,EAEd,MAAM,wBAAwB,CAAA;AAG/B,OAAO,EAAkC,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGxF,OAAO,KAAK,EACV,aAAa,EAIb,oBAAoB,EAGpB,SAAS,EACV,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,8BAA8B;IAC7C;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,MAAM,CAAA;IAChD;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAC/C;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,MAAM,WAAW,uBAAwB,SAAQ,aAAa;IAC5D,sEAAsE;IACtE,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAA;CACtC;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,aAAa,EAAE,aAAa,EAC5B,OAAO,GAAE,8BAAmC,GAC3C,uBAAuB,CAgKzB;AA0HD,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,oBAAoB,EACzB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,aAAa,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAU1C"}
|