@revolugo/common 6.14.6 → 6.15.0-rc.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 (35) hide show
  1. package/package.json +14 -9
  2. package/src/amenities/index.ts +51 -0
  3. package/src/assets/index.ts +3 -0
  4. package/src/assets/placeholder-hotel.png +0 -0
  5. package/src/assets/placeholder-room.png +0 -0
  6. package/src/constants/hotel-room-offer.ts +11 -0
  7. package/src/constants/index.ts +2 -1
  8. package/src/constants/locales.ts +5 -5
  9. package/src/constants/tax.ts +9 -0
  10. package/src/icons/index.ts +2 -1
  11. package/src/schemas/cancellation-policies.ts +18 -0
  12. package/src/schemas/currency.ts +7 -0
  13. package/src/schemas/hotel-offer-request.ts +43 -0
  14. package/src/schemas/hotel-offer.ts +58 -0
  15. package/src/schemas/hotel-room-offer.ts +99 -0
  16. package/src/schemas/hotel-room.ts +106 -0
  17. package/src/schemas/hotel.ts +360 -0
  18. package/src/schemas/index.ts +10 -0
  19. package/src/schemas/list-polling-meta.ts +43 -0
  20. package/src/schemas/tag.ts +13 -0
  21. package/src/schemas/taxes.ts +34 -0
  22. package/src/types/elements/booking-flow.ts +6 -0
  23. package/src/types/elements/contact-person.ts +11 -0
  24. package/src/types/elements/elements-events.ts +84 -0
  25. package/src/types/elements/hotel-offers-filters.ts +19 -0
  26. package/src/types/elements/hotel.ts +2 -0
  27. package/src/types/elements/index.ts +3 -0
  28. package/src/types/severities.ts +1 -0
  29. package/src/utils/case-transformers.ts +5 -5
  30. package/src/utils/get-sanitized-room-count.ts +29 -0
  31. package/src/utils/images.ts +3 -3
  32. package/src/utils/index.ts +4 -0
  33. package/src/utils/is-object.ts +2 -0
  34. package/src/utils/keys-case-transformer.ts +118 -0
  35. package/src/utils/transform-schema-keys.ts +143 -0
package/package.json CHANGED
@@ -1,14 +1,22 @@
1
1
  {
2
2
  "name": "@revolugo/common",
3
- "version": "6.14.6",
3
+ "version": "6.15.0-rc.0",
4
4
  "private": false,
5
5
  "description": "Revolugo common",
6
6
  "author": "Revolugo",
7
7
  "type": "module",
8
+ "engines": {
9
+ "node": ">=20.18.1 <25"
10
+ },
11
+ "volta": {
12
+ "extends": "../../package.json"
13
+ },
8
14
  "files": [
9
15
  "src"
10
16
  ],
11
17
  "exports": {
18
+ "./amenities": "./src/amenities/index.ts",
19
+ "./assets": "./src/assets/index.ts",
12
20
  "./cancellation-policies": "./src/cancellation-policies.ts",
13
21
  "./countries": "./src/countries/index.ts",
14
22
  "./constants": "./src/constants/index.ts",
@@ -17,21 +25,18 @@
17
25
  "./icons": "./src/icons/index.ts",
18
26
  "./map": "./src/map/index.ts",
19
27
  "./models": "./src/models/index.ts",
28
+ "./schemas": "./src/schemas/index.ts",
20
29
  "./types": "./src/types/index.ts",
21
30
  "./utils": "./src/utils/index.ts"
22
31
  },
23
32
  "dependencies": {
24
33
  "change-case": "5.4.4",
25
34
  "dayjs": "1.11.19",
26
- "ky": "1.14.0",
35
+ "ky": "1.14.1",
27
36
  "slugify": "1.6.6",
28
- "uuid": "13.0.0"
29
- },
30
- "engines": {
31
- "node": ">=20.18.1 <25"
32
- },
33
- "volta": {
34
- "extends": "../../package.json"
37
+ "type-fest": "5.3.0",
38
+ "uuid": "13.0.0",
39
+ "zod": "3.25.76"
35
40
  },
36
41
  "scripts": {
37
42
  "test": "vitest"
@@ -0,0 +1,51 @@
1
+ export const AMENITY_TO_ICONS = Object.freeze({
2
+ AirConditioning: 'wind',
3
+ AirportTransportation: 'planeTakeOff',
4
+ BusinessCenter: 'building',
5
+ CarRentDesk: 'car',
6
+ ChildrenAllowed: 'baby',
7
+ ClothingIron: 'shirt',
8
+ CoffeeTeaMaker: 'coffee',
9
+ Combination: 'buildings',
10
+ ContinentalBreakfast: 'egg',
11
+ DataPorts: 'deviceTablet',
12
+ DryCleaning: 'shirt',
13
+ ElectronicRoomKeys: 'key',
14
+ ExteriorRoomEntrance: 'doorOpen',
15
+ FamilyRooms: 'usersThree',
16
+ FitnessFacility: 'gym',
17
+ GameRoom: 'gameController',
18
+ GolfCourse: 'golf',
19
+ HairDryer: 'hairDryer',
20
+ HandicapAccessible: 'wheelchair',
21
+ InHouseBar: 'champagne',
22
+ InHouseDining: 'forkKnife',
23
+ InRoomMovies: 'filmReel',
24
+ IndoorPool: 'swimmingPool',
25
+ InteriorRoomEntrance: 'doorOpen',
26
+ Kitchen: 'forkKnife',
27
+ Map: 'mapPin',
28
+ MeetingRooms: 'chalkboard',
29
+ MiniBarInRoom: 'wine',
30
+ NonSmokingRooms: 'noSmoking',
31
+ OutdoorPool: 'swimmingPool',
32
+ ParkingGarage: 'parkingSign',
33
+ PetsAllowed: 'pawPrint',
34
+ RestrictedAccess: 'lock',
35
+ RoomService: 'bell',
36
+ Safe: 'vault',
37
+ Sauna: 'thermometerHot',
38
+ TennisCourt: 'tennisBall',
39
+ TvInRoom: 'monitor',
40
+ TwentyFourHourSecurity: 'shield',
41
+ ValetParking: 'car',
42
+ VideoCheckOut: 'filmReel',
43
+ VoiceMail: 'phone',
44
+ WakeUpService: 'clock',
45
+ Whirpool: 'swimmingPool',
46
+ Wifi: 'wifiHigh',
47
+ })
48
+
49
+ export const AMENITY_NAMES = Object.keys(AMENITY_TO_ICONS)
50
+
51
+ export type HotelRoomAmenityNames = keyof typeof AMENITY_TO_ICONS
@@ -0,0 +1,3 @@
1
+ export { default as hotelImagePlaceholder } from './placeholder-hotel.png'
2
+
3
+ export { default as roomImagePlaceholder } from './placeholder-room.png'
Binary file
Binary file
@@ -0,0 +1,11 @@
1
+ export enum HotelRoomOfferType {
2
+ HotelRoom = 'HOTEL_ROOM',
3
+ Package = 'PACKAGE',
4
+ }
5
+
6
+ export enum PackageType {
7
+ BestMatch = 'BEST_MATCH',
8
+ Cheapest = 'CHEAPEST',
9
+ MatchingRoomCount = 'MATCHING_ROOM_COUNT',
10
+ Regular = 'REGULAR',
11
+ }
@@ -1,12 +1,13 @@
1
1
  export * from '../countries/constants.ts'
2
2
  export * from '../currencies/constants.ts'
3
-
4
3
  export * from './environment.ts'
5
4
  export * from './hotel.ts'
6
5
  export * from './hotel-offers.ts'
6
+ export * from './hotel-room-offer.ts'
7
7
  export * from './locales.ts'
8
8
  export * from './measurement.ts'
9
9
  export * from './poller.ts'
10
+ export * from './tax.ts'
10
11
  export * from './time.ts'
11
12
  export * from './stay-taxes-info.ts'
12
13
  export * from './venue.ts'
@@ -33,11 +33,11 @@ export function langFromString(langStr: string): Lang | undefined {
33
33
  export const LANG_TO_LOCALE: Record<Lang, Locale> = {
34
34
  [Lang.EN]: Locale.en_US,
35
35
  [Lang.FR]: Locale.fr_FR,
36
- [Lang.DE]: Locale.en_US,
37
- [Lang.ES]: Locale.en_US,
38
- [Lang.IT]: Locale.en_US,
39
- [Lang.NL]: Locale.en_US,
40
- [Lang.PT]: Locale.en_US,
36
+ [Lang.DE]: Locale.de_DE,
37
+ [Lang.ES]: Locale.es_ES,
38
+ [Lang.IT]: Locale.it_IT,
39
+ [Lang.NL]: Locale.nl_NL,
40
+ [Lang.PT]: Locale.pt_PT,
41
41
  }
42
42
 
43
43
  /* @__PURE__ */
@@ -0,0 +1,9 @@
1
+ export enum TaxFrequency {
2
+ PerNight = 'PER_NIGHT',
3
+ PerStay = 'PER_STAY',
4
+ }
5
+
6
+ export enum TaxMode {
7
+ PerAdult = 'PER_ADULT',
8
+ PerBooking = 'PER_BOOKING',
9
+ }
@@ -2,7 +2,9 @@ export const ICONS_NAME = Object.freeze({
2
2
  airplane: 'ph:airplane',
3
3
  archive: 'ph:archive',
4
4
  arrowDown: 'ph:arrow-down',
5
+ arrowHorizontal: 'ph:arrows-horizontal',
5
6
  arrowRight: 'ph:arrow-right',
7
+ arrowsLeftRight: 'ph:arrows-left-right',
6
8
  baby: 'ph:baby',
7
9
  bag: 'ph:bag',
8
10
  bank: 'ph:bank',
@@ -85,7 +87,6 @@ export const ICONS_NAME = Object.freeze({
85
87
  gear: 'ph:gear',
86
88
  globe: 'ph:globe',
87
89
  golf: 'ph:golf',
88
- googleColored: 'flat-color-icons:google',
89
90
  graph: 'ph:graph',
90
91
  gym: 'ph:barbell',
91
92
  hairDryer: 'ph:hair-dryer',
@@ -0,0 +1,18 @@
1
+ /* eslint-disable camelcase */
2
+ import { z } from 'zod'
3
+
4
+ export const CANCELLATION_POLICY_SCHEMA = z.object({
5
+ date_from: z.string().openapi({
6
+ description:
7
+ 'The start date and time of the cancellation policy, given in the hotel timezone.',
8
+ }),
9
+ date_to: z.string().openapi({
10
+ description:
11
+ 'The end date and time of the cancellation policy, given in the hotel timezone.',
12
+ }),
13
+ penalty_percentage: z.number().min(0).max(100).openapi({
14
+ description:
15
+ 'The penalty percentage that is due in case of cancellation during the **date_from** to **date_to** period range.',
16
+ }),
17
+ })
18
+ /* eslint-enable camelcase */
@@ -0,0 +1,7 @@
1
+ import { z } from 'zod'
2
+
3
+ import { STRIPE_CURRENCY_CODES } from '../currencies/index.ts'
4
+
5
+ export const CURRENCY_SCHEMA = z
6
+ .enum(STRIPE_CURRENCY_CODES)
7
+ .openapi({ description: 'ISO 4217 currency code.' })
@@ -0,0 +1,43 @@
1
+ import { z } from 'zod'
2
+
3
+ import { CountryIso2Code } from '../constants/index.ts'
4
+
5
+ export const ADULT_COUNT_SCHEMA = z.number().int().min(1).max(200).openapi({
6
+ description:
7
+ 'The total number of adults who will be staying in the property.',
8
+ })
9
+
10
+ export const CHECK_IN_DATE_SCHEMA = z
11
+ .string()
12
+ .regex(/^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$/u)
13
+ .openapi({ description: 'Date of check-in formatted as YYYY-MM-DD.' })
14
+
15
+ export const CHECK_OUT_DATE_SCHEMA = z
16
+ .string()
17
+ .regex(/^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$/u)
18
+ .openapi({ description: 'Date of check-out formatted as YYYY-MM-DD.' })
19
+
20
+ export const CHILDREN_SCHEMA = z
21
+ .string()
22
+ .regex(/^(([0-9]{1})|(1[0-7]){1})(,(([0-9]{1})|(1[0-7]){1}))*$|^$/u)
23
+ .openapi({
24
+ description:
25
+ 'A comma-separated list of child ages (0 up to 17). e.g.: "3,7" represents 2 children respectively 3 and 7 years old.',
26
+ })
27
+
28
+ export const COUNTRY_ISO2_CODE_SCHEMA = z
29
+ .nativeEnum(CountryIso2Code)
30
+ .refine(check => Object.values(CountryIso2Code).includes(check), {
31
+ message: 'Invalid ISO Alpha-2 country code.',
32
+ })
33
+ .openapi({
34
+ description: 'ISO Alpha-2 country code.',
35
+ })
36
+
37
+ export const SOURCE_MARKET_SCHEMA = COUNTRY_ISO2_CODE_SCHEMA.openapi(
38
+ 'sourceMarket',
39
+ {
40
+ description:
41
+ 'For sourcing availability within certain markets, a source market option may be used to get more accurate prices. You may use any valid ISO Alpha-2 country code, e.g. JP.',
42
+ },
43
+ )
@@ -0,0 +1,58 @@
1
+ /* eslint-disable camelcase */
2
+ import { z } from 'zod'
3
+
4
+ import { CURRENCY_SCHEMA } from './currency.ts'
5
+ import {
6
+ ADULT_COUNT_SCHEMA,
7
+ CHECK_IN_DATE_SCHEMA,
8
+ CHECK_OUT_DATE_SCHEMA,
9
+ CHILDREN_SCHEMA,
10
+ } from './hotel-offer-request.ts'
11
+ import { HOTEL_ROOM_OFFER_SCHEMA } from './hotel-room-offer.ts'
12
+ import { HOTEL_IMAGES, HOTEL_SCHEMA, VENUES_SCHEMA } from './hotel.ts'
13
+ import { LIST_POLLING_META_SCHEMA } from './list-polling-meta.ts'
14
+ import { TAGS_SCHEMA } from './tag.ts'
15
+
16
+ export const HOTEL_OFFER_SCHEMA = HOTEL_SCHEMA.extend({
17
+ hotel_images: HOTEL_IMAGES.openapi({
18
+ description: `⚠️ Cached images of the hotel. May be empty, use the endpoint /hotels/{id}/images to get the latest images.
19
+
20
+ List of hotel images in various sizes featuring an indicator for the primary (hero) image
21
+ `,
22
+ }),
23
+ hotel_room_offers: z.array(HOTEL_ROOM_OFFER_SCHEMA),
24
+ tags: TAGS_SCHEMA,
25
+ venues: VENUES_SCHEMA,
26
+ })
27
+
28
+ export const HOTEL_OFFERS_SCHEMA = z.array(HOTEL_OFFER_SCHEMA)
29
+
30
+ export const HOTEL_OFFERS_RESPONSE_SCHEMA = z.object({
31
+ data: z.object({
32
+ adult_count: ADULT_COUNT_SCHEMA,
33
+ check_in_date: CHECK_IN_DATE_SCHEMA,
34
+ check_out_date: CHECK_OUT_DATE_SCHEMA,
35
+ children: CHILDREN_SCHEMA.optional().nullish(),
36
+ currency: CURRENCY_SCHEMA,
37
+ hotel_offers: HOTEL_OFFERS_SCHEMA.openapi({
38
+ description: 'List of Hotel Offers',
39
+ }),
40
+ price_histogram: z
41
+ .array(z.number())
42
+ .openapi({
43
+ description:
44
+ '**Hotel Offers** price histogram dataset based on the price of the cheapest **Hotel Room Offer** included on each **Hotel Offer** returned. It represents the number of available **Hotel Offers** grouped by price sorted ascendingly. Each item of the list represents a price step based on returned **price_min**, **price_max** and requested **price_histogram_step_count**',
45
+ })
46
+ .nullish(),
47
+ price_max: z.number().nullish().openapi({
48
+ description: 'Maximum price of available returned **Hotel Offers**',
49
+ }),
50
+ price_min: z.number().nullish().openapi({
51
+ description: 'Minimum price of available returned **Hotel Offers**',
52
+ }),
53
+ }),
54
+ event: z.any().optional(),
55
+ meta: LIST_POLLING_META_SCHEMA.extend({
56
+ total_count: z.number(),
57
+ }),
58
+ })
@@ -0,0 +1,99 @@
1
+ /* eslint-disable camelcase */
2
+ import { z } from 'zod'
3
+
4
+ import {
5
+ BreakfastOption,
6
+ HotelRoomOfferType,
7
+ PackageType,
8
+ } from '../constants/index.ts'
9
+
10
+ import { CANCELLATION_POLICY_SCHEMA } from './cancellation-policies.ts'
11
+ import { CURRENCY_SCHEMA } from './currency.ts'
12
+ import { SOURCE_MARKET_SCHEMA } from './hotel-offer-request.ts'
13
+ import { HOTEL_ROOMS_SCHEMA } from './hotel-room.ts'
14
+ import { TAGS_SCHEMA } from './tag.ts'
15
+ import { TAXES_SCHEMA } from './taxes.ts'
16
+
17
+ export const BREAKFAST_OPTION_DESCRIPTION = `This parameter describes the breakfast option for the given **Hotel Room Offer**:
18
+ - **breakfast_option = "${BreakfastOption.Included}"**:
19
+ 1. When **HotelRoomOffer.type = "${HotelRoomOfferType.Package}"**:
20
+ the returned **Hotel Room Offer** includes breakfast for the requested **guest count (adult_count + children over 3)**, you cannot choose otherwise, and the returned **price** already includes it,
21
+ 2. When **HotelRoomOffer.type = "${HotelRoomOfferType.HotelRoom}"**:
22
+ the returned **Hotel Room Offer** includes breakfast for the **Hotel Room Offer** maximum occupancy, you cannot choose otherwise, and the returned **price** already includes it,
23
+ -**breakfast_option = "${BreakfastOption.Optional}"**: the returned **Hotel Room Offer** does not include by default the breakfast and so does the returned **price**, but you'll be able to let your customers choose to add it to their booking. In that case, a **breakfast_price_per_guest_per_night** expressed in the requested **currency** will be available in the returned data, and you'll be to perform one of the two following actions: \n - Call **[Create Hotel Room Offer endpoint](/v1/documentation#operation/postV1Hotel_room_offers)** and get a fresh **Hotel Room Offer** with updated price \n - Compute and display the total price of the **Hotel Room Offer** related to the guest_count and night count requested including extra breafasts.,
24
+ - **breakfast_option = "${BreakfastOption.NotIncluded}"**: the returned **Hotel Room Offer** does not include breakfast and you cannot choose otherwise through API. Guest may still be able to add extra breakfast option(s) at the time of check-in directly at the hotel's reception.`
25
+
26
+ export const PACKAGE_TYPES_DESCRIPTION = `An **Hotel Room Offer** of type **${HotelRoomOfferType.Package}** can be of **4 types**, described by **package_type** parameter: \n\n - **${PackageType.Cheapest}** : The cheapest combination of hotel rooms that can accommodate the requested guest count. Note that it may not match the requested room count (e.g., 4 guests and 2 rooms requested may return an hotel room package including only 1 room with an occupancy of 4). \n\n -**${PackageType.MatchingRoomCount}** : the cheapest hotel room package that can accommodate the given guest count and that matches exactly the room count given. \n\n -**${PackageType.BestMatch}** : The cheapest hotel room package that matches the given room and guest count with a balanced distribution of guests across the rooms (e.g.; 8 guests and 3 rooms requested may return an **Hotel Room Offer** package including 2 rooms with an occupancy of 3 on each one and 1 room with an occupancy of 2). \n\n -**${PackageType.Regular}** : any other available package.`
27
+
28
+ export const HOTEL_ROOM_OFFER_SCHEMA = z
29
+ .object({
30
+ breakfast_count: z.number().min(0).optional().nullish().openapi({
31
+ description:
32
+ 'Quantity of breakfast per night included in the given **Hotel Room Offer**',
33
+ }),
34
+ breakfast_option: z.nativeEnum(BreakfastOption).openapi({
35
+ description: BREAKFAST_OPTION_DESCRIPTION,
36
+ }),
37
+ breakfast_price_per_guest_per_night: z
38
+ .number()
39
+ .optional()
40
+ .nullish()
41
+ .openapi({
42
+ description:
43
+ 'Price of breakfast per guest per night for the given **Hotel Room Offer**, expressed in the requested **currency**, when applicable.\n\n <div style="background-color: #ffffef; padding: 20px; border: 1px solid lightgrey; border-radius: 5px;"><b style="color: red; margin-top: 10px;">🛑 DEPRECATED.</b>\n\n <b style="color: orange;">Field renamed to "breakfast_unit_price"</div>',
44
+ }),
45
+ breakfast_unit_price: z.number().optional().nullish().openapi({
46
+ description:
47
+ 'Price of breakfast per guest per night for the given **Hotel Room Offer**, expressed in the requested **currency**, when applicable.',
48
+ }),
49
+ cancellation_policies: z
50
+ .array(CANCELLATION_POLICY_SCHEMA)
51
+ .openapi('cancellationPoliciesApi', {
52
+ description:
53
+ 'The list of cancellation policies applied to the given **Hotel Room Offer**.',
54
+ }),
55
+ count: z
56
+ .number()
57
+ .optional()
58
+ .nullish()
59
+ .openapi({
60
+ description: `When **type = ${HotelRoomOfferType.HotelRoom}**: this parameters represents the available quantity for the given **Hotel Room Offer**.
61
+ When **type = ${HotelRoomOfferType.Package}**: count = 1 always.`,
62
+ }),
63
+ currency: CURRENCY_SCHEMA,
64
+ hotel_id: z
65
+ .string()
66
+ .openapi({ description: 'id of the associated Hotel.' }),
67
+ hotel_rooms: HOTEL_ROOMS_SCHEMA.openapi({
68
+ description: 'List of Hotel Rooms included in the Hotel Room Offer.',
69
+ }),
70
+ id: z.string().openapi({ description: 'Hotel Room Offer id.' }).optional(),
71
+ package_type: z
72
+ .nativeEnum(PackageType)
73
+ .openapi({
74
+ description: PACKAGE_TYPES_DESCRIPTION,
75
+ })
76
+ .nullish()
77
+ .optional(),
78
+ price: z.number().openapi({
79
+ description:
80
+ 'Price with taxes NOT INCLUDED of the given **Hotel Room Offer** including breakfast(s) when applicable, expressed in the requested **currency**.',
81
+ }),
82
+ source_market: SOURCE_MARKET_SCHEMA,
83
+ tags: TAGS_SCHEMA,
84
+ tax_included_price: z.number().openapi({
85
+ description: `Price of the given **Hotel Room Offer** including breakfast(s) when applicable, and including all taxes from returned **taxes** list parameter expressed in the requested **currency**.\n\nThis data is not returned for a **Hotel Room Offer** of type **${HotelRoomOfferType.HotelRoom}**, you'll need to compute and display the actual tax included price of the final **Hotel Room** package corresponding to the guest count and night count requested, or make a call to the **[Create Hotel Room Offer](/v1/documentation#operation/postV1Hotel_room_offers)** endpoint in order to get a valid and bookable **Hotel Room Offer** where **type = ${HotelRoomOfferType.Package}** based on a packaged list of **Hotel Room Offers** of type **${HotelRoomOfferType.HotelRoom}**.`,
86
+ }),
87
+ taxes: TAXES_SCHEMA,
88
+ type: z
89
+ .nativeEnum(HotelRoomOfferType)
90
+ .openapi({
91
+ description: `Hotel Room Offer type.\n\n **Hotel Room Offers** with **type = "${HotelRoomOfferType.Package}"** are **Hotel Room Offers** that are already bookable and you'll be able to follow the next step of the **Booking Flow** calling **[Create Booking Policies endpoint](/v1/documentation#operation/postV1Booking_policies)**. \n\n Otherwise, you'll be able to create a new **Hotel Room Offer** with **type = "${HotelRoomOfferType.Package}"** from multiple **Hotel Room Offers** with **type = "${HotelRoomOfferType.HotelRoom}"**. See **[Create Hotel Room Offer endpoint](/v1/documentation#operation/postV1Hotel_room_offers)** for details.`,
92
+ })
93
+ .nullish()
94
+ .optional(),
95
+ })
96
+ .openapi('hotelRoomOfferApi', {
97
+ description: 'Description of the Hotel Room Offer.',
98
+ })
99
+ /* eslint-enable camelcase */
@@ -0,0 +1,106 @@
1
+ /* eslint-disable camelcase */
2
+ import { z } from 'zod'
3
+
4
+ import { HOTEL_IMAGE } from './hotel.ts'
5
+
6
+ export const BED_SCHEMA = z
7
+ .object({
8
+ count: z.number().openapi({
9
+ description: 'Number of beds of the given type in the room.',
10
+ }),
11
+ name: z.string().openapi({ description: 'Bed name.' }),
12
+ occupancy: z.number().openapi({ description: 'Bed occupancy.' }),
13
+ })
14
+ .openapi('bedApi')
15
+
16
+ export const BEDS_SCHEMA = z
17
+ .array(z.array(BED_SCHEMA))
18
+ .openapi({
19
+ description: `Beds list.
20
+ Each nested array of beds represents a single combination of possible beds.
21
+ e.g.: The following object represents **1 double bed or 1 sofa bed and 1 double bed or 1 single bed**:
22
+ \`\`\`
23
+ [
24
+ [
25
+ { count: 1, name: 'double', occupancy: 2 },
26
+ { count: 1, name: 'sofa', occupancy: 1 }
27
+ ],
28
+ [
29
+ { count: 1, name: 'double', occupancy: 2 },
30
+ { count: 1, name: 'single', occupancy: 1 }
31
+ ]
32
+ ]
33
+ \`\`\`
34
+ `,
35
+ })
36
+ .openapi('bedsApi')
37
+
38
+ export const HOTEL_ROOM_SCHEMA = z
39
+ .object({
40
+ amenities: z
41
+ .array(z.string().openapi('amenity'))
42
+ .openapi({
43
+ description:
44
+ 'List of amenities in the room. May be subject to changes at the Hotel.',
45
+ })
46
+ .nullish(),
47
+ beds: BEDS_SCHEMA,
48
+ beds_pretty: z
49
+ .string()
50
+ .openapi({ description: 'Prettified and localized list of beds' }),
51
+ count: z.number().openapi({
52
+ description: 'Hotel Room count included in the Hotel Room Offer.',
53
+ }),
54
+ description: z.string().openapi({ description: 'Hotel Room description.' }),
55
+ highres_images: z
56
+ .boolean()
57
+ .openapi({ description: 'Whether high resolution images are available.' })
58
+ .optional()
59
+ .nullish(),
60
+ id: z
61
+ .string()
62
+ .optional()
63
+ .openapi({ description: 'Hotel Room id, when applicable.' }),
64
+ image_indexes: z.array(z.number()).optional().nullish().openapi({
65
+ description:
66
+ 'List of indexes corresponding to image names for the given Hotel Room among the related hotel images.',
67
+ }),
68
+ images: z
69
+ .array(HOTEL_IMAGE)
70
+ .openapi({
71
+ description: 'Hotel Room images.',
72
+ })
73
+ .optional()
74
+ .nullish(),
75
+ lowres_images: z
76
+ .boolean()
77
+ .openapi({ description: 'Whether low resolution images are available.' })
78
+ .optional()
79
+ .nullish(),
80
+ occupancy: z
81
+ .number()
82
+ .openapi({ description: 'Total occupancy of a single hotel room.' }),
83
+ rich_description: z.string().optional().nullish().openapi({
84
+ description: 'Rich Hotel Room description. May contain HTML tags markup.',
85
+ }),
86
+ room_square_feet: z.number().optional().nullish().openapi({
87
+ description:
88
+ 'Room surface in square feet. May be subject to changes at the Hotel.',
89
+ }),
90
+ room_square_meters: z.number().optional().nullish().openapi({
91
+ description:
92
+ 'Room surface in square meters. May be subject to changes at the Hotel.',
93
+ }),
94
+ thumb_images: z
95
+ .boolean()
96
+ .openapi({
97
+ description:
98
+ 'Whether thumb resolution images are available (in order to display them as image carousel navigation for instance).',
99
+ })
100
+ .optional()
101
+ .nullish(),
102
+ })
103
+ .openapi({ description: 'Hotel Room details.' })
104
+
105
+ export const HOTEL_ROOMS_SCHEMA = z.array(HOTEL_ROOM_SCHEMA)
106
+ /* eslint-enable camelcase */