import {z} from 'zod' export type BlockAvailabilityInputDto = {hotel_ids: Array, checkin: string, checkout: string, guest_cc: string, currency?: string | undefined, extras?: (Array<'ADDON_TYPE' | 'NET_PRICE' | 'RACK_RATES' | 'MAX_ROOMS_IN_RESERVATION' | 'SMOKING_STATUS' | 'IMPORTANT_INFORMATION' | 'ALL_EXTRA_CHARGES' | 'ADDITIONAL_ROOM_INFO' | 'GROUP_RECOMMENDATIONS' | 'ROOM_TYPE_ID' | 'CC_REQUIRED' | 'SHOW_CONDITIONAL_CHARGES' | 'POSTCARD_PHOTO' | 'EXTRA_CHARGES' | 'PHOTOS' | 'INTERNET' | 'IF_DOMESTIC_NO_CC' | 'FACILITIES' | 'EXTRA_BEDS' | 'CANCELLATION_INFO' | 'MEALPLANS' | 'DEAL_LASTM' | 'PAYMENT_TERMS' | 'ALL_PRICES' | 'BLOCK_PAYMENT_OPTIONS' | 'MAX_CHILDREN_FREE_AGE' | 'NUMBER_OF_ROOMS_LEFT' | 'MAX_CHILDREN_FREE' | 'POLICIES' | 'PREPAYMENT_INFO' | 'DEAL_FLASH' | 'IF_NO_CC_ALLOWED' | 'DEAL_SMART' | 'ADDONS' | 'ADDRESS_REQUIRED' | 'PPT'>) | undefined, block_ids?: Array | undefined, guest_ip?: string | undefined, guest_qty?: Array | undefined, room1?: Array | undefined, language?: ('ar' | 'bg' | 'ca' | 'cs' | 'da' | 'de' | 'el' | 'en' | 'en-gb' | 'en-us' | 'es' | 'es-ar' | 'es-mx' | 'et' | 'fi' | 'fr' | 'he' | 'hi' | 'hr' | 'hu' | 'id' | 'is' | 'it' | 'ja' | 'ka' | 'ko' | 'lt' | 'lv' | 'ms' | 'nl' | 'no' | 'pl' | 'pt-br' | 'pt-pt' | 'pt' | 'ro' | 'ru' | 'sk' | 'sl' | 'sr' | 'sv' | 'th' | 'tl' | 'tr' | 'uk' | 'vi' | 'zh' | 'zh-cn' | 'zh-tw') | undefined, user_platform?: ('DESKTOP' | 'MOBILE') | undefined, limit_incremental_prices?: number | undefined, allow_past?: boolean | undefined, is24hr?: boolean | undefined, genius?: number | undefined}; export type GetApiDemandApiV2CompatibleBlockAvailabilityArgs = {blockInput: BlockAvailabilityInputDto, Accept?: 'application/json, application/xml' | undefined}; export type GetApiDemandApiV2CompatibleBlockAvailabilityOptions = {baseUrl?: string | undefined, BearerAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const priceOtherCurrency = z.object({currency: z.string().optional(), price: z.number().optional()}); export const blockAvailabilityChargeDto = z.object({currency: z.string().optional(), charge_amount: z.number().optional(), amount: z.number().optional(), type: z.string().optional(), name: z.string().optional(), name_id: z.number().int().optional(), charge_price_mode: z.number().int().optional(), excluded: z.boolean().optional(), other_currency: z.object({currency: z.string().optional(), amount: z.number().optional()}).optional(), is_conditional: z.boolean().optional()}); export const chargesBreakdownDto = z.object({net_price: z.number().optional(), net_price_other_currency: z.object({currency: z.string().optional(), price: z.number().optional()}).optional(), extra_charge: z.array(blockAvailabilityChargeDto).optional()}); export const blockAvailabilityPriceDto = z.object({price: z.number().optional(), currency: z.string().optional(), other_currency: priceOtherCurrency.optional(), extra_charges_breakdown: chargesBreakdownDto.optional()}); export const dealTaggingDto = z.object({deal_name: z.string().optional(), discount_percentage: z.number().int().optional(), platform: z.string().optional(), public_price: z.object({price: z.number().optional(), currency: z.string().optional(), other_currency: priceOtherCurrency.optional(), extra_charges_breakdown: chargesBreakdownDto.optional()}).optional(), best_price_without_genius: z.object({price: z.number().optional(), currency: z.string().optional(), other_currency: priceOtherCurrency.optional(), extra_charges_breakdown: chargesBreakdownDto.optional()}).optional()}); export const cancellationStageDto = z.object({from: z.string().optional(), until: z.string().optional(), fee: z.number().optional(), currency: z.string().optional(), timezone: z.string().optional(), guest_currency: z.string().optional(), guest_currency_fee: z.number().optional(), guest_currency_fee_pretty: z.string().optional()}); export const blockOutputDto = z.object({block_id: z.string().optional(), breakfast_included: z.boolean().optional(), min_price: z.object({price: z.number().optional(), currency: z.string().optional(), other_currency: priceOtherCurrency.optional(), extra_charges_breakdown: chargesBreakdownDto.optional()}).optional(), incremental_price: z.array(blockAvailabilityPriceDto).optional(), room_id: z.number().int().optional(), deposit_required: z.boolean().optional(), refundable: z.boolean().optional(), refundable_until: z.string().optional(), min_rate_nr_available_blocks: z.number().int().optional(), max_occupancy: z.number().int().optional(), name: z.string().optional(), room_description: z.string().optional(), lunch_included: z.boolean().optional(), full_board: z.boolean().optional(), half_board: z.boolean().optional(), dinner_included: z.boolean().optional(), all_inclusive: z.boolean().optional(), taxes: z.string().optional(), number_of_rooms_left: z.number().int().optional(), max_children_free: z.number().int().optional(), max_adults: z.number().int().optional(), room_type_id: z.number().int().optional(), smoking: z.number().int().optional(), max_children_free_age: z.number().int().optional(), deal_tagging: dealTaggingDto.optional(), free_wifi: z.boolean().optional(), internet_included: z.boolean().optional(), mcid: z.number().int().optional(), ppt: z.string().optional(), cancellation_info: z.array(cancellationStageDto).optional()}); export const petsPolicyData = z.object({allowed: z.enum(["YES", "NO", "UPON_REQUEST"]).optional(), charge_mode: z.enum(["FREE", "CHARGES_MAY_APPLY"]).optional()}); export const internetPolicyData = z.object({connection_type: z.enum(["WIFI", "WIRED"]).optional(), coverage: z.enum(["ALL_ROOMS", "SOME_ROOMS", "PUBLIC_AREAS", "BUSINESS_CENTER", "ENTIRE_PROPERTY"]).optional(), charge_mode: z.enum(["FREE", "PAID"]).optional()}); export const parkingPolicyData = z.object({type: z.enum(["PRIVATE", "PUBLIC"]).optional(), location: z.enum(["ON_SITE", "NEARBY"]).optional(), charge_mode: z.enum(["FREE", "PAID"]).optional()}); export const cotsAndBedsData = z.object({type: z.enum(["CRIB", "EXISTING_BED", "EXTRA_BED"]).optional(), from_age: z.number().int().optional(), to_age: z.number().int().optional(), charge_mode: z.enum(["FREE", "PER_NIGHT", "PER_STAY"]).optional(), price: z.number().nullable().optional()}); export const childrenPolicyData = z.object({allowed: z.boolean().optional(), minimum_age: z.number().int().optional(), cots_and_beds: z.array(cotsAndBedsData).optional()}); export const hotelPolicyDto = z.object({class: z.string().optional(), pets: petsPolicyData.optional(), internet: internetPolicyData.optional(), parking: parkingPolicyData.optional(), children: childrenPolicyData.optional(), max_rooms: z.number().int().optional()}); export const blockAvailabilityOutputDto = z.object({block: z.array(blockOutputDto).optional(), can_pay_now: z.boolean().optional(), checkin: z.string().optional(), checkout: z.string().optional(), direct_payment: z.boolean().optional(), hotel_id: z.number().int().optional(), hotel_url: z.string().optional(), is_flash_deal: z.boolean().optional(), policies: z.array(hotelPolicyDto).optional(), max_rooms_in_reservation: z.number().int().optional()}); export const meta = z.object({ruid: z.string().optional()}); export const blockAvailabilityResponseDto = z.object({result: z.array(blockAvailabilityOutputDto).optional(), meta: meta.optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * List all bookable rooms at a property * * GET /demand-api-v2-compatible/blockAvailability */ export const getApiDemandApiV2CompatibleBlockAvailability = async (args: GetApiDemandApiV2CompatibleBlockAvailabilityArgs, options?: GetApiDemandApiV2CompatibleBlockAvailabilityOptions) => { const {baseUrl = "https://metasearch-connect-api.booking.com", fetch: fetchFn = fetch, BearerAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.blockInput != null) query.append("blockInput", JSON.stringify(args.blockInput)) if (args.Accept != null) headers.set("Accept", String(args.Accept)) if (BearerAuth !== undefined) headers.set('authorization', `Bearer ${BearerAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/demand-api-v2-compatible/blockAvailability${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(blockAvailabilityResponseDto, await res.json()) };