{"version":3,"file":"index.mjs","names":["errorCode: number","requestId?: string","statusCode?: number","response?: unknown","endpointCategory: string","timeoutMs: number","DEFAULT_RETRY_OPTIONS: Required<RetryOptions>","lastError: unknown","ENDPOINT_MATCHERS: Array<{\n  method: string;\n  pattern: RegExp;\n  category: string;\n}>","checks: Array<{ key: string; rule: RateLimitRule; margin: number }>","allProperties: PropertiesData","allRoomTypes: RoomTypesData"],"sources":["../src/utils/error.ts","../src/utils/retry.ts","../src/utils/validation.ts","../src/rate-limiter/config.ts","../src/rate-limiter/rate-limiter.ts","../src/client/index.ts"],"sourcesContent":["/**\n * Error handling utilities\n */\n\nimport { HostexApiResponse } from '../types/index.js';\n\n/**\n * Hostex API error\n */\nexport class HostexApiError extends Error {\n  constructor(\n    message: string,\n    public readonly errorCode: number,\n    public readonly requestId?: string,\n    public readonly statusCode?: number,\n    public readonly response?: unknown\n  ) {\n    super(message);\n    this.name = 'HostexApiError';\n    Object.setPrototypeOf(this, HostexApiError.prototype);\n  }\n\n  /**\n   * Check if this is a specific Hostex error code\n   */\n  isErrorCode(code: number): boolean {\n    return this.errorCode === code;\n  }\n\n  /**\n   * Check if this is a network/timeout error\n   */\n  isNetworkError(): boolean {\n    return !this.statusCode || this.statusCode >= 500;\n  }\n\n  /**\n   * Check if this is an authentication error\n   */\n  isAuthError(): boolean {\n    return this.statusCode === 401 || this.statusCode === 403;\n  }\n\n  /**\n   * Check if this is a rate limit error\n   */\n  isRateLimitError(): boolean {\n    return this.statusCode === 429;\n  }\n\n  /**\n   * Convert to JSON\n   */\n  toJSON(): object {\n    return {\n      name: this.name,\n      message: this.message,\n      errorCode: this.errorCode,\n      requestId: this.requestId,\n      statusCode: this.statusCode,\n    };\n  }\n}\n\n/**\n * Thrown when a request times out waiting for rate limit capacity\n */\nexport class RateLimitTimeoutError extends HostexApiError {\n  constructor(\n    public readonly endpointCategory: string,\n    public readonly timeoutMs: number\n  ) {\n    super(\n      `Rate limit timeout: ${endpointCategory} capacity not available within ${timeoutMs}ms`,\n      429,\n      undefined,\n      429\n    );\n    this.name = 'RateLimitTimeoutError';\n    Object.setPrototypeOf(this, RateLimitTimeoutError.prototype);\n  }\n}\n\n/**\n * Create error from Hostex API response\n */\nexport function createErrorFromResponse(\n  response: HostexApiResponse,\n  statusCode?: number\n): HostexApiError {\n  return new HostexApiError(\n    response.error_msg || 'Unknown error',\n    response.error_code,\n    response.request_id,\n    statusCode,\n    response\n  );\n}\n\n/**\n * Check if error is retryable by the withRetry loop.\n * Note: 429 rate limit errors are NOT retried here because\n * the axios interceptor already handles a one-time retry with delay.\n * Retrying 429s in withRetry causes request multiplication that\n * worsens rate limiting.\n */\nexport function isRetryableError(error: unknown): boolean {\n  if (error instanceof HostexApiError) {\n    return error.isNetworkError();\n  }\n  return false;\n}\n","/**\n * Retry logic utilities\n */\n\nimport { isRetryableError } from './error.js';\n\n/**\n * Retry options\n */\nexport interface RetryOptions {\n  /** Maximum number of retry attempts */\n  maxAttempts?: number;\n  /** Initial delay in milliseconds */\n  initialDelay?: number;\n  /** Maximum delay in milliseconds */\n  maxDelay?: number;\n  /** Backoff multiplier */\n  backoffMultiplier?: number;\n  /** Custom retry condition */\n  shouldRetry?: (error: unknown, attempt: number) => boolean;\n}\n\n/**\n * Default retry options\n */\nexport const DEFAULT_RETRY_OPTIONS: Required<RetryOptions> = {\n  maxAttempts: 3,\n  initialDelay: 1000,\n  maxDelay: 10000,\n  backoffMultiplier: 2,\n  shouldRetry: isRetryableError,\n};\n\n/**\n * Delay for a specified time\n */\nexport function delay(ms: number): Promise<void> {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay with exponential backoff\n */\nexport function calculateBackoff(\n  attempt: number,\n  initialDelay: number,\n  maxDelay: number,\n  multiplier: number\n): number {\n  const exponentialDelay = initialDelay * Math.pow(multiplier, attempt - 1);\n  return Math.min(exponentialDelay, maxDelay);\n}\n\n/**\n * Retry a function with exponential backoff\n */\nexport async function withRetry<T>(\n  fn: () => Promise<T>,\n  options: RetryOptions = {}\n): Promise<T> {\n  const opts = { ...DEFAULT_RETRY_OPTIONS, ...options };\n  let lastError: unknown;\n\n  for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {\n    try {\n      return await fn();\n    } catch (error) {\n      lastError = error;\n\n      // Check if we should retry\n      const shouldRetry = opts.shouldRetry(error, attempt);\n      const hasAttemptsLeft = attempt < opts.maxAttempts;\n\n      if (!shouldRetry || !hasAttemptsLeft) {\n        throw error;\n      }\n\n      // Calculate delay and wait\n      const delayMs = calculateBackoff(\n        attempt,\n        opts.initialDelay,\n        opts.maxDelay,\n        opts.backoffMultiplier\n      );\n\n      await delay(delayMs);\n    }\n  }\n\n  // This should never be reached, but TypeScript needs it\n  throw lastError;\n}\n","/**\n * Input validation utilities\n */\n\n/**\n * Date format regex (YYYY-MM-DD)\n */\nconst DATE_REGEX = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n/**\n * Validate date format (YYYY-MM-DD)\n */\nexport function isValidDate(date: string): boolean {\n  if (!DATE_REGEX.test(date)) {\n    return false;\n  }\n\n  // Check if it's a valid date\n  const d = new Date(date);\n  return d instanceof Date && !isNaN(d.getTime());\n}\n\n/**\n * Validate date format and throw if invalid\n */\nexport function validateDate(date: string, fieldName: string): void {\n  if (!isValidDate(date)) {\n    throw new Error(`${fieldName} must be in YYYY-MM-DD format`);\n  }\n}\n\n/**\n * Validate date range\n */\nexport function validateDateRange(startDate: string, endDate: string): void {\n  validateDate(startDate, 'start_date');\n  validateDate(endDate, 'end_date');\n\n  if (new Date(startDate) >= new Date(endDate)) {\n    throw new Error('start_date must be before end_date');\n  }\n}\n\n/**\n * Validate required field\n */\nexport function validateRequired<T>(\n  value: T | null | undefined,\n  fieldName: string\n): asserts value is T {\n  if (value === null || value === undefined) {\n    throw new Error(`${fieldName} is required`);\n  }\n}\n\n/**\n * Validate array is not empty\n */\nexport function validateNonEmptyArray<T>(\n  value: T[],\n  fieldName: string\n): asserts value is [T, ...T[]] {\n  if (!Array.isArray(value) || value.length === 0) {\n    throw new Error(`${fieldName} must be a non-empty array`);\n  }\n}\n\n/**\n * Validate number is positive\n */\nexport function validatePositive(value: number, fieldName: string): void {\n  if (value <= 0) {\n    throw new Error(`${fieldName} must be positive`);\n  }\n}\n\n/**\n * Validate number is within range\n */\nexport function validateRange(\n  value: number,\n  min: number,\n  max: number,\n  fieldName: string\n): void {\n  if (value < min || value > max) {\n    throw new Error(`${fieldName} must be between ${min} and ${max}`);\n  }\n}\n\n/**\n * Validate URL format\n */\nexport function validateUrl(url: string, fieldName: string): void {\n  try {\n    new URL(url);\n  } catch {\n    throw new Error(`${fieldName} must be a valid URL`);\n  }\n}\n","export interface RateLimitRule {\n  windowMs: number;\n  limit: number;\n}\n\nexport const RATE_LIMIT_RULES = {\n  host: [\n    { windowMs: 60_000, limit: 1_200 },\n    { windowMs: 300_000, limit: 12_000 },\n    { windowMs: 3_600_000, limit: 20_000 },\n    { windowMs: 86_400_000, limit: 100_000 },\n  ] as RateLimitRule[],\n  hostPerEndpoint: [\n    { windowMs: 60_000, limit: 600 },\n    { windowMs: 300_000, limit: 6_000 },\n    { windowMs: 3_600_000, limit: 10_000 },\n    { windowMs: 86_400_000, limit: 50_000 },\n  ] as RateLimitRule[],\n  endpoints: {\n    availabilities: [\n      { windowMs: 60_000, limit: 120 },\n    ] as RateLimitRule[],\n    listings: [\n      { windowMs: 60_000, limit: 120 },\n    ] as RateLimitRule[],\n    reservations: [\n      { windowMs: 60_000, limit: 60 },\n    ] as RateLimitRule[],\n    conversations: [\n      { windowMs: 5_000, limit: 5 },\n      { windowMs: 3_600_000, limit: 1_000 },\n    ] as RateLimitRule[],\n  } as Record<string, RateLimitRule[]>,\n};\n\ntype EndpointCategory = keyof typeof RATE_LIMIT_RULES.endpoints | 'default';\n\nconst ENDPOINT_MATCHERS: Array<{\n  method: string;\n  pattern: RegExp;\n  category: string;\n}> = [\n  { method: 'POST', pattern: /^\\/availabilities/, category: 'availabilities' },\n  { method: 'POST', pattern: /^\\/listings/, category: 'listings' },\n  { method: 'POST', pattern: /^\\/reservations$/, category: 'reservations' },\n  { method: 'POST', pattern: /^\\/conversations/, category: 'conversations' },\n];\n\nexport function categorizeRequest(method: string, url: string): EndpointCategory {\n  const upperMethod = method.toUpperCase();\n  for (const matcher of ENDPOINT_MATCHERS) {\n    if (upperMethod === matcher.method && matcher.pattern.test(url)) {\n      return matcher.category as EndpointCategory;\n    }\n  }\n  return 'default';\n}\n","import { Redis } from '@upstash/redis';\nimport { RateLimitTimeoutError } from '../utils/error.js';\nimport { RATE_LIMIT_RULES, categorizeRequest, type RateLimitRule } from './config.js';\n\nexport interface RateLimiterRedisConfig {\n  url: string;\n  token: string;\n}\n\nexport interface RateLimiterLogger {\n  warn: (message: string, ...args: unknown[]) => void;\n  error: (message: string, ...args: unknown[]) => void;\n}\n\nexport interface RateLimiterConfig {\n  redis: RateLimiterRedisConfig;\n  hostId?: string;\n  timeoutMs?: number;\n  safetyMargin?: number;\n  logger?: RateLimiterLogger;\n}\n\nconst DEFAULT_HOST_ID = 'victor';\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_SAFETY_MARGIN = 0.9;\nconst CONVERSATIONS_5S_SAFETY_MARGIN = 0.6;\nconst POLL_INTERVAL_MS = 1_000;\n\nexport class RateLimiter {\n  private readonly redis: Redis;\n  private readonly hostId: string;\n  private readonly timeoutMs: number;\n  private readonly safetyMargin: number;\n  private readonly logger?: RateLimiterLogger;\n\n  constructor(configOrRedis: RateLimiterConfig | Redis, options?: { hostId?: string; timeoutMs?: number; safetyMargin?: number; logger?: RateLimiterLogger }) {\n    if (configOrRedis instanceof Redis) {\n      this.redis = configOrRedis;\n      this.hostId = options?.hostId ?? DEFAULT_HOST_ID;\n      this.timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n      this.safetyMargin = options?.safetyMargin ?? DEFAULT_SAFETY_MARGIN;\n      this.logger = options?.logger;\n    } else {\n      this.redis = new Redis({\n        url: configOrRedis.redis.url,\n        token: configOrRedis.redis.token,\n      });\n      this.hostId = configOrRedis.hostId ?? DEFAULT_HOST_ID;\n      this.timeoutMs = configOrRedis.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n      this.safetyMargin = configOrRedis.safetyMargin ?? DEFAULT_SAFETY_MARGIN;\n      this.logger = configOrRedis.logger;\n    }\n  }\n\n  /**\n   * Create a RateLimiter using an existing @upstash/redis instance.\n   * Use this to share the Redis connection with other parts of the app.\n   */\n  static fromRedisInstance(\n    redis: Redis,\n    options?: { hostId?: string; timeoutMs?: number; safetyMargin?: number; logger?: RateLimiterLogger }\n  ): RateLimiter {\n    return new RateLimiter(redis, options);\n  }\n\n  /**\n   * Acquire rate limit capacity for a request.\n   * Blocks (polls) until capacity is available or timeout is reached.\n   * Fails closed if Redis is unavailable — throws RateLimitTimeoutError to prevent\n   * unthrottled requests from overwhelming the upstream API.\n   */\n  async acquire(method: string, url: string): Promise<void> {\n    const category = categorizeRequest(method, url);\n    const startTime = Date.now();\n    let queued = false;\n\n    while (true) {\n      try {\n        const allowed = await this.tryAcquire(category);\n        if (allowed) return;\n      } catch (err) {\n        if (err instanceof RateLimitTimeoutError) throw err;\n        // Redis error — fail closed to prevent unthrottled requests\n        this.logger?.error(`Rate limiter Redis error, failing closed`, err);\n        throw new RateLimitTimeoutError(category, this.timeoutMs);\n      }\n\n      if (!queued) {\n        this.logger?.warn(`Rate limit reached for ${category}, queuing request (timeout: ${this.timeoutMs}ms)`);\n        queued = true;\n      }\n\n      const elapsed = Date.now() - startTime;\n      if (elapsed + POLL_INTERVAL_MS > this.timeoutMs) {\n        this.logger?.error(`Rate limit timeout for ${category} after ${this.timeoutMs}ms`);\n        throw new RateLimitTimeoutError(category, this.timeoutMs);\n      }\n\n      await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));\n    }\n  }\n\n  /**\n   * Optimistic add-then-check-rollback.\n   * 1. ZADD our entry to all relevant sorted sets\n   * 2. ZCARD to count entries in each window (includes our entry)\n   * 3. If any window exceeds limit → ZREM our entry from all sets (rollback)\n   */\n  private async tryAcquire(category: string): Promise<boolean> {\n    const now = Date.now();\n    const memberId = `${now}:${Math.random().toString(36).slice(2, 10)}`;\n\n    // Collect all rules to check\n    const checks = this.getChecks(category);\n\n    // Step 1: Clean expired entries + optimistically add our entry\n    const addPipeline = this.redis.pipeline();\n    for (const { key, rule } of checks) {\n      const windowStart = now - rule.windowMs;\n      addPipeline.zremrangebyscore(key, 0, windowStart);\n      addPipeline.zadd(key, { score: now, member: memberId });\n      addPipeline.zcard(key);\n      // Auto-expire key slightly after window to prevent leaks\n      addPipeline.pexpire(key, rule.windowMs + 60_000);\n    }\n    const results = await addPipeline.exec();\n\n    // Step 2: Check if any window exceeds its limit\n    // Results order per check: [zremrangebyscore, zadd, zcard, pexpire]\n    let overLimit = false;\n    for (let i = 0; i < checks.length; i++) {\n      const zcardIndex = i * 4 + 2; // 3rd result per check group\n      const count = results[zcardIndex] as number;\n      const effectiveLimit = Math.floor(checks[i].rule.limit * checks[i].margin);\n      if (count > effectiveLimit) {\n        overLimit = true;\n        break;\n      }\n    }\n\n    // Step 3: If over limit, rollback — remove our entry from all sets\n    if (overLimit) {\n      const rollbackPipeline = this.redis.pipeline();\n      for (const { key } of checks) {\n        rollbackPipeline.zrem(key, memberId);\n      }\n      await rollbackPipeline.exec();\n      return false;\n    }\n\n    return true;\n  }\n\n  private getChecks(category: string): Array<{ key: string; rule: RateLimitRule; margin: number }> {\n    const checks: Array<{ key: string; rule: RateLimitRule; margin: number }> = [];\n\n    // Host-level global limits (apply to all requests)\n    for (const rule of RATE_LIMIT_RULES.host) {\n      checks.push({\n        key: `hostex:rate:${this.hostId}:global:${rule.windowMs}`,\n        rule,\n        margin: this.safetyMargin,\n      });\n    }\n\n    // Host-level per-endpoint limits (if categorized)\n    if (category !== 'default') {\n      for (const rule of RATE_LIMIT_RULES.hostPerEndpoint) {\n        checks.push({\n          key: `hostex:rate:${this.hostId}:${category}:host:${rule.windowMs}`,\n          rule,\n          margin: this.safetyMargin,\n        });\n      }\n    }\n\n    // Endpoint-specific limits\n    const endpointRules = RATE_LIMIT_RULES.endpoints[category];\n    if (endpointRules) {\n      for (const rule of endpointRules) {\n        // Conversations 5/5sec uses a tighter margin due to low absolute limit + race window\n        const margin = (category === 'conversations' && rule.windowMs === 5_000)\n          ? CONVERSATIONS_5S_SAFETY_MARGIN\n          : this.safetyMargin;\n        checks.push({\n          key: `hostex:rate:${this.hostId}:${category}:${rule.windowMs}`,\n          rule,\n          margin,\n        });\n      }\n    }\n\n    return checks;\n  }\n\n  /**\n   * Clean up test keys. Only use in tests.\n   */\n  async cleanup(hostId: string): Promise<void> {\n    try {\n      const prefixes = ['global', 'availabilities', 'listings', 'reservations', 'conversations'];\n      // Derive windows from RATE_LIMIT_RULES to stay in sync\n      const allWindows = new Set<number>();\n      for (const rule of [...RATE_LIMIT_RULES.host, ...RATE_LIMIT_RULES.hostPerEndpoint]) {\n        allWindows.add(rule.windowMs);\n      }\n      for (const rules of Object.values(RATE_LIMIT_RULES.endpoints)) {\n        for (const rule of rules) {\n          allWindows.add(rule.windowMs);\n        }\n      }\n      const pipeline = this.redis.pipeline();\n      for (const prefix of prefixes) {\n        for (const window of allWindows) {\n          pipeline.del(`hostex:rate:${hostId}:${prefix}:${window}`);\n          pipeline.del(`hostex:rate:${hostId}:${prefix}:host:${window}`);\n        }\n      }\n      await pipeline.exec();\n    } catch {\n      // Ignore cleanup errors\n    }\n  }\n}\n","/**\n * Hostex API Client\n * Main client for interacting with the Hostex API v3\n */\n\nimport axios, { AxiosInstance, AxiosRequestConfig, AxiosError } from 'axios';\nimport {\n  HostexApiResponse,\n  PropertiesData,\n  PropertiesQueryParams,\n  CreatePropertyParams,\n  CreatePropertyData,\n  RoomTypesData,\n  RoomTypesQueryParams,\n  CreateRoomTypeParams,\n  CreateRoomTypeData,\n  ReservationsData,\n  ReservationsQueryParams,\n  CreateReservationParams,\n  CreateReservationData,\n  UpdateCheckInDetailsParams,\n  UpdateReservationBasicInfoParams,\n  UpdateStayStatusParams,\n  AddTagParams,\n  RemoveTagParams,\n  MoveToBoxParams,\n  AllocateToPropertyParams,\n  UpdateCustomFieldsParams,\n  CustomFieldsData,\n  CustomChannelsData,\n  IncomeMethodsData,\n  AvailabilitiesData,\n  AvailabilitiesQueryParams,\n  UpdateAvailabilitiesParams,\n  CalendarData,\n  CalendarQueryParams,\n  UpdateListingInventoriesParams,\n  UpdateListingPricesParams,\n  UpdateListingRestrictionsParams,\n  ConversationsData,\n  ConversationsQueryParams,\n  ConversationDetailsData,\n  SendMessageParams,\n  ReviewsData,\n  ReviewsQueryParams,\n  CreateReviewParams,\n  WebhooksData,\n  CreateWebhookParams,\n  UpdateWebhookParams,\n  DeleteWebhookParams,\n  OAuthTokenParams,\n  OAuthTokenData,\n  RevokeTokenParams,\n  ChannelAccountsQueryParams,\n  ChannelAccountsData,\n  ListingsQueryParams,\n  ListingsData,\n  UpdateAirbnbPriceAndRulesParams,\n  UpdateVrboPriceAndRulesParams,\n  PricingRatiosQueryParams,\n  PricingRatiosData,\n  CalendarShareLinksQueryParams,\n  CalendarShareLinksData,\n  CreateCalendarShareLinkParams,\n  CreateCalendarShareLinkData,\n  UpdateConversationNoteParams,\n  UpdateConversationNoteData,\n  GroupsQueryParams,\n  GroupsData,\n  CreateGroupParams,\n  CreateGroupData,\n  UpdateGroupParams,\n  TagsQueryParams,\n  TagsData,\n  CreateTagParams,\n  CreateTagData,\n  UpdateTagParams,\n  ReservationTagsQueryParams,\n  ReservationTagsData,\n  CreateReservationTagParams,\n  CreateReservationTagData,\n  StaffsQueryParams,\n  StaffsData,\n  CreateStaffParams,\n  CreateStaffData,\n  UpdateStaffParams,\n  TasksQueryParams,\n  TasksData,\n  CreateTaskParams,\n  CreateTaskData,\n  UpdateTaskParams,\n  IncomeItemsData,\n  ExpenseItemsData,\n  ExpenseMethodsData,\n  TransactionsQueryParams,\n  TransactionsData,\n  CreateTransactionParams,\n  CreateTransactionData,\n  UpdateTransactionParams,\n  KnowledgeBasesQueryParams,\n  KnowledgeBasesData,\n  KnowledgeBaseDetail,\n  CreateKnowledgeBaseParams,\n  UpdateKnowledgeBaseParams,\n  AutomationActionsQueryParams,\n  AutomationActionsData,\n} from '../types/index.js';\nimport { HostexApiError, createErrorFromResponse } from '../utils/error.js';\nimport { withRetry, RetryOptions } from '../utils/retry.js';\nimport {\n  validateDateRange,\n  validateRequired,\n  validateNonEmptyArray,\n  validateUrl,\n} from '../utils/validation.js';\nimport { RateLimiter, type RateLimiterConfig } from '../rate-limiter/index.js';\n\n/**\n * Client configuration options\n */\nexport interface HostexApiClientConfig {\n  /** Hostex access token */\n  accessToken: string;\n  /** API base URL (default: https://api.hostex.io/v3) */\n  baseUrl?: string;\n  /** Request timeout in milliseconds (default: 30000) */\n  timeout?: number;\n  /** Retry options */\n  retry?: RetryOptions;\n  /** Throttle options for mutation requests to avoid rate limiting */\n  throttle?: {\n    /** Minimum delay in ms between mutation requests (POST/PUT/PATCH/DELETE). Default: 0 (no throttle) */\n    minDelayMs?: number;\n  };\n  /** Rate limiter — either config to create one, or a pre-built RateLimiter instance */\n  rateLimiter?: RateLimiterConfig | RateLimiter;\n}\n\n/**\n * Hostex API Client\n */\nexport class HostexApiClient {\n  private readonly axios: AxiosInstance;\n  private readonly retryOptions: RetryOptions;\n  private readonly throttleMinDelayMs: number;\n  private readonly rateLimiter?: RateLimiter;\n  private lastMutationTime = 0;\n  private throttleQueue: Promise<void> = Promise.resolve();\n\n  constructor(config: HostexApiClientConfig) {\n    validateRequired(config.accessToken, 'accessToken');\n\n    this.retryOptions = config.retry || {};\n    this.throttleMinDelayMs = config.throttle?.minDelayMs ?? 0;\n\n    if (config.rateLimiter) {\n      this.rateLimiter = config.rateLimiter instanceof RateLimiter\n        ? config.rateLimiter\n        : new RateLimiter(config.rateLimiter);\n    }\n\n    this.axios = axios.create({\n      baseURL: config.baseUrl || 'https://api.hostex.io/v3',\n      timeout: config.timeout || 30000,\n      headers: {\n        'accept': 'application/json',\n        'Content-Type': 'application/json',\n        'Hostex-Access-Token': config.accessToken,\n      },\n    });\n\n    this.setupInterceptors();\n  }\n\n  private static readonly MUTATION_METHODS = new Set(['post', 'put', 'patch', 'delete']);\n  private static readonly RATE_LIMIT_RETRY_DELAY_MS = 65_000;\n\n  /**\n   * Setup axios interceptors for throttling and error handling\n   */\n  private setupInterceptors(): void {\n    // Request interceptor: cross-process rate limiting via Redis\n    if (this.rateLimiter) {\n      const limiter = this.rateLimiter;\n      this.axios.interceptors.request.use(async (config) => {\n        const method = (config.method || 'get').toUpperCase();\n        const url = config.url || '';\n        await limiter.acquire(method, url);\n        return config;\n      });\n    }\n\n    // Request interceptor: throttle mutation requests to stay under rate limits.\n    // Uses a promise chain so concurrent callers serialize properly —\n    // even if two cron ticks overlap, only one mutation fires at a time.\n    this.axios.interceptors.request.use(async (config) => {\n      const method = (config.method || 'get').toLowerCase();\n      if (this.throttleMinDelayMs > 0 && HostexApiClient.MUTATION_METHODS.has(method)) {\n        await new Promise<void>((resolve) => {\n          this.throttleQueue = this.throttleQueue.then(async () => {\n            const elapsed = Date.now() - this.lastMutationTime;\n            const wait = this.throttleMinDelayMs - elapsed;\n            if (wait > 0) {\n              await new Promise((r) => setTimeout(r, wait));\n            }\n            this.lastMutationTime = Date.now();\n            resolve();\n          });\n        });\n      }\n      return config;\n    });\n\n    // Response interceptor: error handling + one-time retry on rate limit\n    this.axios.interceptors.response.use(\n      (response) => {\n        // Check for Hostex API error codes\n        const data = response.data as HostexApiResponse;\n        if (data.error_code && data.error_code !== 200) {\n          throw createErrorFromResponse(data, response.status);\n        }\n        return response;\n      },\n      async (error: AxiosError) => {\n        // Detect rate limiting: HTTP 429 or \"Too Many Attempts\" message\n        if (this.isRateLimitError(error) && !((error.config as any)?._rateLimitRetried)) {\n          const config = error.config;\n          if (config) {\n            (config as any)._rateLimitRetried = true;\n            await new Promise((resolve) =>\n              setTimeout(resolve, HostexApiClient.RATE_LIMIT_RETRY_DELAY_MS)\n            );\n            // Reset mutation timestamp so throttle doesn't double-wait\n            this.lastMutationTime = 0;\n            return this.axios.request(config);\n          }\n        }\n\n        if (error.response) {\n          const data = error.response.data as HostexApiResponse;\n          throw createErrorFromResponse(data, error.response.status);\n        }\n        // Network or timeout error\n        throw new HostexApiError(\n          error.message || 'Network error',\n          0,\n          undefined,\n          error.code === 'ECONNABORTED' ? 408 : 500\n        );\n      }\n    );\n  }\n\n  /**\n   * Check if an error is a rate limit (\"Too Many Attempts\") error\n   */\n  private isRateLimitError(error: AxiosError): boolean {\n    if (error.response?.status === 429) return true;\n    const data = error.response?.data;\n    if (typeof data === 'object' && data !== null) {\n      const message = (data as any).message || (data as any).error_message || '';\n      if (typeof message === 'string' && message.toLowerCase().includes('too many attempts')) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  /**\n   * Make a request with retry logic\n   */\n  private async request<T>(config: AxiosRequestConfig): Promise<T> {\n    return withRetry(async () => {\n      const response = await this.axios.request<HostexApiResponse<T>>(config);\n      return response.data.data as T;\n    }, this.retryOptions);\n  }\n\n  // =====================\n  // Properties API\n  // =====================\n\n  /**\n   * Query properties\n   * @see https://docs.hostex.io/reference/query-properties\n   */\n  async getProperties(params?: PropertiesQueryParams): Promise<PropertiesData> {\n    return this.request<PropertiesData>({\n      method: 'GET',\n      url: '/properties',\n      params,\n    });\n  }\n\n  /**\n   * Get all properties (handles pagination automatically)\n   */\n  async getAllProperties(): Promise<PropertiesData> {\n    const allProperties: PropertiesData = { properties: [], total: 0 };\n    let offset = 0;\n    const limit = 100;\n\n    while (true) {\n      const data = await this.getProperties({ offset, limit });\n      allProperties.properties.push(...data.properties);\n      allProperties.total = data.total;\n\n      if (data.properties.length < limit) break;\n      offset += limit;\n    }\n\n    return allProperties;\n  }\n\n  /**\n   * Create a property\n   * @see https://docs.hostex.io/reference/create-property\n   */\n  async createProperty(params: CreatePropertyParams): Promise<HostexApiResponse<CreatePropertyData>> {\n    validateRequired(params.title, 'title');\n    const response = await this.axios.post<HostexApiResponse<CreatePropertyData>>('/properties', params);\n    return response.data;\n  }\n\n  // =====================\n  // Room Types API\n  // =====================\n\n  /**\n   * Query room types\n   * @see https://docs.hostex.io/reference/query-room-types\n   */\n  async getRoomTypes(params?: RoomTypesQueryParams): Promise<RoomTypesData> {\n    return this.request<RoomTypesData>({\n      method: 'GET',\n      url: '/room_types',\n      params: {\n        ...params,\n        offset: params?.offset ?? 0,\n        limit: params?.limit ?? 20,\n      },\n    });\n  }\n\n  /**\n   * Get all room types (handles pagination automatically)\n   */\n  async getAllRoomTypes(): Promise<RoomTypesData> {\n    const allRoomTypes: RoomTypesData = { room_types: [], total: 0 };\n    let offset = 0;\n    const limit = 100;\n\n    while (true) {\n      const data = await this.getRoomTypes({ offset, limit });\n      allRoomTypes.room_types.push(...data.room_types);\n      allRoomTypes.total = data.total;\n\n      if (data.room_types.length < limit) break;\n      offset += limit;\n    }\n\n    return allRoomTypes;\n  }\n\n  /**\n   * Create a room type\n   * @see https://docs.hostex.io/reference/create-roomtype\n   */\n  async createRoomType(params: CreateRoomTypeParams): Promise<HostexApiResponse<CreateRoomTypeData>> {\n    validateRequired(params.title, 'title');\n    const response = await this.axios.post<HostexApiResponse<CreateRoomTypeData>>('/room_types', params);\n    return response.data;\n  }\n\n  // =====================\n  // Reservations API\n  // =====================\n\n  /**\n   * Query reservations\n   * @see https://docs.hostex.io/reference/query-reservations\n   */\n  async getReservations(params?: ReservationsQueryParams): Promise<ReservationsData> {\n    return this.request<ReservationsData>({\n      method: 'GET',\n      url: '/reservations',\n      params,\n    });\n  }\n\n  /**\n   * Create a reservation (direct booking)\n   * @see https://docs.hostex.io/reference/create-reservation\n   */\n  async createReservation(params: CreateReservationParams): Promise<HostexApiResponse<CreateReservationData>> {\n    validateRequired(params.property_id, 'property_id');\n    validateRequired(params.custom_channel_id, 'custom_channel_id');\n    validateRequired(params.check_in_date, 'check_in_date');\n    validateRequired(params.check_out_date, 'check_out_date');\n    validateRequired(params.guest_name, 'guest_name');\n    validateRequired(params.currency, 'currency');\n    validateRequired(params.rate_amount, 'rate_amount');\n    validateRequired(params.commission_amount, 'commission_amount');\n    validateRequired(params.received_amount, 'received_amount');\n    validateRequired(params.income_method_id, 'income_method_id');\n    validateDateRange(params.check_in_date, params.check_out_date);\n\n    const response = await this.axios.post<HostexApiResponse<CreateReservationData>>('/reservations', params);\n    return response.data;\n  }\n\n  /**\n   * Cancel a reservation (direct booking only)\n   * @see https://docs.hostex.io/reference/cancel-reservation\n   */\n  async cancelReservation(reservationCode: string): Promise<HostexApiResponse> {\n    validateRequired(reservationCode, 'reservationCode');\n\n    const response = await this.axios.delete<HostexApiResponse>(\n      `/reservations/${reservationCode}`\n    );\n    return response.data;\n  }\n\n  /**\n   * Approve a pending reservation request\n   * The reservation must be in `wait_accept` status.\n   * @see https://docs.hostex.io/reference/approve-reservation\n   */\n  async approveReservation(reservationCode: string): Promise<HostexApiResponse> {\n    validateRequired(reservationCode, 'reservationCode');\n\n    const response = await this.axios.post<HostexApiResponse>(\n      `/reservations/${reservationCode}/approve`\n    );\n    return response.data;\n  }\n\n  /**\n   * Decline a pending reservation request\n   * The reservation must be in `wait_accept` status.\n   * @see https://docs.hostex.io/reference/decline-reservation\n   */\n  async declineReservation(reservationCode: string): Promise<HostexApiResponse> {\n    validateRequired(reservationCode, 'reservationCode');\n\n    const response = await this.axios.post<HostexApiResponse>(\n      `/reservations/${reservationCode}/decline`\n    );\n    return response.data;\n  }\n\n  /**\n   * Update reservation basic info\n   * @see https://docs.hostex.io/reference/update-reservation-basic-info\n   */\n  async updateReservationBasicInfo(params: UpdateReservationBasicInfoParams): Promise<HostexApiResponse> {\n    const { stay_code, reservation_code, ...body } = params;\n    const code = stay_code ?? reservation_code;\n    validateRequired(code, 'stay_code');\n\n    const response = await this.axios.patch<HostexApiResponse>(\n      `/reservations/${code}`,\n      body\n    );\n    return response.data;\n  }\n\n  /**\n   * Update check-in details for a stay\n   * @see https://docs.hostex.io/reference/update-check-in-details\n   */\n  async updateCheckInDetails(params: UpdateCheckInDetailsParams): Promise<HostexApiResponse> {\n    validateRequired(params.stay_code, 'stay_code');\n\n    const { stay_code, ...body } = params;\n    const response = await this.axios.patch<HostexApiResponse>(\n      `/reservations/${stay_code}/check_in_details`,\n      body\n    );\n    return response.data;\n  }\n\n  /**\n   * Update stay status\n   * @see https://docs.hostex.io/reference/update-stay-status\n   */\n  async updateStayStatus(params: UpdateStayStatusParams): Promise<HostexApiResponse> {\n    validateRequired(params.stay_code, 'stay_code');\n    validateRequired(params.stay_status, 'stay_status');\n\n    const response = await this.axios.put<HostexApiResponse>(\n      `/reservations/${params.stay_code}/stay_status`,\n      { stay_status: params.stay_status }\n    );\n    return response.data;\n  }\n\n  /**\n   * Add a tag to a reservation\n   * @see https://docs.hostex.io/reference/add-tag\n   */\n  async addTag(params: AddTagParams): Promise<HostexApiResponse> {\n    validateRequired(params.stay_code, 'stay_code');\n    validateRequired(params.tag_name, 'tag_name');\n\n    const response = await this.axios.post<HostexApiResponse>(\n      `/reservations/${params.stay_code}/tags`,\n      { tag_name: params.tag_name }\n    );\n    return response.data;\n  }\n\n  /**\n   * Remove a tag from a reservation\n   * @see https://docs.hostex.io/reference/remove-tag\n   */\n  async removeTag(params: RemoveTagParams): Promise<HostexApiResponse> {\n    validateRequired(params.stay_code, 'stay_code');\n    validateRequired(params.tag_name, 'tag_name');\n\n    const response = await this.axios.delete<HostexApiResponse>(\n      `/reservations/${params.stay_code}/tags`,\n      { data: { tag_name: params.tag_name } }\n    );\n    return response.data;\n  }\n\n  /**\n   * Move a stay to the reservation box\n   * @see https://docs.hostex.io/reference/move-reservation-to-box\n   */\n  async moveToBox(params: MoveToBoxParams): Promise<HostexApiResponse> {\n    validateRequired(params.stay_code, 'stay_code');\n\n    const response = await this.axios.post<HostexApiResponse>(\n      `/reservations/${params.stay_code}/move_to_box`\n    );\n    return response.data;\n  }\n\n  /**\n   * Allocate a reservation to a property\n   * @see https://docs.hostex.io/reference/allocate-reservation\n   */\n  async allocateToProperty(params: AllocateToPropertyParams): Promise<HostexApiResponse> {\n    validateRequired(params.stay_code, 'stay_code');\n    validateRequired(params.property_id, 'property_id');\n\n    const response = await this.axios.post<HostexApiResponse>(\n      `/reservations/${params.stay_code}/allocate`,\n      { property_id: params.property_id }\n    );\n    return response.data;\n  }\n\n  /**\n   * Query custom fields for a stay\n   * @see https://docs.hostex.io/reference/query-custom-fields\n   */\n  async getCustomFields(stayCode: string): Promise<CustomFieldsData> {\n    validateRequired(stayCode, 'stayCode');\n\n    return this.request<CustomFieldsData>({\n      method: 'GET',\n      url: `/reservations/${stayCode}/custom_fields`,\n    });\n  }\n\n  /**\n   * Update custom fields for a stay\n   * @see https://docs.hostex.io/reference/update-custom-fields\n   */\n  async updateCustomFields(params: UpdateCustomFieldsParams): Promise<CustomFieldsData> {\n    validateRequired(params.stay_code, 'stay_code');\n    validateRequired(params.custom_fields, 'custom_fields');\n\n    return this.request<CustomFieldsData>({\n      method: 'PATCH',\n      url: `/reservations/${params.stay_code}/custom_fields`,\n      data: { custom_fields: params.custom_fields },\n    });\n  }\n\n  /**\n   * Query custom channels\n   * @see https://docs.hostex.io/reference/query-custom-channels\n   */\n  async getCustomChannels(): Promise<CustomChannelsData> {\n    return this.request<CustomChannelsData>({\n      method: 'GET',\n      url: '/custom_channels',\n    });\n  }\n\n  /**\n   * Query income methods\n   * @see https://docs.hostex.io/reference/query-income-methods\n   */\n  async getIncomeMethods(): Promise<IncomeMethodsData> {\n    return this.request<IncomeMethodsData>({\n      method: 'GET',\n      url: '/income_methods',\n    });\n  }\n\n  // =====================\n  // Availability API\n  // =====================\n\n  /**\n   * Query property availabilities\n   * @see https://docs.hostex.io/reference/query-availabilities\n   */\n  async getAvailabilities(params: AvailabilitiesQueryParams): Promise<AvailabilitiesData> {\n    const propertyIds = Array.isArray(params.property_ids)\n      ? params.property_ids.join(',')\n      : params.property_ids;\n\n    validateRequired(propertyIds, 'property_ids');\n    validateDateRange(params.start_date, params.end_date);\n\n    return this.request<AvailabilitiesData>({\n      method: 'GET',\n      url: '/availabilities',\n      params: {\n        property_ids: propertyIds,\n        start_date: params.start_date,\n        end_date: params.end_date,\n      },\n    });\n  }\n\n  /**\n   * Update property availabilities\n   * @see https://docs.hostex.io/reference/update-availabilities\n   */\n  async updateAvailabilities(params: UpdateAvailabilitiesParams): Promise<HostexApiResponse> {\n    validateNonEmptyArray(params.property_ids, 'property_ids');\n    validateRequired(params.available, 'available');\n\n    if (params.start_date && params.end_date) {\n      validateDateRange(params.start_date, params.end_date);\n    } else if (!params.dates || params.dates.length === 0) {\n      throw new Error('Either start_date+end_date or dates must be provided');\n    }\n\n    const response = await this.axios.post<HostexApiResponse>('/availabilities', params);\n    return response.data;\n  }\n\n  // =====================\n  // Listing Calendar API\n  // =====================\n\n  /**\n   * Query listing calendars\n   * @see https://docs.hostex.io/reference/query-listing-calendars\n   */\n  async getListingCalendars(params: CalendarQueryParams): Promise<CalendarData> {\n    validateRequired(params.start_date, 'start_date');\n    validateRequired(params.end_date, 'end_date');\n    validateNonEmptyArray(params.listings, 'listings');\n    validateDateRange(params.start_date, params.end_date);\n\n    return this.request<CalendarData>({\n      method: 'POST',\n      url: '/listings/calendar',\n      data: params,\n    });\n  }\n\n  /**\n   * Update listing inventories\n   * @see https://docs.hostex.io/reference/update-listing-inventories\n   */\n  async updateListingInventories(\n    params: UpdateListingInventoriesParams\n  ): Promise<HostexApiResponse> {\n    validateRequired(params.channel_type, 'channel_type');\n    validateRequired(params.listing_id, 'listing_id');\n    validateNonEmptyArray(params.inventories, 'inventories');\n\n    const response = await this.axios.post<HostexApiResponse>(\n      '/listings/inventories',\n      params\n    );\n    return response.data;\n  }\n\n  /**\n   * Update listing prices\n   * @see https://docs.hostex.io/reference/update-listing-prices\n   */\n  async updateListingPrices(params: UpdateListingPricesParams): Promise<HostexApiResponse> {\n    validateRequired(params.channel_type, 'channel_type');\n    validateRequired(params.listing_id, 'listing_id');\n    validateNonEmptyArray(params.prices, 'prices');\n\n    const response = await this.axios.post<HostexApiResponse>('/listings/prices', params);\n    return response.data;\n  }\n\n  /**\n   * Update listing restrictions\n   * @see https://docs.hostex.io/reference/update-listing-restrictions\n   */\n  async updateListingRestrictions(\n    params: UpdateListingRestrictionsParams\n  ): Promise<HostexApiResponse> {\n    validateRequired(params.channel_type, 'channel_type');\n    validateRequired(params.listing_id, 'listing_id');\n    validateNonEmptyArray(params.restrictions, 'restrictions');\n\n    const response = await this.axios.post<HostexApiResponse>(\n      '/listings/restrictions',\n      params\n    );\n    return response.data;\n  }\n\n  // =====================\n  // Listings Catalogue API\n  // =====================\n\n  /**\n   * Query channel accounts\n   * @see https://docs.hostex.io/reference/query-channel-accounts\n   */\n  async getChannelAccounts(params?: ChannelAccountsQueryParams): Promise<ChannelAccountsData> {\n    return this.request<ChannelAccountsData>({\n      method: 'GET',\n      url: '/channel_accounts',\n      params,\n    });\n  }\n\n  /**\n   * Query channel listings\n   * @see https://docs.hostex.io/reference/query-listings\n   */\n  async getListings(params?: ListingsQueryParams): Promise<ListingsData> {\n    return this.request<ListingsData>({\n      method: 'GET',\n      url: '/listings',\n      params,\n    });\n  }\n\n  /**\n   * Update Airbnb listing price and rules\n   * @see https://docs.hostex.io/reference/update-airbnb-listing-price-and-rules\n   */\n  async updateAirbnbPriceAndRules(params: UpdateAirbnbPriceAndRulesParams): Promise<HostexApiResponse> {\n    validateRequired(params.listing_id, 'listing_id');\n    validateRequired(params.settings, 'settings');\n    const response = await this.axios.post<HostexApiResponse>('/listings/airbnb/price_and_rules', params);\n    return response.data;\n  }\n\n  /**\n   * Update Vrbo listing price and rules\n   * @see https://docs.hostex.io/reference/update-vrbo-listing-price-and-rules\n   */\n  async updateVrboPriceAndRules(params: UpdateVrboPriceAndRulesParams): Promise<HostexApiResponse> {\n    validateRequired(params.listing_id, 'listing_id');\n    validateRequired(params.settings, 'settings');\n    const response = await this.axios.post<HostexApiResponse>('/listings/vrbo/price_and_rules', params);\n    return response.data;\n  }\n\n  /**\n   * Query pricing ratios for a property or room type\n   * @see https://docs.hostex.io/reference/query-pricing-ratios\n   */\n  async getPricingRatios(params: PricingRatiosQueryParams): Promise<PricingRatiosData> {\n    const hasProperty = params.property_id != null;\n    const hasRoomType = params.room_type_id != null;\n    if (hasProperty === hasRoomType) {\n      throw new HostexApiError(\n        'Exactly one of property_id or room_type_id is required',\n        0,\n        undefined,\n        400\n      );\n    }\n    return this.request<PricingRatiosData>({\n      method: 'GET',\n      url: '/pricing_ratios',\n      params,\n    });\n  }\n\n  // =====================\n  // Calendar Share Links API\n  // =====================\n\n  /**\n   * Query calendar share links\n   * @see https://docs.hostex.io/reference/query-calendar-share-links\n   */\n  async getCalendarShareLinks(params?: CalendarShareLinksQueryParams): Promise<CalendarShareLinksData> {\n    return this.request<CalendarShareLinksData>({\n      method: 'GET',\n      url: '/calendar_share_links',\n      params,\n    });\n  }\n\n  /**\n   * Create a calendar share link\n   * @see https://docs.hostex.io/reference/create-calendar-share-link\n   */\n  async createCalendarShareLink(\n    params: CreateCalendarShareLinkParams\n  ): Promise<HostexApiResponse<CreateCalendarShareLinkData>> {\n    validateRequired(params.scope, 'scope');\n    if (params.scope === 'partial') {\n      // validateRequired narrows property_ids from number[] | undefined so the\n      // strict-mode signature of validateNonEmptyArray (value: T[]) accepts it\n      validateRequired(params.property_ids, 'property_ids');\n      validateNonEmptyArray(params.property_ids, 'property_ids');\n    }\n    const response = await this.axios.post<HostexApiResponse<CreateCalendarShareLinkData>>(\n      '/calendar_share_links',\n      params\n    );\n    return response.data;\n  }\n\n  /**\n   * Delete a calendar share link\n   * @see https://docs.hostex.io/reference/delete-calendar-share-link\n   */\n  async deleteCalendarShareLink(id: number): Promise<HostexApiResponse> {\n    validateRequired(id, 'id');\n    const response = await this.axios.delete<HostexApiResponse>(`/calendar_share_links/${id}`);\n    return response.data;\n  }\n\n  // =====================\n  // Messages API\n  // =====================\n\n  /**\n   * Query conversations\n   * @see https://docs.hostex.io/reference/query-conversations\n   */\n  async getConversations(params?: ConversationsQueryParams): Promise<ConversationsData> {\n    return this.request<ConversationsData>({\n      method: 'GET',\n      url: '/conversations',\n      params: {\n        offset: params?.offset ?? 0,\n        limit: params?.limit ?? 20,\n      },\n    });\n  }\n\n  /**\n   * Get conversation details\n   * @see https://docs.hostex.io/reference/get-conversation-details\n   */\n  async getConversationDetails(conversationId: string): Promise<ConversationDetailsData> {\n    validateRequired(conversationId, 'conversationId');\n\n    return this.request<ConversationDetailsData>({\n      method: 'GET',\n      url: `/conversations/${conversationId}`,\n    });\n  }\n\n  /**\n   * Send a message\n   * @see https://docs.hostex.io/reference/send-message\n   */\n  async sendMessage(params: SendMessageParams): Promise<HostexApiResponse> {\n    validateRequired(params.conversation_id, 'conversation_id');\n\n    if (!params.message && !params.jpeg_base64) {\n      throw new Error('Either message or jpeg_base64 must be provided');\n    }\n\n    const response = await this.axios.post<HostexApiResponse>(\n      `/conversations/${params.conversation_id}`,\n      {\n        message: params.message,\n        jpeg_base64: params.jpeg_base64,\n      }\n    );\n    return response.data;\n  }\n\n  /**\n   * Update the host-side private note on a conversation\n   * @see https://docs.hostex.io/reference/update-conversation-note\n   */\n  async updateConversationNote(\n    params: UpdateConversationNoteParams\n  ): Promise<HostexApiResponse<UpdateConversationNoteData>> {\n    validateRequired(params.conversation_id, 'conversation_id');\n    const response = await this.axios.patch<HostexApiResponse<UpdateConversationNoteData>>(\n      `/conversations/${params.conversation_id}/note`,\n      { note: params.note }\n    );\n    return response.data;\n  }\n\n  // =====================\n  // Reviews API\n  // =====================\n\n  /**\n   * Query reviews\n   * @see https://docs.hostex.io/reference/query-reviews\n   */\n  async getReviews(params?: ReviewsQueryParams): Promise<ReviewsData> {\n    return this.request<ReviewsData>({\n      method: 'GET',\n      url: '/reviews',\n      params: {\n        offset: params?.offset ?? 0,\n        limit: params?.limit ?? 20,\n        ...params,\n      },\n    });\n  }\n\n  /**\n   * Create or update a review\n   * @see https://docs.hostex.io/reference/create-review\n   */\n  async createReview(params: CreateReviewParams): Promise<HostexApiResponse> {\n    validateRequired(params.reservation_code, 'reservation_code');\n\n    const response = await this.axios.post<HostexApiResponse>(\n      `/reviews/${params.reservation_code}`,\n      {\n        host_review_score: params.host_review_score,\n        host_review_content: params.host_review_content,\n        host_reply_content: params.host_reply_content,\n        category_ratings: params.category_ratings,\n      }\n    );\n    return response.data;\n  }\n\n  // =====================\n  // Groups API\n  // =====================\n\n  /**\n   * Query groups\n   * @see https://docs.hostex.io/reference/query-groups\n   */\n  async getGroups(params?: GroupsQueryParams): Promise<GroupsData> {\n    return this.request<GroupsData>({ method: 'GET', url: '/groups', params });\n  }\n\n  /**\n   * Create a group\n   * @see https://docs.hostex.io/reference/create-group\n   */\n  async createGroup(params: CreateGroupParams): Promise<HostexApiResponse<CreateGroupData>> {\n    validateRequired(params.name, 'name');\n    const response = await this.axios.post<HostexApiResponse<CreateGroupData>>('/groups', params);\n    return response.data;\n  }\n\n  /**\n   * Update a group\n   * @see https://docs.hostex.io/reference/update-group\n   */\n  async updateGroup(params: UpdateGroupParams): Promise<HostexApiResponse> {\n    validateRequired(params.id, 'id');\n    const { id, ...body } = params;\n    const response = await this.axios.patch<HostexApiResponse>(`/groups/${id}`, body);\n    return response.data;\n  }\n\n  /**\n   * Delete a group\n   * @see https://docs.hostex.io/reference/delete-group\n   */\n  async deleteGroup(id: number): Promise<HostexApiResponse> {\n    validateRequired(id, 'id');\n    const response = await this.axios.delete<HostexApiResponse>(`/groups/${id}`);\n    return response.data;\n  }\n\n  // =====================\n  // Tags API (property / room type tags)\n  // =====================\n\n  /**\n   * Query tags\n   * @see https://docs.hostex.io/reference/query-tags\n   */\n  async getTags(params?: TagsQueryParams): Promise<TagsData> {\n    return this.request<TagsData>({ method: 'GET', url: '/tags', params });\n  }\n\n  /**\n   * Create a tag\n   * @see https://docs.hostex.io/reference/create-tag\n   */\n  async createTag(params: CreateTagParams): Promise<HostexApiResponse<CreateTagData>> {\n    validateRequired(params.name, 'name');\n    const response = await this.axios.post<HostexApiResponse<CreateTagData>>('/tags', params);\n    return response.data;\n  }\n\n  /**\n   * Update a tag\n   * @see https://docs.hostex.io/reference/update-tag\n   */\n  async updateTag(params: UpdateTagParams): Promise<HostexApiResponse> {\n    validateRequired(params.id, 'id');\n    const { id, ...body } = params;\n    const response = await this.axios.patch<HostexApiResponse>(`/tags/${id}`, body);\n    return response.data;\n  }\n\n  /**\n   * Delete a tag\n   * @see https://docs.hostex.io/reference/delete-tag\n   */\n  async deleteTag(id: number): Promise<HostexApiResponse> {\n    validateRequired(id, 'id');\n    const response = await this.axios.delete<HostexApiResponse>(`/tags/${id}`);\n    return response.data;\n  }\n\n  // =====================\n  // Reservation Tags API (tag dictionary for stays)\n  // =====================\n\n  /**\n   * Query reservation tags\n   * @see https://docs.hostex.io/reference/query-reservation-tags\n   */\n  async getReservationTags(params?: ReservationTagsQueryParams): Promise<ReservationTagsData> {\n    return this.request<ReservationTagsData>({ method: 'GET', url: '/reservation_tags', params });\n  }\n\n  /**\n   * Create a reservation tag\n   * @see https://docs.hostex.io/reference/create-reservation-tag\n   */\n  async createReservationTag(\n    params: CreateReservationTagParams\n  ): Promise<HostexApiResponse<CreateReservationTagData>> {\n    validateRequired(params.tag_name, 'tag_name');\n    const response = await this.axios.post<HostexApiResponse<CreateReservationTagData>>(\n      '/reservation_tags',\n      params\n    );\n    return response.data;\n  }\n\n  /**\n   * Delete a reservation tag\n   * @see https://docs.hostex.io/reference/delete-reservation-tag\n   */\n  async deleteReservationTag(id: number): Promise<HostexApiResponse> {\n    validateRequired(id, 'id');\n    const response = await this.axios.delete<HostexApiResponse>(`/reservation_tags/${id}`);\n    return response.data;\n  }\n\n  // =====================\n  // Staffs API\n  // =====================\n\n  /**\n   * Query staffs\n   * @see https://docs.hostex.io/reference/query-staffs\n   */\n  async getStaffs(params?: StaffsQueryParams): Promise<StaffsData> {\n    return this.request<StaffsData>({ method: 'GET', url: '/staffs', params });\n  }\n\n  /**\n   * Create a staff\n   * @see https://docs.hostex.io/reference/create-staff\n   */\n  async createStaff(params: CreateStaffParams): Promise<HostexApiResponse<CreateStaffData>> {\n    validateRequired(params.name, 'name');\n    validateRequired(params.mobile, 'mobile');\n    const response = await this.axios.post<HostexApiResponse<CreateStaffData>>('/staffs', params);\n    return response.data;\n  }\n\n  /**\n   * Update a staff\n   * @see https://docs.hostex.io/reference/update-staff\n   */\n  async updateStaff(params: UpdateStaffParams): Promise<HostexApiResponse> {\n    validateRequired(params.id, 'id');\n    const { id, ...body } = params;\n    const response = await this.axios.patch<HostexApiResponse>(`/staffs/${id}`, body);\n    return response.data;\n  }\n\n  /**\n   * Delete a staff\n   * @see https://docs.hostex.io/reference/delete-staff\n   */\n  async deleteStaff(id: number): Promise<HostexApiResponse> {\n    validateRequired(id, 'id');\n    const response = await this.axios.delete<HostexApiResponse>(`/staffs/${id}`);\n    return response.data;\n  }\n\n  // =====================\n  // Tasks API\n  // =====================\n\n  /**\n   * Query tasks\n   * @see https://docs.hostex.io/reference/query-tasks\n   */\n  async getTasks(params?: TasksQueryParams): Promise<TasksData> {\n    return this.request<TasksData>({ method: 'GET', url: '/tasks', params });\n  }\n\n  /**\n   * Create a task\n   * @see https://docs.hostex.io/reference/create-task\n   */\n  async createTask(params: CreateTaskParams): Promise<HostexApiResponse<CreateTaskData>> {\n    validateRequired(params.type, 'type');\n    validateRequired(params.expected_date, 'expected_date');\n    validateRequired(params.currency, 'currency');\n    const response = await this.axios.post<HostexApiResponse<CreateTaskData>>('/tasks', params);\n    return response.data;\n  }\n\n  /**\n   * Update a task\n   * @see https://docs.hostex.io/reference/update-task\n   */\n  async updateTask(params: UpdateTaskParams): Promise<HostexApiResponse> {\n    validateRequired(params.id, 'id');\n    const { id, ...body } = params;\n    const response = await this.axios.patch<HostexApiResponse>(`/tasks/${id}`, body);\n    return response.data;\n  }\n\n  /**\n   * Delete a task\n   * @see https://docs.hostex.io/reference/delete-task\n   */\n  async deleteTask(id: number): Promise<HostexApiResponse> {\n    validateRequired(id, 'id');\n    const response = await this.axios.delete<HostexApiResponse>(`/tasks/${id}`);\n    return response.data;\n  }\n\n  // =====================\n  // Incomes & Expenses API\n  // =====================\n\n  /**\n   * Query income items\n   * @see https://docs.hostex.io/reference/query-income-items\n   */\n  async getIncomeItems(): Promise<IncomeItemsData> {\n    return this.request<IncomeItemsData>({ method: 'GET', url: '/income_items' });\n  }\n\n  /**\n   * Query expense items\n   * @see https://docs.hostex.io/reference/query-expense-items\n   */\n  async getExpenseItems(): Promise<ExpenseItemsData> {\n    return this.request<ExpenseItemsData>({ method: 'GET', url: '/expense_items' });\n  }\n\n  /**\n   * Query expense methods\n   * @see https://docs.hostex.io/reference/query-expense-methods\n   */\n  async getExpenseMethods(): Promise<ExpenseMethodsData> {\n    return this.request<ExpenseMethodsData>({ method: 'GET', url: '/expense_methods' });\n  }\n\n  /**\n   * Query incomes & expenses\n   * @see https://docs.hostex.io/reference/query-transactions\n   */\n  async getTransactions(params?: TransactionsQueryParams): Promise<TransactionsData> {\n    return this.request<TransactionsData>({ method: 'GET', url: '/transactions', params });\n  }\n\n  /**\n   * Create a transaction (income or expense entry)\n   * @see https://docs.hostex.io/reference/create-transaction\n   */\n  async createTransaction(params: CreateTransactionParams): Promise<HostexApiResponse<CreateTransactionData>> {\n    validateRequired(params.direction, 'direction');\n    validateRequired(params.amount, 'amount');\n    validateRequired(params.item_id, 'item_id');\n    validateRequired(params.payment_method_id, 'payment_method_id');\n    if (!params.stay_code) {\n      validateRequired(params.currency, 'currency');\n    }\n    const response = await this.axios.post<HostexApiResponse<CreateTransactionData>>('/transactions', params);\n    return response.data;\n  }\n\n  /**\n   * Update a transaction\n   * @see https://docs.hostex.io/reference/update-transaction\n   */\n  async updateTransaction(params: UpdateTransactionParams): Promise<HostexApiResponse> {\n    validateRequired(params.id, 'id');\n    const { id, ...body } = params;\n    const response = await this.axios.patch<HostexApiResponse>(`/transactions/${id}`, body);\n    return response.data;\n  }\n\n  /**\n   * Delete a transaction\n   * @see https://docs.hostex.io/reference/delete-transaction\n   */\n  async deleteTransaction(id: number): Promise<HostexApiResponse> {\n    validateRequired(id, 'id');\n    const response = await this.axios.delete<HostexApiResponse>(`/transactions/${id}`);\n    return response.data;\n  }\n\n  // =====================\n  // Knowledge Bases API\n  // =====================\n\n  /**\n   * Query knowledge bases\n   * @see https://docs.hostex.io/reference/query-knowledge-bases\n   */\n  async getKnowledgeBases(params?: KnowledgeBasesQueryParams): Promise<KnowledgeBasesData> {\n    return this.request<KnowledgeBasesData>({ method: 'GET', url: '/knowledge_bases', params });\n  }\n\n  /**\n   * Get knowledge base detail\n   * @see https://docs.hostex.io/reference/get-knowledge-base-detail\n   */\n  async getKnowledgeBaseDetail(id: number): Promise<KnowledgeBaseDetail> {\n    validateRequired(id, 'id');\n    return this.request<KnowledgeBaseDetail>({ method: 'GET', url: `/knowledge_bases/${id}` });\n  }\n\n  /**\n   * Create a knowledge base entry\n   * @see https://docs.hostex.io/reference/create-knowledge-base\n   */\n  async createKnowledgeBase(params: CreateKnowledgeBaseParams): Promise<HostexApiResponse> {\n    validateRequired(params.scope_property, 'scope_property');\n    validateRequired(params.scope_channel, 'scope_channel');\n    validateNonEmptyArray(params.contents, 'contents');\n    if (params.is_enable == null) {\n      throw new Error('is_enable is required');\n    }\n    const response = await this.axios.post<HostexApiResponse>('/knowledge_bases', params);\n    return response.data;\n  }\n\n  /**\n   * Update a knowledge base entry\n   * @see https://docs.hostex.io/reference/update-knowledge-base\n   */\n  async updateKnowledgeBase(params: UpdateKnowledgeBaseParams): Promise<HostexApiResponse> {\n    validateRequired(params.id, 'id');\n    validateRequired(params.scope_property, 'scope_property');\n    validateRequired(params.scope_channel, 'scope_channel');\n    validateNonEmptyArray(params.contents, 'contents');\n    if (params.is_enable == null) {\n      throw new Error('is_enable is required');\n    }\n    const { id, ...body } = params;\n    const response = await this.axios.patch<HostexApiResponse>(`/knowledge_bases/${id}`, body);\n    return response.data;\n  }\n\n  /**\n   * Delete a knowledge base entry\n   * @see https://docs.hostex.io/reference/delete-knowledge-base\n   */\n  async deleteKnowledgeBase(id: number): Promise<HostexApiResponse> {\n    validateRequired(id, 'id');\n    const response = await this.axios.delete<HostexApiResponse>(`/knowledge_bases/${id}`);\n    return response.data;\n  }\n\n  // =====================\n  // Automation Actions API\n  // =====================\n\n  /**\n   * Query upcoming automation actions\n   * @see https://docs.hostex.io/reference/query-automation-actions\n   */\n  async getAutomationActions(params: AutomationActionsQueryParams): Promise<AutomationActionsData> {\n    validateRequired(params.type, 'type');\n    return this.request<AutomationActionsData>({\n      method: 'GET',\n      url: '/automation/actions',\n      params,\n    });\n  }\n\n  /**\n   * Delete an upcoming automation action\n   * @see https://docs.hostex.io/reference/delete-automation-action\n   */\n  async deleteAutomationAction(planId: number): Promise<HostexApiResponse> {\n    validateRequired(planId, 'planId');\n    const response = await this.axios.delete<HostexApiResponse>(`/automation/actions/${planId}`);\n    return response.data;\n  }\n\n  /**\n   * Execute an automation action immediately\n   * @see https://docs.hostex.io/reference/execute-automation-action\n   */\n  async executeAutomationAction(planId: number): Promise<HostexApiResponse> {\n    validateRequired(planId, 'planId');\n    const response = await this.axios.post<HostexApiResponse>(`/automation/actions/${planId}/execute`);\n    return response.data;\n  }\n\n  // =====================\n  // Webhooks API\n  // =====================\n\n  /**\n   * Query webhooks\n   * @see https://docs.hostex.io/reference/query-webhooks\n   */\n  async getWebhooks(): Promise<WebhooksData> {\n    return this.request<WebhooksData>({\n      method: 'GET',\n      url: '/webhooks',\n    });\n  }\n\n  /**\n   * Create a webhook\n   * @see https://docs.hostex.io/reference/create-webhook\n   */\n  async createWebhook(params: CreateWebhookParams): Promise<HostexApiResponse> {\n    validateRequired(params.url, 'url');\n    validateUrl(params.url, 'url');\n\n    const response = await this.axios.post<HostexApiResponse>('/webhooks', params);\n    return response.data;\n  }\n\n  /**\n   * Update a webhook\n   * @see https://docs.hostex.io/reference/update-webhook\n   */\n  async updateWebhook(params: UpdateWebhookParams): Promise<HostexApiResponse> {\n    validateRequired(params.id, 'id');\n\n    if (params.url !== undefined) {\n      validateUrl(params.url, 'url');\n    }\n\n    const { id, ...body } = params;\n    const response = await this.axios.patch<HostexApiResponse>(`/webhooks/${id}`, body);\n    return response.data;\n  }\n\n  /**\n   * Delete a webhook\n   * @see https://docs.hostex.io/reference/delete-webhook\n   */\n  async deleteWebhook(params: DeleteWebhookParams): Promise<HostexApiResponse> {\n    validateRequired(params.id, 'id');\n\n    const response = await this.axios.delete<HostexApiResponse>(`/webhooks/${params.id}`);\n    return response.data;\n  }\n\n  // =====================\n  // OAuth API\n  // =====================\n\n  /**\n   * Obtain or refresh an access token\n   * @see https://docs.hostex.io/reference/obtain-token\n   */\n  async obtainToken(params: OAuthTokenParams): Promise<OAuthTokenData> {\n    validateRequired(params.client_id, 'client_id');\n    validateRequired(params.client_secret, 'client_secret');\n    validateRequired(params.grant_type, 'grant_type');\n\n    if (params.grant_type === 'authorization_code') {\n      validateRequired(params.code, 'code');\n    } else if (params.grant_type === 'refresh_token') {\n      validateRequired(params.refresh_token, 'refresh_token');\n    }\n\n    return this.request<OAuthTokenData>({\n      method: 'POST',\n      url: '/oauth/authorizations',\n      data: params,\n    });\n  }\n\n  /**\n   * Revoke a token\n   * @see https://docs.hostex.io/reference/revoke-token\n   */\n  async revokeToken(params: RevokeTokenParams): Promise<HostexApiResponse> {\n    validateRequired(params.client_id, 'client_id');\n    validateRequired(params.client_secret, 'client_secret');\n    validateRequired(params.token, 'token');\n\n    const response = await this.axios.post<HostexApiResponse>('/oauth/revoke', params);\n    return response.data;\n  }\n}\n"],"mappings":"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"}