@voyant-travel/catalog 0.117.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 +190 -0
- package/dist/adapter/booking-forwarding.d.ts +2 -0
- package/dist/adapter/booking-forwarding.d.ts.map +1 -0
- package/dist/adapter/booking-forwarding.js +1 -0
- package/dist/adapter/channel-push-contracts.d.ts +2 -0
- package/dist/adapter/channel-push-contracts.d.ts.map +1 -0
- package/dist/adapter/channel-push-contracts.js +1 -0
- package/dist/adapter/contract.d.ts +2 -0
- package/dist/adapter/contract.d.ts.map +1 -0
- package/dist/adapter/contract.js +1 -0
- package/dist/adapter/contract.test.d.ts +2 -0
- package/dist/adapter/contract.test.d.ts.map +1 -0
- package/dist/adapter/contract.test.js +390 -0
- package/dist/adapter/provider-contracts.d.ts +2 -0
- package/dist/adapter/provider-contracts.d.ts.map +1 -0
- package/dist/adapter/provider-contracts.js +1 -0
- package/dist/adapter/provider-contracts.test.d.ts +2 -0
- package/dist/adapter/provider-contracts.test.d.ts.map +1 -0
- package/dist/adapter/provider-contracts.test.js +206 -0
- package/dist/adapter/schemas.d.ts +2 -0
- package/dist/adapter/schemas.d.ts.map +1 -0
- package/dist/adapter/schemas.js +1 -0
- package/dist/adapter/schemas.test.d.ts +2 -0
- package/dist/adapter/schemas.test.d.ts.map +1 -0
- package/dist/adapter/schemas.test.js +344 -0
- package/dist/booking-engine/book.d.ts +124 -0
- package/dist/booking-engine/book.d.ts.map +1 -0
- package/dist/booking-engine/book.js +311 -0
- package/dist/booking-engine/cancel.d.ts +40 -0
- package/dist/booking-engine/cancel.d.ts.map +1 -0
- package/dist/booking-engine/cancel.js +56 -0
- package/dist/booking-engine/checkout-finalize.d.ts +146 -0
- package/dist/booking-engine/checkout-finalize.d.ts.map +1 -0
- package/dist/booking-engine/checkout-finalize.js +132 -0
- package/dist/booking-engine/contracts.d.ts +9 -0
- package/dist/booking-engine/contracts.d.ts.map +1 -0
- package/dist/booking-engine/contracts.js +8 -0
- package/dist/booking-engine/contracts.test.d.ts +2 -0
- package/dist/booking-engine/contracts.test.d.ts.map +1 -0
- package/dist/booking-engine/contracts.test.js +116 -0
- package/dist/booking-engine/draft-shape.d.ts +10 -0
- package/dist/booking-engine/draft-shape.d.ts.map +1 -0
- package/dist/booking-engine/draft-shape.js +9 -0
- package/dist/booking-engine/draft-shape.test.d.ts +2 -0
- package/dist/booking-engine/draft-shape.test.d.ts.map +1 -0
- package/dist/booking-engine/draft-shape.test.js +74 -0
- package/dist/booking-engine/drafts-schema.d.ts +302 -0
- package/dist/booking-engine/drafts-schema.d.ts.map +1 -0
- package/dist/booking-engine/drafts-schema.js +53 -0
- package/dist/booking-engine/drafts-service.d.ts +41 -0
- package/dist/booking-engine/drafts-service.d.ts.map +1 -0
- package/dist/booking-engine/drafts-service.js +108 -0
- package/dist/booking-engine/errors.d.ts +81 -0
- package/dist/booking-engine/errors.d.ts.map +1 -0
- package/dist/booking-engine/errors.js +113 -0
- package/dist/booking-engine/index.d.ts +36 -0
- package/dist/booking-engine/index.d.ts.map +1 -0
- package/dist/booking-engine/index.js +34 -0
- package/dist/booking-engine/orders.d.ts +41 -0
- package/dist/booking-engine/orders.d.ts.map +1 -0
- package/dist/booking-engine/orders.js +49 -0
- package/dist/booking-engine/owned-handler.d.ts +166 -0
- package/dist/booking-engine/owned-handler.d.ts.map +1 -0
- package/dist/booking-engine/owned-handler.js +50 -0
- package/dist/booking-engine/owned-handler.test.d.ts +2 -0
- package/dist/booking-engine/owned-handler.test.d.ts.map +1 -0
- package/dist/booking-engine/owned-handler.test.js +63 -0
- package/dist/booking-engine/promotions-contract.d.ts +8 -0
- package/dist/booking-engine/promotions-contract.d.ts.map +1 -0
- package/dist/booking-engine/promotions-contract.js +7 -0
- package/dist/booking-engine/quote-enricher.test.d.ts +12 -0
- package/dist/booking-engine/quote-enricher.test.d.ts.map +1 -0
- package/dist/booking-engine/quote-enricher.test.js +138 -0
- package/dist/booking-engine/quote.d.ts +163 -0
- package/dist/booking-engine/quote.d.ts.map +1 -0
- package/dist/booking-engine/quote.js +259 -0
- package/dist/booking-engine/registry.d.ts +85 -0
- package/dist/booking-engine/registry.d.ts.map +1 -0
- package/dist/booking-engine/registry.js +118 -0
- package/dist/booking-engine/registry.test.d.ts +2 -0
- package/dist/booking-engine/registry.test.d.ts.map +1 -0
- package/dist/booking-engine/registry.test.js +132 -0
- package/dist/booking-engine/routes-contracts.d.ts +169 -0
- package/dist/booking-engine/routes-contracts.d.ts.map +1 -0
- package/dist/booking-engine/routes-contracts.js +63 -0
- package/dist/booking-engine/routes.d.ts +7 -0
- package/dist/booking-engine/routes.d.ts.map +1 -0
- package/dist/booking-engine/routes.js +443 -0
- package/dist/booking-engine/routes.test.d.ts +2 -0
- package/dist/booking-engine/routes.test.d.ts.map +1 -0
- package/dist/booking-engine/routes.test.js +304 -0
- package/dist/booking-engine/schema.d.ts +455 -0
- package/dist/booking-engine/schema.d.ts.map +1 -0
- package/dist/booking-engine/schema.js +75 -0
- package/dist/booking-engine/snapshot-content.d.ts +120 -0
- package/dist/booking-engine/snapshot-content.d.ts.map +1 -0
- package/dist/booking-engine/snapshot-content.js +110 -0
- package/dist/booking-engine/snapshot-content.test.d.ts +2 -0
- package/dist/booking-engine/snapshot-content.test.d.ts.map +1 -0
- package/dist/booking-engine/snapshot-content.test.js +213 -0
- package/dist/booking-engine/sync.d.ts +136 -0
- package/dist/booking-engine/sync.d.ts.map +1 -0
- package/dist/booking-engine/sync.js +177 -0
- package/dist/booking-engine/sync.test.d.ts +2 -0
- package/dist/booking-engine/sync.test.d.ts.map +1 -0
- package/dist/booking-engine/sync.test.js +377 -0
- package/dist/contract.d.ts +2 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +1 -0
- package/dist/contract.test.d.ts +2 -0
- package/dist/contract.test.d.ts.map +1 -0
- package/dist/contract.test.js +107 -0
- package/dist/drift/events.d.ts +2 -0
- package/dist/drift/events.d.ts.map +1 -0
- package/dist/drift/events.js +1 -0
- package/dist/drift/events.test.d.ts +2 -0
- package/dist/drift/events.test.d.ts.map +1 -0
- package/dist/drift/events.test.js +100 -0
- package/dist/embeddings/contract.d.ts +85 -0
- package/dist/embeddings/contract.d.ts.map +1 -0
- package/dist/embeddings/contract.js +42 -0
- package/dist/embeddings/contract.test.d.ts +2 -0
- package/dist/embeddings/contract.test.d.ts.map +1 -0
- package/dist/embeddings/contract.test.js +30 -0
- package/dist/embeddings/gemini.d.ts +110 -0
- package/dist/embeddings/gemini.d.ts.map +1 -0
- package/dist/embeddings/gemini.js +118 -0
- package/dist/embeddings/gemini.test.d.ts +2 -0
- package/dist/embeddings/gemini.test.d.ts.map +1 -0
- package/dist/embeddings/gemini.test.js +132 -0
- package/dist/embeddings/model-registry.d.ts +62 -0
- package/dist/embeddings/model-registry.d.ts.map +1 -0
- package/dist/embeddings/model-registry.js +78 -0
- package/dist/embeddings/model-registry.test.d.ts +2 -0
- package/dist/embeddings/model-registry.test.d.ts.map +1 -0
- package/dist/embeddings/model-registry.test.js +81 -0
- package/dist/embeddings/openai.d.ts +81 -0
- package/dist/embeddings/openai.d.ts.map +1 -0
- package/dist/embeddings/openai.js +123 -0
- package/dist/embeddings/openai.test.d.ts +2 -0
- package/dist/embeddings/openai.test.d.ts.map +1 -0
- package/dist/embeddings/openai.test.js +164 -0
- package/dist/events/taxonomy.d.ts +158 -0
- package/dist/events/taxonomy.d.ts.map +1 -0
- package/dist/events/taxonomy.js +99 -0
- package/dist/events/taxonomy.test.d.ts +2 -0
- package/dist/events/taxonomy.test.d.ts.map +1 -0
- package/dist/events/taxonomy.test.js +48 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/indexer/contract.d.ts +203 -0
- package/dist/indexer/contract.d.ts.map +1 -0
- package/dist/indexer/contract.js +16 -0
- package/dist/indexer/typesense-search-query.d.ts +31 -0
- package/dist/indexer/typesense-search-query.d.ts.map +1 -0
- package/dist/indexer/typesense-search-query.js +185 -0
- package/dist/indexer/typesense.d.ts +105 -0
- package/dist/indexer/typesense.d.ts.map +1 -0
- package/dist/indexer/typesense.js +394 -0
- package/dist/indexer/typesense.test.d.ts +2 -0
- package/dist/indexer/typesense.test.d.ts.map +1 -0
- package/dist/indexer/typesense.test.js +253 -0
- package/dist/overlay/resolver.d.ts +101 -0
- package/dist/overlay/resolver.d.ts.map +1 -0
- package/dist/overlay/resolver.js +167 -0
- package/dist/overlay/resolver.test.d.ts +2 -0
- package/dist/overlay/resolver.test.d.ts.map +1 -0
- package/dist/overlay/resolver.test.js +179 -0
- package/dist/overlay/schema.d.ts +266 -0
- package/dist/overlay/schema.d.ts.map +1 -0
- package/dist/overlay/schema.js +71 -0
- package/dist/provenance.d.ts +2 -0
- package/dist/provenance.d.ts.map +1 -0
- package/dist/provenance.js +1 -0
- package/dist/schema-sourced-entries.d.ts +344 -0
- package/dist/schema-sourced-entries.d.ts.map +1 -0
- package/dist/schema-sourced-entries.js +75 -0
- package/dist/schema.d.ts +21 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +20 -0
- package/dist/search/federate.d.ts +58 -0
- package/dist/search/federate.d.ts.map +1 -0
- package/dist/search/federate.js +103 -0
- package/dist/search/federate.test.d.ts +2 -0
- package/dist/search/federate.test.d.ts.map +1 -0
- package/dist/search/federate.test.js +146 -0
- package/dist/search/rerank.d.ts +77 -0
- package/dist/search/rerank.d.ts.map +1 -0
- package/dist/search/rerank.js +68 -0
- package/dist/search/rerank.test.d.ts +2 -0
- package/dist/search/rerank.test.d.ts.map +1 -0
- package/dist/search/rerank.test.js +60 -0
- package/dist/search/routes.d.ts +144 -0
- package/dist/search/routes.d.ts.map +1 -0
- package/dist/search/routes.js +288 -0
- package/dist/search/routes.test.d.ts +2 -0
- package/dist/search/routes.test.d.ts.map +1 -0
- package/dist/search/routes.test.js +322 -0
- package/dist/search/semantic.d.ts +63 -0
- package/dist/search/semantic.d.ts.map +1 -0
- package/dist/search/semantic.js +75 -0
- package/dist/search/semantic.test.d.ts +2 -0
- package/dist/search/semantic.test.d.ts.map +1 -0
- package/dist/search/semantic.test.js +143 -0
- package/dist/services/build-indexer-document.test.d.ts +2 -0
- package/dist/services/build-indexer-document.test.d.ts.map +1 -0
- package/dist/services/build-indexer-document.test.js +102 -0
- package/dist/services/content-service.d.ts +125 -0
- package/dist/services/content-service.d.ts.map +1 -0
- package/dist/services/content-service.js +139 -0
- package/dist/services/content-service.test.d.ts +2 -0
- package/dist/services/content-service.test.d.ts.map +1 -0
- package/dist/services/content-service.test.js +322 -0
- package/dist/services/indexer-service.d.ts +109 -0
- package/dist/services/indexer-service.d.ts.map +1 -0
- package/dist/services/indexer-service.js +123 -0
- package/dist/services/indexer-service.test.d.ts +2 -0
- package/dist/services/indexer-service.test.d.ts.map +1 -0
- package/dist/services/indexer-service.test.js +176 -0
- package/dist/services/overlay-service.d.ts +108 -0
- package/dist/services/overlay-service.d.ts.map +1 -0
- package/dist/services/overlay-service.js +211 -0
- package/dist/services/overlay-service.test.d.ts +2 -0
- package/dist/services/overlay-service.test.d.ts.map +1 -0
- package/dist/services/overlay-service.test.js +79 -0
- package/dist/services/snapshot-builder.test.d.ts +2 -0
- package/dist/services/snapshot-builder.test.d.ts.map +1 -0
- package/dist/services/snapshot-builder.test.js +93 -0
- package/dist/services/snapshot-service.d.ts +78 -0
- package/dist/services/snapshot-service.d.ts.map +1 -0
- package/dist/services/snapshot-service.js +165 -0
- package/dist/services/sourced-entry-service.d.ts +142 -0
- package/dist/services/sourced-entry-service.d.ts.map +1 -0
- package/dist/services/sourced-entry-service.js +203 -0
- package/dist/services/sourced-entry-service.test.d.ts +10 -0
- package/dist/services/sourced-entry-service.test.d.ts.map +1 -0
- package/dist/services/sourced-entry-service.test.js +66 -0
- package/dist/snapshot/schema.d.ts +362 -0
- package/dist/snapshot/schema.d.ts.map +1 -0
- package/dist/snapshot/schema.js +102 -0
- package/package.json +210 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable error codes returned from the booking engine.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the catalog plane's `CAPABILITY_NOT_SUPPORTED` convention:
|
|
5
|
+
* codes are stable strings, callers branch on them, and each carries a
|
|
6
|
+
* dedicated `Error` subclass for stack-trace clarity.
|
|
7
|
+
*/
|
|
8
|
+
/** No SourceAdapter was registered for the row's `source.kind`. */
|
|
9
|
+
export const NO_ADAPTER_REGISTERED = "NO_ADAPTER_REGISTERED";
|
|
10
|
+
/**
|
|
11
|
+
* No OwnedBookingHandler was registered for the row's `entity_module`.
|
|
12
|
+
* Sibling to `NO_ADAPTER_REGISTERED` — sourced rows dispatch through
|
|
13
|
+
* adapters keyed by connection, owned rows dispatch through handlers
|
|
14
|
+
* keyed by entity module. Per booking-journey-architecture §6.
|
|
15
|
+
*/
|
|
16
|
+
export const NO_HANDLER_REGISTERED = "NO_HANDLER_REGISTERED";
|
|
17
|
+
/** The supplied `quoteId` is unknown or already consumed. */
|
|
18
|
+
export const QUOTE_NOT_FOUND = "QUOTE_NOT_FOUND";
|
|
19
|
+
/** The quote's `expires_at` has passed; caller must re-quote. */
|
|
20
|
+
export const QUOTE_EXPIRED = "QUOTE_EXPIRED";
|
|
21
|
+
/** The quote's entity_module/entity_id doesn't match the book request. */
|
|
22
|
+
export const QUOTE_MISMATCH = "QUOTE_MISMATCH";
|
|
23
|
+
/** The adapter returned `failed` for the requested entity. */
|
|
24
|
+
export const RESERVE_FAILED = "RESERVE_FAILED";
|
|
25
|
+
/** No snapshot row exists for the given (booking_id, entity_*). */
|
|
26
|
+
export const ORDER_NOT_FOUND = "ORDER_NOT_FOUND";
|
|
27
|
+
/** The order has already been cancelled. */
|
|
28
|
+
export const ORDER_ALREADY_CANCELLED = "ORDER_ALREADY_CANCELLED";
|
|
29
|
+
/**
|
|
30
|
+
* Snapshot content capture failed: neither a fresh adapter fetch nor a
|
|
31
|
+
* cache fallback produced a content payload. Per sourced-content §5.1,
|
|
32
|
+
* we deliberately fail the commit rather than snapshot from the
|
|
33
|
+
* indexed projection — refunds and audit need real "what was sold"
|
|
34
|
+
* content, not a stub.
|
|
35
|
+
*/
|
|
36
|
+
export const SNAPSHOT_CONTENT_UNAVAILABLE = "SNAPSHOT_CONTENT_UNAVAILABLE";
|
|
37
|
+
export class BookingEngineError extends Error {
|
|
38
|
+
code;
|
|
39
|
+
context;
|
|
40
|
+
constructor(code, message, context) {
|
|
41
|
+
super(message);
|
|
42
|
+
this.code = code;
|
|
43
|
+
this.context = context;
|
|
44
|
+
this.name = "BookingEngineError";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export class NoAdapterRegisteredError extends BookingEngineError {
|
|
48
|
+
/**
|
|
49
|
+
* Thrown when the registry has no adapter for the given identifier.
|
|
50
|
+
* The identifier is a connection id when dispatched per-connection
|
|
51
|
+
* (channel push, sourced bookings with a known connection) or a source
|
|
52
|
+
* kind when the caller has no connection id (legacy dispatch).
|
|
53
|
+
*/
|
|
54
|
+
constructor(identifier) {
|
|
55
|
+
super(NO_ADAPTER_REGISTERED, `no SourceAdapter registered for "${identifier}"`, {
|
|
56
|
+
identifier,
|
|
57
|
+
});
|
|
58
|
+
this.name = "NoAdapterRegisteredError";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export class NoOwnedHandlerRegisteredError extends BookingEngineError {
|
|
62
|
+
/** Thrown when the owned-handler registry has no entry for the
|
|
63
|
+
* given `entity_module`. */
|
|
64
|
+
constructor(entityModule) {
|
|
65
|
+
super(NO_HANDLER_REGISTERED, `no OwnedBookingHandler registered for "${entityModule}"`, {
|
|
66
|
+
entityModule,
|
|
67
|
+
});
|
|
68
|
+
this.name = "NoOwnedHandlerRegisteredError";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export class QuoteExpiredError extends BookingEngineError {
|
|
72
|
+
constructor(quoteId, expiredAt) {
|
|
73
|
+
super(QUOTE_EXPIRED, `quote ${quoteId} expired at ${expiredAt.toISOString()}`, {
|
|
74
|
+
quoteId,
|
|
75
|
+
expiredAt: expiredAt.toISOString(),
|
|
76
|
+
});
|
|
77
|
+
this.name = "QuoteExpiredError";
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export class QuoteMismatchError extends BookingEngineError {
|
|
81
|
+
constructor(quoteId, expected, actual) {
|
|
82
|
+
super(QUOTE_MISMATCH, `quote ${quoteId} is for ${expected.entityModule}:${expected.entityId} but book request is for ${actual.entityModule}:${actual.entityId}`, { quoteId, expected, actual });
|
|
83
|
+
this.name = "QuoteMismatchError";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export class ReserveFailedError extends BookingEngineError {
|
|
87
|
+
upstreamPayload;
|
|
88
|
+
sourceKind;
|
|
89
|
+
entityId;
|
|
90
|
+
constructor(upstreamPayload, sourceKind, entityId) {
|
|
91
|
+
super(RESERVE_FAILED, `adapter "${sourceKind}" returned failed status for ${entityId}`, {
|
|
92
|
+
sourceKind,
|
|
93
|
+
entityId,
|
|
94
|
+
upstreamPayload,
|
|
95
|
+
});
|
|
96
|
+
this.upstreamPayload = upstreamPayload;
|
|
97
|
+
this.sourceKind = sourceKind;
|
|
98
|
+
this.entityId = entityId;
|
|
99
|
+
this.name = "ReserveFailedError";
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export class SnapshotContentUnavailableError extends BookingEngineError {
|
|
103
|
+
entityModule;
|
|
104
|
+
entityId;
|
|
105
|
+
fallbackReason;
|
|
106
|
+
constructor(entityModule, entityId, fallbackReason) {
|
|
107
|
+
super(SNAPSHOT_CONTENT_UNAVAILABLE, `cannot capture snapshot content for ${entityModule}:${entityId} — adapter fetch failed and no cache row available (reason: ${fallbackReason})`, { entityModule, entityId, fallbackReason });
|
|
108
|
+
this.entityModule = entityModule;
|
|
109
|
+
this.entityId = entityId;
|
|
110
|
+
this.fallbackReason = fallbackReason;
|
|
111
|
+
this.name = "SnapshotContentUnavailableError";
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@voyant-travel/catalog/booking-engine` — cross-vertical booking lifecycle
|
|
3
|
+
* on top of the Phase 1 `SourceAdapter` contract.
|
|
4
|
+
*
|
|
5
|
+
* See `docs/architecture/catalog-booking-engine.md` for the full design.
|
|
6
|
+
*
|
|
7
|
+
* Lifecycle:
|
|
8
|
+
* 1. `quoteEntity` → write to `catalog_quotes`, return short-lived quote.
|
|
9
|
+
* 2. `bookEntity` → call `adapter.reserve`, write `booking_catalog_snapshot`.
|
|
10
|
+
* 3. `cancelEntity` → call `adapter.cancel`, snapshot stays for audit.
|
|
11
|
+
*
|
|
12
|
+
* Reads:
|
|
13
|
+
* - `listOrders` / `getOrderById` — surface snapshot rows cross-vertically.
|
|
14
|
+
*
|
|
15
|
+
* Adapters:
|
|
16
|
+
* - Templates wire a `SourceAdapterRegistry` at process start. The
|
|
17
|
+
* engine consults it on every dispatch.
|
|
18
|
+
*/
|
|
19
|
+
export { type BookEntityDeps, type BookEntityRequest, type BookEntityResult, type BookingPaymentIntent, bookEntity, } from "./book.js";
|
|
20
|
+
export { type CancelEntityDeps, type CancelEntityRequest, type CancelEntityResult, cancelEntity, } from "./cancel.js";
|
|
21
|
+
export { type CheckoutFinalizeDeps, type CheckoutFinalizeInput, type CheckoutFinalizeStepRecorder, checkoutFinalizeWorkflow, runCheckoutFinalize, } from "./checkout-finalize.js";
|
|
22
|
+
export { accommodationSubStepV1, addonGroupV1, addonOfferV1, type BookingDraftShapeV1, type BookingDraftV1, type BookRequestV1, type BookResponseV1, bookingDraftShapeV1, bookingDraftV1, bookingFieldRequirementV1, bookRequestV1, bookResponseV1, cabinCategoryOptionV1, cabinNumberOptionV1, configureSubStepV1, ENGINE_CONTRACT_V1, type EngineContractVersion, extensionOptionV1, type HoldExtendRequestV1, type HoldReleaseRequestV1, holdExtendRequestV1, holdReleaseRequestV1, type PaxBandCode, type PaxBandSpecV1, type PricingBreakdownV1, paxBandCodeSchema, paxBandSpecV1, pricingBreakdownV1, pricingLineV1, pricingTaxV1, type QuoteRequestV1, type QuoteResponseV1, quoteRequestV1, quoteResponseV1, quoteScopeV1, roomOptionV1, type TravelerEntryV1, travelerEntryV1, travelerFieldRequirementV1, } from "./contracts.js";
|
|
23
|
+
export { type AccommodationSubStep, type AddonGroup, type AddonOffer, type BookingDraftShape, type BookingFieldRequirement, type CabinCategoryOption, type CabinNumberOption, type ConfigureSubStep, DEFAULT_PAX_BANDS, DEFAULT_PAX_TOTAL, defaultBookingFields, defaultDraftShapeFlags, defaultTravelerFields, type ExtensionOption, type PaxBandDependency, type PaxBandSpec, type ProductVariantOption, type ProductVariantUnitOption, paxBandsAllowedTotalFrom, type RatePlanOption, type RoomOption, type TravelerFieldRequirement, } from "./draft-shape.js";
|
|
24
|
+
export { bookingDraftsTable, type InsertBookingDraft, type SelectBookingDraft, } from "./drafts-schema.js";
|
|
25
|
+
export { createBookingDraft, DEFAULT_DRAFT_TTL_MS, deleteBookingDraft, findExpiredDrafts, getBookingDraft, markDraftConsumed, type UpdateDraftPatch, type UpsertDraftInput, updateBookingDraft, } from "./drafts-service.js";
|
|
26
|
+
export { BookingEngineError, type BookingEngineErrorCode, NO_ADAPTER_REGISTERED, NO_HANDLER_REGISTERED, NoAdapterRegisteredError, NoOwnedHandlerRegisteredError, ORDER_ALREADY_CANCELLED, ORDER_NOT_FOUND, QUOTE_EXPIRED, QUOTE_MISMATCH, QUOTE_NOT_FOUND, QuoteExpiredError, QuoteMismatchError, RESERVE_FAILED, ReserveFailedError, SNAPSHOT_CONTENT_UNAVAILABLE, SnapshotContentUnavailableError, } from "./errors.js";
|
|
27
|
+
export { getOrderById, type ListOrdersQuery, type ListOrdersResult, listOrders, } from "./orders.js";
|
|
28
|
+
export { type CommitOwnedRequest, type CommitOwnedResult, type ComputeQuoteRequest, type ComputeQuoteResult, createOwnedBookingHandlerRegistry, type HoldRequest, type HoldResult, OWNED_SOURCE_KIND, type OwnedBookingHandler, type OwnedBookingHandlerRegistry, type OwnedHandlerContext, type OwnedQuoteScope, } from "./owned-handler.js";
|
|
29
|
+
export type { AppliedOffer, CodeStatus, PromotionEvaluationInput, PromotionEvaluationOutput, } from "./promotions-contract.js";
|
|
30
|
+
export { DEFAULT_QUOTE_TTL_MS, type QuoteContentEnricher, type QuoteContentEnrichmentInput, type QuoteEntityDeps, type QuoteEntityRequest, type QuoteEntityResult, type QuoteScope, quoteEntity, } from "./quote.js";
|
|
31
|
+
export { createSourceAdapterRegistry, type SourceAdapterRegistry, } from "./registry.js";
|
|
32
|
+
export { type CatalogBookingAdapterContextInput, type CatalogBookingBookBody, type CatalogBookingBookTransformInput, type CatalogBookingCommittedEvent, type CatalogBookingContentScopeInput, type CatalogBookingDraftBody, type CatalogBookingDraftConsumedError, type CatalogBookingHoldPlaceBody, type CatalogBookingHoldReleaseBody, type CatalogBookingHoldTtlInput, type CatalogBookingProvenance, type CatalogBookingProvenanceInput, type CatalogBookingQuoteBody, type CatalogBookingQuoteTransformInput, type CatalogBookingRoutesOptions, createCatalogBookingHonoModule, createCatalogBookingRoutes, } from "./routes.js";
|
|
33
|
+
export { catalogQuotesTable, type InsertCatalogQuote, type SelectCatalogQuote, } from "./schema.js";
|
|
34
|
+
export { type ContentSnapshotAdapter, composeSnapshotContentCapturer, type SnapshotContentCapture, type SnapshotContentCaptureInput, type SnapshotContentCapturer, } from "./snapshot-content.js";
|
|
35
|
+
export { type SyncAdapterSummary, type SyncProgressEvent, type SyncSourcesOptions, type SyncSourcesSummary, syncSources, } from "./sync.js";
|
|
36
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/booking-engine/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,UAAU,GACX,MAAM,WAAW,CAAA;AAClB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,YAAY,GACb,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,4BAA4B,EACjC,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,YAAY,EACZ,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,mBAAmB,EACnB,cAAc,EACd,yBAAyB,EACzB,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,mBAAmB,EACnB,oBAAoB,EACpB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,cAAc,EACd,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,KAAK,eAAe,EACpB,eAAe,EACf,0BAA0B,GAC3B,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,wBAAwB,EACxB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,wBAAwB,GAC9B,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,kBAAkB,GACnB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,kBAAkB,EAClB,KAAK,sBAAsB,EAC3B,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,6BAA6B,EAC7B,uBAAuB,EACvB,eAAe,EACf,aAAa,EACb,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,YAAY,EACZ,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,UAAU,GACX,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,iCAAiC,EACjC,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,2BAA2B,EAChC,KAAK,mBAAmB,EACxB,KAAK,eAAe,GACrB,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,YAAY,EACZ,UAAU,EACV,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACL,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,WAAW,GACZ,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,2BAA2B,EAC3B,KAAK,qBAAqB,GAC3B,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,KAAK,iCAAiC,EACtC,KAAK,sBAAsB,EAC3B,KAAK,gCAAgC,EACrC,KAAK,4BAA4B,EACjC,KAAK,+BAA+B,EACpC,KAAK,uBAAuB,EAC5B,KAAK,gCAAgC,EACrC,KAAK,2BAA2B,EAChC,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAC5B,KAAK,iCAAiC,EACtC,KAAK,2BAA2B,EAChC,8BAA8B,EAC9B,0BAA0B,GAC3B,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,KAAK,sBAAsB,EAC3B,8BAA8B,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,EAChC,KAAK,uBAAuB,GAC7B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,WAAW,GACZ,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@voyant-travel/catalog/booking-engine` — cross-vertical booking lifecycle
|
|
3
|
+
* on top of the Phase 1 `SourceAdapter` contract.
|
|
4
|
+
*
|
|
5
|
+
* See `docs/architecture/catalog-booking-engine.md` for the full design.
|
|
6
|
+
*
|
|
7
|
+
* Lifecycle:
|
|
8
|
+
* 1. `quoteEntity` → write to `catalog_quotes`, return short-lived quote.
|
|
9
|
+
* 2. `bookEntity` → call `adapter.reserve`, write `booking_catalog_snapshot`.
|
|
10
|
+
* 3. `cancelEntity` → call `adapter.cancel`, snapshot stays for audit.
|
|
11
|
+
*
|
|
12
|
+
* Reads:
|
|
13
|
+
* - `listOrders` / `getOrderById` — surface snapshot rows cross-vertically.
|
|
14
|
+
*
|
|
15
|
+
* Adapters:
|
|
16
|
+
* - Templates wire a `SourceAdapterRegistry` at process start. The
|
|
17
|
+
* engine consults it on every dispatch.
|
|
18
|
+
*/
|
|
19
|
+
export { bookEntity, } from "./book.js";
|
|
20
|
+
export { cancelEntity, } from "./cancel.js";
|
|
21
|
+
export { checkoutFinalizeWorkflow, runCheckoutFinalize, } from "./checkout-finalize.js";
|
|
22
|
+
export { accommodationSubStepV1, addonGroupV1, addonOfferV1, bookingDraftShapeV1, bookingDraftV1, bookingFieldRequirementV1, bookRequestV1, bookResponseV1, cabinCategoryOptionV1, cabinNumberOptionV1, configureSubStepV1, ENGINE_CONTRACT_V1, extensionOptionV1, holdExtendRequestV1, holdReleaseRequestV1, paxBandCodeSchema, paxBandSpecV1, pricingBreakdownV1, pricingLineV1, pricingTaxV1, quoteRequestV1, quoteResponseV1, quoteScopeV1, roomOptionV1, travelerEntryV1, travelerFieldRequirementV1, } from "./contracts.js";
|
|
23
|
+
export { DEFAULT_PAX_BANDS, DEFAULT_PAX_TOTAL, defaultBookingFields, defaultDraftShapeFlags, defaultTravelerFields, paxBandsAllowedTotalFrom, } from "./draft-shape.js";
|
|
24
|
+
export { bookingDraftsTable, } from "./drafts-schema.js";
|
|
25
|
+
export { createBookingDraft, DEFAULT_DRAFT_TTL_MS, deleteBookingDraft, findExpiredDrafts, getBookingDraft, markDraftConsumed, updateBookingDraft, } from "./drafts-service.js";
|
|
26
|
+
export { BookingEngineError, NO_ADAPTER_REGISTERED, NO_HANDLER_REGISTERED, NoAdapterRegisteredError, NoOwnedHandlerRegisteredError, ORDER_ALREADY_CANCELLED, ORDER_NOT_FOUND, QUOTE_EXPIRED, QUOTE_MISMATCH, QUOTE_NOT_FOUND, QuoteExpiredError, QuoteMismatchError, RESERVE_FAILED, ReserveFailedError, SNAPSHOT_CONTENT_UNAVAILABLE, SnapshotContentUnavailableError, } from "./errors.js";
|
|
27
|
+
export { getOrderById, listOrders, } from "./orders.js";
|
|
28
|
+
export { createOwnedBookingHandlerRegistry, OWNED_SOURCE_KIND, } from "./owned-handler.js";
|
|
29
|
+
export { DEFAULT_QUOTE_TTL_MS, quoteEntity, } from "./quote.js";
|
|
30
|
+
export { createSourceAdapterRegistry, } from "./registry.js";
|
|
31
|
+
export { createCatalogBookingHonoModule, createCatalogBookingRoutes, } from "./routes.js";
|
|
32
|
+
export { catalogQuotesTable, } from "./schema.js";
|
|
33
|
+
export { composeSnapshotContentCapturer, } from "./snapshot-content.js";
|
|
34
|
+
export { syncSources, } from "./sync.js";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-side of the booking engine — `getOrder` / `listOrders`.
|
|
3
|
+
*
|
|
4
|
+
* The engine does not introduce a new "orders" table; `bookings` is
|
|
5
|
+
* already the parent and `booking_catalog_snapshot` is the per-line
|
|
6
|
+
* record. These helpers expose the cross-vertical view by selecting
|
|
7
|
+
* snapshot rows directly.
|
|
8
|
+
*
|
|
9
|
+
* Bookings-module joins (status, customer, payment) are layered on at
|
|
10
|
+
* the route level — these helpers stay scoped to what the catalog plane
|
|
11
|
+
* itself owns.
|
|
12
|
+
*/
|
|
13
|
+
import type { AnyDrizzleDb } from "@voyant-travel/db";
|
|
14
|
+
import { type SelectBookingCatalogSnapshot } from "../snapshot/schema.js";
|
|
15
|
+
export interface ListOrdersQuery {
|
|
16
|
+
/** Restrict to a specific booking. */
|
|
17
|
+
bookingId?: string;
|
|
18
|
+
/** Restrict to a specific catalog vertical (`"products"`, `"accommodations"`, etc.). */
|
|
19
|
+
entityModule?: string;
|
|
20
|
+
/** Restrict to one or more source kinds — e.g. `["demo"]`. */
|
|
21
|
+
sourceKinds?: ReadonlyArray<string>;
|
|
22
|
+
/** Pagination — capped at 100 by callers. */
|
|
23
|
+
limit?: number;
|
|
24
|
+
offset?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface ListOrdersResult {
|
|
27
|
+
rows: ReadonlyArray<SelectBookingCatalogSnapshot>;
|
|
28
|
+
/**
|
|
29
|
+
* `null` when the caller didn't request a count; populated when the
|
|
30
|
+
* query is bounded enough that an EXACT count is cheap (currently when
|
|
31
|
+
* `bookingId` is provided).
|
|
32
|
+
*/
|
|
33
|
+
total?: number;
|
|
34
|
+
}
|
|
35
|
+
export declare function listOrders(db: AnyDrizzleDb, query?: ListOrdersQuery): Promise<ListOrdersResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Fetch one snapshot row by its id. Used by the operator starter's
|
|
38
|
+
* `GET /v1/admin/catalog/orders/:id` route. Returns `null` when absent.
|
|
39
|
+
*/
|
|
40
|
+
export declare function getOrderById(db: AnyDrizzleDb, snapshotId: string): Promise<SelectBookingCatalogSnapshot | null>;
|
|
41
|
+
//# sourceMappingURL=orders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orders.d.ts","sourceRoot":"","sources":["../../src/booking-engine/orders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrD,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,uBAAuB,CAAA;AAE9B,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wFAAwF;IACxF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACnC,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,aAAa,CAAC,4BAA4B,CAAC,CAAA;IACjD;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,YAAY,EAChB,KAAK,GAAE,eAAoB,GAC1B,OAAO,CAAC,gBAAgB,CAAC,CAyB3B;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,YAAY,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAAC,CAO9C"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-side of the booking engine — `getOrder` / `listOrders`.
|
|
3
|
+
*
|
|
4
|
+
* The engine does not introduce a new "orders" table; `bookings` is
|
|
5
|
+
* already the parent and `booking_catalog_snapshot` is the per-line
|
|
6
|
+
* record. These helpers expose the cross-vertical view by selecting
|
|
7
|
+
* snapshot rows directly.
|
|
8
|
+
*
|
|
9
|
+
* Bookings-module joins (status, customer, payment) are layered on at
|
|
10
|
+
* the route level — these helpers stay scoped to what the catalog plane
|
|
11
|
+
* itself owns.
|
|
12
|
+
*/
|
|
13
|
+
import { and, desc, eq, inArray } from "drizzle-orm";
|
|
14
|
+
import { bookingCatalogSnapshotTable, } from "../snapshot/schema.js";
|
|
15
|
+
export async function listOrders(db, query = {}) {
|
|
16
|
+
const conditions = [];
|
|
17
|
+
if (query.bookingId) {
|
|
18
|
+
conditions.push(eq(bookingCatalogSnapshotTable.booking_id, query.bookingId));
|
|
19
|
+
}
|
|
20
|
+
if (query.entityModule) {
|
|
21
|
+
conditions.push(eq(bookingCatalogSnapshotTable.entity_module, query.entityModule));
|
|
22
|
+
}
|
|
23
|
+
if (query.sourceKinds?.length) {
|
|
24
|
+
conditions.push(inArray(bookingCatalogSnapshotTable.source_kind, [...query.sourceKinds]));
|
|
25
|
+
}
|
|
26
|
+
const where = conditions.length ? and(...conditions) : undefined;
|
|
27
|
+
const limit = Math.min(Math.max(query.limit ?? 50, 1), 100);
|
|
28
|
+
const offset = Math.max(query.offset ?? 0, 0);
|
|
29
|
+
const rows = (await db
|
|
30
|
+
.select()
|
|
31
|
+
.from(bookingCatalogSnapshotTable)
|
|
32
|
+
.where(where)
|
|
33
|
+
.orderBy(desc(bookingCatalogSnapshotTable.captured_at))
|
|
34
|
+
.limit(limit)
|
|
35
|
+
.offset(offset));
|
|
36
|
+
return { rows };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Fetch one snapshot row by its id. Used by the operator starter's
|
|
40
|
+
* `GET /v1/admin/catalog/orders/:id` route. Returns `null` when absent.
|
|
41
|
+
*/
|
|
42
|
+
export async function getOrderById(db, snapshotId) {
|
|
43
|
+
const rows = (await db
|
|
44
|
+
.select()
|
|
45
|
+
.from(bookingCatalogSnapshotTable)
|
|
46
|
+
.where(eq(bookingCatalogSnapshotTable.id, snapshotId))
|
|
47
|
+
.limit(1));
|
|
48
|
+
return rows[0] ?? null;
|
|
49
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `OwnedBookingHandler` + `OwnedBookingHandlerRegistry` — the
|
|
3
|
+
* dispatch seam for owned-arm bookings.
|
|
4
|
+
*
|
|
5
|
+
* Per `docs/architecture/booking-journey-architecture.md` §6, the
|
|
6
|
+
* catalog booking engine has two dispatch axes:
|
|
7
|
+
*
|
|
8
|
+
* - Sourced rows go through `SourceAdapterRegistry` keyed by
|
|
9
|
+
* `connection_id` (one adapter per upstream connection).
|
|
10
|
+
* - Owned rows go through `OwnedBookingHandlerRegistry` keyed by
|
|
11
|
+
* `entity_module` (one handler per vertical — products,
|
|
12
|
+
* accommodations, cruises, etc.).
|
|
13
|
+
*
|
|
14
|
+
* The two registries live side-by-side, never wrap each other. The
|
|
15
|
+
* dispatch direction inverts: instead of `@voyant-travel/catalog`
|
|
16
|
+
* importing every vertical, each vertical imports this interface
|
|
17
|
+
* and provides an implementation. Catalog stays a contract package;
|
|
18
|
+
* verticals stay self-contained.
|
|
19
|
+
*
|
|
20
|
+
* Phase A (per doc §10) ships the registry + interface + the first
|
|
21
|
+
* vertical handler (products). Subsequent phases land accommodations,
|
|
22
|
+
* cruises, etc. against the same interface without re-architecting
|
|
23
|
+
* the dispatch.
|
|
24
|
+
*/
|
|
25
|
+
import type { AnyDrizzleDb } from "@voyant-travel/db";
|
|
26
|
+
import type { SourceAdapterContext } from "../adapter/contract.js";
|
|
27
|
+
import type { PricingBasis } from "../snapshot/schema.js";
|
|
28
|
+
import type { BookingDraftShape } from "./draft-shape.js";
|
|
29
|
+
export interface OwnedHandlerContext {
|
|
30
|
+
db: AnyDrizzleDb;
|
|
31
|
+
/** Echoed through from the engine — handlers may use it for audit. */
|
|
32
|
+
adapterContext: SourceAdapterContext;
|
|
33
|
+
}
|
|
34
|
+
export interface OwnedQuoteScope {
|
|
35
|
+
locale: string;
|
|
36
|
+
audience: string;
|
|
37
|
+
market: string;
|
|
38
|
+
currency?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface ComputeQuoteRequest {
|
|
41
|
+
entityModule: string;
|
|
42
|
+
entityId: string;
|
|
43
|
+
scope: OwnedQuoteScope;
|
|
44
|
+
/**
|
|
45
|
+
* Vertical-specific parameters echoed by callers. Free-form today;
|
|
46
|
+
* Phase B adds a typed `BookingDraft` payload that supersedes this.
|
|
47
|
+
*/
|
|
48
|
+
parameters?: Record<string, unknown>;
|
|
49
|
+
/**
|
|
50
|
+
* Optional partial draft state — used when the wizard re-quotes
|
|
51
|
+
* mid-journey. Owned handlers read pax counts, addons, accommodation
|
|
52
|
+
* picks, billing country off this to compute the correct price.
|
|
53
|
+
*
|
|
54
|
+
* Typed as `unknown` here so Phase A doesn't pin the schema in the
|
|
55
|
+
* catalog package; Phase B replaces with a Zod-validated
|
|
56
|
+
* `BookingDraftV1` (see §8.5 of the doc).
|
|
57
|
+
*/
|
|
58
|
+
draft?: unknown;
|
|
59
|
+
}
|
|
60
|
+
export interface ComputeQuoteResult {
|
|
61
|
+
available: boolean;
|
|
62
|
+
invalidReason?: string;
|
|
63
|
+
pricing?: PricingBasis;
|
|
64
|
+
/**
|
|
65
|
+
* Per-quote journey descriptor. Owned handlers return this when
|
|
66
|
+
* they have enough context (always, for products in Phase A; the
|
|
67
|
+
* journey falls back to defaults when omitted).
|
|
68
|
+
*/
|
|
69
|
+
shape?: BookingDraftShape;
|
|
70
|
+
/** Echoed back into `catalog_quotes.upstream_payload` for audit. */
|
|
71
|
+
upstreamPayload?: Record<string, unknown>;
|
|
72
|
+
}
|
|
73
|
+
export interface CommitOwnedRequest {
|
|
74
|
+
entityModule: string;
|
|
75
|
+
entityId: string;
|
|
76
|
+
/** Booking shell id — generated by the engine when the caller
|
|
77
|
+
* doesn't pass one. Always defined here. */
|
|
78
|
+
bookingId: string;
|
|
79
|
+
/**
|
|
80
|
+
* Free-form party / passenger payload echoed from the caller. Phase
|
|
81
|
+
* B supersedes with a typed draft.
|
|
82
|
+
*/
|
|
83
|
+
party?: Record<string, unknown>;
|
|
84
|
+
parameters?: Record<string, unknown>;
|
|
85
|
+
/** Pre-validated quote pricing — handlers MAY trust this for cost
|
|
86
|
+
* basis or recompute on their own (some verticals re-price at
|
|
87
|
+
* commit). */
|
|
88
|
+
pricing?: PricingBasis;
|
|
89
|
+
/** Optional draft payload — Phase B routes the full draft here. */
|
|
90
|
+
draft?: unknown;
|
|
91
|
+
}
|
|
92
|
+
export interface CommitOwnedResult {
|
|
93
|
+
status: "held" | "confirmed" | "ticketed" | "failed";
|
|
94
|
+
orderRef: string;
|
|
95
|
+
/**
|
|
96
|
+
* The id of the booking row the handler actually created. The engine adopts
|
|
97
|
+
* this as the canonical booking id (the handler mints its own rather than use
|
|
98
|
+
* the provided `request.bookingId`), so the response + snapshot + quote-
|
|
99
|
+
* consumed marker all point at the real row.
|
|
100
|
+
*/
|
|
101
|
+
bookingId?: string;
|
|
102
|
+
/** Re-priced or echoed pricing — written into the snapshot. */
|
|
103
|
+
pricing?: PricingBasis;
|
|
104
|
+
/** Free-form payload preserved in the snapshot's frozen_payload. */
|
|
105
|
+
upstreamPayload?: Record<string, unknown>;
|
|
106
|
+
}
|
|
107
|
+
export interface HoldRequest {
|
|
108
|
+
entityModule: string;
|
|
109
|
+
entityId: string;
|
|
110
|
+
/** Caller-supplied draft id; handlers tie holds to the draft so
|
|
111
|
+
* abandonment is observable. */
|
|
112
|
+
draftId?: string;
|
|
113
|
+
ttlMs: number;
|
|
114
|
+
parameters?: Record<string, unknown>;
|
|
115
|
+
}
|
|
116
|
+
export interface HoldResult {
|
|
117
|
+
holdToken: string;
|
|
118
|
+
expiresAt: Date;
|
|
119
|
+
}
|
|
120
|
+
export interface OwnedBookingHandler {
|
|
121
|
+
/** Vertical this handler claims. One handler per `entity_module`. */
|
|
122
|
+
readonly entityModule: string;
|
|
123
|
+
/**
|
|
124
|
+
* Per-vertical hold-release grace period in milliseconds. The
|
|
125
|
+
* reaper defers calling `releaseHold` for `grace` past a draft's
|
|
126
|
+
* expiry. Default `0` (immediate release).
|
|
127
|
+
*
|
|
128
|
+
* Mirrors `AdapterCapabilities.holdReleaseGraceMs` for sourced
|
|
129
|
+
* holds. Per booking-journey-architecture §12.9.
|
|
130
|
+
*/
|
|
131
|
+
readonly holdReleaseGraceMs?: number;
|
|
132
|
+
/**
|
|
133
|
+
* Live-quote an owned row for a draft. The engine calls this on
|
|
134
|
+
* every meaningful input change. Returns shape + pricing +
|
|
135
|
+
* availability.
|
|
136
|
+
*
|
|
137
|
+
* Implementations should be idempotent — the same input must
|
|
138
|
+
* produce the same output (modulo time-sensitive fields like
|
|
139
|
+
* promo windows, which are explicitly OK to vary).
|
|
140
|
+
*/
|
|
141
|
+
computeQuote(ctx: OwnedHandlerContext, request: ComputeQuoteRequest): Promise<ComputeQuoteResult>;
|
|
142
|
+
/**
|
|
143
|
+
* Commit the draft to a booking row. Phase A handlers map the
|
|
144
|
+
* draft into `bookingsCreate`'s input shape; later phases
|
|
145
|
+
* extend this to model extras, accommodation stays, encrypted
|
|
146
|
+
* travel details, tax lines, snapshot graphs.
|
|
147
|
+
*/
|
|
148
|
+
commit(ctx: OwnedHandlerContext, request: CommitOwnedRequest): Promise<CommitOwnedResult>;
|
|
149
|
+
/** Optional: place / extend / release a soft hold on the row. */
|
|
150
|
+
placeHold?(ctx: OwnedHandlerContext, request: HoldRequest): Promise<HoldResult>;
|
|
151
|
+
extendHold?(ctx: OwnedHandlerContext, holdToken: string, request?: Pick<HoldRequest, "ttlMs" | "parameters">): Promise<HoldResult>;
|
|
152
|
+
releaseHold?(ctx: OwnedHandlerContext, holdToken: string): Promise<void>;
|
|
153
|
+
}
|
|
154
|
+
export interface OwnedBookingHandlerRegistry {
|
|
155
|
+
/** Register a handler. Re-registering the same `entityModule`
|
|
156
|
+
* replaces the previous handler. */
|
|
157
|
+
register(handler: OwnedBookingHandler): void;
|
|
158
|
+
resolve(entityModule: string): OwnedBookingHandler | undefined;
|
|
159
|
+
resolveOrThrow(entityModule: string): OwnedBookingHandler;
|
|
160
|
+
has(entityModule: string): boolean;
|
|
161
|
+
modules(): ReadonlyArray<string>;
|
|
162
|
+
}
|
|
163
|
+
export declare function createOwnedBookingHandlerRegistry(): OwnedBookingHandlerRegistry;
|
|
164
|
+
/** Stable string the engine inspects when deciding which arm to use. */
|
|
165
|
+
export declare const OWNED_SOURCE_KIND: "owned";
|
|
166
|
+
//# sourceMappingURL=owned-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owned-handler.d.ts","sourceRoot":"","sources":["../../src/booking-engine/owned-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `OwnedBookingHandler` + `OwnedBookingHandlerRegistry` — the
|
|
3
|
+
* dispatch seam for owned-arm bookings.
|
|
4
|
+
*
|
|
5
|
+
* Per `docs/architecture/booking-journey-architecture.md` §6, the
|
|
6
|
+
* catalog booking engine has two dispatch axes:
|
|
7
|
+
*
|
|
8
|
+
* - Sourced rows go through `SourceAdapterRegistry` keyed by
|
|
9
|
+
* `connection_id` (one adapter per upstream connection).
|
|
10
|
+
* - Owned rows go through `OwnedBookingHandlerRegistry` keyed by
|
|
11
|
+
* `entity_module` (one handler per vertical — products,
|
|
12
|
+
* accommodations, cruises, etc.).
|
|
13
|
+
*
|
|
14
|
+
* The two registries live side-by-side, never wrap each other. The
|
|
15
|
+
* dispatch direction inverts: instead of `@voyant-travel/catalog`
|
|
16
|
+
* importing every vertical, each vertical imports this interface
|
|
17
|
+
* and provides an implementation. Catalog stays a contract package;
|
|
18
|
+
* verticals stay self-contained.
|
|
19
|
+
*
|
|
20
|
+
* Phase A (per doc §10) ships the registry + interface + the first
|
|
21
|
+
* vertical handler (products). Subsequent phases land accommodations,
|
|
22
|
+
* cruises, etc. against the same interface without re-architecting
|
|
23
|
+
* the dispatch.
|
|
24
|
+
*/
|
|
25
|
+
import { NoOwnedHandlerRegisteredError } from "./errors.js";
|
|
26
|
+
export function createOwnedBookingHandlerRegistry() {
|
|
27
|
+
const byModule = new Map();
|
|
28
|
+
return {
|
|
29
|
+
register(handler) {
|
|
30
|
+
byModule.set(handler.entityModule, handler);
|
|
31
|
+
},
|
|
32
|
+
resolve(entityModule) {
|
|
33
|
+
return byModule.get(entityModule);
|
|
34
|
+
},
|
|
35
|
+
resolveOrThrow(entityModule) {
|
|
36
|
+
const handler = byModule.get(entityModule);
|
|
37
|
+
if (!handler)
|
|
38
|
+
throw new NoOwnedHandlerRegisteredError(entityModule);
|
|
39
|
+
return handler;
|
|
40
|
+
},
|
|
41
|
+
has(entityModule) {
|
|
42
|
+
return byModule.has(entityModule);
|
|
43
|
+
},
|
|
44
|
+
modules() {
|
|
45
|
+
return [...byModule.keys()];
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Stable string the engine inspects when deciding which arm to use. */
|
|
50
|
+
export const OWNED_SOURCE_KIND = "owned";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owned-handler.test.d.ts","sourceRoot":"","sources":["../../src/booking-engine/owned-handler.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { NoOwnedHandlerRegisteredError } from "./errors.js";
|
|
3
|
+
import { createOwnedBookingHandlerRegistry, } from "./owned-handler.js";
|
|
4
|
+
function stubHandler(entityModule) {
|
|
5
|
+
return {
|
|
6
|
+
entityModule,
|
|
7
|
+
async computeQuote(_ctx, _req) {
|
|
8
|
+
return { available: true };
|
|
9
|
+
},
|
|
10
|
+
async commit(_ctx, req) {
|
|
11
|
+
return { status: "held", orderRef: `ord-${req.bookingId}` };
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const stubDb = {};
|
|
16
|
+
describe("OwnedBookingHandlerRegistry", () => {
|
|
17
|
+
it("registers and resolves handlers by entity_module", () => {
|
|
18
|
+
const reg = createOwnedBookingHandlerRegistry();
|
|
19
|
+
const products = stubHandler("products");
|
|
20
|
+
reg.register(products);
|
|
21
|
+
expect(reg.has("products")).toBe(true);
|
|
22
|
+
expect(reg.has("accommodations")).toBe(false);
|
|
23
|
+
expect(reg.resolve("products")).toBe(products);
|
|
24
|
+
expect(reg.resolveOrThrow("products")).toBe(products);
|
|
25
|
+
expect(reg.modules()).toEqual(["products"]);
|
|
26
|
+
});
|
|
27
|
+
it("replaces handler when a module re-registers", () => {
|
|
28
|
+
const reg = createOwnedBookingHandlerRegistry();
|
|
29
|
+
const a = stubHandler("products");
|
|
30
|
+
const b = stubHandler("products");
|
|
31
|
+
reg.register(a);
|
|
32
|
+
reg.register(b);
|
|
33
|
+
expect(reg.resolveOrThrow("products")).toBe(b);
|
|
34
|
+
expect(reg.modules()).toHaveLength(1);
|
|
35
|
+
});
|
|
36
|
+
it("throws NoOwnedHandlerRegisteredError when missing", () => {
|
|
37
|
+
const reg = createOwnedBookingHandlerRegistry();
|
|
38
|
+
expect(() => reg.resolveOrThrow("accommodations")).toThrow(NoOwnedHandlerRegisteredError);
|
|
39
|
+
expect(reg.resolve("accommodations")).toBeUndefined();
|
|
40
|
+
});
|
|
41
|
+
it("dispatches computeQuote through resolved handler", async () => {
|
|
42
|
+
const reg = createOwnedBookingHandlerRegistry();
|
|
43
|
+
const captured = [];
|
|
44
|
+
reg.register({
|
|
45
|
+
entityModule: "products",
|
|
46
|
+
async computeQuote(_ctx, req) {
|
|
47
|
+
captured.push(req);
|
|
48
|
+
return { available: true, pricing: undefined };
|
|
49
|
+
},
|
|
50
|
+
async commit() {
|
|
51
|
+
return { status: "held", orderRef: "x" };
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
const handler = reg.resolveOrThrow("products");
|
|
55
|
+
const result = await handler.computeQuote({ db: stubDb, adapterContext: { connection_id: "test" } }, {
|
|
56
|
+
entityModule: "products",
|
|
57
|
+
entityId: "prod_1",
|
|
58
|
+
scope: { locale: "en-GB", audience: "staff", market: "default" },
|
|
59
|
+
});
|
|
60
|
+
expect(result.available).toBe(true);
|
|
61
|
+
expect(captured[0]?.entityId).toBe("prod_1");
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Promotion-evaluation contract types now live in `@voyant-travel/catalog-contracts`
|
|
3
|
+
* so external consumers can validate promotion payloads without the catalog
|
|
4
|
+
* runtime. Re-exported here to keep existing `@voyant-travel/catalog` import paths
|
|
5
|
+
* stable. See `docs/adr/0002-contract-packages.md`.
|
|
6
|
+
*/
|
|
7
|
+
export * from "@voyant-travel/catalog-contracts/booking-engine/promotions-contract";
|
|
8
|
+
//# sourceMappingURL=promotions-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promotions-contract.d.ts","sourceRoot":"","sources":["../../src/booking-engine/promotions-contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,qEAAqE,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Promotion-evaluation contract types now live in `@voyant-travel/catalog-contracts`
|
|
3
|
+
* so external consumers can validate promotion payloads without the catalog
|
|
4
|
+
* runtime. Re-exported here to keep existing `@voyant-travel/catalog` import paths
|
|
5
|
+
* stable. See `docs/adr/0002-contract-packages.md`.
|
|
6
|
+
*/
|
|
7
|
+
export * from "@voyant-travel/catalog-contracts/booking-engine/promotions-contract";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focused tests for the `contentEnricher` hook on `quoteEntity`. The
|
|
3
|
+
* full quote path needs a real DB — these tests stub the drizzle
|
|
4
|
+
* insert chain just enough to verify the hook's call contract:
|
|
5
|
+
* - Called with the right input when wired and live-resolve succeeds.
|
|
6
|
+
* - Result attached to the quote response as `shape`.
|
|
7
|
+
* - Errors swallowed + reported via `onEnricherError` instead of
|
|
8
|
+
* failing the quote.
|
|
9
|
+
* - Skipped when the entity is not available (failed live-resolve).
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=quote-enricher.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quote-enricher.test.d.ts","sourceRoot":"","sources":["../../src/booking-engine/quote-enricher.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|