@voyant-travel/cruises 0.118.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +50 -0
- package/dist/adapters/connect-compat.d.ts +20 -0
- package/dist/adapters/connect-compat.d.ts.map +1 -0
- package/dist/adapters/connect-compat.js +71 -0
- package/dist/adapters/contract-fixture.d.ts +32 -0
- package/dist/adapters/contract-fixture.d.ts.map +1 -0
- package/dist/adapters/contract-fixture.js +152 -0
- package/dist/adapters/index.d.ts +331 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +16 -0
- package/dist/adapters/memoize.d.ts +28 -0
- package/dist/adapters/memoize.d.ts.map +1 -0
- package/dist/adapters/memoize.js +131 -0
- package/dist/adapters/mock.d.ts +44 -0
- package/dist/adapters/mock.d.ts.map +1 -0
- package/dist/adapters/mock.js +192 -0
- package/dist/adapters/registry.d.ts +26 -0
- package/dist/adapters/registry.d.ts.map +1 -0
- package/dist/adapters/registry.js +42 -0
- package/dist/adapters/source-adapter-shim.d.ts +80 -0
- package/dist/adapters/source-adapter-shim.d.ts.map +1 -0
- package/dist/adapters/source-adapter-shim.js +390 -0
- package/dist/booking-engine/handler.d.ts +108 -0
- package/dist/booking-engine/handler.d.ts.map +1 -0
- package/dist/booking-engine/handler.js +225 -0
- package/dist/booking-engine/index.d.ts +9 -0
- package/dist/booking-engine/index.d.ts.map +1 -0
- package/dist/booking-engine/index.js +8 -0
- package/dist/booking-extension.d.ts +1179 -0
- package/dist/booking-extension.d.ts.map +1 -0
- package/dist/booking-extension.js +342 -0
- package/dist/cabin-features.d.ts +8 -0
- package/dist/cabin-features.d.ts.map +1 -0
- package/dist/cabin-features.js +7 -0
- package/dist/catalog-policy-cabins.d.ts +18 -0
- package/dist/catalog-policy-cabins.d.ts.map +1 -0
- package/dist/catalog-policy-cabins.js +96 -0
- package/dist/catalog-policy-core.d.ts +3 -0
- package/dist/catalog-policy-core.d.ts.map +1 -0
- package/dist/catalog-policy-core.js +247 -0
- package/dist/catalog-policy-structure.d.ts +3 -0
- package/dist/catalog-policy-structure.d.ts.map +1 -0
- package/dist/catalog-policy-structure.js +387 -0
- package/dist/catalog-policy.d.ts +15 -0
- package/dist/catalog-policy.d.ts.map +1 -0
- package/dist/catalog-policy.js +19 -0
- package/dist/content-shape.d.ts +5 -0
- package/dist/content-shape.d.ts.map +1 -0
- package/dist/content-shape.js +13 -0
- package/dist/draft-shape.d.ts +59 -0
- package/dist/draft-shape.d.ts.map +1 -0
- package/dist/draft-shape.js +98 -0
- package/dist/events.d.ts +21 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +21 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -0
- package/dist/lib/key.d.ts +41 -0
- package/dist/lib/key.d.ts.map +1 -0
- package/dist/lib/key.js +100 -0
- package/dist/routes-booking-payloads.d.ts +133 -0
- package/dist/routes-booking-payloads.d.ts.map +1 -0
- package/dist/routes-booking-payloads.js +142 -0
- package/dist/routes-content.d.ts +53 -0
- package/dist/routes-content.d.ts.map +1 -0
- package/dist/routes-content.js +158 -0
- package/dist/routes-core.d.ts +4 -0
- package/dist/routes-core.d.ts.map +1 -0
- package/dist/routes-core.js +68 -0
- package/dist/routes-detail.d.ts +4 -0
- package/dist/routes-detail.d.ts.map +1 -0
- package/dist/routes-detail.js +261 -0
- package/dist/routes-env.d.ts +13 -0
- package/dist/routes-env.d.ts.map +1 -0
- package/dist/routes-env.js +1 -0
- package/dist/routes-keying.d.ts +28 -0
- package/dist/routes-keying.d.ts.map +1 -0
- package/dist/routes-keying.js +70 -0
- package/dist/routes-public.d.ts +911 -0
- package/dist/routes-public.d.ts.map +1 -0
- package/dist/routes-public.js +252 -0
- package/dist/routes-sailings-prices.d.ts +4 -0
- package/dist/routes-sailings-prices.d.ts.map +1 -0
- package/dist/routes-sailings-prices.js +278 -0
- package/dist/routes-search-index.d.ts +4 -0
- package/dist/routes-search-index.d.ts.map +1 -0
- package/dist/routes-search-index.js +25 -0
- package/dist/routes-ships.d.ts +4 -0
- package/dist/routes-ships.d.ts.map +1 -0
- package/dist/routes-ships.js +147 -0
- package/dist/routes-voyage-groups.d.ts +4 -0
- package/dist/routes-voyage-groups.d.ts.map +1 -0
- package/dist/routes-voyage-groups.js +85 -0
- package/dist/routes.d.ts +5 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +14 -0
- package/dist/schema-cabins.d.ts +1098 -0
- package/dist/schema-cabins.d.ts.map +1 -0
- package/dist/schema-cabins.js +105 -0
- package/dist/schema-content.d.ts +577 -0
- package/dist/schema-content.d.ts.map +1 -0
- package/dist/schema-content.js +63 -0
- package/dist/schema-core.d.ts +1790 -0
- package/dist/schema-core.d.ts.map +1 -0
- package/dist/schema-core.js +171 -0
- package/dist/schema-itinerary.d.ts +556 -0
- package/dist/schema-itinerary.d.ts.map +1 -0
- package/dist/schema-itinerary.js +50 -0
- package/dist/schema-pricing.d.ts +633 -0
- package/dist/schema-pricing.d.ts.map +1 -0
- package/dist/schema-pricing.js +73 -0
- package/dist/schema-search.d.ts +611 -0
- package/dist/schema-search.d.ts.map +1 -0
- package/dist/schema-search.js +64 -0
- package/dist/schema-shared.d.ts +23 -0
- package/dist/schema-shared.d.ts.map +1 -0
- package/dist/schema-shared.js +107 -0
- package/dist/schema-sourced-content.d.ts +247 -0
- package/dist/schema-sourced-content.d.ts.map +1 -0
- package/dist/schema-sourced-content.js +38 -0
- package/dist/schema.d.ts +10 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +9 -0
- package/dist/service-booking-helpers.d.ts +12 -0
- package/dist/service-booking-helpers.d.ts.map +1 -0
- package/dist/service-booking-helpers.js +94 -0
- package/dist/service-booking-types.d.ts +101 -0
- package/dist/service-booking-types.d.ts.map +1 -0
- package/dist/service-booking-types.js +1 -0
- package/dist/service-bookings.d.ts +46 -0
- package/dist/service-bookings.d.ts.map +1 -0
- package/dist/service-bookings.js +420 -0
- package/dist/service-catalog-plane-cabins.d.ts +24 -0
- package/dist/service-catalog-plane-cabins.d.ts.map +1 -0
- package/dist/service-catalog-plane-cabins.js +90 -0
- package/dist/service-catalog-plane.d.ts +74 -0
- package/dist/service-catalog-plane.d.ts.map +1 -0
- package/dist/service-catalog-plane.js +194 -0
- package/dist/service-content-synthesizer.d.ts +42 -0
- package/dist/service-content-synthesizer.d.ts.map +1 -0
- package/dist/service-content-synthesizer.js +144 -0
- package/dist/service-content.d.ts +74 -0
- package/dist/service-content.d.ts.map +1 -0
- package/dist/service-content.js +315 -0
- package/dist/service-core.d.ts +134 -0
- package/dist/service-core.d.ts.map +1 -0
- package/dist/service-core.js +257 -0
- package/dist/service-detach.d.ts +18 -0
- package/dist/service-detach.d.ts.map +1 -0
- package/dist/service-detach.js +199 -0
- package/dist/service-enrichment.d.ts +11 -0
- package/dist/service-enrichment.d.ts.map +1 -0
- package/dist/service-enrichment.js +47 -0
- package/dist/service-external-refresh.d.ts +39 -0
- package/dist/service-external-refresh.d.ts.map +1 -0
- package/dist/service-external-refresh.js +47 -0
- package/dist/service-itinerary.d.ts +22 -0
- package/dist/service-itinerary.d.ts.map +1 -0
- package/dist/service-itinerary.js +34 -0
- package/dist/service-prices.d.ts +46 -0
- package/dist/service-prices.d.ts.map +1 -0
- package/dist/service-prices.js +89 -0
- package/dist/service-pricing.d.ts +97 -0
- package/dist/service-pricing.d.ts.map +1 -0
- package/dist/service-pricing.js +198 -0
- package/dist/service-sailings.d.ts +48 -0
- package/dist/service-sailings.d.ts.map +1 -0
- package/dist/service-sailings.js +145 -0
- package/dist/service-search-types.d.ts +54 -0
- package/dist/service-search-types.d.ts.map +1 -0
- package/dist/service-search-types.js +1 -0
- package/dist/service-search.d.ts +65 -0
- package/dist/service-search.d.ts.map +1 -0
- package/dist/service-search.js +467 -0
- package/dist/service-shared.d.ts +22 -0
- package/dist/service-shared.d.ts.map +1 -0
- package/dist/service-shared.js +22 -0
- package/dist/service-ships.d.ts +47 -0
- package/dist/service-ships.d.ts.map +1 -0
- package/dist/service-ships.js +156 -0
- package/dist/service.d.ts +255 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +12 -0
- package/dist/validation-cabins.d.ts +267 -0
- package/dist/validation-cabins.d.ts.map +1 -0
- package/dist/validation-cabins.js +77 -0
- package/dist/validation-content.d.ts +123 -0
- package/dist/validation-content.d.ts.map +1 -0
- package/dist/validation-content.js +40 -0
- package/dist/validation-core.d.ts +393 -0
- package/dist/validation-core.d.ts.map +1 -0
- package/dist/validation-core.js +162 -0
- package/dist/validation-itinerary.d.ts +123 -0
- package/dist/validation-itinerary.d.ts.map +1 -0
- package/dist/validation-itinerary.js +47 -0
- package/dist/validation-pricing.d.ts +137 -0
- package/dist/validation-pricing.d.ts.map +1 -0
- package/dist/validation-pricing.js +49 -0
- package/dist/validation-search.d.ts +118 -0
- package/dist/validation-search.d.ts.map +1 -0
- package/dist/validation-search.js +60 -0
- package/dist/validation-shared.d.ts +123 -0
- package/dist/validation-shared.d.ts.map +1 -0
- package/dist/validation-shared.js +103 -0
- package/dist/validation.d.ts +8 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +7 -0
- package/package.json +146 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { typeId, typeIdRef } from "@voyant-travel/db/lib/typeid-column";
|
|
2
|
+
import { sql } from "drizzle-orm";
|
|
3
|
+
import { char, date, index, integer, jsonb, pgTable, text, timestamp, uniqueIndex, } from "drizzle-orm/pg-core";
|
|
4
|
+
import { cruises } from "./schema-core.js";
|
|
5
|
+
import { cruiseSourceEnum, cruiseTypeEnum } from "./schema-shared.js";
|
|
6
|
+
export const cruiseSearchIndex = pgTable("cruise_search_index", {
|
|
7
|
+
id: typeId("cruise_search_index"),
|
|
8
|
+
source: cruiseSourceEnum("source").notNull(),
|
|
9
|
+
sourceProvider: text("source_provider"),
|
|
10
|
+
sourceRef: jsonb("source_ref").$type(),
|
|
11
|
+
localCruiseId: typeIdRef("local_cruise_id").references(() => cruises.id, {
|
|
12
|
+
onDelete: "cascade",
|
|
13
|
+
}),
|
|
14
|
+
slug: text("slug").notNull(),
|
|
15
|
+
name: text("name").notNull(),
|
|
16
|
+
cruiseType: cruiseTypeEnum("cruise_type").notNull(),
|
|
17
|
+
lineName: text("line_name").notNull(),
|
|
18
|
+
shipName: text("ship_name").notNull(),
|
|
19
|
+
nights: integer("nights").notNull(),
|
|
20
|
+
embarkPortName: text("embark_port_name"),
|
|
21
|
+
embarkPortCanonicalPlaceId: text("embark_port_canonical_place_id"),
|
|
22
|
+
disembarkPortName: text("disembark_port_name"),
|
|
23
|
+
disembarkPortCanonicalPlaceId: text("disembark_port_canonical_place_id"),
|
|
24
|
+
regionIds: jsonb("region_ids").$type().default([]),
|
|
25
|
+
waterwayIds: jsonb("waterway_ids").$type().default([]),
|
|
26
|
+
portIds: jsonb("port_ids").$type().default([]),
|
|
27
|
+
countryIso: jsonb("country_iso").$type().default([]),
|
|
28
|
+
regions: jsonb("regions").$type().default([]),
|
|
29
|
+
waterways: jsonb("waterways").$type().default([]),
|
|
30
|
+
ports: jsonb("ports").$type().default([]),
|
|
31
|
+
countries: jsonb("countries").$type().default([]),
|
|
32
|
+
themes: jsonb("themes").$type().default([]),
|
|
33
|
+
earliestDeparture: date("earliest_departure"),
|
|
34
|
+
latestDeparture: date("latest_departure"),
|
|
35
|
+
departureCount: integer("departure_count"),
|
|
36
|
+
lowestPriceCents: integer("lowest_price_cents"),
|
|
37
|
+
lowestPriceCurrency: char("lowest_price_currency", { length: 3 }),
|
|
38
|
+
salesStatus: text("sales_status"),
|
|
39
|
+
heroImageUrl: text("hero_image_url"),
|
|
40
|
+
refreshedAt: timestamp("refreshed_at", { withTimezone: true }).notNull().defaultNow(),
|
|
41
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
42
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
43
|
+
}, (table) => [
|
|
44
|
+
uniqueIndex("uidx_cruise_search_index_slug").on(table.slug),
|
|
45
|
+
index("idx_cruise_search_index_source_refreshed").on(table.source, table.refreshedAt),
|
|
46
|
+
index("idx_cruise_search_index_type_price").on(table.cruiseType, table.lowestPriceCents),
|
|
47
|
+
index("idx_cruise_search_index_earliest_departure").on(table.earliestDeparture),
|
|
48
|
+
index("idx_cruise_search_index_latest_departure").on(table.latestDeparture),
|
|
49
|
+
index("idx_cruise_search_index_embark_place").on(table.embarkPortCanonicalPlaceId),
|
|
50
|
+
index("idx_cruise_search_index_disembark_place").on(table.disembarkPortCanonicalPlaceId),
|
|
51
|
+
index("idx_cruise_search_index_region_ids_gin").using("gin", table.regionIds),
|
|
52
|
+
index("idx_cruise_search_index_waterway_ids_gin").using("gin", table.waterwayIds),
|
|
53
|
+
index("idx_cruise_search_index_port_ids_gin").using("gin", table.portIds),
|
|
54
|
+
index("idx_cruise_search_index_country_iso_gin").using("gin", table.countryIso),
|
|
55
|
+
index("idx_cruise_search_index_regions_gin").using("gin", table.regions),
|
|
56
|
+
index("idx_cruise_search_index_waterways_gin").using("gin", table.waterways),
|
|
57
|
+
index("idx_cruise_search_index_ports_gin").using("gin", table.ports),
|
|
58
|
+
index("idx_cruise_search_index_countries_gin").using("gin", table.countries),
|
|
59
|
+
index("idx_cruise_search_index_themes_gin").using("gin", table.themes),
|
|
60
|
+
uniqueIndex("uidx_cruise_search_index_external")
|
|
61
|
+
.on(table.sourceProvider, table.sourceRef)
|
|
62
|
+
// agent-quality: raw-sql reviewed -- owner: cruises; dynamic SQL interpolation uses Drizzle parameter binding or vetted SQL identifiers.
|
|
63
|
+
.where(sql `${table.source} = 'external'`),
|
|
64
|
+
]);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const cruiseTypeEnum: import("drizzle-orm/pg-core").PgEnum<["ocean", "river", "expedition", "coastal"]>;
|
|
2
|
+
export declare const cruiseStatusEnum: import("drizzle-orm/pg-core").PgEnum<["draft", "awaiting_review", "live", "archived"]>;
|
|
3
|
+
export declare const cruiseSourceEnum: import("drizzle-orm/pg-core").PgEnum<["local", "external"]>;
|
|
4
|
+
export declare const cruiseVoyageGroupKindEnum: import("drizzle-orm/pg-core").PgEnum<["combination", "grand_voyage", "world_cruise", "cruise_tour"]>;
|
|
5
|
+
export declare const cruiseVoyageSegmentKindEnum: import("drizzle-orm/pg-core").PgEnum<["cruise", "land", "hotel", "transfer", "rail", "air", "other"]>;
|
|
6
|
+
export declare const cruiseVoyageSegmentRoleEnum: import("drizzle-orm/pg-core").PgEnum<["core", "pre_extension", "post_extension"]>;
|
|
7
|
+
export declare const shipTypeEnum: import("drizzle-orm/pg-core").PgEnum<["ocean", "river", "expedition", "yacht", "sailing", "coastal"]>;
|
|
8
|
+
export declare const cabinRoomTypeEnum: import("drizzle-orm/pg-core").PgEnum<["inside", "oceanview", "balcony", "suite", "penthouse", "single"]>;
|
|
9
|
+
export declare const sailingSalesStatusEnum: import("drizzle-orm/pg-core").PgEnum<["open", "on_request", "wait_list", "sold_out", "closed"]>;
|
|
10
|
+
export declare const priceAvailabilityEnum: import("drizzle-orm/pg-core").PgEnum<["available", "limited", "on_request", "wait_list", "sold_out"]>;
|
|
11
|
+
export declare const priceFareVariantEnum: import("drizzle-orm/pg-core").PgEnum<["cruise_only", "air_inclusive"]>;
|
|
12
|
+
export declare const priceComponentKindEnum: import("drizzle-orm/pg-core").PgEnum<["gratuity", "onboard_credit", "port_charge", "tax", "ncf", "airfare", "transfer", "insurance"]>;
|
|
13
|
+
export declare const priceComponentDirectionEnum: import("drizzle-orm/pg-core").PgEnum<["addition", "inclusion", "credit"]>;
|
|
14
|
+
export declare const cruiseMediaTypeEnum: import("drizzle-orm/pg-core").PgEnum<["image", "video", "document"]>;
|
|
15
|
+
export declare const cruiseInclusionKindEnum: import("drizzle-orm/pg-core").PgEnum<["meals", "drinks", "gratuities", "transfers", "excursions", "wifi", "other"]>;
|
|
16
|
+
export declare const enrichmentProgramKindEnum: import("drizzle-orm/pg-core").PgEnum<["naturalist", "historian", "photographer", "lecturer", "expert", "other"]>;
|
|
17
|
+
/**
|
|
18
|
+
* Sailing direction. River cruises use upstream/downstream; ocean cruises
|
|
19
|
+
* typically use round_trip (return to embark port) — though many lines
|
|
20
|
+
* leave it null, which is valid.
|
|
21
|
+
*/
|
|
22
|
+
export declare const cruiseSailingDirectionEnum: import("drizzle-orm/pg-core").PgEnum<["upstream", "downstream", "round_trip", "one_way"]>;
|
|
23
|
+
//# sourceMappingURL=schema-shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-shared.d.ts","sourceRoot":"","sources":["../src/schema-shared.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,mFAAqE,CAAA;AAEhG,eAAO,MAAM,gBAAgB,wFAK3B,CAAA;AAEF,eAAO,MAAM,gBAAgB,6DAAiD,CAAA;AAE9E,eAAO,MAAM,yBAAyB,sGAKpC,CAAA;AAEF,eAAO,MAAM,2BAA2B,uGAQtC,CAAA;AAEF,eAAO,MAAM,2BAA2B,mFAItC,CAAA;AAEF,eAAO,MAAM,YAAY,uGAOvB,CAAA;AAEF,eAAO,MAAM,iBAAiB,0GAO5B,CAAA;AAEF,eAAO,MAAM,sBAAsB,iGAMjC,CAAA;AAEF,eAAO,MAAM,qBAAqB,uGAMhC,CAAA;AAEF,eAAO,MAAM,oBAAoB,wEAG/B,CAAA;AAEF,eAAO,MAAM,sBAAsB,uIASjC,CAAA;AAEF,eAAO,MAAM,2BAA2B,2EAItC,CAAA;AAEF,eAAO,MAAM,mBAAmB,sEAA8D,CAAA;AAE9F,eAAO,MAAM,uBAAuB,qHAQlC,CAAA;AAEF,eAAO,MAAM,yBAAyB,kHAOpC,CAAA;AAEF;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,2FAKrC,CAAA"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { pgEnum } from "drizzle-orm/pg-core";
|
|
2
|
+
export const cruiseTypeEnum = pgEnum("cruise_type", ["ocean", "river", "expedition", "coastal"]);
|
|
3
|
+
export const cruiseStatusEnum = pgEnum("cruise_status", [
|
|
4
|
+
"draft",
|
|
5
|
+
"awaiting_review",
|
|
6
|
+
"live",
|
|
7
|
+
"archived",
|
|
8
|
+
]);
|
|
9
|
+
export const cruiseSourceEnum = pgEnum("cruise_source", ["local", "external"]);
|
|
10
|
+
export const cruiseVoyageGroupKindEnum = pgEnum("cruise_voyage_group_kind", [
|
|
11
|
+
"combination",
|
|
12
|
+
"grand_voyage",
|
|
13
|
+
"world_cruise",
|
|
14
|
+
"cruise_tour",
|
|
15
|
+
]);
|
|
16
|
+
export const cruiseVoyageSegmentKindEnum = pgEnum("cruise_voyage_segment_kind", [
|
|
17
|
+
"cruise",
|
|
18
|
+
"land",
|
|
19
|
+
"hotel",
|
|
20
|
+
"transfer",
|
|
21
|
+
"rail",
|
|
22
|
+
"air",
|
|
23
|
+
"other",
|
|
24
|
+
]);
|
|
25
|
+
export const cruiseVoyageSegmentRoleEnum = pgEnum("cruise_voyage_segment_role", [
|
|
26
|
+
"core",
|
|
27
|
+
"pre_extension",
|
|
28
|
+
"post_extension",
|
|
29
|
+
]);
|
|
30
|
+
export const shipTypeEnum = pgEnum("cruise_ship_type", [
|
|
31
|
+
"ocean",
|
|
32
|
+
"river",
|
|
33
|
+
"expedition",
|
|
34
|
+
"yacht",
|
|
35
|
+
"sailing",
|
|
36
|
+
"coastal",
|
|
37
|
+
]);
|
|
38
|
+
export const cabinRoomTypeEnum = pgEnum("cruise_cabin_room_type", [
|
|
39
|
+
"inside",
|
|
40
|
+
"oceanview",
|
|
41
|
+
"balcony",
|
|
42
|
+
"suite",
|
|
43
|
+
"penthouse",
|
|
44
|
+
"single",
|
|
45
|
+
]);
|
|
46
|
+
export const sailingSalesStatusEnum = pgEnum("cruise_sailing_sales_status", [
|
|
47
|
+
"open",
|
|
48
|
+
"on_request",
|
|
49
|
+
"wait_list",
|
|
50
|
+
"sold_out",
|
|
51
|
+
"closed",
|
|
52
|
+
]);
|
|
53
|
+
export const priceAvailabilityEnum = pgEnum("cruise_price_availability", [
|
|
54
|
+
"available",
|
|
55
|
+
"limited",
|
|
56
|
+
"on_request",
|
|
57
|
+
"wait_list",
|
|
58
|
+
"sold_out",
|
|
59
|
+
]);
|
|
60
|
+
export const priceFareVariantEnum = pgEnum("cruise_price_fare_variant", [
|
|
61
|
+
"cruise_only",
|
|
62
|
+
"air_inclusive",
|
|
63
|
+
]);
|
|
64
|
+
export const priceComponentKindEnum = pgEnum("cruise_price_component_kind", [
|
|
65
|
+
"gratuity",
|
|
66
|
+
"onboard_credit",
|
|
67
|
+
"port_charge",
|
|
68
|
+
"tax",
|
|
69
|
+
"ncf",
|
|
70
|
+
"airfare",
|
|
71
|
+
"transfer",
|
|
72
|
+
"insurance",
|
|
73
|
+
]);
|
|
74
|
+
export const priceComponentDirectionEnum = pgEnum("cruise_price_component_direction", [
|
|
75
|
+
"addition",
|
|
76
|
+
"inclusion",
|
|
77
|
+
"credit",
|
|
78
|
+
]);
|
|
79
|
+
export const cruiseMediaTypeEnum = pgEnum("cruise_media_type", ["image", "video", "document"]);
|
|
80
|
+
export const cruiseInclusionKindEnum = pgEnum("cruise_inclusion_kind", [
|
|
81
|
+
"meals",
|
|
82
|
+
"drinks",
|
|
83
|
+
"gratuities",
|
|
84
|
+
"transfers",
|
|
85
|
+
"excursions",
|
|
86
|
+
"wifi",
|
|
87
|
+
"other",
|
|
88
|
+
]);
|
|
89
|
+
export const enrichmentProgramKindEnum = pgEnum("cruise_enrichment_program_kind", [
|
|
90
|
+
"naturalist",
|
|
91
|
+
"historian",
|
|
92
|
+
"photographer",
|
|
93
|
+
"lecturer",
|
|
94
|
+
"expert",
|
|
95
|
+
"other",
|
|
96
|
+
]);
|
|
97
|
+
/**
|
|
98
|
+
* Sailing direction. River cruises use upstream/downstream; ocean cruises
|
|
99
|
+
* typically use round_trip (return to embark port) — though many lines
|
|
100
|
+
* leave it null, which is valid.
|
|
101
|
+
*/
|
|
102
|
+
export const cruiseSailingDirectionEnum = pgEnum("cruise_sailing_direction", [
|
|
103
|
+
"upstream",
|
|
104
|
+
"downstream",
|
|
105
|
+
"round_trip",
|
|
106
|
+
"one_way",
|
|
107
|
+
]);
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cruises sourced-content cache. Sibling to
|
|
3
|
+
* `products_sourced_content` — same shape, different vertical.
|
|
4
|
+
*
|
|
5
|
+
* One row per sourced cruise × locale × market. Stores the rich
|
|
6
|
+
* detail-page content the upstream adapter served via `getContent`,
|
|
7
|
+
* plus the SWR metadata the read service needs.
|
|
8
|
+
*
|
|
9
|
+
* See `docs/architecture/catalog-sourced-content.md` §3.2.
|
|
10
|
+
*/
|
|
11
|
+
export type CruisesSourcedContentFetchStatus = "ok" | "stale" | "error" | "unsupported";
|
|
12
|
+
export declare const CRUISES_CONTENT_MARKET_ANY = "*";
|
|
13
|
+
export declare const cruisesSourcedContentTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
14
|
+
name: "cruises_sourced_content";
|
|
15
|
+
schema: undefined;
|
|
16
|
+
columns: {
|
|
17
|
+
entity_id: import("drizzle-orm/pg-core").PgColumn<{
|
|
18
|
+
name: "entity_id";
|
|
19
|
+
tableName: "cruises_sourced_content";
|
|
20
|
+
dataType: "string";
|
|
21
|
+
columnType: "PgText";
|
|
22
|
+
data: string;
|
|
23
|
+
driverParam: string;
|
|
24
|
+
notNull: true;
|
|
25
|
+
hasDefault: false;
|
|
26
|
+
isPrimaryKey: false;
|
|
27
|
+
isAutoincrement: false;
|
|
28
|
+
hasRuntimeDefault: false;
|
|
29
|
+
enumValues: [string, ...string[]];
|
|
30
|
+
baseColumn: never;
|
|
31
|
+
identity: undefined;
|
|
32
|
+
generated: undefined;
|
|
33
|
+
}, {}, {}>;
|
|
34
|
+
locale: import("drizzle-orm/pg-core").PgColumn<{
|
|
35
|
+
name: "locale";
|
|
36
|
+
tableName: "cruises_sourced_content";
|
|
37
|
+
dataType: "string";
|
|
38
|
+
columnType: "PgText";
|
|
39
|
+
data: string;
|
|
40
|
+
driverParam: string;
|
|
41
|
+
notNull: true;
|
|
42
|
+
hasDefault: false;
|
|
43
|
+
isPrimaryKey: false;
|
|
44
|
+
isAutoincrement: false;
|
|
45
|
+
hasRuntimeDefault: false;
|
|
46
|
+
enumValues: [string, ...string[]];
|
|
47
|
+
baseColumn: never;
|
|
48
|
+
identity: undefined;
|
|
49
|
+
generated: undefined;
|
|
50
|
+
}, {}, {}>;
|
|
51
|
+
market: import("drizzle-orm/pg-core").PgColumn<{
|
|
52
|
+
name: "market";
|
|
53
|
+
tableName: "cruises_sourced_content";
|
|
54
|
+
dataType: "string";
|
|
55
|
+
columnType: "PgText";
|
|
56
|
+
data: string;
|
|
57
|
+
driverParam: string;
|
|
58
|
+
notNull: true;
|
|
59
|
+
hasDefault: true;
|
|
60
|
+
isPrimaryKey: false;
|
|
61
|
+
isAutoincrement: false;
|
|
62
|
+
hasRuntimeDefault: false;
|
|
63
|
+
enumValues: [string, ...string[]];
|
|
64
|
+
baseColumn: never;
|
|
65
|
+
identity: undefined;
|
|
66
|
+
generated: undefined;
|
|
67
|
+
}, {}, {}>;
|
|
68
|
+
payload: import("drizzle-orm/pg-core").PgColumn<{
|
|
69
|
+
name: "payload";
|
|
70
|
+
tableName: "cruises_sourced_content";
|
|
71
|
+
dataType: "json";
|
|
72
|
+
columnType: "PgJsonb";
|
|
73
|
+
data: Record<string, unknown>;
|
|
74
|
+
driverParam: unknown;
|
|
75
|
+
notNull: true;
|
|
76
|
+
hasDefault: false;
|
|
77
|
+
isPrimaryKey: false;
|
|
78
|
+
isAutoincrement: false;
|
|
79
|
+
hasRuntimeDefault: false;
|
|
80
|
+
enumValues: undefined;
|
|
81
|
+
baseColumn: never;
|
|
82
|
+
identity: undefined;
|
|
83
|
+
generated: undefined;
|
|
84
|
+
}, {}, {
|
|
85
|
+
$type: Record<string, unknown>;
|
|
86
|
+
}>;
|
|
87
|
+
content_schema_version: import("drizzle-orm/pg-core").PgColumn<{
|
|
88
|
+
name: "content_schema_version";
|
|
89
|
+
tableName: "cruises_sourced_content";
|
|
90
|
+
dataType: "string";
|
|
91
|
+
columnType: "PgText";
|
|
92
|
+
data: string;
|
|
93
|
+
driverParam: string;
|
|
94
|
+
notNull: true;
|
|
95
|
+
hasDefault: false;
|
|
96
|
+
isPrimaryKey: false;
|
|
97
|
+
isAutoincrement: false;
|
|
98
|
+
hasRuntimeDefault: false;
|
|
99
|
+
enumValues: [string, ...string[]];
|
|
100
|
+
baseColumn: never;
|
|
101
|
+
identity: undefined;
|
|
102
|
+
generated: undefined;
|
|
103
|
+
}, {}, {}>;
|
|
104
|
+
returned_locale: import("drizzle-orm/pg-core").PgColumn<{
|
|
105
|
+
name: "returned_locale";
|
|
106
|
+
tableName: "cruises_sourced_content";
|
|
107
|
+
dataType: "string";
|
|
108
|
+
columnType: "PgText";
|
|
109
|
+
data: string;
|
|
110
|
+
driverParam: string;
|
|
111
|
+
notNull: true;
|
|
112
|
+
hasDefault: false;
|
|
113
|
+
isPrimaryKey: false;
|
|
114
|
+
isAutoincrement: false;
|
|
115
|
+
hasRuntimeDefault: false;
|
|
116
|
+
enumValues: [string, ...string[]];
|
|
117
|
+
baseColumn: never;
|
|
118
|
+
identity: undefined;
|
|
119
|
+
generated: undefined;
|
|
120
|
+
}, {}, {}>;
|
|
121
|
+
machine_translated: import("drizzle-orm/pg-core").PgColumn<{
|
|
122
|
+
name: "machine_translated";
|
|
123
|
+
tableName: "cruises_sourced_content";
|
|
124
|
+
dataType: "boolean";
|
|
125
|
+
columnType: "PgBoolean";
|
|
126
|
+
data: boolean;
|
|
127
|
+
driverParam: boolean;
|
|
128
|
+
notNull: true;
|
|
129
|
+
hasDefault: true;
|
|
130
|
+
isPrimaryKey: false;
|
|
131
|
+
isAutoincrement: false;
|
|
132
|
+
hasRuntimeDefault: false;
|
|
133
|
+
enumValues: undefined;
|
|
134
|
+
baseColumn: never;
|
|
135
|
+
identity: undefined;
|
|
136
|
+
generated: undefined;
|
|
137
|
+
}, {}, {}>;
|
|
138
|
+
source_updated_at: import("drizzle-orm/pg-core").PgColumn<{
|
|
139
|
+
name: "source_updated_at";
|
|
140
|
+
tableName: "cruises_sourced_content";
|
|
141
|
+
dataType: "date";
|
|
142
|
+
columnType: "PgTimestamp";
|
|
143
|
+
data: Date;
|
|
144
|
+
driverParam: string;
|
|
145
|
+
notNull: false;
|
|
146
|
+
hasDefault: false;
|
|
147
|
+
isPrimaryKey: false;
|
|
148
|
+
isAutoincrement: false;
|
|
149
|
+
hasRuntimeDefault: false;
|
|
150
|
+
enumValues: undefined;
|
|
151
|
+
baseColumn: never;
|
|
152
|
+
identity: undefined;
|
|
153
|
+
generated: undefined;
|
|
154
|
+
}, {}, {}>;
|
|
155
|
+
fetched_at: import("drizzle-orm/pg-core").PgColumn<{
|
|
156
|
+
name: "fetched_at";
|
|
157
|
+
tableName: "cruises_sourced_content";
|
|
158
|
+
dataType: "date";
|
|
159
|
+
columnType: "PgTimestamp";
|
|
160
|
+
data: Date;
|
|
161
|
+
driverParam: string;
|
|
162
|
+
notNull: true;
|
|
163
|
+
hasDefault: true;
|
|
164
|
+
isPrimaryKey: false;
|
|
165
|
+
isAutoincrement: false;
|
|
166
|
+
hasRuntimeDefault: false;
|
|
167
|
+
enumValues: undefined;
|
|
168
|
+
baseColumn: never;
|
|
169
|
+
identity: undefined;
|
|
170
|
+
generated: undefined;
|
|
171
|
+
}, {}, {}>;
|
|
172
|
+
fresh_until: import("drizzle-orm/pg-core").PgColumn<{
|
|
173
|
+
name: "fresh_until";
|
|
174
|
+
tableName: "cruises_sourced_content";
|
|
175
|
+
dataType: "date";
|
|
176
|
+
columnType: "PgTimestamp";
|
|
177
|
+
data: Date;
|
|
178
|
+
driverParam: string;
|
|
179
|
+
notNull: false;
|
|
180
|
+
hasDefault: false;
|
|
181
|
+
isPrimaryKey: false;
|
|
182
|
+
isAutoincrement: false;
|
|
183
|
+
hasRuntimeDefault: false;
|
|
184
|
+
enumValues: undefined;
|
|
185
|
+
baseColumn: never;
|
|
186
|
+
identity: undefined;
|
|
187
|
+
generated: undefined;
|
|
188
|
+
}, {}, {}>;
|
|
189
|
+
etag: import("drizzle-orm/pg-core").PgColumn<{
|
|
190
|
+
name: "etag";
|
|
191
|
+
tableName: "cruises_sourced_content";
|
|
192
|
+
dataType: "string";
|
|
193
|
+
columnType: "PgText";
|
|
194
|
+
data: string;
|
|
195
|
+
driverParam: string;
|
|
196
|
+
notNull: false;
|
|
197
|
+
hasDefault: false;
|
|
198
|
+
isPrimaryKey: false;
|
|
199
|
+
isAutoincrement: false;
|
|
200
|
+
hasRuntimeDefault: false;
|
|
201
|
+
enumValues: [string, ...string[]];
|
|
202
|
+
baseColumn: never;
|
|
203
|
+
identity: undefined;
|
|
204
|
+
generated: undefined;
|
|
205
|
+
}, {}, {}>;
|
|
206
|
+
fetch_status: import("drizzle-orm/pg-core").PgColumn<{
|
|
207
|
+
name: "fetch_status";
|
|
208
|
+
tableName: "cruises_sourced_content";
|
|
209
|
+
dataType: "string";
|
|
210
|
+
columnType: "PgText";
|
|
211
|
+
data: CruisesSourcedContentFetchStatus;
|
|
212
|
+
driverParam: string;
|
|
213
|
+
notNull: true;
|
|
214
|
+
hasDefault: true;
|
|
215
|
+
isPrimaryKey: false;
|
|
216
|
+
isAutoincrement: false;
|
|
217
|
+
hasRuntimeDefault: false;
|
|
218
|
+
enumValues: [string, ...string[]];
|
|
219
|
+
baseColumn: never;
|
|
220
|
+
identity: undefined;
|
|
221
|
+
generated: undefined;
|
|
222
|
+
}, {}, {
|
|
223
|
+
$type: CruisesSourcedContentFetchStatus;
|
|
224
|
+
}>;
|
|
225
|
+
fetch_error: import("drizzle-orm/pg-core").PgColumn<{
|
|
226
|
+
name: "fetch_error";
|
|
227
|
+
tableName: "cruises_sourced_content";
|
|
228
|
+
dataType: "string";
|
|
229
|
+
columnType: "PgText";
|
|
230
|
+
data: string;
|
|
231
|
+
driverParam: string;
|
|
232
|
+
notNull: false;
|
|
233
|
+
hasDefault: false;
|
|
234
|
+
isPrimaryKey: false;
|
|
235
|
+
isAutoincrement: false;
|
|
236
|
+
hasRuntimeDefault: false;
|
|
237
|
+
enumValues: [string, ...string[]];
|
|
238
|
+
baseColumn: never;
|
|
239
|
+
identity: undefined;
|
|
240
|
+
generated: undefined;
|
|
241
|
+
}, {}, {}>;
|
|
242
|
+
};
|
|
243
|
+
dialect: "pg";
|
|
244
|
+
}>;
|
|
245
|
+
export type InsertCruisesSourcedContent = typeof cruisesSourcedContentTable.$inferInsert;
|
|
246
|
+
export type SelectCruisesSourcedContent = typeof cruisesSourcedContentTable.$inferSelect;
|
|
247
|
+
//# sourceMappingURL=schema-sourced-content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-sourced-content.d.ts","sourceRoot":"","sources":["../src/schema-sourced-content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,MAAM,gCAAgC,GAAG,IAAI,GAAG,OAAO,GAAG,OAAO,GAAG,aAAa,CAAA;AAEvF,eAAO,MAAM,0BAA0B,MAAM,CAAA;AAE7C,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCtC,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG,OAAO,0BAA0B,CAAC,YAAY,CAAA;AACxF,MAAM,MAAM,2BAA2B,GAAG,OAAO,0BAA0B,CAAC,YAAY,CAAA"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cruises sourced-content cache. Sibling to
|
|
3
|
+
* `products_sourced_content` — same shape, different vertical.
|
|
4
|
+
*
|
|
5
|
+
* One row per sourced cruise × locale × market. Stores the rich
|
|
6
|
+
* detail-page content the upstream adapter served via `getContent`,
|
|
7
|
+
* plus the SWR metadata the read service needs.
|
|
8
|
+
*
|
|
9
|
+
* See `docs/architecture/catalog-sourced-content.md` §3.2.
|
|
10
|
+
*/
|
|
11
|
+
import { boolean, index, jsonb, pgTable, primaryKey, text, timestamp } from "drizzle-orm/pg-core";
|
|
12
|
+
export const CRUISES_CONTENT_MARKET_ANY = "*";
|
|
13
|
+
export const cruisesSourcedContentTable = pgTable("cruises_sourced_content", {
|
|
14
|
+
/** TypeID matching the cruises module — `crus_*`. */
|
|
15
|
+
entity_id: text("entity_id").notNull(),
|
|
16
|
+
/** BCP 47 language tag. */
|
|
17
|
+
locale: text("locale").notNull(),
|
|
18
|
+
/** Market id, or `'*'` for all-markets. */
|
|
19
|
+
market: text("market").notNull().default(CRUISES_CONTENT_MARKET_ANY),
|
|
20
|
+
payload: jsonb("payload").$type().notNull(),
|
|
21
|
+
content_schema_version: text("content_schema_version").notNull(),
|
|
22
|
+
returned_locale: text("returned_locale").notNull(),
|
|
23
|
+
machine_translated: boolean("machine_translated").notNull().default(false),
|
|
24
|
+
source_updated_at: timestamp("source_updated_at", { withTimezone: true }),
|
|
25
|
+
fetched_at: timestamp("fetched_at", { withTimezone: true }).notNull().defaultNow(),
|
|
26
|
+
fresh_until: timestamp("fresh_until", { withTimezone: true }),
|
|
27
|
+
etag: text("etag"),
|
|
28
|
+
fetch_status: text("fetch_status")
|
|
29
|
+
.$type()
|
|
30
|
+
.notNull()
|
|
31
|
+
.default("ok"),
|
|
32
|
+
fetch_error: text("fetch_error"),
|
|
33
|
+
}, (table) => [
|
|
34
|
+
primaryKey({ columns: [table.entity_id, table.locale, table.market] }),
|
|
35
|
+
index("cruises_sourced_content_locale_fresh_idx").on(table.locale, table.fresh_until),
|
|
36
|
+
index("cruises_sourced_content_returned_locale_idx").on(table.entity_id, table.returned_locale),
|
|
37
|
+
index("cruises_sourced_content_schema_version_idx").on(table.content_schema_version),
|
|
38
|
+
]);
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { bookingCruiseDetails, bookingGroupCruiseDetails, cruiseBookingModeEnum, } from "./booking-extension.js";
|
|
2
|
+
export * from "./schema-cabins.js";
|
|
3
|
+
export * from "./schema-content.js";
|
|
4
|
+
export * from "./schema-core.js";
|
|
5
|
+
export * from "./schema-itinerary.js";
|
|
6
|
+
export * from "./schema-pricing.js";
|
|
7
|
+
export * from "./schema-search.js";
|
|
8
|
+
export * from "./schema-shared.js";
|
|
9
|
+
export { CRUISES_CONTENT_MARKET_ANY, type CruisesSourcedContentFetchStatus, cruisesSourcedContentTable, type InsertCruisesSourcedContent, type SelectCruisesSourcedContent, } from "./schema-sourced-content.js";
|
|
10
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,wBAAwB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AACnC,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,OAAO,EACL,0BAA0B,EAC1B,KAAK,gCAAgC,EACrC,0BAA0B,EAC1B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,GACjC,MAAM,6BAA6B,CAAA"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { bookingCruiseDetails, bookingGroupCruiseDetails, cruiseBookingModeEnum, } from "./booking-extension.js";
|
|
2
|
+
export * from "./schema-cabins.js";
|
|
3
|
+
export * from "./schema-content.js";
|
|
4
|
+
export * from "./schema-core.js";
|
|
5
|
+
export * from "./schema-itinerary.js";
|
|
6
|
+
export * from "./schema-pricing.js";
|
|
7
|
+
export * from "./schema-search.js";
|
|
8
|
+
export * from "./schema-shared.js";
|
|
9
|
+
export { CRUISES_CONTENT_MARKET_ANY, cruisesSourcedContentTable, } from "./schema-sourced-content.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ExternalPassengerComposition, SourceRef } from "./adapters/index.js";
|
|
2
|
+
import type { CruiseBookingPassenger } from "./service-booking-types.js";
|
|
3
|
+
export declare function generateCruiseBookingNumber(suffix?: string | number): string;
|
|
4
|
+
export declare function priceCentsFromString(s: string): number;
|
|
5
|
+
export declare function passengerCompositionFromPassengers(passengers: CruiseBookingPassenger[]): ExternalPassengerComposition;
|
|
6
|
+
export declare function passengerCompositionCount(composition: ExternalPassengerComposition): number;
|
|
7
|
+
export declare function assertPassengerCompositionMatchesPassengers(supplied: ExternalPassengerComposition | null | undefined, passengers: CruiseBookingPassenger[]): ExternalPassengerComposition;
|
|
8
|
+
export declare function sourceRefKey(ref: SourceRef): string;
|
|
9
|
+
export declare function sortValue(value: unknown): unknown;
|
|
10
|
+
export declare function sourceRefMatches(candidate: SourceRef, requested: SourceRef): boolean;
|
|
11
|
+
export declare function passengerCompositionMatches(candidate: ExternalPassengerComposition | null | undefined, requested: ExternalPassengerComposition | null | undefined): boolean;
|
|
12
|
+
//# sourceMappingURL=service-booking-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-booking-helpers.d.ts","sourceRoot":"","sources":["../src/service-booking-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAClF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AAExE,wBAAgB,2BAA2B,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAI5E;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAWtD;AAED,wBAAgB,kCAAkC,CAChD,UAAU,EAAE,sBAAsB,EAAE,GACnC,4BAA4B,CAY9B;AAED,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,4BAA4B,GAAG,MAAM,CAO3F;AAED,wBAAgB,2CAA2C,CACzD,QAAQ,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,EACzD,UAAU,EAAE,sBAAsB,EAAE,GACnC,4BAA4B,CAkC9B;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAEnD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAQjD;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAKpF;AAED,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,EAC1D,SAAS,EAAE,4BAA4B,GAAG,IAAI,GAAG,SAAS,GACzD,OAAO,CAMT"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export function generateCruiseBookingNumber(suffix) {
|
|
2
|
+
const ts = Date.now().toString(36).toUpperCase();
|
|
3
|
+
const rand = Math.random().toString(36).slice(2, 6).toUpperCase();
|
|
4
|
+
return suffix === undefined ? `CR-${ts}-${rand}` : `CR-${ts}-${rand}-${suffix}`;
|
|
5
|
+
}
|
|
6
|
+
export function priceCentsFromString(s) {
|
|
7
|
+
// For passing to bookingsService which expects integer cents.
|
|
8
|
+
// Pricing service emits decimal strings already validated to ^-?\d+(\.\d{1,2})?$
|
|
9
|
+
const negative = s.startsWith("-");
|
|
10
|
+
const abs = negative ? s.slice(1) : s;
|
|
11
|
+
const parts = abs.split(".");
|
|
12
|
+
const whole = parts[0] ?? "0";
|
|
13
|
+
const frac = parts[1] ?? "";
|
|
14
|
+
const fracPadded = `${frac}00`.slice(0, 2);
|
|
15
|
+
const cents = Number(whole) * 100 + Number(fracPadded);
|
|
16
|
+
return negative ? -cents : cents;
|
|
17
|
+
}
|
|
18
|
+
export function passengerCompositionFromPassengers(passengers) {
|
|
19
|
+
let adults = 0;
|
|
20
|
+
let children = 0;
|
|
21
|
+
let infants = 0;
|
|
22
|
+
let seniors = 0;
|
|
23
|
+
for (const passenger of passengers) {
|
|
24
|
+
if (passenger.travelerCategory === "child")
|
|
25
|
+
children += 1;
|
|
26
|
+
else if (passenger.travelerCategory === "infant")
|
|
27
|
+
infants += 1;
|
|
28
|
+
else if (passenger.travelerCategory === "senior")
|
|
29
|
+
seniors += 1;
|
|
30
|
+
else
|
|
31
|
+
adults += 1;
|
|
32
|
+
}
|
|
33
|
+
return { adults, children, infants, seniors };
|
|
34
|
+
}
|
|
35
|
+
export function passengerCompositionCount(composition) {
|
|
36
|
+
return (composition.adults +
|
|
37
|
+
(composition.children ?? 0) +
|
|
38
|
+
(composition.infants ?? 0) +
|
|
39
|
+
(composition.seniors ?? 0));
|
|
40
|
+
}
|
|
41
|
+
export function assertPassengerCompositionMatchesPassengers(supplied, passengers) {
|
|
42
|
+
const inferred = passengerCompositionFromPassengers(passengers);
|
|
43
|
+
if (!supplied)
|
|
44
|
+
return inferred;
|
|
45
|
+
const expected = {
|
|
46
|
+
adults: supplied.adults,
|
|
47
|
+
children: supplied.children ?? 0,
|
|
48
|
+
infants: supplied.infants ?? 0,
|
|
49
|
+
seniors: supplied.seniors ?? 0,
|
|
50
|
+
};
|
|
51
|
+
const actual = {
|
|
52
|
+
adults: inferred.adults,
|
|
53
|
+
children: inferred.children ?? 0,
|
|
54
|
+
infants: inferred.infants ?? 0,
|
|
55
|
+
seniors: inferred.seniors ?? 0,
|
|
56
|
+
};
|
|
57
|
+
if (expected.adults !== actual.adults ||
|
|
58
|
+
expected.children !== actual.children ||
|
|
59
|
+
expected.infants !== actual.infants ||
|
|
60
|
+
expected.seniors !== actual.seniors) {
|
|
61
|
+
throw new Error(`passengerComposition does not match passengers: composition=${JSON.stringify(expected)} passengers=${JSON.stringify(actual)}`);
|
|
62
|
+
}
|
|
63
|
+
if (supplied.childAges && supplied.childAges.length !== expected.children) {
|
|
64
|
+
throw new Error(`passengerComposition.childAges length (${supplied.childAges.length}) must match children (${expected.children})`);
|
|
65
|
+
}
|
|
66
|
+
return supplied;
|
|
67
|
+
}
|
|
68
|
+
export function sourceRefKey(ref) {
|
|
69
|
+
return JSON.stringify(sortValue(ref));
|
|
70
|
+
}
|
|
71
|
+
export function sortValue(value) {
|
|
72
|
+
if (Array.isArray(value))
|
|
73
|
+
return value.map(sortValue);
|
|
74
|
+
if (!value || typeof value !== "object")
|
|
75
|
+
return value;
|
|
76
|
+
const out = {};
|
|
77
|
+
for (const key of Object.keys(value).sort()) {
|
|
78
|
+
out[key] = sortValue(value[key]);
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
export function sourceRefMatches(candidate, requested) {
|
|
83
|
+
if (sourceRefKey(candidate) === sourceRefKey(requested))
|
|
84
|
+
return true;
|
|
85
|
+
const candidateIsLegacy = Object.keys(candidate).length === 1;
|
|
86
|
+
const requestedIsLegacy = Object.keys(requested).length === 1;
|
|
87
|
+
return (candidateIsLegacy || requestedIsLegacy) && candidate.externalId === requested.externalId;
|
|
88
|
+
}
|
|
89
|
+
export function passengerCompositionMatches(candidate, requested) {
|
|
90
|
+
if (!candidate || !requested)
|
|
91
|
+
return true;
|
|
92
|
+
return (sourceRefKey({ externalId: "composition", ...candidate }) ===
|
|
93
|
+
sourceRefKey({ externalId: "composition", ...requested }));
|
|
94
|
+
}
|