@voyantjs/accommodations 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +11 -0
  2. package/dist/booking-engine/handler.d.ts +103 -0
  3. package/dist/booking-engine/handler.d.ts.map +1 -0
  4. package/dist/booking-engine/handler.js +254 -0
  5. package/dist/booking-engine/index.d.ts +8 -0
  6. package/dist/booking-engine/index.d.ts.map +1 -0
  7. package/dist/booking-engine/index.js +7 -0
  8. package/dist/catalog-policy.d.ts +23 -0
  9. package/dist/catalog-policy.d.ts.map +1 -0
  10. package/dist/catalog-policy.js +422 -0
  11. package/dist/content-shape.d.ts +185 -0
  12. package/dist/content-shape.d.ts.map +1 -0
  13. package/dist/content-shape.js +122 -0
  14. package/dist/draft-shape.d.ts +35 -0
  15. package/dist/draft-shape.d.ts.map +1 -0
  16. package/dist/draft-shape.js +84 -0
  17. package/dist/index.d.ts +8 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +7 -0
  20. package/dist/routes-content.d.ts +31 -0
  21. package/dist/routes-content.d.ts.map +1 -0
  22. package/dist/routes-content.js +87 -0
  23. package/dist/schema-bookings.d.ts +582 -0
  24. package/dist/schema-bookings.d.ts.map +1 -0
  25. package/dist/schema-bookings.js +65 -0
  26. package/dist/schema-inventory.d.ts +1361 -0
  27. package/dist/schema-inventory.d.ts.map +1 -0
  28. package/dist/schema-inventory.js +132 -0
  29. package/dist/schema-shared.d.ts +5 -0
  30. package/dist/schema-shared.d.ts.map +1 -0
  31. package/dist/schema-shared.js +24 -0
  32. package/dist/schema-sourced-content.d.ts +254 -0
  33. package/dist/schema-sourced-content.d.ts.map +1 -0
  34. package/dist/schema-sourced-content.js +48 -0
  35. package/dist/schema.d.ts +5 -0
  36. package/dist/schema.d.ts.map +1 -0
  37. package/dist/schema.js +4 -0
  38. package/dist/service-catalog-plane.d.ts +55 -0
  39. package/dist/service-catalog-plane.d.ts.map +1 -0
  40. package/dist/service-catalog-plane.js +202 -0
  41. package/dist/service-content-synthesizer.d.ts +43 -0
  42. package/dist/service-content-synthesizer.d.ts.map +1 -0
  43. package/dist/service-content-synthesizer.js +149 -0
  44. package/dist/service-content.d.ts +54 -0
  45. package/dist/service-content.d.ts.map +1 -0
  46. package/dist/service-content.js +480 -0
  47. package/package.json +113 -0
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Catalog-plane integration for the accommodation service.
3
+ *
4
+ * The accommodation vertical's catalog entry is the **room type** — the
5
+ * sellable variant within a property. Properties live in
6
+ * `packages/facilities` and are referenced via `propertyId`.
7
+ *
8
+ * Mirrors the pattern in `packages/products/src/service-catalog-plane.ts`.
9
+ *
10
+ * See `docs/architecture/catalog-architecture.md` §9.1.
11
+ */
12
+ import { buildIndexerDocument, buildSnapshotInputFromView, createFieldPolicyRegistry, resolveEntityView, } from "@voyantjs/catalog";
13
+ import { and, eq } from "drizzle-orm";
14
+ import { accommodationCatalogPolicy } from "./catalog-policy.js";
15
+ import { roomTypes } from "./schema-inventory.js";
16
+ import { ACCOMMODATION_CONTENT_MARKET_ANY, accommodationSourcedContentTable, } from "./schema-sourced-content.js";
17
+ let _registry;
18
+ function getAccommodationRegistry() {
19
+ if (!_registry) {
20
+ _registry = createFieldPolicyRegistry(accommodationCatalogPolicy);
21
+ }
22
+ return _registry;
23
+ }
24
+ /**
25
+ * Maps a room-type row to a field-keyed projection. Provenance covers sourced
26
+ * and direct-supplier lodging inventory; the caller declares the source kind.
27
+ */
28
+ export function roomTypeRowToProjection(row, context) {
29
+ return new Map([
30
+ // Provenance
31
+ ["source.kind", context.sourceKind ?? "direct"],
32
+ ["source.ref", context.sourceRef],
33
+ ["seller.operator_id", context.sellerOperatorId],
34
+ // Identity
35
+ ["id", row.id],
36
+ ["code", row.code],
37
+ ["createdAt", row.createdAt],
38
+ ["updatedAt", row.updatedAt],
39
+ // Cross-module reference
40
+ ["propertyId", row.propertyId],
41
+ ["supplierId", row.supplierId],
42
+ // Merchandisable
43
+ ["name", row.name],
44
+ ["description", row.description],
45
+ ["accessibilityNotes", row.accessibilityNotes],
46
+ ["thumbnailUrl", pickThumbnailUrl(row.metadata)],
47
+ // Structural / facets
48
+ ["inventoryMode", row.inventoryMode],
49
+ ["roomClass", row.roomClass],
50
+ ["active", row.active],
51
+ ["smokingAllowed", row.smokingAllowed],
52
+ ["sortOrder", row.sortOrder],
53
+ // Occupancy
54
+ ["maxAdults", row.maxAdults],
55
+ ["maxChildren", row.maxChildren],
56
+ ["maxInfants", row.maxInfants],
57
+ ["standardOccupancy", row.standardOccupancy],
58
+ ["maxOccupancy", row.maxOccupancy],
59
+ ["minOccupancy", row.minOccupancy],
60
+ // Physical
61
+ ["bedroomCount", row.bedroomCount],
62
+ ["bathroomCount", row.bathroomCount],
63
+ ["areaValue", row.areaValue],
64
+ ["areaUnit", row.areaUnit],
65
+ ]);
66
+ }
67
+ export function roomTypeProvenance(_row, context) {
68
+ return {
69
+ source_kind: context.sourceKind ?? "direct",
70
+ source_freshness: context.sourceKind && context.sourceKind !== "direct" ? "sync" : "static",
71
+ source_ref: context.sourceRef,
72
+ };
73
+ }
74
+ export async function getResolvedRoomTypeById(db, id, context) {
75
+ const rows = await db.select().from(roomTypes).where(eq(roomTypes.id, id)).limit(1);
76
+ const row = rows[0];
77
+ if (!row)
78
+ return null;
79
+ const projection = roomTypeRowToProjection(row, {
80
+ sellerOperatorId: context.sellerOperatorId,
81
+ sourceKind: context.sourceKind,
82
+ sourceRef: context.sourceRef,
83
+ });
84
+ return resolveEntityView(db, getAccommodationRegistry(), "accommodations", id, projection, context.scope);
85
+ }
86
+ export async function listResolvedRoomTypes(db, rows, context) {
87
+ const registry = getAccommodationRegistry();
88
+ const views = [];
89
+ for (const row of rows) {
90
+ const projection = roomTypeRowToProjection(row, {
91
+ sellerOperatorId: context.sellerOperatorId,
92
+ sourceKind: context.sourceKind,
93
+ sourceRef: context.sourceRef,
94
+ });
95
+ const view = await resolveEntityView(db, registry, "accommodations", row.id, projection, context.scope);
96
+ views.push(view);
97
+ }
98
+ return views;
99
+ }
100
+ /**
101
+ * Build a `CaptureSnapshotInput` for a accommodation room type. Used by
102
+ * booking commit flows to capture the room-type view at booking time.
103
+ */
104
+ export async function buildRoomTypeSnapshotInput(db, roomTypeId, context) {
105
+ const view = await getResolvedRoomTypeById(db, roomTypeId, context);
106
+ if (!view)
107
+ return null;
108
+ return buildSnapshotInputFromView(view, {
109
+ entityModule: "accommodations",
110
+ entityId: roomTypeId,
111
+ sourceKind: context.sourceKind ?? "direct",
112
+ sourceRef: context.sourceRef,
113
+ pricingBasis: context.pricingBasis,
114
+ });
115
+ }
116
+ // ─────────────────────────────────────────────────────────────────────────────
117
+ // Indexer document emission
118
+ // ─────────────────────────────────────────────────────────────────────────────
119
+ export function createRoomTypeDocumentEmitter(context) {
120
+ const registry = getAccommodationRegistry();
121
+ return {
122
+ vertical: "accommodations",
123
+ emit(source, slice) {
124
+ const projection = roomTypeRowToProjection(source, {
125
+ sellerOperatorId: context.sellerOperatorId,
126
+ sourceKind: context.sourceKind,
127
+ sourceRef: context.sourceRef,
128
+ });
129
+ return buildIndexerDocument(registry, projection, slice, source.id);
130
+ },
131
+ };
132
+ }
133
+ export function createRoomTypeDocumentBuilder(db, context) {
134
+ const registry = getAccommodationRegistry();
135
+ return async (entityId, slice) => {
136
+ const rows = await db.select().from(roomTypes).where(eq(roomTypes.id, entityId)).limit(1);
137
+ const row = rows[0];
138
+ if (!row)
139
+ return null;
140
+ const projection = new Map(roomTypeRowToProjection(row, {
141
+ sellerOperatorId: context.sellerOperatorId,
142
+ sourceKind: context.sourceKind,
143
+ sourceRef: context.sourceRef,
144
+ }));
145
+ const sourcedThumbnailUrl = await fetchSourcedContentThumbnailUrl(db, entityId, slice);
146
+ if (sourcedThumbnailUrl) {
147
+ projection.set("thumbnailUrl", sourcedThumbnailUrl);
148
+ }
149
+ return buildIndexerDocument(registry, projection, slice, entityId);
150
+ };
151
+ }
152
+ async function fetchSourcedContentThumbnailUrl(db, entityId, slice) {
153
+ const rows = await db
154
+ .select({
155
+ market: accommodationSourcedContentTable.market,
156
+ payload: accommodationSourcedContentTable.payload,
157
+ })
158
+ .from(accommodationSourcedContentTable)
159
+ .where(and(eq(accommodationSourcedContentTable.entity_id, entityId), eq(accommodationSourcedContentTable.locale, slice.locale)));
160
+ const row = rows.find((candidate) => candidate.market === slice.market) ??
161
+ rows.find((candidate) => candidate.market === ACCOMMODATION_CONTENT_MARKET_ANY) ??
162
+ rows[0];
163
+ return pickThumbnailUrl(row?.payload);
164
+ }
165
+ function pickThumbnailUrl(value) {
166
+ const record = asRecord(value);
167
+ if (!record)
168
+ return null;
169
+ return (firstString(record.thumbnailUrl, record.heroImageUrl, record.hero_image_url, record.imageUrl, record.image_url) ??
170
+ firstMediaUrl(record.media) ??
171
+ firstStringFromArray(record.images) ??
172
+ firstStringFromArray(record.galleryUrls));
173
+ }
174
+ function firstMediaUrl(value) {
175
+ if (!Array.isArray(value))
176
+ return null;
177
+ for (const item of value) {
178
+ const media = asRecord(item);
179
+ if (!media)
180
+ continue;
181
+ const type = typeof media.type === "string" ? media.type : null;
182
+ if (type && type !== "image")
183
+ continue;
184
+ const url = firstString(media.url, media.src);
185
+ if (url)
186
+ return url;
187
+ }
188
+ return null;
189
+ }
190
+ function firstStringFromArray(value) {
191
+ if (!Array.isArray(value))
192
+ return null;
193
+ return value.find((item) => typeof item === "string" && item.length > 0) ?? null;
194
+ }
195
+ function firstString(...values) {
196
+ return (values.find((value) => typeof value === "string" && value.length > 0) ?? null);
197
+ }
198
+ function asRecord(value) {
199
+ return value && typeof value === "object" && !Array.isArray(value)
200
+ ? value
201
+ : null;
202
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Accommodation content synthesizer — fallback for thin adapters that
3
+ * declare `supportsContentFetch: false`.
4
+ *
5
+ * Produces the most complete `AccommodationContent` blob we can
6
+ * legitimately synthesize from the durable sourced-entry projection +
7
+ * locale-aware overlays + plane-level provenance. Fields the
8
+ * projection doesn't carry render as typed empty states (`room_types:
9
+ * []`, `rate_plans: []`).
10
+ *
11
+ * Per §3.6: never invents plausible-but-unverified fields ("hotels
12
+ * usually have a pool" is not a basis for an amenity), never
13
+ * machine-translates, never mines snapshots, never caches its own
14
+ * output.
15
+ */
16
+ import { type ProvenanceReadResult } from "@voyantjs/catalog";
17
+ import type { AnyDrizzleDb } from "@voyantjs/db";
18
+ import { type AccommodationContent } from "./content-shape.js";
19
+ export interface SynthesizeAccommodationContentOptions {
20
+ provenance: Extract<ProvenanceReadResult, {
21
+ kind: "sourced";
22
+ }>;
23
+ overlays?: ReadonlyArray<{
24
+ field_path: string;
25
+ value: unknown;
26
+ }>;
27
+ }
28
+ export interface SynthesizedAccommodationContent {
29
+ content: AccommodationContent;
30
+ content_schema_version: string;
31
+ served_locale: string;
32
+ source_kind: string;
33
+ source_provider?: string;
34
+ }
35
+ export declare function synthesizeAccommodationContent(scope: {
36
+ locale: string;
37
+ }, options: SynthesizeAccommodationContentOptions): SynthesizedAccommodationContent;
38
+ export declare function synthesizeAccommodationContentFromDb(db: AnyDrizzleDb, scope: {
39
+ locale: string;
40
+ }, provenance: Extract<ProvenanceReadResult, {
41
+ kind: "sourced";
42
+ }>): Promise<SynthesizedAccommodationContent>;
43
+ //# sourceMappingURL=service-content-synthesizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-content-synthesizer.d.ts","sourceRoot":"","sources":["../src/service-content-synthesizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,oBAAoB,CAAA;AAE3B,MAAM,WAAW,qCAAqC;IACpD,UAAU,EAAE,OAAO,CAAC,oBAAoB,EAAE;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC,CAAA;IAC9D,QAAQ,CAAC,EAAE,aAAa,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;CACjE;AAED,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,oBAAoB,CAAA;IAC7B,sBAAsB,EAAE,MAAM,CAAA;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EACzB,OAAO,EAAE,qCAAqC,GAC7C,+BAA+B,CAmCjC;AAED,wBAAsB,oCAAoC,CACxD,EAAE,EAAE,YAAY,EAChB,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EACzB,UAAU,EAAE,OAAO,CAAC,oBAAoB,EAAE;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC,GAC7D,OAAO,CAAC,+BAA+B,CAAC,CAO1C"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Accommodation content synthesizer — fallback for thin adapters that
3
+ * declare `supportsContentFetch: false`.
4
+ *
5
+ * Produces the most complete `AccommodationContent` blob we can
6
+ * legitimately synthesize from the durable sourced-entry projection +
7
+ * locale-aware overlays + plane-level provenance. Fields the
8
+ * projection doesn't carry render as typed empty states (`room_types:
9
+ * []`, `rate_plans: []`).
10
+ *
11
+ * Per §3.6: never invents plausible-but-unverified fields ("hotels
12
+ * usually have a pool" is not a basis for an amenity), never
13
+ * machine-translates, never mines snapshots, never caches its own
14
+ * output.
15
+ */
16
+ import { fetchOverlaysForEntity, mergeOverlaysIntoContent, } from "@voyantjs/catalog";
17
+ import { ACCOMMODATION_CONTENT_SCHEMA_VERSION, accommodationContentSchema, } from "./content-shape.js";
18
+ export function synthesizeAccommodationContent(scope, options) {
19
+ const projection = options.provenance.projection;
20
+ const hotel = pickHotelSummary(projection, options.provenance);
21
+ const amenities = pickAmenities(projection);
22
+ const policies = pickPolicies(projection);
23
+ const baseContent = {
24
+ hotel,
25
+ room_types: [],
26
+ rate_plans: [],
27
+ meal_plans: [],
28
+ amenities,
29
+ policies,
30
+ };
31
+ let merged = baseContent;
32
+ if (options.overlays && options.overlays.length > 0) {
33
+ const result = mergeOverlaysIntoContent(baseContent, options.overlays, {
34
+ validate(p) {
35
+ const r = accommodationContentSchema.safeParse(p);
36
+ return r.success
37
+ ? { valid: true }
38
+ : { valid: false, reason: r.error.issues[0]?.message ?? "invalid" };
39
+ },
40
+ });
41
+ merged = accommodationContentSchema.parse(result);
42
+ }
43
+ return {
44
+ content: merged,
45
+ content_schema_version: ACCOMMODATION_CONTENT_SCHEMA_VERSION,
46
+ served_locale: scope.locale,
47
+ source_kind: options.provenance.provenance.source_kind,
48
+ source_provider: options.provenance.provenance.source_provider,
49
+ };
50
+ }
51
+ export async function synthesizeAccommodationContentFromDb(db, scope, provenance) {
52
+ const entityId = entityIdFromProvenance(provenance);
53
+ const overlays = await fetchOverlaysForEntity(db, "accommodations", entityId);
54
+ return synthesizeAccommodationContent(scope, {
55
+ provenance,
56
+ overlays: overlays.map((o) => ({ field_path: o.field_path, value: o.value })),
57
+ });
58
+ }
59
+ function entityIdFromProvenance(provenance) {
60
+ const fromProjection = provenance.projection.id;
61
+ if (typeof fromProjection === "string" && fromProjection.length > 0) {
62
+ return fromProjection;
63
+ }
64
+ return provenance.entry_id;
65
+ }
66
+ function pickHotelSummary(projection, provenance) {
67
+ return {
68
+ id: stringOr(projection.id, "") || provenance.entry_id,
69
+ name: stringOr(projection.name, "") || stringOr(projection.title, "") || "Unnamed property",
70
+ description: stringOr(projection.description, null),
71
+ star_rating: numberOr(projection.star_rating, null),
72
+ hero_image_url: stringOr(projection.hero_image_url, null),
73
+ highlights: stringArrayOr(projection.highlights, []),
74
+ brand: stringOr(projection.brand, null) ?? provenance.provenance.source_provider ?? null,
75
+ country: stringOr(projection.country, null),
76
+ city: stringOr(projection.city, null),
77
+ address: stringOr(projection.address, null),
78
+ postal_code: stringOr(projection.postal_code, null),
79
+ latitude: numberOr(projection.latitude, null),
80
+ longitude: numberOr(projection.longitude, null),
81
+ check_in_time: stringOr(projection.check_in_time, null),
82
+ check_out_time: stringOr(projection.check_out_time, null),
83
+ };
84
+ }
85
+ function pickAmenities(projection) {
86
+ // Bedbanks commonly emit a flat string array for amenities. We map
87
+ // each into the structured shape with no inferred category — that's
88
+ // genuinely unknown without a real getContent.
89
+ const list = projection.amenities;
90
+ if (!Array.isArray(list))
91
+ return [];
92
+ const out = [];
93
+ for (const item of list) {
94
+ if (typeof item === "string" && item.length > 0) {
95
+ out.push({
96
+ id: slugifyAmenityId(item),
97
+ category: null,
98
+ name: item,
99
+ description: null,
100
+ });
101
+ }
102
+ else if (item && typeof item === "object") {
103
+ const obj = item;
104
+ const name = stringOr(obj.name, null) ?? stringOr(obj.label, null);
105
+ if (!name)
106
+ continue;
107
+ out.push({
108
+ id: stringOr(obj.id, null) ?? slugifyAmenityId(name),
109
+ category: stringOr(obj.category, null),
110
+ name,
111
+ description: stringOr(obj.description, null),
112
+ is_free: typeof obj.is_free === "boolean" ? obj.is_free : undefined,
113
+ });
114
+ }
115
+ }
116
+ return out;
117
+ }
118
+ function pickPolicies(projection) {
119
+ const out = [];
120
+ const cancel = stringOr(projection.cancellation_policy, null);
121
+ if (cancel)
122
+ out.push({ kind: "cancellation", body: cancel });
123
+ const payment = stringOr(projection.payment_terms, null);
124
+ if (payment)
125
+ out.push({ kind: "payment", body: payment });
126
+ const checkin = stringOr(projection.check_in_policy, null);
127
+ if (checkin)
128
+ out.push({ kind: "check_in", body: checkin });
129
+ return out;
130
+ }
131
+ function slugifyAmenityId(value) {
132
+ return (value
133
+ .toLowerCase()
134
+ .replace(/[^a-z0-9]+/g, "_")
135
+ .replace(/^_+|_+$/g, "")
136
+ .slice(0, 64) || "amenity");
137
+ }
138
+ function stringOr(value, fallback) {
139
+ return typeof value === "string" && value.length > 0 ? value : fallback;
140
+ }
141
+ function numberOr(value, fallback) {
142
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
143
+ }
144
+ function stringArrayOr(value, fallback) {
145
+ if (!Array.isArray(value))
146
+ return fallback;
147
+ const out = value.filter((v) => typeof v === "string");
148
+ return out.length > 0 ? out : fallback;
149
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Accommodation content service — `getAccommodationContent` with locale-
3
+ * resolved cache reads, SWR refresh, and synthesizer fallback.
4
+ *
5
+ * Mirrors `service-content.ts` in the products and cruises packages
6
+ * but accommodation-shaped. The accommodation content aggregate (§3.2 /
7
+ * §3.6) is `{ hotel, room_types[], rate_plans[], meal_plans[],
8
+ * amenities[], policies[] }` — one payload returned by a single
9
+ * getContent. Pricing stays out (volatile-live, flows through
10
+ * `liveResolve`); rate plans here are the structural plan definitions,
11
+ * not their per-night rates.
12
+ */
13
+ import { type ContentLocaleMatchKind, type ContentLocaleResolution, type InvalidateOnDrift, type SourceAdapter, type SourceAdapterContext } from "@voyantjs/catalog";
14
+ import type { SourceAdapterRegistry } from "@voyantjs/catalog/booking-engine";
15
+ import type { AnyDrizzleDb } from "@voyantjs/db";
16
+ import { type AccommodationContent } from "./content-shape.js";
17
+ export interface AccommodationContentScope {
18
+ preferredLocales: ReadonlyArray<string>;
19
+ market?: string;
20
+ currency?: string;
21
+ acceptMachineTranslated?: boolean;
22
+ }
23
+ export interface GetAccommodationContentOptions {
24
+ registry: SourceAdapterRegistry;
25
+ buildAdapterContext?: (adapter: SourceAdapter) => SourceAdapterContext;
26
+ onOverlayError?: (event: {
27
+ field_path: string;
28
+ reason: string;
29
+ }) => void;
30
+ }
31
+ export interface ResolvedAccommodationContent {
32
+ content: AccommodationContent;
33
+ resolution: ContentLocaleResolution<{
34
+ locale: string;
35
+ payload: AccommodationContent;
36
+ }>;
37
+ source: "sourced-cache" | "sourced-fresh" | "synthesized" | "owned";
38
+ served_stale: boolean;
39
+ synthesized: boolean;
40
+ machine_translated: boolean;
41
+ }
42
+ export interface BuildOwnedAccommodationContentOptions {
43
+ preferredLocales: ReadonlyArray<string>;
44
+ }
45
+ export interface BuildOwnedAccommodationContentResult {
46
+ content: AccommodationContent;
47
+ servedLocale: string;
48
+ matchKind: ContentLocaleMatchKind;
49
+ }
50
+ export declare function getAccommodationContent(db: AnyDrizzleDb, entityId: string, scope: AccommodationContentScope, options: GetAccommodationContentOptions): Promise<ResolvedAccommodationContent | null>;
51
+ export declare function buildOwnedAccommodationContent(db: AnyDrizzleDb, entityId: string, options: BuildOwnedAccommodationContentOptions): Promise<BuildOwnedAccommodationContentResult | null>;
52
+ /** Drift event consumer for the accommodation content cache. Per §3.4.1. */
53
+ export declare const invalidateAccommodationContentOnDrift: InvalidateOnDrift;
54
+ //# sourceMappingURL=service-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-content.d.ts","sourceRoot":"","sources":["../src/service-content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAK5B,KAAK,iBAAiB,EAKtB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EAE1B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAA;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAShD,OAAO,EAEL,KAAK,oBAAoB,EAI1B,MAAM,oBAAoB,CAAA;AAyB3B,MAAM,WAAW,yBAAyB;IACxC,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAClC;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,oBAAoB,CAAA;IACtE,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACzE;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,oBAAoB,CAAA;IAC7B,UAAU,EAAE,uBAAuB,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,oBAAoB,CAAA;KAAE,CAAC,CAAA;IACtF,MAAM,EAAE,eAAe,GAAG,eAAe,GAAG,aAAa,GAAG,OAAO,CAAA;IACnE,YAAY,EAAE,OAAO,CAAA;IACrB,WAAW,EAAE,OAAO,CAAA;IACpB,kBAAkB,EAAE,OAAO,CAAA;CAC5B;AAED,MAAM,WAAW,qCAAqC;IACpD,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACxC;AAED,MAAM,WAAW,oCAAoC;IACnD,OAAO,EAAE,oBAAoB,CAAA;IAC7B,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,sBAAsB,CAAA;CAClC;AAED,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,YAAY,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,yBAAyB,EAChC,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAAC,CAyH9C;AAED,wBAAsB,8BAA8B,CAClD,EAAE,EAAE,YAAY,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,qCAAqC,GAC7C,OAAO,CAAC,oCAAoC,GAAG,IAAI,CAAC,CAsItD;AAwTD,4EAA4E;AAC5E,eAAO,MAAM,qCAAqC,EAAE,iBAGnD,CAAA"}