@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,93 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { buildSnapshotInputFromView, viewToFrozenPayload, viewToOverlayState, } from "./snapshot-service.js";
|
|
3
|
+
const sampleView = {
|
|
4
|
+
values: new Map([
|
|
5
|
+
["title", "Resolved title"],
|
|
6
|
+
["description", "Resolved description"],
|
|
7
|
+
["status", "active"],
|
|
8
|
+
]),
|
|
9
|
+
hidden: new Set(["internal_notes"]),
|
|
10
|
+
provenance: new Map([
|
|
11
|
+
["title", { locale: "en-GB", audience: "customer", market: "default" }],
|
|
12
|
+
["description", null],
|
|
13
|
+
["status", null],
|
|
14
|
+
]),
|
|
15
|
+
};
|
|
16
|
+
describe("viewToFrozenPayload", () => {
|
|
17
|
+
it("converts the resolved value Map into a JSONB-shaped object", () => {
|
|
18
|
+
const frozen = viewToFrozenPayload(sampleView);
|
|
19
|
+
expect(frozen).toEqual({
|
|
20
|
+
title: "Resolved title",
|
|
21
|
+
description: "Resolved description",
|
|
22
|
+
status: "active",
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
it("does not include hidden fields", () => {
|
|
26
|
+
const frozen = viewToFrozenPayload(sampleView);
|
|
27
|
+
expect(frozen).not.toHaveProperty("internal_notes");
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe("viewToOverlayState", () => {
|
|
31
|
+
it("includes only fields where an overlay was applied", () => {
|
|
32
|
+
const state = viewToOverlayState(sampleView);
|
|
33
|
+
expect(state).toHaveProperty("title");
|
|
34
|
+
expect(state).not.toHaveProperty("description");
|
|
35
|
+
expect(state).not.toHaveProperty("status");
|
|
36
|
+
});
|
|
37
|
+
it("records the variant slice that satisfied each overlay", () => {
|
|
38
|
+
const state = viewToOverlayState(sampleView);
|
|
39
|
+
expect(state.title).toEqual({
|
|
40
|
+
locale: "en-GB",
|
|
41
|
+
audience: "customer",
|
|
42
|
+
market: "default",
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe("buildSnapshotInputFromView", () => {
|
|
47
|
+
it("composes a CaptureSnapshotInput with frozen payload + overlay state", () => {
|
|
48
|
+
const input = buildSnapshotInputFromView(sampleView, {
|
|
49
|
+
entityModule: "products",
|
|
50
|
+
entityId: "prod_xyz",
|
|
51
|
+
sourceKind: "owned",
|
|
52
|
+
});
|
|
53
|
+
expect(input.entityModule).toBe("products");
|
|
54
|
+
expect(input.entityId).toBe("prod_xyz");
|
|
55
|
+
expect(input.sourceKind).toBe("owned");
|
|
56
|
+
expect(input.frozenPayload).toEqual({
|
|
57
|
+
title: "Resolved title",
|
|
58
|
+
description: "Resolved description",
|
|
59
|
+
status: "active",
|
|
60
|
+
});
|
|
61
|
+
expect(input.overlayStateAtCapture).toEqual({
|
|
62
|
+
title: { locale: "en-GB", audience: "customer", market: "default" },
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
it("passes through pricingBasis when supplied", () => {
|
|
66
|
+
const input = buildSnapshotInputFromView(sampleView, {
|
|
67
|
+
entityModule: "products",
|
|
68
|
+
entityId: "prod_xyz",
|
|
69
|
+
sourceKind: "owned",
|
|
70
|
+
pricingBasis: {
|
|
71
|
+
base_amount: 1000,
|
|
72
|
+
taxes: 100,
|
|
73
|
+
fees: 50,
|
|
74
|
+
surcharges: 0,
|
|
75
|
+
currency: "EUR",
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
expect(input.pricingBasis?.base_amount).toBe(1000);
|
|
79
|
+
expect(input.pricingBasis?.currency).toBe("EUR");
|
|
80
|
+
});
|
|
81
|
+
it("forwards source connection identifiers when provided", () => {
|
|
82
|
+
const input = buildSnapshotInputFromView(sampleView, {
|
|
83
|
+
entityModule: "cruises",
|
|
84
|
+
entityId: "crse_abc",
|
|
85
|
+
sourceKind: "voyant-connect",
|
|
86
|
+
sourceConnectionId: "conn_viking",
|
|
87
|
+
sourceRef: "WAVE2026-RHN-15D",
|
|
88
|
+
});
|
|
89
|
+
expect(input.sourceKind).toBe("voyant-connect");
|
|
90
|
+
expect(input.sourceConnectionId).toBe("conn_viking");
|
|
91
|
+
expect(input.sourceRef).toBe("WAVE2026-RHN-15D");
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SnapshotService — drizzle-bound capture and read of booking snapshot
|
|
3
|
+
* graphs.
|
|
4
|
+
*
|
|
5
|
+
* One booking commit may produce multiple snapshot rows — one per
|
|
6
|
+
* participating CatalogEntry (a TUI package booking captures the package,
|
|
7
|
+
* the referenced hotel, each selected excursion, the chosen departure, the
|
|
8
|
+
* selected flight). Snapshots are immutable once written and preserved
|
|
9
|
+
* through source disconnection.
|
|
10
|
+
*
|
|
11
|
+
* Functions take an `AnyDrizzleDb` as their first parameter to match the
|
|
12
|
+
* existing voyant convention.
|
|
13
|
+
*
|
|
14
|
+
* See `docs/architecture/catalog-architecture.md` §5.3 for the design.
|
|
15
|
+
*/
|
|
16
|
+
import type { CaptureSnapshotInput } from "@voyant-travel/catalog-contracts/snapshot";
|
|
17
|
+
import type { AnyDrizzleDb } from "@voyant-travel/db";
|
|
18
|
+
import type { ResolvedView } from "../overlay/resolver.js";
|
|
19
|
+
import { type PricingBasis, type SelectBookingCatalogSnapshot } from "../snapshot/schema.js";
|
|
20
|
+
export type { CaptureSnapshotInput };
|
|
21
|
+
/**
|
|
22
|
+
* Capture a single booking-catalog-snapshot row. Idempotent on
|
|
23
|
+
* `(booking_id, entity_module, entity_id)` — re-capturing the same entity
|
|
24
|
+
* inside the same booking is a logic bug; this function lets the unique
|
|
25
|
+
* constraint catch it rather than silently overwriting.
|
|
26
|
+
*/
|
|
27
|
+
export declare function captureSnapshot(db: AnyDrizzleDb, input: CaptureSnapshotInput): Promise<SelectBookingCatalogSnapshot>;
|
|
28
|
+
/**
|
|
29
|
+
* Capture multiple snapshot rows for a single booking in one transaction.
|
|
30
|
+
* Used by the booking-commit pipeline when a booking participates with
|
|
31
|
+
* multiple CatalogEntries (composite packages, cruises with selected
|
|
32
|
+
* cabins, flights with passengers).
|
|
33
|
+
*
|
|
34
|
+
* If any single capture fails, the whole transaction rolls back — the
|
|
35
|
+
* booking's snapshot graph is all-or-nothing.
|
|
36
|
+
*/
|
|
37
|
+
export declare function captureSnapshotGraph(db: AnyDrizzleDb, bookingId: string, inputs: ReadonlyArray<Omit<CaptureSnapshotInput, "bookingId">>): Promise<SelectBookingCatalogSnapshot[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Fetch all snapshot rows for a single booking. Returns the full snapshot
|
|
40
|
+
* graph — one row per participating CatalogEntry. Used by refunds, audits,
|
|
41
|
+
* post-book operations.
|
|
42
|
+
*/
|
|
43
|
+
export declare function fetchSnapshotsForBooking(db: AnyDrizzleDb, bookingId: string): Promise<SelectBookingCatalogSnapshot[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Fetch a specific entity's snapshot for a booking. Returns `null` if no
|
|
46
|
+
* snapshot was captured for the entity.
|
|
47
|
+
*/
|
|
48
|
+
export declare function fetchEntitySnapshot(db: AnyDrizzleDb, bookingId: string, entityModule: string, entityId: string): Promise<SelectBookingCatalogSnapshot | null>;
|
|
49
|
+
/**
|
|
50
|
+
* Converts a `ResolvedView`'s value Map into a plain object suitable for
|
|
51
|
+
* storing as the JSONB `frozen_payload`. Field paths become keys.
|
|
52
|
+
*/
|
|
53
|
+
export declare function viewToFrozenPayload(view: ResolvedView): Record<string, unknown>;
|
|
54
|
+
/**
|
|
55
|
+
* Converts a `ResolvedView`'s provenance Map into a plain object suitable
|
|
56
|
+
* for storing as the JSONB `overlay_state_at_capture`. Records which
|
|
57
|
+
* variant slice satisfied each overlayed field at capture time. Fields
|
|
58
|
+
* with `null` provenance (no overlay applied) are omitted.
|
|
59
|
+
*/
|
|
60
|
+
export declare function viewToOverlayState(view: ResolvedView): Record<string, unknown>;
|
|
61
|
+
/**
|
|
62
|
+
* Composition helper: turn a `ResolvedView` plus identity / provenance /
|
|
63
|
+
* pricing context into a `CaptureSnapshotInput` ready to pass into
|
|
64
|
+
* `captureSnapshot` or `captureSnapshotGraph`.
|
|
65
|
+
*
|
|
66
|
+
* Verticals' `buildXSnapshotInput` helpers wrap this with the vertical-
|
|
67
|
+
* specific row fetching + resolution.
|
|
68
|
+
*/
|
|
69
|
+
export declare function buildSnapshotInputFromView(view: ResolvedView, context: {
|
|
70
|
+
entityModule: string;
|
|
71
|
+
entityId: string;
|
|
72
|
+
sourceKind: string;
|
|
73
|
+
sourceProvider?: string;
|
|
74
|
+
sourceConnectionId?: string;
|
|
75
|
+
sourceRef?: string;
|
|
76
|
+
pricingBasis?: PricingBasis;
|
|
77
|
+
}): Omit<CaptureSnapshotInput, "bookingId">;
|
|
78
|
+
//# sourceMappingURL=snapshot-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-service.d.ts","sourceRoot":"","sources":["../../src/services/snapshot-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,4BAA4B,EAClC,MAAM,uBAAuB,CAAA;AAQ9B,YAAY,EAAE,oBAAoB,EAAE,CAAA;AAEpC;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,YAAY,EAChB,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,4BAA4B,CAAC,CAkCvC;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,YAAY,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC,GAC7D,OAAO,CAAC,4BAA4B,EAAE,CAAC,CA2BzC;AAMD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,EAAE,EAAE,YAAY,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,4BAA4B,EAAE,CAAC,CAMzC;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,YAAY,EAChB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAAC,CAa9C;AAMD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAM/E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAM9E;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE;IACP,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,YAAY,CAAA;CAC5B,GACA,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAYzC"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SnapshotService — drizzle-bound capture and read of booking snapshot
|
|
3
|
+
* graphs.
|
|
4
|
+
*
|
|
5
|
+
* One booking commit may produce multiple snapshot rows — one per
|
|
6
|
+
* participating CatalogEntry (a TUI package booking captures the package,
|
|
7
|
+
* the referenced hotel, each selected excursion, the chosen departure, the
|
|
8
|
+
* selected flight). Snapshots are immutable once written and preserved
|
|
9
|
+
* through source disconnection.
|
|
10
|
+
*
|
|
11
|
+
* Functions take an `AnyDrizzleDb` as their first parameter to match the
|
|
12
|
+
* existing voyant convention.
|
|
13
|
+
*
|
|
14
|
+
* See `docs/architecture/catalog-architecture.md` §5.3 for the design.
|
|
15
|
+
*/
|
|
16
|
+
import { newId } from "@voyant-travel/db/lib/typeid";
|
|
17
|
+
import { and, eq } from "drizzle-orm";
|
|
18
|
+
import { bookingCatalogSnapshotTable, } from "../snapshot/schema.js";
|
|
19
|
+
/**
|
|
20
|
+
* Capture a single booking-catalog-snapshot row. Idempotent on
|
|
21
|
+
* `(booking_id, entity_module, entity_id)` — re-capturing the same entity
|
|
22
|
+
* inside the same booking is a logic bug; this function lets the unique
|
|
23
|
+
* constraint catch it rather than silently overwriting.
|
|
24
|
+
*/
|
|
25
|
+
export async function captureSnapshot(db, input) {
|
|
26
|
+
const inserted = await db
|
|
27
|
+
.insert(bookingCatalogSnapshotTable)
|
|
28
|
+
.values({
|
|
29
|
+
id: newId("booking_catalog_snapshot"),
|
|
30
|
+
booking_id: input.bookingId,
|
|
31
|
+
entity_module: input.entityModule,
|
|
32
|
+
entity_id: input.entityId,
|
|
33
|
+
source_kind: input.sourceKind,
|
|
34
|
+
source_provider: input.sourceProvider,
|
|
35
|
+
source_connection_id: input.sourceConnectionId,
|
|
36
|
+
source_ref: input.sourceRef,
|
|
37
|
+
frozen_payload: input.frozenPayload,
|
|
38
|
+
overlay_state_at_capture: input.overlayStateAtCapture,
|
|
39
|
+
pricing_base_amount: input.pricingBasis?.base_amount != null
|
|
40
|
+
? String(input.pricingBasis.base_amount)
|
|
41
|
+
: undefined,
|
|
42
|
+
pricing_taxes: input.pricingBasis?.taxes != null ? String(input.pricingBasis.taxes) : undefined,
|
|
43
|
+
pricing_fees: input.pricingBasis?.fees != null ? String(input.pricingBasis.fees) : undefined,
|
|
44
|
+
pricing_surcharges: input.pricingBasis?.surcharges != null ? String(input.pricingBasis.surcharges) : undefined,
|
|
45
|
+
pricing_currency: input.pricingBasis?.currency,
|
|
46
|
+
pricing_breakdown: input.pricingBasis?.breakdown,
|
|
47
|
+
pricing_applied_offers: input.pricingBasis?.appliedOffers,
|
|
48
|
+
idempotency_key: input.idempotencyKey,
|
|
49
|
+
})
|
|
50
|
+
.returning();
|
|
51
|
+
if (!inserted[0]) {
|
|
52
|
+
throw new Error("captureSnapshot: insert returned no rows");
|
|
53
|
+
}
|
|
54
|
+
return inserted[0];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Capture multiple snapshot rows for a single booking in one transaction.
|
|
58
|
+
* Used by the booking-commit pipeline when a booking participates with
|
|
59
|
+
* multiple CatalogEntries (composite packages, cruises with selected
|
|
60
|
+
* cabins, flights with passengers).
|
|
61
|
+
*
|
|
62
|
+
* If any single capture fails, the whole transaction rolls back — the
|
|
63
|
+
* booking's snapshot graph is all-or-nothing.
|
|
64
|
+
*/
|
|
65
|
+
export async function captureSnapshotGraph(db, bookingId, inputs) {
|
|
66
|
+
if (inputs.length === 0)
|
|
67
|
+
return [];
|
|
68
|
+
const rows = inputs.map((input) => ({
|
|
69
|
+
id: newId("booking_catalog_snapshot"),
|
|
70
|
+
booking_id: bookingId,
|
|
71
|
+
entity_module: input.entityModule,
|
|
72
|
+
entity_id: input.entityId,
|
|
73
|
+
source_kind: input.sourceKind,
|
|
74
|
+
source_provider: input.sourceProvider,
|
|
75
|
+
source_connection_id: input.sourceConnectionId,
|
|
76
|
+
source_ref: input.sourceRef,
|
|
77
|
+
frozen_payload: input.frozenPayload,
|
|
78
|
+
overlay_state_at_capture: input.overlayStateAtCapture,
|
|
79
|
+
pricing_base_amount: input.pricingBasis?.base_amount != null ? String(input.pricingBasis.base_amount) : undefined,
|
|
80
|
+
pricing_taxes: input.pricingBasis?.taxes != null ? String(input.pricingBasis.taxes) : undefined,
|
|
81
|
+
pricing_fees: input.pricingBasis?.fees != null ? String(input.pricingBasis.fees) : undefined,
|
|
82
|
+
pricing_surcharges: input.pricingBasis?.surcharges != null ? String(input.pricingBasis.surcharges) : undefined,
|
|
83
|
+
pricing_currency: input.pricingBasis?.currency,
|
|
84
|
+
pricing_breakdown: input.pricingBasis?.breakdown,
|
|
85
|
+
pricing_applied_offers: input.pricingBasis?.appliedOffers,
|
|
86
|
+
}));
|
|
87
|
+
const inserted = await db.insert(bookingCatalogSnapshotTable).values(rows).returning();
|
|
88
|
+
return inserted;
|
|
89
|
+
}
|
|
90
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
91
|
+
// Reads
|
|
92
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
93
|
+
/**
|
|
94
|
+
* Fetch all snapshot rows for a single booking. Returns the full snapshot
|
|
95
|
+
* graph — one row per participating CatalogEntry. Used by refunds, audits,
|
|
96
|
+
* post-book operations.
|
|
97
|
+
*/
|
|
98
|
+
export async function fetchSnapshotsForBooking(db, bookingId) {
|
|
99
|
+
const rows = await db
|
|
100
|
+
.select()
|
|
101
|
+
.from(bookingCatalogSnapshotTable)
|
|
102
|
+
.where(eq(bookingCatalogSnapshotTable.booking_id, bookingId));
|
|
103
|
+
return rows;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Fetch a specific entity's snapshot for a booking. Returns `null` if no
|
|
107
|
+
* snapshot was captured for the entity.
|
|
108
|
+
*/
|
|
109
|
+
export async function fetchEntitySnapshot(db, bookingId, entityModule, entityId) {
|
|
110
|
+
const rows = await db
|
|
111
|
+
.select()
|
|
112
|
+
.from(bookingCatalogSnapshotTable)
|
|
113
|
+
.where(and(eq(bookingCatalogSnapshotTable.booking_id, bookingId), eq(bookingCatalogSnapshotTable.entity_module, entityModule), eq(bookingCatalogSnapshotTable.entity_id, entityId)))
|
|
114
|
+
.limit(1);
|
|
115
|
+
return (rows[0] ?? null);
|
|
116
|
+
}
|
|
117
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
118
|
+
// View → snapshot input helpers
|
|
119
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
120
|
+
/**
|
|
121
|
+
* Converts a `ResolvedView`'s value Map into a plain object suitable for
|
|
122
|
+
* storing as the JSONB `frozen_payload`. Field paths become keys.
|
|
123
|
+
*/
|
|
124
|
+
export function viewToFrozenPayload(view) {
|
|
125
|
+
const result = {};
|
|
126
|
+
for (const [path, value] of view.values) {
|
|
127
|
+
result[path] = value;
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Converts a `ResolvedView`'s provenance Map into a plain object suitable
|
|
133
|
+
* for storing as the JSONB `overlay_state_at_capture`. Records which
|
|
134
|
+
* variant slice satisfied each overlayed field at capture time. Fields
|
|
135
|
+
* with `null` provenance (no overlay applied) are omitted.
|
|
136
|
+
*/
|
|
137
|
+
export function viewToOverlayState(view) {
|
|
138
|
+
const result = {};
|
|
139
|
+
for (const [path, prov] of view.provenance) {
|
|
140
|
+
if (prov)
|
|
141
|
+
result[path] = prov;
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Composition helper: turn a `ResolvedView` plus identity / provenance /
|
|
147
|
+
* pricing context into a `CaptureSnapshotInput` ready to pass into
|
|
148
|
+
* `captureSnapshot` or `captureSnapshotGraph`.
|
|
149
|
+
*
|
|
150
|
+
* Verticals' `buildXSnapshotInput` helpers wrap this with the vertical-
|
|
151
|
+
* specific row fetching + resolution.
|
|
152
|
+
*/
|
|
153
|
+
export function buildSnapshotInputFromView(view, context) {
|
|
154
|
+
return {
|
|
155
|
+
entityModule: context.entityModule,
|
|
156
|
+
entityId: context.entityId,
|
|
157
|
+
sourceKind: context.sourceKind,
|
|
158
|
+
sourceProvider: context.sourceProvider,
|
|
159
|
+
sourceConnectionId: context.sourceConnectionId,
|
|
160
|
+
sourceRef: context.sourceRef,
|
|
161
|
+
frozenPayload: viewToFrozenPayload(view),
|
|
162
|
+
overlayStateAtCapture: viewToOverlayState(view),
|
|
163
|
+
pricingBasis: context.pricingBasis,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SourcedEntryService — drizzle-bound entry point for the
|
|
3
|
+
* `catalog_sourced_entries` store.
|
|
4
|
+
*
|
|
5
|
+
* One row per sourced entity, written at `discover()` time. The row carries
|
|
6
|
+
* provenance, lifecycle markers, and the canonical local copy of the
|
|
7
|
+
* indexed projection (so the read service and the thin-content synthesizer
|
|
8
|
+
* can dispatch without round-tripping the search index).
|
|
9
|
+
*
|
|
10
|
+
* Three primitives:
|
|
11
|
+
*
|
|
12
|
+
* - `upsertSourcedEntry` — called from `sync.ts` for every projection;
|
|
13
|
+
* idempotent on (entity_module, entity_id) and on
|
|
14
|
+
* (source_kind, source_connection_id, source_ref).
|
|
15
|
+
* - `readSourcedEntry` — point-read by Voyant-side identity. Returns
|
|
16
|
+
* null for owned entities (which have no row here).
|
|
17
|
+
* - `createReadProvenance` — factory that composes `readSourcedEntry`
|
|
18
|
+
* with vertical-specific owned-checkers to produce a unified
|
|
19
|
+
* `readProvenance(db, entity_module, entity_id)` that returns one of:
|
|
20
|
+
* `{ kind: "owned" }`, `{ kind: "sourced", ... }`, or `null`.
|
|
21
|
+
*
|
|
22
|
+
* The factory pattern keeps this package neutral — it doesn't know how to
|
|
23
|
+
* read the products / cruises / hotels owned tables. Each vertical
|
|
24
|
+
* registers its owned-checker once when wiring its content service (Phase
|
|
25
|
+
* D and beyond).
|
|
26
|
+
*
|
|
27
|
+
* See `docs/architecture/catalog-sourced-content.md` §2.5.
|
|
28
|
+
*/
|
|
29
|
+
import type { AnyDrizzleDb } from "@voyant-travel/db";
|
|
30
|
+
import type { CatalogProjection } from "../adapter/contract.js";
|
|
31
|
+
import type { Provenance } from "../provenance.js";
|
|
32
|
+
import { type SelectCatalogSourcedEntry, type SourcedEntryStatus } from "../schema-sourced-entries.js";
|
|
33
|
+
/**
|
|
34
|
+
* Result of a `readProvenance` call. Three shapes:
|
|
35
|
+
*
|
|
36
|
+
* - `{ kind: "owned" }` — entity exists in the vertical's owned
|
|
37
|
+
* table; no sourced-entry row.
|
|
38
|
+
* - `{ kind: "sourced", ... }` — entity is sourced; carries the durable
|
|
39
|
+
* provenance row + entry id.
|
|
40
|
+
* - `null` — entity not found in either store.
|
|
41
|
+
*
|
|
42
|
+
* Callers pattern-match on `kind` to dispatch owned-vs-sourced reads.
|
|
43
|
+
*/
|
|
44
|
+
export type ProvenanceReadResult = {
|
|
45
|
+
kind: "owned";
|
|
46
|
+
provenance: Provenance;
|
|
47
|
+
} | {
|
|
48
|
+
kind: "sourced";
|
|
49
|
+
provenance: Provenance;
|
|
50
|
+
entry_id: string;
|
|
51
|
+
status: SourcedEntryStatus;
|
|
52
|
+
projection: Record<string, unknown>;
|
|
53
|
+
projection_etag: string | null;
|
|
54
|
+
projection_seen_at: Date;
|
|
55
|
+
first_seen_at: Date;
|
|
56
|
+
last_seen_at: Date;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Vertical-specific owned-checker. Returns `true` iff the entity exists in
|
|
60
|
+
* the vertical's owned table (i.e. its id matches a row that has no source
|
|
61
|
+
* link). Implementations are tiny per-vertical helpers and live in the
|
|
62
|
+
* vertical package — the catalog plane doesn't import them directly.
|
|
63
|
+
*/
|
|
64
|
+
export type OwnedChecker = (db: AnyDrizzleDb, entityId: string) => Promise<boolean>;
|
|
65
|
+
/**
|
|
66
|
+
* Read one sourced-entry row by Voyant-side identity. Returns `null` for
|
|
67
|
+
* entities that aren't in the sourced-entry store — owned entities, or
|
|
68
|
+
* sourced entities the deployment hasn't yet discovered.
|
|
69
|
+
*/
|
|
70
|
+
export declare function readSourcedEntry(db: AnyDrizzleDb, entityModule: string, entityId: string): Promise<SelectCatalogSourcedEntry | null>;
|
|
71
|
+
/**
|
|
72
|
+
* Build a unified `readProvenance(db, entity_module, entity_id)` against a
|
|
73
|
+
* registry of vertical-specific owned-checkers. The returned function:
|
|
74
|
+
*
|
|
75
|
+
* 1. Calls the vertical's owned-checker. If it returns `true`, the entity
|
|
76
|
+
* is owned — return `{ kind: "owned", provenance: ... }` without
|
|
77
|
+
* touching the sourced-entry table.
|
|
78
|
+
* 2. Otherwise, look up the sourced-entry row. If found, return
|
|
79
|
+
* `{ kind: "sourced", ... }`.
|
|
80
|
+
* 3. If neither, return `null`.
|
|
81
|
+
*
|
|
82
|
+
* Verticals not in `ownedCheckers` skip the owned check (treated as
|
|
83
|
+
* sourced-only). This is intentional: not every vertical has an owned
|
|
84
|
+
* counterpart for every sourced entity.
|
|
85
|
+
*/
|
|
86
|
+
export declare function createReadProvenance(options: {
|
|
87
|
+
ownedCheckers?: ReadonlyMap<string, OwnedChecker>;
|
|
88
|
+
}): (db: AnyDrizzleDb, entityModule: string, entityId: string) => Promise<ProvenanceReadResult | null>;
|
|
89
|
+
/**
|
|
90
|
+
* Input for `upsertSourcedEntry`. Accepts a `CatalogProjection` (the shape
|
|
91
|
+
* `discover()` emits) plus optional metadata the adapter chose not to put
|
|
92
|
+
* on the projection (etag, freshness override).
|
|
93
|
+
*/
|
|
94
|
+
export interface UpsertSourcedEntryInput {
|
|
95
|
+
/** The projection emitted by `adapter.discover()`. */
|
|
96
|
+
projection: CatalogProjection;
|
|
97
|
+
/**
|
|
98
|
+
* Optional ETag-style marker for the projection itself. Distinct from
|
|
99
|
+
* the content cache's etag — this one stamps the indexed projection.
|
|
100
|
+
*/
|
|
101
|
+
projectionEtag?: string;
|
|
102
|
+
/**
|
|
103
|
+
* When the upstream said this projection was last sourced. Defaults to
|
|
104
|
+
* `provenance.last_sourced_at` if set, otherwise `new Date()`.
|
|
105
|
+
*/
|
|
106
|
+
lastSourcedAt?: Date;
|
|
107
|
+
/**
|
|
108
|
+
* Optional override for the lifecycle status. Withdrawal sweepers set
|
|
109
|
+
* this to `"withdrawn"` for rows the upstream stopped emitting.
|
|
110
|
+
*/
|
|
111
|
+
status?: SourcedEntryStatus;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Upsert a sourced-entry row. Idempotent on `(entity_module, entity_id)`
|
|
115
|
+
* — repeated calls update `projection`, `projection_etag`,
|
|
116
|
+
* `projection_seen_at`, `last_seen_at`, `last_sourced_at`,
|
|
117
|
+
* `source_freshness`, and `updated_at`. The first-seen timestamp is
|
|
118
|
+
* preserved.
|
|
119
|
+
*
|
|
120
|
+
* Owned projections are rejected — `provenance.source_kind === "owned"`
|
|
121
|
+
* has no place in the sourced-entry store. Callers in `sync.ts` should
|
|
122
|
+
* already filter these out, but this guard makes the invariant explicit.
|
|
123
|
+
*/
|
|
124
|
+
export declare function upsertSourcedEntry(db: AnyDrizzleDb, input: UpsertSourcedEntryInput): Promise<SelectCatalogSourcedEntry>;
|
|
125
|
+
/**
|
|
126
|
+
* Mark a sourced-entry row as withdrawn (the upstream stopped emitting
|
|
127
|
+
* it). Used by the periodic withdrawal sweeper or by drift events of kind
|
|
128
|
+
* `entity_archived`. Does not delete the row — withdrawals are auditable.
|
|
129
|
+
*/
|
|
130
|
+
export declare function markSourcedEntryWithdrawn(db: AnyDrizzleDb, entityModule: string, entityId: string): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Mark active sourced rows missing from a successful full-source discovery pass
|
|
133
|
+
* as withdrawn. Callers should invoke this only after an adapter completed its
|
|
134
|
+
* projection stream; failed refreshes must leave existing rows untouched.
|
|
135
|
+
*/
|
|
136
|
+
export declare function markMissingSourcedEntriesWithdrawn(db: AnyDrizzleDb, input: {
|
|
137
|
+
entityModule: string;
|
|
138
|
+
sourceKind: string;
|
|
139
|
+
sourceConnectionId?: string | null;
|
|
140
|
+
seenEntityIds: ReadonlySet<string>;
|
|
141
|
+
}): Promise<SelectCatalogSourcedEntry[]>;
|
|
142
|
+
//# sourceMappingURL=sourced-entry-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sourced-entry-service.d.ts","sourceRoot":"","sources":["../../src/services/sourced-entry-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,kBAAkB,CAAA;AAC9D,OAAO,EAEL,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACxB,MAAM,8BAA8B,CAAA;AAMrC;;;;;;;;;;GAUG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,GACzC;IACE,IAAI,EAAE,SAAS,CAAA;IACf,UAAU,EAAE,UAAU,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,kBAAkB,CAAA;IAC1B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACnC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,kBAAkB,EAAE,IAAI,CAAA;IACxB,aAAa,EAAE,IAAI,CAAA;IACnB,YAAY,EAAE,IAAI,CAAA;CACnB,CAAA;AAEL;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAMnF;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,YAAY,EAChB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAY3C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE;IAC5C,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;CAClD,GAAG,CACF,EAAE,EAAE,YAAY,EAChB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAyCxC;AAMD;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,sDAAsD;IACtD,UAAU,EAAE,iBAAiB,CAAA;IAC7B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,aAAa,CAAC,EAAE,IAAI,CAAA;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAA;CAC5B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,YAAY,EAChB,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,yBAAyB,CAAC,CA2DpC;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,YAAY,EAChB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;;;GAIG;AACH,wBAAsB,kCAAkC,CACtD,EAAE,EAAE,YAAY,EAChB,KAAK,EAAE;IACL,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CACnC,GACA,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAkCtC"}
|