@resira/sdk 0.4.16 → 0.4.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -174,6 +174,47 @@ function deepKeysToCamel(obj) {
174
174
  }
175
175
  return obj;
176
176
  }
177
+ function toIsoIfValid(value) {
178
+ if (typeof value !== "string" || !value.trim()) return null;
179
+ const date = new Date(value);
180
+ if (Number.isNaN(date.getTime())) return null;
181
+ return date.toISOString();
182
+ }
183
+ function normalizeDurationMinutes(value) {
184
+ if (typeof value !== "number" || !Number.isFinite(value)) return null;
185
+ const rounded = Math.round(value);
186
+ return rounded > 0 ? rounded : null;
187
+ }
188
+ function withCanonicalDurationWindow(payload) {
189
+ const next = { ...payload };
190
+ const hoursAsMinutes = normalizeDurationMinutes(next.durationHours) ? Math.round(next.durationHours * 60) : null;
191
+ const durationMinutes = normalizeDurationMinutes(next.durationMinutes) ?? hoursAsMinutes;
192
+ if (durationMinutes) {
193
+ next.durationMinutes = durationMinutes;
194
+ next.durationHours = Number((durationMinutes / 60).toFixed(6));
195
+ }
196
+ const startIso = toIsoIfValid(next.startTime);
197
+ const endIso = toIsoIfValid(next.endTime);
198
+ if (startIso) next.startTime = startIso;
199
+ if (durationMinutes && startIso) {
200
+ const computedEnd = new Date(
201
+ new Date(startIso).getTime() + durationMinutes * 6e4
202
+ ).toISOString();
203
+ if (!endIso) {
204
+ next.endTime = computedEnd;
205
+ } else {
206
+ const mismatch = new Date(endIso).getTime() - new Date(startIso).getTime() !== durationMinutes * 6e4;
207
+ if (mismatch) {
208
+ next.endTime = computedEnd;
209
+ } else {
210
+ next.endTime = endIso;
211
+ }
212
+ }
213
+ } else if (endIso) {
214
+ next.endTime = endIso;
215
+ }
216
+ return next;
217
+ }
177
218
  var Resira = class {
178
219
  constructor(config) {
179
220
  if (!config.apiKey) {
@@ -593,7 +634,7 @@ var Resira = class {
593
634
  const init = {
594
635
  method: "POST",
595
636
  headers,
596
- body: JSON.stringify(payload)
637
+ body: JSON.stringify(withCanonicalDurationWindow(payload))
597
638
  };
598
639
  let lastError;
599
640
  for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
@@ -659,7 +700,7 @@ var Resira = class {
659
700
  const raw = await this.request(
660
701
  "POST",
661
702
  "/payments/create-intent",
662
- payload,
703
+ withCanonicalDurationWindow(payload),
663
704
  { "Idempotency-Key": idempotencyKey }
664
705
  );
665
706
  const data = deepKeysToCamel(raw);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/routing.ts","../src/client.ts"],"names":["url"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ApiErrorBody } from \"./types.js\";\n\n// ═══════════════════════════════════════════════════════════════\n// Base error\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Base error class for all SDK errors.\n *\n * Use `instanceof` checks to distinguish error types:\n *\n * ```ts\n * try { … } catch (e) {\n * if (e instanceof ResiraRateLimitError) { … }\n * if (e instanceof ResiraApiError) { … }\n * if (e instanceof ResiraNetworkError) { … }\n * }\n * ```\n */\nexport class ResiraError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ResiraError\";\n // Fix prototype chain for instanceof to work after transpilation\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// API error (4xx / 5xx with a parsed body)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Thrown when the API returns a non-2xx response with a JSON body.\n *\n * ```ts\n * err.status // 400, 404, 409, 422, 500, …\n * err.code // HTTP status text (e.g. \"Not Found\")\n * err.body // Parsed `{ error: \"…\" }` from the server\n * ```\n */\nexport class ResiraApiError extends ResiraError {\n /** HTTP status code. */\n readonly status: number;\n /** HTTP status text (e.g. `\"Bad Request\"`). */\n readonly code: string;\n /** Parsed error body from the API. */\n readonly body: ApiErrorBody;\n /** The full `Response` object (headers are still accessible). */\n readonly response: Response;\n\n constructor(status: number, code: string, body: ApiErrorBody, response: Response) {\n super(body.error || `API error ${status}`);\n this.name = \"ResiraApiError\";\n this.status = status;\n this.code = code;\n this.body = body;\n this.response = response;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n /** Whether this error is retryable (5xx or 429). */\n get retryable(): boolean {\n return this.status === 429 || this.status >= 500;\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Rate limit error (429)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Thrown when the API returns 429 Too Many Requests.\n *\n * ```ts\n * err.retryAfter // Seconds until the client should retry\n * ```\n */\nexport class ResiraRateLimitError extends ResiraApiError {\n /** Seconds to wait before retrying (from `Retry-After` header). */\n readonly retryAfter: number;\n\n constructor(body: ApiErrorBody, response: Response) {\n super(429, \"Too Many Requests\", body, response);\n this.name = \"ResiraRateLimitError\";\n this.retryAfter =\n body.retryAfter ??\n (Number.parseInt(response.headers.get(\"retry-after\") ?? \"60\", 10) ||\n 60);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Network error (fetch failed, DNS, timeout, etc.)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Thrown when the request never reached the server.\n *\n * This wraps the underlying `TypeError` or `DOMException` from\n * `fetch()` failures (DNS resolution, TLS, network offline, etc.).\n */\nexport class ResiraNetworkError extends ResiraError {\n /** The original error thrown by `fetch`. */\n readonly cause: unknown;\n\n constructor(message: string, cause: unknown) {\n super(message);\n this.name = \"ResiraNetworkError\";\n this.cause = cause;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import type { ResiraConfig, WeightedBaseUrl } from \"./types.js\";\n\ninterface ResolvedBaseUrl {\n url: string;\n weight: number;\n}\n\nconst DEFAULT_LOCAL_BASE_URLS: ResolvedBaseUrl[] = [\n { url: \"http://localhost:3001\", weight: 100 },\n];\n\nconst DEFAULT_PRODUCTION_BASE_URLS: ResolvedBaseUrl[] = [\n { url: \"https://api.resira.app\", weight: 100 },\n];\n\nfunction readEnv(name: string): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return process.env?.[name];\n}\n\n\nfunction normalizeUrl(url: string): string {\n return url.trim().replace(/\\/+$/, \"\");\n}\n\nfunction isPositiveNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\nfunction toResolvedBaseUrl(value: string | WeightedBaseUrl): ResolvedBaseUrl | null {\n if (typeof value === \"string\") {\n const url = normalizeUrl(value);\n return url ? { url, weight: 1 } : null;\n }\n\n const url = normalizeUrl(value.url);\n if (!url) return null;\n\n return {\n url,\n weight: isPositiveNumber(value.weight) ? value.weight : 1,\n };\n}\n\nfunction parseJsonBaseUrls(value: string): ResolvedBaseUrl[] {\n const parsed = JSON.parse(value) as unknown;\n if (!Array.isArray(parsed)) return [];\n\n return parsed.flatMap((entry) => {\n const resolved =\n typeof entry === \"string\"\n ? toResolvedBaseUrl(entry)\n : entry && typeof entry === \"object\"\n ? toResolvedBaseUrl(entry as WeightedBaseUrl)\n : null;\n\n return resolved ? [resolved] : [];\n });\n}\n\nfunction parseDelimitedBaseUrls(value: string): ResolvedBaseUrl[] {\n return value\n .split(\",\")\n .flatMap((entry) => {\n const [rawUrl, rawWeight] = entry.split(\"|\");\n const url = normalizeUrl(rawUrl ?? \"\");\n if (!url) return [];\n\n const parsedWeight = rawWeight ? Number(rawWeight.trim()) : 1;\n return [{\n url,\n weight: isPositiveNumber(parsedWeight) ? parsedWeight : 1,\n }];\n });\n}\n\nfunction parseEnvBaseUrls(value: string | undefined): ResolvedBaseUrl[] {\n if (!value) return [];\n\n try {\n const parsed = parseJsonBaseUrls(value);\n if (parsed.length > 0) return parsed;\n } catch {\n // Fall back to delimiter parsing.\n }\n\n return parseDelimitedBaseUrls(value);\n}\n\nexport function resolveBaseUrls(config: ResiraConfig): ResolvedBaseUrl[] {\n if (config.baseUrl) {\n return [{ url: normalizeUrl(config.baseUrl), weight: 100 }];\n }\n\n if (config.baseUrls?.length) {\n const explicit = config.baseUrls.flatMap((entry) => {\n const resolved = toResolvedBaseUrl(entry);\n return resolved ? [resolved] : [];\n });\n\n if (explicit.length > 0) return explicit;\n }\n\n const envBaseUrls = parseEnvBaseUrls(readEnv(\"RESIRA_API_BASE_URLS\"));\n if (envBaseUrls.length > 0) {\n return envBaseUrls;\n }\n\n if (readEnv(\"NODE_ENV\") === \"development\") {\n return DEFAULT_LOCAL_BASE_URLS;\n }\n\n return DEFAULT_PRODUCTION_BASE_URLS;\n}\n\nexport function pickBaseUrl(baseUrls: ResolvedBaseUrl[]): string {\n return baseUrls[0]?.url ?? DEFAULT_PRODUCTION_BASE_URLS[0].url;\n}\n\nexport function getRoutingStats(): Record<string, never> {\n return {};\n}","import { ResiraApiError, ResiraNetworkError, ResiraRateLimitError } from \"./errors.js\";\nimport { pickBaseUrl, resolveBaseUrls } from \"./routing.js\";\nimport type {\n ApiErrorBody,\n Availability,\n AvailabilityParams,\n CheckoutSessionResponse,\n ConfirmPaymentRequest,\n ConfirmPaymentResponse,\n CreateCheckoutSessionRequest,\n CreateCheckoutSessionResponse,\n CreatePaymentIntentRequest,\n CreateReservationRequest,\n Dish,\n DishListResponse,\n DishResponse,\n ListReservationsParams,\n PaginatedReservations,\n PaymentIntentResponse,\n ProductListResponse,\n PropertyConfig,\n Reservation,\n ReservationResponse,\n ResiraConfig,\n ResourceListResponse,\n ValidatePromoCodeResponse,\n} from \"./types.js\";\n\n// ═══════════════════════════════════════════════════════════════\n// Constants\n// ═══════════════════════════════════════════════════════════════\n\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_RETRY_BASE_DELAY = 500; // ms\nconst API_PREFIX = \"/v1/public\";\n\n// ═══════════════════════════════════════════════════════════════\n// Helpers\n// ═══════════════════════════════════════════════════════════════\n\n/** Generate a random UUID v4 for idempotency keys. */\nfunction uuid(): string {\n // Use crypto.randomUUID when available (Node 19+, all modern browsers)\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID();\n }\n // Fallback: manual v4 UUID\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n return (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n });\n}\n\n/** Build a query string from a flat params object. Skips `undefined` values. */\nfunction toQueryString(params: Record<string, string | number | boolean | undefined>): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n }\n }\n return parts.length > 0 ? `?${parts.join(\"&\")}` : \"\";\n}\n\n/** Sleep for `ms` milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Convert camelCase keys to snake_case for query parameters.\n * The API expects snake_case query params (`start_date`, `party_size`).\n */\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/** Convert an object's keys from camelCase to snake_case. */\nfunction keysToSnake(\n obj: Record<string, string | number | boolean | undefined>,\n): Record<string, string | number | boolean | undefined> {\n const result: Record<string, string | number | boolean | undefined> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[camelToSnake(key)] = value;\n }\n return result;\n}\n\n/** Convert snake_case string to camelCase. */\nfunction snakeToCamel(str: string): string {\n return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\n}\n\n/** Deep-convert all keys in an object/array from camelCase to snake_case. */\nfunction deepKeysToSnake(obj: unknown): unknown {\n if (Array.isArray(obj)) return obj.map(deepKeysToSnake);\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[camelToSnake(key)] = deepKeysToSnake(value);\n }\n return result;\n }\n return obj;\n}\n\n/** Deep-convert all keys in an object/array from snake_case to camelCase. */\nfunction deepKeysToCamel(obj: unknown): unknown {\n if (Array.isArray(obj)) return obj.map(deepKeysToCamel);\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[snakeToCamel(key)] = deepKeysToCamel(value);\n }\n return result;\n }\n return obj;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Client\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Resira SDK client.\n *\n * ```ts\n * const resira = new Resira({\n * apiKey: \"resira_live_abc123…\",\n * baseUrl: \"https://api.example.com\", // optional\n * });\n *\n * const availability = await resira.getAvailability(\"prop-1\", {\n * startDate: \"2026-07-01\",\n * endDate: \"2026-07-07\",\n * });\n * ```\n */\nexport class Resira {\n private readonly apiKey: string;\n private readonly baseUrls: ReturnType<typeof resolveBaseUrls>;\n private readonly maxRetries: number;\n private readonly retryBaseDelay: number;\n private readonly _fetch: typeof globalThis.fetch;\n\n constructor(config: ResiraConfig) {\n if (!config.apiKey) {\n throw new Error(\"Resira: apiKey is required\");\n }\n this.apiKey = config.apiKey;\n this.baseUrls = resolveBaseUrls(config);\n this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.retryBaseDelay = config.retryBaseDelay ?? DEFAULT_RETRY_BASE_DELAY;\n this._fetch = config.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n /** The resolved API origin used by this client instance. */\n getBaseUrl(): string {\n return pickBaseUrl(this.baseUrls);\n }\n\n // ─────────────────────────────────────────────────────────────\n // Public API methods\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Fetch the public property configuration.\n *\n * Returns non-sensitive settings such as the Stripe publishable\n * key, deposit percentage, currency, and branding info.\n *\n * ```ts\n * const config = await resira.getConfig();\n * console.log(config.stripePublishableKey); // \"pk_test_…\"\n * ```\n */\n async getConfig(): Promise<PropertyConfig> {\n return this.request<PropertyConfig>(\"GET\", \"/config\");\n }\n\n /**\n * Validate a promo/discount code.\n *\n * Returns discount details if valid, or an error message if not.\n *\n * ```ts\n * const result = await resira.validatePromoCode(\"SUMMER20\");\n * if (result.valid) {\n * console.log(result.discountType, result.discountValue);\n * }\n * ```\n */\n async validatePromoCode(code: string): Promise<ValidatePromoCodeResponse> {\n try {\n const raw = await this.request<Record<string, unknown>>(\n \"POST\",\n \"/promo-codes/validate\",\n { code },\n );\n const data = deepKeysToCamel(raw) as Record<string, unknown>;\n return {\n valid: true,\n discountType: data.discountType as \"percent\" | \"fixed\" | undefined,\n discountValue: data.discountValue as number | undefined,\n currency: data.currency as string | undefined,\n minOrderCents: data.minOrderCents as number | undefined,\n };\n } catch (err: unknown) {\n // 4xx errors mean invalid code\n if (\n err &&\n typeof err === \"object\" &&\n \"status\" in err &&\n (err as { status: number }).status < 500\n ) {\n const apiErr = err as { body?: { error?: string } };\n return {\n valid: false,\n error: apiErr.body?.error ?? \"Invalid promo code\",\n };\n }\n throw err;\n }\n }\n\n /**\n * List all active resources for the organization.\n *\n * Returns resource cards with name, description, price, duration,\n * image, and type — suitable for building a resource picker.\n *\n * ```ts\n * const { resources } = await resira.listResources();\n * ```\n */\n async listResources(): Promise<ResourceListResponse> {\n return this.request<ResourceListResponse>(\"GET\", \"/resources\");\n }\n\n /**\n * Query availability for a resource.\n *\n * **Properties** (date-based):\n * ```ts\n * await resira.getAvailability(\"prop-1\", {\n * startDate: \"2026-07-01\",\n * endDate: \"2026-07-07\",\n * });\n * ```\n *\n * **Restaurants** (time-slot):\n * ```ts\n * await resira.getAvailability(\"table-5\", {\n * date: \"2026-07-01\",\n * partySize: 4,\n * });\n * ```\n *\n * Omit params to get all blocked dates (for calendar rendering).\n */\n async getAvailability(\n resourceId: string,\n params: AvailabilityParams = {},\n ): Promise<Availability> {\n if (!resourceId) {\n throw new Error(\"resourceId is required for getAvailability\");\n }\n const qs = toQueryString(keysToSnake(params as Record<string, string | number | undefined>));\n return this.request<Availability>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/availability${qs}`,\n );\n }\n\n /**\n * Query availability for a product/service.\n *\n * Aggregates capacity across all linked equipment. If a product\n * has 2 jet skis (each capacity=1), slots show capacity: 2.\n * Both pending and confirmed reservations count as occupied.\n *\n * ```ts\n * await resira.getProductAvailability(\"prod-123\", {\n * date: \"2026-07-01\",\n * durationMinutes: 30,\n * });\n * ```\n */\n async getProductAvailability(\n productId: string,\n params: AvailabilityParams = {},\n ): Promise<Availability> {\n if (!productId) {\n throw new Error(\"productId is required for getProductAvailability\");\n }\n const qs = toQueryString(keysToSnake(params as Record<string, string | number | undefined>));\n return this.request<Availability>(\n \"GET\",\n `/products/${encodeURIComponent(productId)}/availability${qs}`,\n );\n }\n\n /**\n * Create a reservation.\n *\n * Uses `POST /v2/api/reservations` — the `resourceId` is sent in\n * the request body, **not** in the URL path.\n *\n * An `Idempotency-Key` header is automatically attached so that\n * retries (including those from exponential backoff) are safe.\n *\n * ```ts\n * const { reservation } = await resira.createReservation({\n * resourceId: \"prop-1\",\n * guestName: \"Jane Doe\",\n * guestEmail: \"jane@example.com\",\n * startDate: \"2026-07-01\",\n * endDate: \"2026-07-07\",\n * partySize: 3,\n * });\n * ```\n */\n async createReservation(\n payload: CreateReservationRequest,\n options?: { idempotencyKey?: string },\n ): Promise<ReservationResponse> {\n if (!payload.resourceId && !payload.checkoutSessionToken) {\n throw new Error(\"resourceId or checkoutSessionToken is required for createReservation\");\n }\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n\n // Note: uses /v2/api prefix, not /v1/public\n const url = `${this.getBaseUrl()}/v2/api/reservations`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n };\n\n const init: RequestInit = {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | ResiraRateLimitError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n let response: Response;\n try {\n response = await this._fetch(url, init);\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n continue;\n }\n\n if (response.ok) {\n const raw = (await response.json()) as Record<string, unknown>;\n // The API may nest under \"reservation\" or \"booking\" depending on endpoint\n const resData = (raw.reservation ?? raw.booking ?? {}) as Record<string, unknown>;\n\n // Augment with request data: API response doesn't include\n // startTime/endTime/startDate/endDate/resourceId for v2 reservations\n const reservation: Reservation = {\n id: (resData.id as string) ?? \"\",\n resourceId: (resData.resourceId as string) ?? payload.resourceId,\n status: (resData.status as string) ?? \"pending\",\n startDate: (resData.startDate as string) ?? payload.startDate,\n endDate: (resData.endDate as string) ?? payload.endDate,\n startTime: (resData.startTime as string) ?? payload.startTime,\n endTime: (resData.endTime as string) ?? payload.endTime,\n startDatetime: (resData.startDatetime as string) ?? payload.startTime,\n endDatetime: (resData.endDatetime as string) ?? payload.endTime,\n guestName: (resData.guestName as string) ?? payload.guestName,\n partySize: (resData.partySize as number) ?? (resData.guests as number) ?? payload.partySize ?? 2,\n totalPrice: (resData.totalPrice as number) ?? 0,\n currency: (resData.currency as string) ?? \"EUR\",\n createdAt: (resData.createdAt as string) ?? new Date().toISOString(),\n };\n\n return { reservation };\n }\n\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n continue;\n }\n\n if (response.status >= 500) {\n lastError = new ResiraApiError(response.status, response.statusText, errorBody, response);\n continue;\n }\n\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n\n throw lastError!;\n }\n\n /**\n * List reservations for a resource (paginated).\n *\n * ```ts\n * const page = await resira.listReservations(\"prop-1\", {\n * status: \"confirmed\",\n * page: 1,\n * limit: 50,\n * });\n * console.log(page.data); // Reservation[]\n * console.log(page.totalPages); // number\n * ```\n */\n async listReservations(\n resourceId: string,\n params: ListReservationsParams = {},\n ): Promise<PaginatedReservations> {\n const qs = toQueryString(params as Record<string, string | number | undefined>);\n return this.request<PaginatedReservations>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/reservations${qs}`,\n );\n }\n\n /**\n * Get a single reservation by ID.\n *\n * ```ts\n * const { reservation } = await resira.getReservation(\"prop-1\", \"res-uuid\");\n * ```\n */\n async getReservation(\n resourceId: string,\n reservationId: string,\n ): Promise<ReservationResponse> {\n return this.request<ReservationResponse>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/reservations/${encodeURIComponent(reservationId)}`,\n );\n }\n\n /**\n * List all active products/services for the organisation.\n *\n * Calls `GET /v1/public/products` which returns products with\n * pricing, duration, and linked equipment.\n *\n * Falls back to mapping resources → products if the endpoint\n * returns 404 (backend hasn't been updated yet).\n *\n * ```ts\n * const { products } = await resira.listProducts();\n * ```\n */\n async listProducts(): Promise<ProductListResponse> {\n try {\n return await this.request<ProductListResponse>(\"GET\", \"/products\");\n } catch (err: unknown) {\n // Fallback: if /products endpoint doesn't exist yet (404),\n // map resources → products shape\n if (\n err &&\n typeof err === \"object\" &&\n \"status\" in err &&\n (err as { status: number }).status === 404\n ) {\n const resourceResponse = await this.listResources();\n const products = resourceResponse.resources.map((r) => ({\n id: r.id,\n name: r.name,\n description: r.description,\n durationMinutes: r.durationMinutes ?? 60,\n priceCents: r.pricePerSession ?? 0,\n currency: r.currency ?? \"EUR\",\n imageUrl: r.imageUrl,\n active: r.active,\n sortOrder: 0,\n pricingModel: \"per_session\" as const,\n equipmentIds: [r.id],\n equipmentNames: [r.name],\n }));\n return { products, count: products.length };\n }\n throw err;\n }\n }\n\n /**\n * List all dishes with 3D model data for the organisation.\n *\n * Returns dishes with name, description, price, image, and\n * 3D model URLs for AR/preview rendering.\n *\n * ```ts\n * const { dishes } = await resira.listDishes();\n * ```\n */\n async listDishes(): Promise<DishListResponse> {\n return this.request<DishListResponse>(\"GET\", \"/dishes\");\n }\n\n /**\n * Get a single dish by ID.\n *\n * ```ts\n * const { dish } = await resira.getDish(\"dish-uuid\");\n * console.log(dish.name, dish.model?.glbUrl);\n * ```\n */\n async getDish(dishId: string): Promise<DishResponse> {\n if (!dishId) {\n throw new Error(\"dishId is required for getDish\");\n }\n return this.request<DishResponse>(\n \"GET\",\n `/dishes/${encodeURIComponent(dishId)}`,\n );\n }\n\n /**\n * Retrieve a checkout session by its token.\n *\n * Used to hydrate the checkout screen when opening the widget\n * with a pre-created session token (skip service selection).\n *\n * ```ts\n * const { session } = await resira.getCheckoutSession(\"cs_ab12cd34ef56\");\n * console.log(session.productName, session.priceCents);\n * ```\n */\n async getCheckoutSession(token: string): Promise<CheckoutSessionResponse> {\n if (!token) {\n throw new Error(\"token is required for getCheckoutSession\");\n }\n const url = `${this.getBaseUrl()}/v2/public/checkout-sessions/${encodeURIComponent(token)}`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n let response: Response;\n try {\n response = await this._fetch(url, { method: \"GET\", headers });\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n continue;\n }\n\n if (response.ok) {\n const raw = await response.json();\n return deepKeysToCamel(raw) as CheckoutSessionResponse;\n }\n\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n continue;\n }\n if (response.status >= 500) {\n lastError = new ResiraApiError(response.status, response.statusText, errorBody, response);\n continue;\n }\n\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n\n throw lastError!;\n }\n\n /**\n * Create a new checkout session.\n *\n * External sites can create a session with product, slot, and guest\n * details, then pass the returned token to the widget to skip\n * directly to checkout.\n *\n * ```ts\n * const { sessionToken } = await resira.createCheckoutSession({\n * productId: \"prod-123\",\n * durationMinutes: 30,\n * partySize: 2,\n * date: \"2026-07-01\",\n * startTime: \"2026-07-01T10:00:00Z\",\n * endTime: \"2026-07-01T10:30:00Z\",\n * });\n * ```\n */\n async createCheckoutSession(\n payload: CreateCheckoutSessionRequest,\n options?: { idempotencyKey?: string },\n ): Promise<CreateCheckoutSessionResponse> {\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n const url = `${this.getBaseUrl()}/v2/public/checkout-sessions`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n };\n\n const init: RequestInit = {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n let response: Response;\n try {\n response = await this._fetch(url, init);\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n continue;\n }\n\n if (response.ok) {\n const raw = await response.json();\n return deepKeysToCamel(raw) as CreateCheckoutSessionResponse;\n }\n\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n continue;\n }\n if (response.status >= 500) {\n lastError = new ResiraApiError(response.status, response.statusText, errorBody, response);\n continue;\n }\n\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n\n throw lastError!;\n }\n\n /**\n * Create a Stripe payment intent for a booking.\n *\n * The server creates the payment intent, calculates the amount,\n * and returns a `clientSecret` to confirm payment on the frontend\n * using Stripe Elements.\n *\n * ```ts\n * const { clientSecret, amountNow, amountAtVenue } =\n * await resira.createPaymentIntent({\n * productId: \"prod-123\",\n * resourceId: \"res-456\",\n * partySize: 2,\n * startDate: \"2026-07-01\",\n * startTime: \"2026-07-01T10:00:00Z\",\n * endTime: \"2026-07-01T11:00:00Z\",\n * guestName: \"Jane Doe\",\n * guestEmail: \"jane@example.com\",\n * });\n * ```\n */\n async createPaymentIntent(\n payload: CreatePaymentIntentRequest,\n options?: { idempotencyKey?: string },\n ): Promise<PaymentIntentResponse> {\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n const raw = await this.request<Record<string, unknown>>(\n \"POST\",\n \"/payments/create-intent\",\n payload,\n { \"Idempotency-Key\": idempotencyKey },\n );\n // Normalize response keys to camelCase\n const data = deepKeysToCamel(raw) as Record<string, unknown>;\n // Map backend field names to SDK field names:\n // backend: amountDue, totalPrice\n // SDK: amountNow, totalAmount, amountAtVenue\n const totalAmount = (data.totalAmount as number) ?? (data.totalPrice as number) ?? 0;\n const amountNow = (data.amountNow as number) ?? (data.amountDue as number) ?? totalAmount;\n const amountAtVenue = (data.amountAtVenue as number) ?? (totalAmount - amountNow);\n return {\n clientSecret: data.clientSecret as string,\n paymentIntentId: data.paymentIntentId as string,\n amountNow,\n amountAtVenue,\n totalAmount,\n currency: (data.currency as string) ?? \"EUR\",\n paymentOption: data.paymentOption as string | undefined,\n reservationId: data.reservationId as string | undefined,\n discountAmount: (data.discountAmount as number) ?? undefined,\n originalPrice: (data.originalPrice as number) ?? undefined,\n promoCodeApplied: (data.promoCodeApplied as string) ?? undefined,\n };\n }\n\n /**\n * Confirm that a payment was successful after the guest\n * completes the Stripe payment flow.\n *\n * This transitions the reservation from `pending` to `confirmed`.\n *\n * ```ts\n * const { reservation, paymentStatus } =\n * await resira.confirmPayment({\n * paymentIntentId: \"pi_xxx\",\n * reservationId: \"res-uuid\",\n * });\n * ```\n */\n async confirmPayment(\n payload: ConfirmPaymentRequest,\n ): Promise<ConfirmPaymentResponse> {\n const raw = await this.request<Record<string, unknown>>(\n \"POST\",\n \"/payments/confirm\",\n payload,\n );\n // Normalize response keys to camelCase in case backend returns snake_case\n return deepKeysToCamel(raw) as ConfirmPaymentResponse;\n }\n\n // ─────────────────────────────────────────────────────────────\n // Internal HTTP layer\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Execute an HTTP request with retry logic and error normalization.\n *\n * - Attaches `Authorization: Bearer <apiKey>` on every request.\n * - Retries on 429 and 5xx with exponential backoff + jitter.\n * - Parses error bodies and throws typed error classes.\n */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n extraHeaders?: Record<string, string>,\n ): Promise<T> {\n const url = `${this.getBaseUrl()}${API_PREFIX}${path}`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n ...extraHeaders,\n };\n\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n const init: RequestInit = {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n // ── Wait before retry ────────────────────────────────\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n // ── Execute the request ──────────────────────────────\n let response: Response;\n try {\n response = await this._fetch(url, init);\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n // Network errors are always retryable\n continue;\n }\n\n // ── Success ──────────────────────────────────────────\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n // ── Parse error body ─────────────────────────────────\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n // ── Rate limit ───────────────────────────────────────\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n // Always retry 429s (up to maxRetries)\n continue;\n }\n\n // ── Server error (5xx) — retryable ───────────────────\n if (response.status >= 500) {\n lastError = new ResiraApiError(\n response.status,\n response.statusText,\n errorBody,\n response,\n );\n continue;\n }\n\n // ── Client error (4xx) — NOT retryable ───────────────\n throw new ResiraApiError(\n response.status,\n response.statusText,\n errorBody,\n response,\n );\n }\n\n // All retries exhausted — throw the last error\n throw lastError!;\n }\n\n /**\n * Calculate backoff delay in milliseconds for a given retry attempt.\n *\n * Uses exponential backoff with full jitter:\n * delay = random(0, base * 2^attempt)\n *\n * For 429 responses, respects the `Retry-After` header as a minimum.\n */\n private calculateBackoff(\n attempt: number,\n lastError?: ResiraApiError | ResiraNetworkError,\n ): number {\n const exponential = this.retryBaseDelay * 2 ** (attempt - 1);\n const jittered = Math.random() * exponential;\n\n // If the server told us to wait, use that as the floor\n if (lastError instanceof ResiraRateLimitError) {\n const serverDelay = lastError.retryAfter * 1000;\n return Math.max(serverDelay, jittered);\n }\n\n return jittered;\n }\n\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/routing.ts","../src/client.ts"],"names":["url"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ApiErrorBody } from \"./types.js\";\n\n// ═══════════════════════════════════════════════════════════════\n// Base error\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Base error class for all SDK errors.\n *\n * Use `instanceof` checks to distinguish error types:\n *\n * ```ts\n * try { … } catch (e) {\n * if (e instanceof ResiraRateLimitError) { … }\n * if (e instanceof ResiraApiError) { … }\n * if (e instanceof ResiraNetworkError) { … }\n * }\n * ```\n */\nexport class ResiraError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ResiraError\";\n // Fix prototype chain for instanceof to work after transpilation\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// API error (4xx / 5xx with a parsed body)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Thrown when the API returns a non-2xx response with a JSON body.\n *\n * ```ts\n * err.status // 400, 404, 409, 422, 500, …\n * err.code // HTTP status text (e.g. \"Not Found\")\n * err.body // Parsed `{ error: \"…\" }` from the server\n * ```\n */\nexport class ResiraApiError extends ResiraError {\n /** HTTP status code. */\n readonly status: number;\n /** HTTP status text (e.g. `\"Bad Request\"`). */\n readonly code: string;\n /** Parsed error body from the API. */\n readonly body: ApiErrorBody;\n /** The full `Response` object (headers are still accessible). */\n readonly response: Response;\n\n constructor(status: number, code: string, body: ApiErrorBody, response: Response) {\n super(body.error || `API error ${status}`);\n this.name = \"ResiraApiError\";\n this.status = status;\n this.code = code;\n this.body = body;\n this.response = response;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n /** Whether this error is retryable (5xx or 429). */\n get retryable(): boolean {\n return this.status === 429 || this.status >= 500;\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Rate limit error (429)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Thrown when the API returns 429 Too Many Requests.\n *\n * ```ts\n * err.retryAfter // Seconds until the client should retry\n * ```\n */\nexport class ResiraRateLimitError extends ResiraApiError {\n /** Seconds to wait before retrying (from `Retry-After` header). */\n readonly retryAfter: number;\n\n constructor(body: ApiErrorBody, response: Response) {\n super(429, \"Too Many Requests\", body, response);\n this.name = \"ResiraRateLimitError\";\n this.retryAfter =\n body.retryAfter ??\n (Number.parseInt(response.headers.get(\"retry-after\") ?? \"60\", 10) ||\n 60);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Network error (fetch failed, DNS, timeout, etc.)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Thrown when the request never reached the server.\n *\n * This wraps the underlying `TypeError` or `DOMException` from\n * `fetch()` failures (DNS resolution, TLS, network offline, etc.).\n */\nexport class ResiraNetworkError extends ResiraError {\n /** The original error thrown by `fetch`. */\n readonly cause: unknown;\n\n constructor(message: string, cause: unknown) {\n super(message);\n this.name = \"ResiraNetworkError\";\n this.cause = cause;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import type { ResiraConfig, WeightedBaseUrl } from \"./types.js\";\n\ninterface ResolvedBaseUrl {\n url: string;\n weight: number;\n}\n\nconst DEFAULT_LOCAL_BASE_URLS: ResolvedBaseUrl[] = [\n { url: \"http://localhost:3001\", weight: 100 },\n];\n\nconst DEFAULT_PRODUCTION_BASE_URLS: ResolvedBaseUrl[] = [\n { url: \"https://api.resira.app\", weight: 100 },\n];\n\nfunction readEnv(name: string): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return process.env?.[name];\n}\n\n\nfunction normalizeUrl(url: string): string {\n return url.trim().replace(/\\/+$/, \"\");\n}\n\nfunction isPositiveNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\nfunction toResolvedBaseUrl(value: string | WeightedBaseUrl): ResolvedBaseUrl | null {\n if (typeof value === \"string\") {\n const url = normalizeUrl(value);\n return url ? { url, weight: 1 } : null;\n }\n\n const url = normalizeUrl(value.url);\n if (!url) return null;\n\n return {\n url,\n weight: isPositiveNumber(value.weight) ? value.weight : 1,\n };\n}\n\nfunction parseJsonBaseUrls(value: string): ResolvedBaseUrl[] {\n const parsed = JSON.parse(value) as unknown;\n if (!Array.isArray(parsed)) return [];\n\n return parsed.flatMap((entry) => {\n const resolved =\n typeof entry === \"string\"\n ? toResolvedBaseUrl(entry)\n : entry && typeof entry === \"object\"\n ? toResolvedBaseUrl(entry as WeightedBaseUrl)\n : null;\n\n return resolved ? [resolved] : [];\n });\n}\n\nfunction parseDelimitedBaseUrls(value: string): ResolvedBaseUrl[] {\n return value\n .split(\",\")\n .flatMap((entry) => {\n const [rawUrl, rawWeight] = entry.split(\"|\");\n const url = normalizeUrl(rawUrl ?? \"\");\n if (!url) return [];\n\n const parsedWeight = rawWeight ? Number(rawWeight.trim()) : 1;\n return [{\n url,\n weight: isPositiveNumber(parsedWeight) ? parsedWeight : 1,\n }];\n });\n}\n\nfunction parseEnvBaseUrls(value: string | undefined): ResolvedBaseUrl[] {\n if (!value) return [];\n\n try {\n const parsed = parseJsonBaseUrls(value);\n if (parsed.length > 0) return parsed;\n } catch {\n // Fall back to delimiter parsing.\n }\n\n return parseDelimitedBaseUrls(value);\n}\n\nexport function resolveBaseUrls(config: ResiraConfig): ResolvedBaseUrl[] {\n if (config.baseUrl) {\n return [{ url: normalizeUrl(config.baseUrl), weight: 100 }];\n }\n\n if (config.baseUrls?.length) {\n const explicit = config.baseUrls.flatMap((entry) => {\n const resolved = toResolvedBaseUrl(entry);\n return resolved ? [resolved] : [];\n });\n\n if (explicit.length > 0) return explicit;\n }\n\n const envBaseUrls = parseEnvBaseUrls(readEnv(\"RESIRA_API_BASE_URLS\"));\n if (envBaseUrls.length > 0) {\n return envBaseUrls;\n }\n\n if (readEnv(\"NODE_ENV\") === \"development\") {\n return DEFAULT_LOCAL_BASE_URLS;\n }\n\n return DEFAULT_PRODUCTION_BASE_URLS;\n}\n\nexport function pickBaseUrl(baseUrls: ResolvedBaseUrl[]): string {\n return baseUrls[0]?.url ?? DEFAULT_PRODUCTION_BASE_URLS[0].url;\n}\n\nexport function getRoutingStats(): Record<string, never> {\n return {};\n}","import { ResiraApiError, ResiraNetworkError, ResiraRateLimitError } from \"./errors.js\";\nimport { pickBaseUrl, resolveBaseUrls } from \"./routing.js\";\nimport type {\n ApiErrorBody,\n Availability,\n AvailabilityParams,\n CheckoutSessionResponse,\n ConfirmPaymentRequest,\n ConfirmPaymentResponse,\n CreateCheckoutSessionRequest,\n CreateCheckoutSessionResponse,\n CreatePaymentIntentRequest,\n CreateReservationRequest,\n Dish,\n DishListResponse,\n DishResponse,\n ListReservationsParams,\n PaginatedReservations,\n PaymentIntentResponse,\n ProductListResponse,\n PropertyConfig,\n Reservation,\n ReservationResponse,\n ResiraConfig,\n ResourceListResponse,\n ValidatePromoCodeResponse,\n} from \"./types.js\";\n\n// ═══════════════════════════════════════════════════════════════\n// Constants\n// ═══════════════════════════════════════════════════════════════\n\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_RETRY_BASE_DELAY = 500; // ms\nconst API_PREFIX = \"/v1/public\";\n\n// ═══════════════════════════════════════════════════════════════\n// Helpers\n// ═══════════════════════════════════════════════════════════════\n\n/** Generate a random UUID v4 for idempotency keys. */\nfunction uuid(): string {\n // Use crypto.randomUUID when available (Node 19+, all modern browsers)\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID();\n }\n // Fallback: manual v4 UUID\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n return (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n });\n}\n\n/** Build a query string from a flat params object. Skips `undefined` values. */\nfunction toQueryString(params: Record<string, string | number | boolean | undefined>): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n }\n }\n return parts.length > 0 ? `?${parts.join(\"&\")}` : \"\";\n}\n\n/** Sleep for `ms` milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Convert camelCase keys to snake_case for query parameters.\n * The API expects snake_case query params (`start_date`, `party_size`).\n */\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/** Convert an object's keys from camelCase to snake_case. */\nfunction keysToSnake(\n obj: Record<string, string | number | boolean | undefined>,\n): Record<string, string | number | boolean | undefined> {\n const result: Record<string, string | number | boolean | undefined> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[camelToSnake(key)] = value;\n }\n return result;\n}\n\n/** Convert snake_case string to camelCase. */\nfunction snakeToCamel(str: string): string {\n return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\n}\n\n/** Deep-convert all keys in an object/array from camelCase to snake_case. */\nfunction deepKeysToSnake(obj: unknown): unknown {\n if (Array.isArray(obj)) return obj.map(deepKeysToSnake);\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[camelToSnake(key)] = deepKeysToSnake(value);\n }\n return result;\n }\n return obj;\n}\n\n/** Deep-convert all keys in an object/array from snake_case to camelCase. */\nfunction deepKeysToCamel(obj: unknown): unknown {\n if (Array.isArray(obj)) return obj.map(deepKeysToCamel);\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[snakeToCamel(key)] = deepKeysToCamel(value);\n }\n return result;\n }\n return obj;\n}\n\nfunction toIsoIfValid(value: unknown): string | null {\n if (typeof value !== \"string\" || !value.trim()) return null;\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return null;\n return date.toISOString();\n}\n\nfunction normalizeDurationMinutes(value: unknown): number | null {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return null;\n const rounded = Math.round(value);\n return rounded > 0 ? rounded : null;\n}\n\nfunction withCanonicalDurationWindow<T extends {\n durationMinutes?: number;\n durationHours?: number;\n startTime?: string;\n endTime?: string;\n}>(payload: T): T {\n const next = { ...payload };\n const hoursAsMinutes = normalizeDurationMinutes(next.durationHours)\n ? Math.round((next.durationHours as number) * 60)\n : null;\n const durationMinutes =\n normalizeDurationMinutes(next.durationMinutes) ?? hoursAsMinutes;\n\n if (durationMinutes) {\n next.durationMinutes = durationMinutes;\n next.durationHours = Number((durationMinutes / 60).toFixed(6));\n }\n\n const startIso = toIsoIfValid(next.startTime);\n const endIso = toIsoIfValid(next.endTime);\n\n if (startIso) next.startTime = startIso;\n if (durationMinutes && startIso) {\n const computedEnd = new Date(\n new Date(startIso).getTime() + durationMinutes * 60_000,\n ).toISOString();\n if (!endIso) {\n next.endTime = computedEnd;\n } else {\n const mismatch =\n new Date(endIso).getTime() - new Date(startIso).getTime() !==\n durationMinutes * 60_000;\n if (mismatch) {\n next.endTime = computedEnd;\n } else {\n next.endTime = endIso;\n }\n }\n } else if (endIso) {\n next.endTime = endIso;\n }\n\n return next;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Client\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Resira SDK client.\n *\n * ```ts\n * const resira = new Resira({\n * apiKey: \"resira_live_abc123…\",\n * baseUrl: \"https://api.example.com\", // optional\n * });\n *\n * const availability = await resira.getAvailability(\"prop-1\", {\n * startDate: \"2026-07-01\",\n * endDate: \"2026-07-07\",\n * });\n * ```\n */\nexport class Resira {\n private readonly apiKey: string;\n private readonly baseUrls: ReturnType<typeof resolveBaseUrls>;\n private readonly maxRetries: number;\n private readonly retryBaseDelay: number;\n private readonly _fetch: typeof globalThis.fetch;\n\n constructor(config: ResiraConfig) {\n if (!config.apiKey) {\n throw new Error(\"Resira: apiKey is required\");\n }\n this.apiKey = config.apiKey;\n this.baseUrls = resolveBaseUrls(config);\n this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.retryBaseDelay = config.retryBaseDelay ?? DEFAULT_RETRY_BASE_DELAY;\n this._fetch = config.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n /** The resolved API origin used by this client instance. */\n getBaseUrl(): string {\n return pickBaseUrl(this.baseUrls);\n }\n\n // ─────────────────────────────────────────────────────────────\n // Public API methods\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Fetch the public property configuration.\n *\n * Returns non-sensitive settings such as the Stripe publishable\n * key, deposit percentage, currency, and branding info.\n *\n * ```ts\n * const config = await resira.getConfig();\n * console.log(config.stripePublishableKey); // \"pk_test_…\"\n * ```\n */\n async getConfig(): Promise<PropertyConfig> {\n return this.request<PropertyConfig>(\"GET\", \"/config\");\n }\n\n /**\n * Validate a promo/discount code.\n *\n * Returns discount details if valid, or an error message if not.\n *\n * ```ts\n * const result = await resira.validatePromoCode(\"SUMMER20\");\n * if (result.valid) {\n * console.log(result.discountType, result.discountValue);\n * }\n * ```\n */\n async validatePromoCode(code: string): Promise<ValidatePromoCodeResponse> {\n try {\n const raw = await this.request<Record<string, unknown>>(\n \"POST\",\n \"/promo-codes/validate\",\n { code },\n );\n const data = deepKeysToCamel(raw) as Record<string, unknown>;\n return {\n valid: true,\n discountType: data.discountType as \"percent\" | \"fixed\" | undefined,\n discountValue: data.discountValue as number | undefined,\n currency: data.currency as string | undefined,\n minOrderCents: data.minOrderCents as number | undefined,\n };\n } catch (err: unknown) {\n // 4xx errors mean invalid code\n if (\n err &&\n typeof err === \"object\" &&\n \"status\" in err &&\n (err as { status: number }).status < 500\n ) {\n const apiErr = err as { body?: { error?: string } };\n return {\n valid: false,\n error: apiErr.body?.error ?? \"Invalid promo code\",\n };\n }\n throw err;\n }\n }\n\n /**\n * List all active resources for the organization.\n *\n * Returns resource cards with name, description, price, duration,\n * image, and type — suitable for building a resource picker.\n *\n * ```ts\n * const { resources } = await resira.listResources();\n * ```\n */\n async listResources(): Promise<ResourceListResponse> {\n return this.request<ResourceListResponse>(\"GET\", \"/resources\");\n }\n\n /**\n * Query availability for a resource.\n *\n * **Properties** (date-based):\n * ```ts\n * await resira.getAvailability(\"prop-1\", {\n * startDate: \"2026-07-01\",\n * endDate: \"2026-07-07\",\n * });\n * ```\n *\n * **Restaurants** (time-slot):\n * ```ts\n * await resira.getAvailability(\"table-5\", {\n * date: \"2026-07-01\",\n * partySize: 4,\n * });\n * ```\n *\n * Omit params to get all blocked dates (for calendar rendering).\n */\n async getAvailability(\n resourceId: string,\n params: AvailabilityParams = {},\n ): Promise<Availability> {\n if (!resourceId) {\n throw new Error(\"resourceId is required for getAvailability\");\n }\n const qs = toQueryString(keysToSnake(params as Record<string, string | number | undefined>));\n return this.request<Availability>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/availability${qs}`,\n );\n }\n\n /**\n * Query availability for a product/service.\n *\n * Aggregates capacity across all linked equipment. If a product\n * has 2 jet skis (each capacity=1), slots show capacity: 2.\n * Both pending and confirmed reservations count as occupied.\n *\n * ```ts\n * await resira.getProductAvailability(\"prod-123\", {\n * date: \"2026-07-01\",\n * durationMinutes: 30,\n * });\n * ```\n */\n async getProductAvailability(\n productId: string,\n params: AvailabilityParams = {},\n ): Promise<Availability> {\n if (!productId) {\n throw new Error(\"productId is required for getProductAvailability\");\n }\n const qs = toQueryString(keysToSnake(params as Record<string, string | number | undefined>));\n return this.request<Availability>(\n \"GET\",\n `/products/${encodeURIComponent(productId)}/availability${qs}`,\n );\n }\n\n /**\n * Create a reservation.\n *\n * Uses `POST /v2/api/reservations` — the `resourceId` is sent in\n * the request body, **not** in the URL path.\n *\n * An `Idempotency-Key` header is automatically attached so that\n * retries (including those from exponential backoff) are safe.\n *\n * ```ts\n * const { reservation } = await resira.createReservation({\n * resourceId: \"prop-1\",\n * guestName: \"Jane Doe\",\n * guestEmail: \"jane@example.com\",\n * startDate: \"2026-07-01\",\n * endDate: \"2026-07-07\",\n * partySize: 3,\n * });\n * ```\n */\n async createReservation(\n payload: CreateReservationRequest,\n options?: { idempotencyKey?: string },\n ): Promise<ReservationResponse> {\n if (!payload.resourceId && !payload.checkoutSessionToken) {\n throw new Error(\"resourceId or checkoutSessionToken is required for createReservation\");\n }\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n\n // Note: uses /v2/api prefix, not /v1/public\n const url = `${this.getBaseUrl()}/v2/api/reservations`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n };\n\n const init: RequestInit = {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | ResiraRateLimitError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n let response: Response;\n try {\n response = await this._fetch(url, init);\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n continue;\n }\n\n if (response.ok) {\n const raw = (await response.json()) as Record<string, unknown>;\n // The API may nest under \"reservation\" or \"booking\" depending on endpoint\n const resData = (raw.reservation ?? raw.booking ?? {}) as Record<string, unknown>;\n\n // Augment with request data: API response doesn't include\n // startTime/endTime/startDate/endDate/resourceId for v2 reservations\n const reservation: Reservation = {\n id: (resData.id as string) ?? \"\",\n resourceId: (resData.resourceId as string) ?? payload.resourceId,\n status: (resData.status as string) ?? \"pending\",\n startDate: (resData.startDate as string) ?? payload.startDate,\n endDate: (resData.endDate as string) ?? payload.endDate,\n startTime: (resData.startTime as string) ?? payload.startTime,\n endTime: (resData.endTime as string) ?? payload.endTime,\n startDatetime: (resData.startDatetime as string) ?? payload.startTime,\n endDatetime: (resData.endDatetime as string) ?? payload.endTime,\n guestName: (resData.guestName as string) ?? payload.guestName,\n partySize: (resData.partySize as number) ?? (resData.guests as number) ?? payload.partySize ?? 2,\n totalPrice: (resData.totalPrice as number) ?? 0,\n currency: (resData.currency as string) ?? \"EUR\",\n createdAt: (resData.createdAt as string) ?? new Date().toISOString(),\n };\n\n return { reservation };\n }\n\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n continue;\n }\n\n if (response.status >= 500) {\n lastError = new ResiraApiError(response.status, response.statusText, errorBody, response);\n continue;\n }\n\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n\n throw lastError!;\n }\n\n /**\n * List reservations for a resource (paginated).\n *\n * ```ts\n * const page = await resira.listReservations(\"prop-1\", {\n * status: \"confirmed\",\n * page: 1,\n * limit: 50,\n * });\n * console.log(page.data); // Reservation[]\n * console.log(page.totalPages); // number\n * ```\n */\n async listReservations(\n resourceId: string,\n params: ListReservationsParams = {},\n ): Promise<PaginatedReservations> {\n const qs = toQueryString(params as Record<string, string | number | undefined>);\n return this.request<PaginatedReservations>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/reservations${qs}`,\n );\n }\n\n /**\n * Get a single reservation by ID.\n *\n * ```ts\n * const { reservation } = await resira.getReservation(\"prop-1\", \"res-uuid\");\n * ```\n */\n async getReservation(\n resourceId: string,\n reservationId: string,\n ): Promise<ReservationResponse> {\n return this.request<ReservationResponse>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/reservations/${encodeURIComponent(reservationId)}`,\n );\n }\n\n /**\n * List all active products/services for the organisation.\n *\n * Calls `GET /v1/public/products` which returns products with\n * pricing, duration, and linked equipment.\n *\n * Falls back to mapping resources → products if the endpoint\n * returns 404 (backend hasn't been updated yet).\n *\n * ```ts\n * const { products } = await resira.listProducts();\n * ```\n */\n async listProducts(): Promise<ProductListResponse> {\n try {\n return await this.request<ProductListResponse>(\"GET\", \"/products\");\n } catch (err: unknown) {\n // Fallback: if /products endpoint doesn't exist yet (404),\n // map resources → products shape\n if (\n err &&\n typeof err === \"object\" &&\n \"status\" in err &&\n (err as { status: number }).status === 404\n ) {\n const resourceResponse = await this.listResources();\n const products = resourceResponse.resources.map((r) => ({\n id: r.id,\n name: r.name,\n description: r.description,\n durationMinutes: r.durationMinutes ?? 60,\n priceCents: r.pricePerSession ?? 0,\n currency: r.currency ?? \"EUR\",\n imageUrl: r.imageUrl,\n active: r.active,\n sortOrder: 0,\n pricingModel: \"per_session\" as const,\n equipmentIds: [r.id],\n equipmentNames: [r.name],\n }));\n return { products, count: products.length };\n }\n throw err;\n }\n }\n\n /**\n * List all dishes with 3D model data for the organisation.\n *\n * Returns dishes with name, description, price, image, and\n * 3D model URLs for AR/preview rendering.\n *\n * ```ts\n * const { dishes } = await resira.listDishes();\n * ```\n */\n async listDishes(): Promise<DishListResponse> {\n return this.request<DishListResponse>(\"GET\", \"/dishes\");\n }\n\n /**\n * Get a single dish by ID.\n *\n * ```ts\n * const { dish } = await resira.getDish(\"dish-uuid\");\n * console.log(dish.name, dish.model?.glbUrl);\n * ```\n */\n async getDish(dishId: string): Promise<DishResponse> {\n if (!dishId) {\n throw new Error(\"dishId is required for getDish\");\n }\n return this.request<DishResponse>(\n \"GET\",\n `/dishes/${encodeURIComponent(dishId)}`,\n );\n }\n\n /**\n * Retrieve a checkout session by its token.\n *\n * Used to hydrate the checkout screen when opening the widget\n * with a pre-created session token (skip service selection).\n *\n * ```ts\n * const { session } = await resira.getCheckoutSession(\"cs_ab12cd34ef56\");\n * console.log(session.productName, session.priceCents);\n * ```\n */\n async getCheckoutSession(token: string): Promise<CheckoutSessionResponse> {\n if (!token) {\n throw new Error(\"token is required for getCheckoutSession\");\n }\n const url = `${this.getBaseUrl()}/v2/public/checkout-sessions/${encodeURIComponent(token)}`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n let response: Response;\n try {\n response = await this._fetch(url, { method: \"GET\", headers });\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n continue;\n }\n\n if (response.ok) {\n const raw = await response.json();\n return deepKeysToCamel(raw) as CheckoutSessionResponse;\n }\n\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n continue;\n }\n if (response.status >= 500) {\n lastError = new ResiraApiError(response.status, response.statusText, errorBody, response);\n continue;\n }\n\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n\n throw lastError!;\n }\n\n /**\n * Create a new checkout session.\n *\n * External sites can create a session with product, slot, and guest\n * details, then pass the returned token to the widget to skip\n * directly to checkout.\n *\n * ```ts\n * const { sessionToken } = await resira.createCheckoutSession({\n * productId: \"prod-123\",\n * durationMinutes: 30,\n * partySize: 2,\n * date: \"2026-07-01\",\n * startTime: \"2026-07-01T10:00:00Z\",\n * endTime: \"2026-07-01T10:30:00Z\",\n * });\n * ```\n */\n async createCheckoutSession(\n payload: CreateCheckoutSessionRequest,\n options?: { idempotencyKey?: string },\n ): Promise<CreateCheckoutSessionResponse> {\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n const url = `${this.getBaseUrl()}/v2/public/checkout-sessions`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n };\n\n const init: RequestInit = {\n method: \"POST\",\n headers,\n body: JSON.stringify(withCanonicalDurationWindow(payload)),\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n let response: Response;\n try {\n response = await this._fetch(url, init);\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n continue;\n }\n\n if (response.ok) {\n const raw = await response.json();\n return deepKeysToCamel(raw) as CreateCheckoutSessionResponse;\n }\n\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n continue;\n }\n if (response.status >= 500) {\n lastError = new ResiraApiError(response.status, response.statusText, errorBody, response);\n continue;\n }\n\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n\n throw lastError!;\n }\n\n /**\n * Create a Stripe payment intent for a booking.\n *\n * The server creates the payment intent, calculates the amount,\n * and returns a `clientSecret` to confirm payment on the frontend\n * using Stripe Elements.\n *\n * ```ts\n * const { clientSecret, amountNow, amountAtVenue } =\n * await resira.createPaymentIntent({\n * productId: \"prod-123\",\n * resourceId: \"res-456\",\n * partySize: 2,\n * startDate: \"2026-07-01\",\n * startTime: \"2026-07-01T10:00:00Z\",\n * endTime: \"2026-07-01T11:00:00Z\",\n * guestName: \"Jane Doe\",\n * guestEmail: \"jane@example.com\",\n * });\n * ```\n */\n async createPaymentIntent(\n payload: CreatePaymentIntentRequest,\n options?: { idempotencyKey?: string },\n ): Promise<PaymentIntentResponse> {\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n const raw = await this.request<Record<string, unknown>>(\n \"POST\",\n \"/payments/create-intent\",\n withCanonicalDurationWindow(payload),\n { \"Idempotency-Key\": idempotencyKey },\n );\n // Normalize response keys to camelCase\n const data = deepKeysToCamel(raw) as Record<string, unknown>;\n // Map backend field names to SDK field names:\n // backend: amountDue, totalPrice\n // SDK: amountNow, totalAmount, amountAtVenue\n const totalAmount = (data.totalAmount as number) ?? (data.totalPrice as number) ?? 0;\n const amountNow = (data.amountNow as number) ?? (data.amountDue as number) ?? totalAmount;\n const amountAtVenue = (data.amountAtVenue as number) ?? (totalAmount - amountNow);\n return {\n clientSecret: data.clientSecret as string,\n paymentIntentId: data.paymentIntentId as string,\n amountNow,\n amountAtVenue,\n totalAmount,\n currency: (data.currency as string) ?? \"EUR\",\n paymentOption: data.paymentOption as string | undefined,\n reservationId: data.reservationId as string | undefined,\n discountAmount: (data.discountAmount as number) ?? undefined,\n originalPrice: (data.originalPrice as number) ?? undefined,\n promoCodeApplied: (data.promoCodeApplied as string) ?? undefined,\n };\n }\n\n /**\n * Confirm that a payment was successful after the guest\n * completes the Stripe payment flow.\n *\n * This transitions the reservation from `pending` to `confirmed`.\n *\n * ```ts\n * const { reservation, paymentStatus } =\n * await resira.confirmPayment({\n * paymentIntentId: \"pi_xxx\",\n * reservationId: \"res-uuid\",\n * });\n * ```\n */\n async confirmPayment(\n payload: ConfirmPaymentRequest,\n ): Promise<ConfirmPaymentResponse> {\n const raw = await this.request<Record<string, unknown>>(\n \"POST\",\n \"/payments/confirm\",\n payload,\n );\n // Normalize response keys to camelCase in case backend returns snake_case\n return deepKeysToCamel(raw) as ConfirmPaymentResponse;\n }\n\n // ─────────────────────────────────────────────────────────────\n // Internal HTTP layer\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Execute an HTTP request with retry logic and error normalization.\n *\n * - Attaches `Authorization: Bearer <apiKey>` on every request.\n * - Retries on 429 and 5xx with exponential backoff + jitter.\n * - Parses error bodies and throws typed error classes.\n */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n extraHeaders?: Record<string, string>,\n ): Promise<T> {\n const url = `${this.getBaseUrl()}${API_PREFIX}${path}`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n ...extraHeaders,\n };\n\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n const init: RequestInit = {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n // ── Wait before retry ────────────────────────────────\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n // ── Execute the request ──────────────────────────────\n let response: Response;\n try {\n response = await this._fetch(url, init);\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n // Network errors are always retryable\n continue;\n }\n\n // ── Success ──────────────────────────────────────────\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n // ── Parse error body ─────────────────────────────────\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n // ── Rate limit ───────────────────────────────────────\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n // Always retry 429s (up to maxRetries)\n continue;\n }\n\n // ── Server error (5xx) — retryable ───────────────────\n if (response.status >= 500) {\n lastError = new ResiraApiError(\n response.status,\n response.statusText,\n errorBody,\n response,\n );\n continue;\n }\n\n // ── Client error (4xx) — NOT retryable ───────────────\n throw new ResiraApiError(\n response.status,\n response.statusText,\n errorBody,\n response,\n );\n }\n\n // All retries exhausted — throw the last error\n throw lastError!;\n }\n\n /**\n * Calculate backoff delay in milliseconds for a given retry attempt.\n *\n * Uses exponential backoff with full jitter:\n * delay = random(0, base * 2^attempt)\n *\n * For 429 responses, respects the `Retry-After` header as a minimum.\n */\n private calculateBackoff(\n attempt: number,\n lastError?: ResiraApiError | ResiraNetworkError,\n ): number {\n const exponential = this.retryBaseDelay * 2 ** (attempt - 1);\n const jittered = Math.random() * exponential;\n\n // If the server told us to wait, use that as the floor\n if (lastError instanceof ResiraRateLimitError) {\n const serverDelay = lastError.retryAfter * 1000;\n return Math.max(serverDelay, jittered);\n }\n\n return jittered;\n }\n\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -415,6 +415,8 @@ interface CreatePaymentIntentRequest {
415
415
  partySize?: number;
416
416
  /** Selected duration in minutes (for multi-duration products). */
417
417
  durationMinutes?: number;
418
+ /** Optional duration in hours for compatibility with older integrations. */
419
+ durationHours?: number;
418
420
  /** Start date (YYYY-MM-DD). */
419
421
  startDate?: string;
420
422
  /** Start time (ISO 8601, optional). */
@@ -645,6 +647,8 @@ interface CreateCheckoutSessionRequest {
645
647
  productId: string;
646
648
  /** Duration in minutes. */
647
649
  durationMinutes: number;
650
+ /** Optional duration in hours for compatibility with older integrations. */
651
+ durationHours?: number;
648
652
  /** Party size. */
649
653
  partySize: number;
650
654
  /** Booking date (YYYY-MM-DD). */
@@ -652,7 +656,7 @@ interface CreateCheckoutSessionRequest {
652
656
  /** Start time (ISO 8601). */
653
657
  startTime: string;
654
658
  /** End time (ISO 8601). */
655
- endTime: string;
659
+ endTime?: string;
656
660
  /** Guest name (optional). */
657
661
  guestName?: string;
658
662
  /** Guest email (optional). */
package/dist/index.d.ts CHANGED
@@ -415,6 +415,8 @@ interface CreatePaymentIntentRequest {
415
415
  partySize?: number;
416
416
  /** Selected duration in minutes (for multi-duration products). */
417
417
  durationMinutes?: number;
418
+ /** Optional duration in hours for compatibility with older integrations. */
419
+ durationHours?: number;
418
420
  /** Start date (YYYY-MM-DD). */
419
421
  startDate?: string;
420
422
  /** Start time (ISO 8601, optional). */
@@ -645,6 +647,8 @@ interface CreateCheckoutSessionRequest {
645
647
  productId: string;
646
648
  /** Duration in minutes. */
647
649
  durationMinutes: number;
650
+ /** Optional duration in hours for compatibility with older integrations. */
651
+ durationHours?: number;
648
652
  /** Party size. */
649
653
  partySize: number;
650
654
  /** Booking date (YYYY-MM-DD). */
@@ -652,7 +656,7 @@ interface CreateCheckoutSessionRequest {
652
656
  /** Start time (ISO 8601). */
653
657
  startTime: string;
654
658
  /** End time (ISO 8601). */
655
- endTime: string;
659
+ endTime?: string;
656
660
  /** Guest name (optional). */
657
661
  guestName?: string;
658
662
  /** Guest email (optional). */
package/dist/index.js CHANGED
@@ -172,6 +172,47 @@ function deepKeysToCamel(obj) {
172
172
  }
173
173
  return obj;
174
174
  }
175
+ function toIsoIfValid(value) {
176
+ if (typeof value !== "string" || !value.trim()) return null;
177
+ const date = new Date(value);
178
+ if (Number.isNaN(date.getTime())) return null;
179
+ return date.toISOString();
180
+ }
181
+ function normalizeDurationMinutes(value) {
182
+ if (typeof value !== "number" || !Number.isFinite(value)) return null;
183
+ const rounded = Math.round(value);
184
+ return rounded > 0 ? rounded : null;
185
+ }
186
+ function withCanonicalDurationWindow(payload) {
187
+ const next = { ...payload };
188
+ const hoursAsMinutes = normalizeDurationMinutes(next.durationHours) ? Math.round(next.durationHours * 60) : null;
189
+ const durationMinutes = normalizeDurationMinutes(next.durationMinutes) ?? hoursAsMinutes;
190
+ if (durationMinutes) {
191
+ next.durationMinutes = durationMinutes;
192
+ next.durationHours = Number((durationMinutes / 60).toFixed(6));
193
+ }
194
+ const startIso = toIsoIfValid(next.startTime);
195
+ const endIso = toIsoIfValid(next.endTime);
196
+ if (startIso) next.startTime = startIso;
197
+ if (durationMinutes && startIso) {
198
+ const computedEnd = new Date(
199
+ new Date(startIso).getTime() + durationMinutes * 6e4
200
+ ).toISOString();
201
+ if (!endIso) {
202
+ next.endTime = computedEnd;
203
+ } else {
204
+ const mismatch = new Date(endIso).getTime() - new Date(startIso).getTime() !== durationMinutes * 6e4;
205
+ if (mismatch) {
206
+ next.endTime = computedEnd;
207
+ } else {
208
+ next.endTime = endIso;
209
+ }
210
+ }
211
+ } else if (endIso) {
212
+ next.endTime = endIso;
213
+ }
214
+ return next;
215
+ }
175
216
  var Resira = class {
176
217
  constructor(config) {
177
218
  if (!config.apiKey) {
@@ -591,7 +632,7 @@ var Resira = class {
591
632
  const init = {
592
633
  method: "POST",
593
634
  headers,
594
- body: JSON.stringify(payload)
635
+ body: JSON.stringify(withCanonicalDurationWindow(payload))
595
636
  };
596
637
  let lastError;
597
638
  for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
@@ -657,7 +698,7 @@ var Resira = class {
657
698
  const raw = await this.request(
658
699
  "POST",
659
700
  "/payments/create-intent",
660
- payload,
701
+ withCanonicalDurationWindow(payload),
661
702
  { "Idempotency-Key": idempotencyKey }
662
703
  );
663
704
  const data = deepKeysToCamel(raw);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/routing.ts","../src/client.ts"],"names":["url"],"mappings":"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","file":"index.js","sourcesContent":["import type { ApiErrorBody } from \"./types.js\";\n\n// ═══════════════════════════════════════════════════════════════\n// Base error\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Base error class for all SDK errors.\n *\n * Use `instanceof` checks to distinguish error types:\n *\n * ```ts\n * try { … } catch (e) {\n * if (e instanceof ResiraRateLimitError) { … }\n * if (e instanceof ResiraApiError) { … }\n * if (e instanceof ResiraNetworkError) { … }\n * }\n * ```\n */\nexport class ResiraError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ResiraError\";\n // Fix prototype chain for instanceof to work after transpilation\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// API error (4xx / 5xx with a parsed body)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Thrown when the API returns a non-2xx response with a JSON body.\n *\n * ```ts\n * err.status // 400, 404, 409, 422, 500, …\n * err.code // HTTP status text (e.g. \"Not Found\")\n * err.body // Parsed `{ error: \"…\" }` from the server\n * ```\n */\nexport class ResiraApiError extends ResiraError {\n /** HTTP status code. */\n readonly status: number;\n /** HTTP status text (e.g. `\"Bad Request\"`). */\n readonly code: string;\n /** Parsed error body from the API. */\n readonly body: ApiErrorBody;\n /** The full `Response` object (headers are still accessible). */\n readonly response: Response;\n\n constructor(status: number, code: string, body: ApiErrorBody, response: Response) {\n super(body.error || `API error ${status}`);\n this.name = \"ResiraApiError\";\n this.status = status;\n this.code = code;\n this.body = body;\n this.response = response;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n /** Whether this error is retryable (5xx or 429). */\n get retryable(): boolean {\n return this.status === 429 || this.status >= 500;\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Rate limit error (429)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Thrown when the API returns 429 Too Many Requests.\n *\n * ```ts\n * err.retryAfter // Seconds until the client should retry\n * ```\n */\nexport class ResiraRateLimitError extends ResiraApiError {\n /** Seconds to wait before retrying (from `Retry-After` header). */\n readonly retryAfter: number;\n\n constructor(body: ApiErrorBody, response: Response) {\n super(429, \"Too Many Requests\", body, response);\n this.name = \"ResiraRateLimitError\";\n this.retryAfter =\n body.retryAfter ??\n (Number.parseInt(response.headers.get(\"retry-after\") ?? \"60\", 10) ||\n 60);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Network error (fetch failed, DNS, timeout, etc.)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Thrown when the request never reached the server.\n *\n * This wraps the underlying `TypeError` or `DOMException` from\n * `fetch()` failures (DNS resolution, TLS, network offline, etc.).\n */\nexport class ResiraNetworkError extends ResiraError {\n /** The original error thrown by `fetch`. */\n readonly cause: unknown;\n\n constructor(message: string, cause: unknown) {\n super(message);\n this.name = \"ResiraNetworkError\";\n this.cause = cause;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import type { ResiraConfig, WeightedBaseUrl } from \"./types.js\";\n\ninterface ResolvedBaseUrl {\n url: string;\n weight: number;\n}\n\nconst DEFAULT_LOCAL_BASE_URLS: ResolvedBaseUrl[] = [\n { url: \"http://localhost:3001\", weight: 100 },\n];\n\nconst DEFAULT_PRODUCTION_BASE_URLS: ResolvedBaseUrl[] = [\n { url: \"https://api.resira.app\", weight: 100 },\n];\n\nfunction readEnv(name: string): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return process.env?.[name];\n}\n\n\nfunction normalizeUrl(url: string): string {\n return url.trim().replace(/\\/+$/, \"\");\n}\n\nfunction isPositiveNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\nfunction toResolvedBaseUrl(value: string | WeightedBaseUrl): ResolvedBaseUrl | null {\n if (typeof value === \"string\") {\n const url = normalizeUrl(value);\n return url ? { url, weight: 1 } : null;\n }\n\n const url = normalizeUrl(value.url);\n if (!url) return null;\n\n return {\n url,\n weight: isPositiveNumber(value.weight) ? value.weight : 1,\n };\n}\n\nfunction parseJsonBaseUrls(value: string): ResolvedBaseUrl[] {\n const parsed = JSON.parse(value) as unknown;\n if (!Array.isArray(parsed)) return [];\n\n return parsed.flatMap((entry) => {\n const resolved =\n typeof entry === \"string\"\n ? toResolvedBaseUrl(entry)\n : entry && typeof entry === \"object\"\n ? toResolvedBaseUrl(entry as WeightedBaseUrl)\n : null;\n\n return resolved ? [resolved] : [];\n });\n}\n\nfunction parseDelimitedBaseUrls(value: string): ResolvedBaseUrl[] {\n return value\n .split(\",\")\n .flatMap((entry) => {\n const [rawUrl, rawWeight] = entry.split(\"|\");\n const url = normalizeUrl(rawUrl ?? \"\");\n if (!url) return [];\n\n const parsedWeight = rawWeight ? Number(rawWeight.trim()) : 1;\n return [{\n url,\n weight: isPositiveNumber(parsedWeight) ? parsedWeight : 1,\n }];\n });\n}\n\nfunction parseEnvBaseUrls(value: string | undefined): ResolvedBaseUrl[] {\n if (!value) return [];\n\n try {\n const parsed = parseJsonBaseUrls(value);\n if (parsed.length > 0) return parsed;\n } catch {\n // Fall back to delimiter parsing.\n }\n\n return parseDelimitedBaseUrls(value);\n}\n\nexport function resolveBaseUrls(config: ResiraConfig): ResolvedBaseUrl[] {\n if (config.baseUrl) {\n return [{ url: normalizeUrl(config.baseUrl), weight: 100 }];\n }\n\n if (config.baseUrls?.length) {\n const explicit = config.baseUrls.flatMap((entry) => {\n const resolved = toResolvedBaseUrl(entry);\n return resolved ? [resolved] : [];\n });\n\n if (explicit.length > 0) return explicit;\n }\n\n const envBaseUrls = parseEnvBaseUrls(readEnv(\"RESIRA_API_BASE_URLS\"));\n if (envBaseUrls.length > 0) {\n return envBaseUrls;\n }\n\n if (readEnv(\"NODE_ENV\") === \"development\") {\n return DEFAULT_LOCAL_BASE_URLS;\n }\n\n return DEFAULT_PRODUCTION_BASE_URLS;\n}\n\nexport function pickBaseUrl(baseUrls: ResolvedBaseUrl[]): string {\n return baseUrls[0]?.url ?? DEFAULT_PRODUCTION_BASE_URLS[0].url;\n}\n\nexport function getRoutingStats(): Record<string, never> {\n return {};\n}","import { ResiraApiError, ResiraNetworkError, ResiraRateLimitError } from \"./errors.js\";\nimport { pickBaseUrl, resolveBaseUrls } from \"./routing.js\";\nimport type {\n ApiErrorBody,\n Availability,\n AvailabilityParams,\n CheckoutSessionResponse,\n ConfirmPaymentRequest,\n ConfirmPaymentResponse,\n CreateCheckoutSessionRequest,\n CreateCheckoutSessionResponse,\n CreatePaymentIntentRequest,\n CreateReservationRequest,\n Dish,\n DishListResponse,\n DishResponse,\n ListReservationsParams,\n PaginatedReservations,\n PaymentIntentResponse,\n ProductListResponse,\n PropertyConfig,\n Reservation,\n ReservationResponse,\n ResiraConfig,\n ResourceListResponse,\n ValidatePromoCodeResponse,\n} from \"./types.js\";\n\n// ═══════════════════════════════════════════════════════════════\n// Constants\n// ═══════════════════════════════════════════════════════════════\n\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_RETRY_BASE_DELAY = 500; // ms\nconst API_PREFIX = \"/v1/public\";\n\n// ═══════════════════════════════════════════════════════════════\n// Helpers\n// ═══════════════════════════════════════════════════════════════\n\n/** Generate a random UUID v4 for idempotency keys. */\nfunction uuid(): string {\n // Use crypto.randomUUID when available (Node 19+, all modern browsers)\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID();\n }\n // Fallback: manual v4 UUID\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n return (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n });\n}\n\n/** Build a query string from a flat params object. Skips `undefined` values. */\nfunction toQueryString(params: Record<string, string | number | boolean | undefined>): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n }\n }\n return parts.length > 0 ? `?${parts.join(\"&\")}` : \"\";\n}\n\n/** Sleep for `ms` milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Convert camelCase keys to snake_case for query parameters.\n * The API expects snake_case query params (`start_date`, `party_size`).\n */\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/** Convert an object's keys from camelCase to snake_case. */\nfunction keysToSnake(\n obj: Record<string, string | number | boolean | undefined>,\n): Record<string, string | number | boolean | undefined> {\n const result: Record<string, string | number | boolean | undefined> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[camelToSnake(key)] = value;\n }\n return result;\n}\n\n/** Convert snake_case string to camelCase. */\nfunction snakeToCamel(str: string): string {\n return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\n}\n\n/** Deep-convert all keys in an object/array from camelCase to snake_case. */\nfunction deepKeysToSnake(obj: unknown): unknown {\n if (Array.isArray(obj)) return obj.map(deepKeysToSnake);\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[camelToSnake(key)] = deepKeysToSnake(value);\n }\n return result;\n }\n return obj;\n}\n\n/** Deep-convert all keys in an object/array from snake_case to camelCase. */\nfunction deepKeysToCamel(obj: unknown): unknown {\n if (Array.isArray(obj)) return obj.map(deepKeysToCamel);\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[snakeToCamel(key)] = deepKeysToCamel(value);\n }\n return result;\n }\n return obj;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Client\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Resira SDK client.\n *\n * ```ts\n * const resira = new Resira({\n * apiKey: \"resira_live_abc123…\",\n * baseUrl: \"https://api.example.com\", // optional\n * });\n *\n * const availability = await resira.getAvailability(\"prop-1\", {\n * startDate: \"2026-07-01\",\n * endDate: \"2026-07-07\",\n * });\n * ```\n */\nexport class Resira {\n private readonly apiKey: string;\n private readonly baseUrls: ReturnType<typeof resolveBaseUrls>;\n private readonly maxRetries: number;\n private readonly retryBaseDelay: number;\n private readonly _fetch: typeof globalThis.fetch;\n\n constructor(config: ResiraConfig) {\n if (!config.apiKey) {\n throw new Error(\"Resira: apiKey is required\");\n }\n this.apiKey = config.apiKey;\n this.baseUrls = resolveBaseUrls(config);\n this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.retryBaseDelay = config.retryBaseDelay ?? DEFAULT_RETRY_BASE_DELAY;\n this._fetch = config.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n /** The resolved API origin used by this client instance. */\n getBaseUrl(): string {\n return pickBaseUrl(this.baseUrls);\n }\n\n // ─────────────────────────────────────────────────────────────\n // Public API methods\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Fetch the public property configuration.\n *\n * Returns non-sensitive settings such as the Stripe publishable\n * key, deposit percentage, currency, and branding info.\n *\n * ```ts\n * const config = await resira.getConfig();\n * console.log(config.stripePublishableKey); // \"pk_test_…\"\n * ```\n */\n async getConfig(): Promise<PropertyConfig> {\n return this.request<PropertyConfig>(\"GET\", \"/config\");\n }\n\n /**\n * Validate a promo/discount code.\n *\n * Returns discount details if valid, or an error message if not.\n *\n * ```ts\n * const result = await resira.validatePromoCode(\"SUMMER20\");\n * if (result.valid) {\n * console.log(result.discountType, result.discountValue);\n * }\n * ```\n */\n async validatePromoCode(code: string): Promise<ValidatePromoCodeResponse> {\n try {\n const raw = await this.request<Record<string, unknown>>(\n \"POST\",\n \"/promo-codes/validate\",\n { code },\n );\n const data = deepKeysToCamel(raw) as Record<string, unknown>;\n return {\n valid: true,\n discountType: data.discountType as \"percent\" | \"fixed\" | undefined,\n discountValue: data.discountValue as number | undefined,\n currency: data.currency as string | undefined,\n minOrderCents: data.minOrderCents as number | undefined,\n };\n } catch (err: unknown) {\n // 4xx errors mean invalid code\n if (\n err &&\n typeof err === \"object\" &&\n \"status\" in err &&\n (err as { status: number }).status < 500\n ) {\n const apiErr = err as { body?: { error?: string } };\n return {\n valid: false,\n error: apiErr.body?.error ?? \"Invalid promo code\",\n };\n }\n throw err;\n }\n }\n\n /**\n * List all active resources for the organization.\n *\n * Returns resource cards with name, description, price, duration,\n * image, and type — suitable for building a resource picker.\n *\n * ```ts\n * const { resources } = await resira.listResources();\n * ```\n */\n async listResources(): Promise<ResourceListResponse> {\n return this.request<ResourceListResponse>(\"GET\", \"/resources\");\n }\n\n /**\n * Query availability for a resource.\n *\n * **Properties** (date-based):\n * ```ts\n * await resira.getAvailability(\"prop-1\", {\n * startDate: \"2026-07-01\",\n * endDate: \"2026-07-07\",\n * });\n * ```\n *\n * **Restaurants** (time-slot):\n * ```ts\n * await resira.getAvailability(\"table-5\", {\n * date: \"2026-07-01\",\n * partySize: 4,\n * });\n * ```\n *\n * Omit params to get all blocked dates (for calendar rendering).\n */\n async getAvailability(\n resourceId: string,\n params: AvailabilityParams = {},\n ): Promise<Availability> {\n if (!resourceId) {\n throw new Error(\"resourceId is required for getAvailability\");\n }\n const qs = toQueryString(keysToSnake(params as Record<string, string | number | undefined>));\n return this.request<Availability>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/availability${qs}`,\n );\n }\n\n /**\n * Query availability for a product/service.\n *\n * Aggregates capacity across all linked equipment. If a product\n * has 2 jet skis (each capacity=1), slots show capacity: 2.\n * Both pending and confirmed reservations count as occupied.\n *\n * ```ts\n * await resira.getProductAvailability(\"prod-123\", {\n * date: \"2026-07-01\",\n * durationMinutes: 30,\n * });\n * ```\n */\n async getProductAvailability(\n productId: string,\n params: AvailabilityParams = {},\n ): Promise<Availability> {\n if (!productId) {\n throw new Error(\"productId is required for getProductAvailability\");\n }\n const qs = toQueryString(keysToSnake(params as Record<string, string | number | undefined>));\n return this.request<Availability>(\n \"GET\",\n `/products/${encodeURIComponent(productId)}/availability${qs}`,\n );\n }\n\n /**\n * Create a reservation.\n *\n * Uses `POST /v2/api/reservations` — the `resourceId` is sent in\n * the request body, **not** in the URL path.\n *\n * An `Idempotency-Key` header is automatically attached so that\n * retries (including those from exponential backoff) are safe.\n *\n * ```ts\n * const { reservation } = await resira.createReservation({\n * resourceId: \"prop-1\",\n * guestName: \"Jane Doe\",\n * guestEmail: \"jane@example.com\",\n * startDate: \"2026-07-01\",\n * endDate: \"2026-07-07\",\n * partySize: 3,\n * });\n * ```\n */\n async createReservation(\n payload: CreateReservationRequest,\n options?: { idempotencyKey?: string },\n ): Promise<ReservationResponse> {\n if (!payload.resourceId && !payload.checkoutSessionToken) {\n throw new Error(\"resourceId or checkoutSessionToken is required for createReservation\");\n }\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n\n // Note: uses /v2/api prefix, not /v1/public\n const url = `${this.getBaseUrl()}/v2/api/reservations`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n };\n\n const init: RequestInit = {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | ResiraRateLimitError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n let response: Response;\n try {\n response = await this._fetch(url, init);\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n continue;\n }\n\n if (response.ok) {\n const raw = (await response.json()) as Record<string, unknown>;\n // The API may nest under \"reservation\" or \"booking\" depending on endpoint\n const resData = (raw.reservation ?? raw.booking ?? {}) as Record<string, unknown>;\n\n // Augment with request data: API response doesn't include\n // startTime/endTime/startDate/endDate/resourceId for v2 reservations\n const reservation: Reservation = {\n id: (resData.id as string) ?? \"\",\n resourceId: (resData.resourceId as string) ?? payload.resourceId,\n status: (resData.status as string) ?? \"pending\",\n startDate: (resData.startDate as string) ?? payload.startDate,\n endDate: (resData.endDate as string) ?? payload.endDate,\n startTime: (resData.startTime as string) ?? payload.startTime,\n endTime: (resData.endTime as string) ?? payload.endTime,\n startDatetime: (resData.startDatetime as string) ?? payload.startTime,\n endDatetime: (resData.endDatetime as string) ?? payload.endTime,\n guestName: (resData.guestName as string) ?? payload.guestName,\n partySize: (resData.partySize as number) ?? (resData.guests as number) ?? payload.partySize ?? 2,\n totalPrice: (resData.totalPrice as number) ?? 0,\n currency: (resData.currency as string) ?? \"EUR\",\n createdAt: (resData.createdAt as string) ?? new Date().toISOString(),\n };\n\n return { reservation };\n }\n\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n continue;\n }\n\n if (response.status >= 500) {\n lastError = new ResiraApiError(response.status, response.statusText, errorBody, response);\n continue;\n }\n\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n\n throw lastError!;\n }\n\n /**\n * List reservations for a resource (paginated).\n *\n * ```ts\n * const page = await resira.listReservations(\"prop-1\", {\n * status: \"confirmed\",\n * page: 1,\n * limit: 50,\n * });\n * console.log(page.data); // Reservation[]\n * console.log(page.totalPages); // number\n * ```\n */\n async listReservations(\n resourceId: string,\n params: ListReservationsParams = {},\n ): Promise<PaginatedReservations> {\n const qs = toQueryString(params as Record<string, string | number | undefined>);\n return this.request<PaginatedReservations>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/reservations${qs}`,\n );\n }\n\n /**\n * Get a single reservation by ID.\n *\n * ```ts\n * const { reservation } = await resira.getReservation(\"prop-1\", \"res-uuid\");\n * ```\n */\n async getReservation(\n resourceId: string,\n reservationId: string,\n ): Promise<ReservationResponse> {\n return this.request<ReservationResponse>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/reservations/${encodeURIComponent(reservationId)}`,\n );\n }\n\n /**\n * List all active products/services for the organisation.\n *\n * Calls `GET /v1/public/products` which returns products with\n * pricing, duration, and linked equipment.\n *\n * Falls back to mapping resources → products if the endpoint\n * returns 404 (backend hasn't been updated yet).\n *\n * ```ts\n * const { products } = await resira.listProducts();\n * ```\n */\n async listProducts(): Promise<ProductListResponse> {\n try {\n return await this.request<ProductListResponse>(\"GET\", \"/products\");\n } catch (err: unknown) {\n // Fallback: if /products endpoint doesn't exist yet (404),\n // map resources → products shape\n if (\n err &&\n typeof err === \"object\" &&\n \"status\" in err &&\n (err as { status: number }).status === 404\n ) {\n const resourceResponse = await this.listResources();\n const products = resourceResponse.resources.map((r) => ({\n id: r.id,\n name: r.name,\n description: r.description,\n durationMinutes: r.durationMinutes ?? 60,\n priceCents: r.pricePerSession ?? 0,\n currency: r.currency ?? \"EUR\",\n imageUrl: r.imageUrl,\n active: r.active,\n sortOrder: 0,\n pricingModel: \"per_session\" as const,\n equipmentIds: [r.id],\n equipmentNames: [r.name],\n }));\n return { products, count: products.length };\n }\n throw err;\n }\n }\n\n /**\n * List all dishes with 3D model data for the organisation.\n *\n * Returns dishes with name, description, price, image, and\n * 3D model URLs for AR/preview rendering.\n *\n * ```ts\n * const { dishes } = await resira.listDishes();\n * ```\n */\n async listDishes(): Promise<DishListResponse> {\n return this.request<DishListResponse>(\"GET\", \"/dishes\");\n }\n\n /**\n * Get a single dish by ID.\n *\n * ```ts\n * const { dish } = await resira.getDish(\"dish-uuid\");\n * console.log(dish.name, dish.model?.glbUrl);\n * ```\n */\n async getDish(dishId: string): Promise<DishResponse> {\n if (!dishId) {\n throw new Error(\"dishId is required for getDish\");\n }\n return this.request<DishResponse>(\n \"GET\",\n `/dishes/${encodeURIComponent(dishId)}`,\n );\n }\n\n /**\n * Retrieve a checkout session by its token.\n *\n * Used to hydrate the checkout screen when opening the widget\n * with a pre-created session token (skip service selection).\n *\n * ```ts\n * const { session } = await resira.getCheckoutSession(\"cs_ab12cd34ef56\");\n * console.log(session.productName, session.priceCents);\n * ```\n */\n async getCheckoutSession(token: string): Promise<CheckoutSessionResponse> {\n if (!token) {\n throw new Error(\"token is required for getCheckoutSession\");\n }\n const url = `${this.getBaseUrl()}/v2/public/checkout-sessions/${encodeURIComponent(token)}`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n let response: Response;\n try {\n response = await this._fetch(url, { method: \"GET\", headers });\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n continue;\n }\n\n if (response.ok) {\n const raw = await response.json();\n return deepKeysToCamel(raw) as CheckoutSessionResponse;\n }\n\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n continue;\n }\n if (response.status >= 500) {\n lastError = new ResiraApiError(response.status, response.statusText, errorBody, response);\n continue;\n }\n\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n\n throw lastError!;\n }\n\n /**\n * Create a new checkout session.\n *\n * External sites can create a session with product, slot, and guest\n * details, then pass the returned token to the widget to skip\n * directly to checkout.\n *\n * ```ts\n * const { sessionToken } = await resira.createCheckoutSession({\n * productId: \"prod-123\",\n * durationMinutes: 30,\n * partySize: 2,\n * date: \"2026-07-01\",\n * startTime: \"2026-07-01T10:00:00Z\",\n * endTime: \"2026-07-01T10:30:00Z\",\n * });\n * ```\n */\n async createCheckoutSession(\n payload: CreateCheckoutSessionRequest,\n options?: { idempotencyKey?: string },\n ): Promise<CreateCheckoutSessionResponse> {\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n const url = `${this.getBaseUrl()}/v2/public/checkout-sessions`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n };\n\n const init: RequestInit = {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n let response: Response;\n try {\n response = await this._fetch(url, init);\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n continue;\n }\n\n if (response.ok) {\n const raw = await response.json();\n return deepKeysToCamel(raw) as CreateCheckoutSessionResponse;\n }\n\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n continue;\n }\n if (response.status >= 500) {\n lastError = new ResiraApiError(response.status, response.statusText, errorBody, response);\n continue;\n }\n\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n\n throw lastError!;\n }\n\n /**\n * Create a Stripe payment intent for a booking.\n *\n * The server creates the payment intent, calculates the amount,\n * and returns a `clientSecret` to confirm payment on the frontend\n * using Stripe Elements.\n *\n * ```ts\n * const { clientSecret, amountNow, amountAtVenue } =\n * await resira.createPaymentIntent({\n * productId: \"prod-123\",\n * resourceId: \"res-456\",\n * partySize: 2,\n * startDate: \"2026-07-01\",\n * startTime: \"2026-07-01T10:00:00Z\",\n * endTime: \"2026-07-01T11:00:00Z\",\n * guestName: \"Jane Doe\",\n * guestEmail: \"jane@example.com\",\n * });\n * ```\n */\n async createPaymentIntent(\n payload: CreatePaymentIntentRequest,\n options?: { idempotencyKey?: string },\n ): Promise<PaymentIntentResponse> {\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n const raw = await this.request<Record<string, unknown>>(\n \"POST\",\n \"/payments/create-intent\",\n payload,\n { \"Idempotency-Key\": idempotencyKey },\n );\n // Normalize response keys to camelCase\n const data = deepKeysToCamel(raw) as Record<string, unknown>;\n // Map backend field names to SDK field names:\n // backend: amountDue, totalPrice\n // SDK: amountNow, totalAmount, amountAtVenue\n const totalAmount = (data.totalAmount as number) ?? (data.totalPrice as number) ?? 0;\n const amountNow = (data.amountNow as number) ?? (data.amountDue as number) ?? totalAmount;\n const amountAtVenue = (data.amountAtVenue as number) ?? (totalAmount - amountNow);\n return {\n clientSecret: data.clientSecret as string,\n paymentIntentId: data.paymentIntentId as string,\n amountNow,\n amountAtVenue,\n totalAmount,\n currency: (data.currency as string) ?? \"EUR\",\n paymentOption: data.paymentOption as string | undefined,\n reservationId: data.reservationId as string | undefined,\n discountAmount: (data.discountAmount as number) ?? undefined,\n originalPrice: (data.originalPrice as number) ?? undefined,\n promoCodeApplied: (data.promoCodeApplied as string) ?? undefined,\n };\n }\n\n /**\n * Confirm that a payment was successful after the guest\n * completes the Stripe payment flow.\n *\n * This transitions the reservation from `pending` to `confirmed`.\n *\n * ```ts\n * const { reservation, paymentStatus } =\n * await resira.confirmPayment({\n * paymentIntentId: \"pi_xxx\",\n * reservationId: \"res-uuid\",\n * });\n * ```\n */\n async confirmPayment(\n payload: ConfirmPaymentRequest,\n ): Promise<ConfirmPaymentResponse> {\n const raw = await this.request<Record<string, unknown>>(\n \"POST\",\n \"/payments/confirm\",\n payload,\n );\n // Normalize response keys to camelCase in case backend returns snake_case\n return deepKeysToCamel(raw) as ConfirmPaymentResponse;\n }\n\n // ─────────────────────────────────────────────────────────────\n // Internal HTTP layer\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Execute an HTTP request with retry logic and error normalization.\n *\n * - Attaches `Authorization: Bearer <apiKey>` on every request.\n * - Retries on 429 and 5xx with exponential backoff + jitter.\n * - Parses error bodies and throws typed error classes.\n */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n extraHeaders?: Record<string, string>,\n ): Promise<T> {\n const url = `${this.getBaseUrl()}${API_PREFIX}${path}`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n ...extraHeaders,\n };\n\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n const init: RequestInit = {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n // ── Wait before retry ────────────────────────────────\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n // ── Execute the request ──────────────────────────────\n let response: Response;\n try {\n response = await this._fetch(url, init);\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n // Network errors are always retryable\n continue;\n }\n\n // ── Success ──────────────────────────────────────────\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n // ── Parse error body ─────────────────────────────────\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n // ── Rate limit ───────────────────────────────────────\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n // Always retry 429s (up to maxRetries)\n continue;\n }\n\n // ── Server error (5xx) — retryable ───────────────────\n if (response.status >= 500) {\n lastError = new ResiraApiError(\n response.status,\n response.statusText,\n errorBody,\n response,\n );\n continue;\n }\n\n // ── Client error (4xx) — NOT retryable ───────────────\n throw new ResiraApiError(\n response.status,\n response.statusText,\n errorBody,\n response,\n );\n }\n\n // All retries exhausted — throw the last error\n throw lastError!;\n }\n\n /**\n * Calculate backoff delay in milliseconds for a given retry attempt.\n *\n * Uses exponential backoff with full jitter:\n * delay = random(0, base * 2^attempt)\n *\n * For 429 responses, respects the `Retry-After` header as a minimum.\n */\n private calculateBackoff(\n attempt: number,\n lastError?: ResiraApiError | ResiraNetworkError,\n ): number {\n const exponential = this.retryBaseDelay * 2 ** (attempt - 1);\n const jittered = Math.random() * exponential;\n\n // If the server told us to wait, use that as the floor\n if (lastError instanceof ResiraRateLimitError) {\n const serverDelay = lastError.retryAfter * 1000;\n return Math.max(serverDelay, jittered);\n }\n\n return jittered;\n }\n\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/routing.ts","../src/client.ts"],"names":["url"],"mappings":";AAmBO,IAAM,WAAA,GAAN,cAA0B,KAAA,CAAM;AAAA,EACrC,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,aAAA;AAEZ,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,GAAA,CAAA,MAAA,CAAW,SAAS,CAAA;AAAA,EAClD;AACF;AAeO,IAAM,cAAA,GAAN,cAA6B,WAAA,CAAY;AAAA,EAU9C,WAAA,CAAY,MAAA,EAAgB,IAAA,EAAc,IAAA,EAAoB,QAAA,EAAoB;AAChF,IAAA,KAAA,CAAM,IAAA,CAAK,KAAA,IAAS,CAAA,UAAA,EAAa,MAAM,CAAA,CAAE,CAAA;AACzC,IAAA,IAAA,CAAK,IAAA,GAAO,gBAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,GAAA,CAAA,MAAA,CAAW,SAAS,CAAA;AAAA,EAClD;AAAA;AAAA,EAGA,IAAI,SAAA,GAAqB;AACvB,IAAA,OAAO,IAAA,CAAK,MAAA,KAAW,GAAA,IAAO,IAAA,CAAK,MAAA,IAAU,GAAA;AAAA,EAC/C;AACF;AAaO,IAAM,oBAAA,GAAN,cAAmC,cAAA,CAAe;AAAA,EAIvD,WAAA,CAAY,MAAoB,QAAA,EAAoB;AAClD,IAAA,KAAA,CAAM,GAAA,EAAK,mBAAA,EAAqB,IAAA,EAAM,QAAQ,CAAA;AAC9C,IAAA,IAAA,CAAK,IAAA,GAAO,sBAAA;AACZ,IAAA,IAAA,CAAK,UAAA,GACH,IAAA,CAAK,UAAA,KACJ,MAAA,CAAO,QAAA,CAAS,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAA,IAAK,IAAA,EAAM,EAAE,CAAA,IAChE,EAAA,CAAA;AACF,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,GAAA,CAAA,MAAA,CAAW,SAAS,CAAA;AAAA,EAClD;AACF;AAYO,IAAM,kBAAA,GAAN,cAAiC,WAAA,CAAY;AAAA,EAIlD,WAAA,CAAY,SAAiB,KAAA,EAAgB;AAC3C,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,oBAAA;AACZ,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,GAAA,CAAA,MAAA,CAAW,SAAS,CAAA;AAAA,EAClD;AACF;;;AC1GA,IAAM,uBAAA,GAA6C;AAAA,EACjD,EAAE,GAAA,EAAK,uBAAA,EAAyB,MAAA,EAAQ,GAAA;AAC1C,CAAA;AAEA,IAAM,4BAAA,GAAkD;AAAA,EACtD,EAAE,GAAA,EAAK,wBAAA,EAA0B,MAAA,EAAQ,GAAA;AAC3C,CAAA;AAEA,SAAS,QAAQ,IAAA,EAAkC;AACjD,EAAA,IAAI,OAAO,OAAA,KAAY,WAAA,EAAa,OAAO,MAAA;AAC3C,EAAA,OAAO,OAAA,CAAQ,MAAM,IAAI,CAAA;AAC3B;AAGA,SAAS,aAAa,GAAA,EAAqB;AACzC,EAAA,OAAO,GAAA,CAAI,IAAA,EAAK,CAAE,OAAA,CAAQ,QAAQ,EAAE,CAAA;AACtC;AAEA,SAAS,iBAAiB,KAAA,EAAiC;AACzD,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,OAAO,QAAA,CAAS,KAAK,KAAK,KAAA,GAAQ,CAAA;AACxE;AAEA,SAAS,kBAAkB,KAAA,EAAyD;AAClF,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,MAAMA,IAAAA,GAAM,aAAa,KAAK,CAAA;AAC9B,IAAA,OAAOA,OAAM,EAAE,GAAA,EAAAA,IAAAA,EAAK,MAAA,EAAQ,GAAE,GAAI,IAAA;AAAA,EACpC;AAEA,EAAA,MAAM,GAAA,GAAM,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA;AAClC,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AAEjB,EAAA,OAAO;AAAA,IACL,GAAA;AAAA,IACA,QAAQ,gBAAA,CAAiB,KAAA,CAAM,MAAM,CAAA,GAAI,MAAM,MAAA,GAAS;AAAA,GAC1D;AACF;AAEA,SAAS,kBAAkB,KAAA,EAAkC;AAC3D,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA;AAC/B,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,SAAU,EAAC;AAEpC,EAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,CAAC,KAAA,KAAU;AAC/B,IAAA,MAAM,QAAA,GACJ,OAAO,KAAA,KAAU,QAAA,GACb,iBAAA,CAAkB,KAAK,CAAA,GACvB,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,GACxB,iBAAA,CAAkB,KAAwB,CAAA,GAC1C,IAAA;AAER,IAAA,OAAO,QAAA,GAAW,CAAC,QAAQ,CAAA,GAAI,EAAC;AAAA,EAClC,CAAC,CAAA;AACH;AAEA,SAAS,uBAAuB,KAAA,EAAkC;AAChE,EAAA,OAAO,MACJ,KAAA,CAAM,GAAG,CAAA,CACT,OAAA,CAAQ,CAAC,KAAA,KAAU;AAClB,IAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,KAAA,CAAM,MAAM,GAAG,CAAA;AAC3C,IAAA,MAAM,GAAA,GAAM,YAAA,CAAa,MAAA,IAAU,EAAE,CAAA;AACrC,IAAA,IAAI,CAAC,GAAA,EAAK,OAAO,EAAC;AAElB,IAAA,MAAM,eAAe,SAAA,GAAY,MAAA,CAAO,SAAA,CAAU,IAAA,EAAM,CAAA,GAAI,CAAA;AAC5D,IAAA,OAAO,CAAC;AAAA,MACN,GAAA;AAAA,MACA,MAAA,EAAQ,gBAAA,CAAiB,YAAY,CAAA,GAAI,YAAA,GAAe;AAAA,KACzD,CAAA;AAAA,EACH,CAAC,CAAA;AACL;AAEA,SAAS,iBAAiB,KAAA,EAA8C;AACtE,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAC;AAEpB,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,kBAAkB,KAAK,CAAA;AACtC,IAAA,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,OAAO,MAAA;AAAA,EAChC,CAAA,CAAA,MAAQ;AAAA,EAER;AAEA,EAAA,OAAO,uBAAuB,KAAK,CAAA;AACrC;AAEO,SAAS,gBAAgB,MAAA,EAAyC;AACvE,EAAA,IAAI,OAAO,OAAA,EAAS;AAClB,IAAA,OAAO,CAAC,EAAE,GAAA,EAAK,YAAA,CAAa,OAAO,OAAO,CAAA,EAAG,MAAA,EAAQ,GAAA,EAAK,CAAA;AAAA,EAC5D;AAEA,EAAA,IAAI,MAAA,CAAO,UAAU,MAAA,EAAQ;AAC3B,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,QAAA,CAAS,OAAA,CAAQ,CAAC,KAAA,KAAU;AAClD,MAAA,MAAM,QAAA,GAAW,kBAAkB,KAAK,CAAA;AACxC,MAAA,OAAO,QAAA,GAAW,CAAC,QAAQ,CAAA,GAAI,EAAC;AAAA,IAClC,CAAC,CAAA;AAED,IAAA,IAAI,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG,OAAO,QAAA;AAAA,EAClC;AAEA,EAAA,MAAM,WAAA,GAAc,gBAAA,CAAiB,OAAA,CAAQ,sBAAsB,CAAC,CAAA;AACpE,EAAA,IAAI,WAAA,CAAY,SAAS,CAAA,EAAG;AAC1B,IAAA,OAAO,WAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAA,CAAQ,UAAU,CAAA,KAAM,aAAA,EAAe;AACzC,IAAA,OAAO,uBAAA;AAAA,EACT;AAEA,EAAA,OAAO,4BAAA;AACT;AAEO,SAAS,YAAY,QAAA,EAAqC;AAC/D,EAAA,OAAO,SAAS,CAAC,CAAA,EAAG,GAAA,IAAO,4BAAA,CAA6B,CAAC,CAAA,CAAE,GAAA;AAC7D;AAEO,SAAS,eAAA,GAAyC;AACvD,EAAA,OAAO,EAAC;AACV;;;ACzFA,IAAM,mBAAA,GAAsB,CAAA;AAC5B,IAAM,wBAAA,GAA2B,GAAA;AACjC,IAAM,UAAA,GAAa,YAAA;AAOnB,SAAS,IAAA,GAAe;AAEtB,EAAA,IAAI,OAAO,UAAA,CAAW,MAAA,EAAQ,UAAA,KAAe,UAAA,EAAY;AACvD,IAAA,OAAO,UAAA,CAAW,OAAO,UAAA,EAAW;AAAA,EACtC;AAEA,EAAA,OAAO,sCAAA,CAAuC,OAAA,CAAQ,OAAA,EAAS,CAAC,CAAA,KAAM;AACpE,IAAA,MAAM,CAAA,GAAK,IAAA,CAAK,MAAA,EAAO,GAAI,EAAA,GAAM,CAAA;AACjC,IAAA,OAAA,CAAQ,MAAM,GAAA,GAAM,CAAA,GAAK,IAAI,CAAA,GAAO,CAAA,EAAK,SAAS,EAAE,CAAA;AAAA,EACtD,CAAC,CAAA;AACH;AAGA,SAAS,cAAc,MAAA,EAAuE;AAC5F,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,EAAG;AACjD,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM;AACzC,MAAA,KAAA,CAAM,IAAA,CAAK,CAAA,EAAG,kBAAA,CAAmB,GAAG,CAAC,CAAA,CAAA,EAAI,kBAAA,CAAmB,MAAA,CAAO,KAAK,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,IAC9E;AAAA,EACF;AACA,EAAA,OAAO,KAAA,CAAM,SAAS,CAAA,GAAI,CAAA,CAAA,EAAI,MAAM,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,GAAK,EAAA;AACpD;AAGA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAMA,SAAS,aAAa,GAAA,EAAqB;AACzC,EAAA,OAAO,GAAA,CAAI,QAAQ,QAAA,EAAU,CAAC,WAAW,CAAA,CAAA,EAAI,MAAA,CAAO,WAAA,EAAa,CAAA,CAAE,CAAA;AACrE;AAGA,SAAS,YACP,GAAA,EACuD;AACvD,EAAA,MAAM,SAAgE,EAAC;AACvE,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AAC9C,IAAA,MAAA,CAAO,YAAA,CAAa,GAAG,CAAC,CAAA,GAAI,KAAA;AAAA,EAC9B;AACA,EAAA,OAAO,MAAA;AACT;AAGA,SAAS,aAAa,GAAA,EAAqB;AACzC,EAAA,OAAO,GAAA,CAAI,QAAQ,WAAA,EAAa,CAAC,GAAG,MAAA,KAAW,MAAA,CAAO,aAAa,CAAA;AACrE;AAgBA,SAAS,gBAAgB,GAAA,EAAuB;AAC9C,EAAA,IAAI,MAAM,OAAA,CAAQ,GAAG,GAAG,OAAO,GAAA,CAAI,IAAI,eAAe,CAAA;AACtD,EAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,OAAO,GAAA,KAAQ,QAAA,EAAU;AAC3C,IAAA,MAAM,SAAkC,EAAC;AACzC,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAA8B,CAAA,EAAG;AACzE,MAAA,MAAA,CAAO,YAAA,CAAa,GAAG,CAAC,CAAA,GAAI,gBAAgB,KAAK,CAAA;AAAA,IACnD;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,aAAa,KAAA,EAA+B;AACnD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,KAAA,CAAM,IAAA,IAAQ,OAAO,IAAA;AACvD,EAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,KAAK,CAAA;AAC3B,EAAA,IAAI,OAAO,KAAA,CAAM,IAAA,CAAK,OAAA,EAAS,GAAG,OAAO,IAAA;AACzC,EAAA,OAAO,KAAK,WAAA,EAAY;AAC1B;AAEA,SAAS,yBAAyB,KAAA,EAA+B;AAC/D,EAAA,IAAI,OAAO,UAAU,QAAA,IAAY,CAAC,OAAO,QAAA,CAAS,KAAK,GAAG,OAAO,IAAA;AACjE,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA;AAChC,EAAA,OAAO,OAAA,GAAU,IAAI,OAAA,GAAU,IAAA;AACjC;AAEA,SAAS,4BAKN,OAAA,EAAe;AAChB,EAAA,MAAM,IAAA,GAAO,EAAE,GAAG,OAAA,EAAQ;AAC1B,EAAA,MAAM,cAAA,GAAiB,wBAAA,CAAyB,IAAA,CAAK,aAAa,CAAA,GAC9D,KAAK,KAAA,CAAO,IAAA,CAAK,aAAA,GAA2B,EAAE,CAAA,GAC9C,IAAA;AACJ,EAAA,MAAM,eAAA,GACJ,wBAAA,CAAyB,IAAA,CAAK,eAAe,CAAA,IAAK,cAAA;AAEpD,EAAA,IAAI,eAAA,EAAiB;AACnB,IAAA,IAAA,CAAK,eAAA,GAAkB,eAAA;AACvB,IAAA,IAAA,CAAK,gBAAgB,MAAA,CAAA,CAAQ,eAAA,GAAkB,EAAA,EAAI,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,EAC/D;AAEA,EAAA,MAAM,QAAA,GAAW,YAAA,CAAa,IAAA,CAAK,SAAS,CAAA;AAC5C,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,IAAA,CAAK,OAAO,CAAA;AAExC,EAAA,IAAI,QAAA,OAAe,SAAA,GAAY,QAAA;AAC/B,EAAA,IAAI,mBAAmB,QAAA,EAAU;AAC/B,IAAA,MAAM,cAAc,IAAI,IAAA;AAAA,MACtB,IAAI,IAAA,CAAK,QAAQ,CAAA,CAAE,OAAA,KAAY,eAAA,GAAkB;AAAA,MACjD,WAAA,EAAY;AACd,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,IAAA,CAAK,OAAA,GAAU,WAAA;AAAA,IACjB,CAAA,MAAO;AACL,MAAA,MAAM,QAAA,GACJ,IAAI,IAAA,CAAK,MAAM,CAAA,CAAE,OAAA,EAAQ,GAAI,IAAI,IAAA,CAAK,QAAQ,CAAA,CAAE,OAAA,OAChD,eAAA,GAAkB,GAAA;AACpB,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,IAAA,CAAK,OAAA,GAAU,WAAA;AAAA,MACjB,CAAA,MAAO;AACL,QAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAAA,MACjB;AAAA,IACF;AAAA,EACF,WAAW,MAAA,EAAQ;AACjB,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAAA,EACjB;AAEA,EAAA,OAAO,IAAA;AACT;AAqBO,IAAM,SAAN,MAAa;AAAA,EAOlB,YAAY,MAAA,EAAsB;AAChC,IAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAClB,MAAA,MAAM,IAAI,MAAM,4BAA4B,CAAA;AAAA,IAC9C;AACA,IAAA,IAAA,CAAK,SAAS,MAAA,CAAO,MAAA;AACrB,IAAA,IAAA,CAAK,QAAA,GAAW,gBAAgB,MAAM,CAAA;AACtC,IAAA,IAAA,CAAK,UAAA,GAAa,OAAO,UAAA,IAAc,mBAAA;AACvC,IAAA,IAAA,CAAK,cAAA,GAAiB,OAAO,cAAA,IAAkB,wBAAA;AAC/C,IAAA,IAAA,CAAK,SAAS,MAAA,CAAO,KAAA,IAAS,UAAA,CAAW,KAAA,CAAM,KAAK,UAAU,CAAA;AAAA,EAChE;AAAA;AAAA,EAGA,UAAA,GAAqB;AACnB,IAAA,OAAO,WAAA,CAAY,KAAK,QAAQ,CAAA;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,SAAA,GAAqC;AACzC,IAAA,OAAO,IAAA,CAAK,OAAA,CAAwB,KAAA,EAAO,SAAS,CAAA;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,kBAAkB,IAAA,EAAkD;AACxE,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,OAAA;AAAA,QACrB,MAAA;AAAA,QACA,uBAAA;AAAA,QACA,EAAE,IAAA;AAAK,OACT;AACA,MAAA,MAAM,IAAA,GAAO,gBAAgB,GAAG,CAAA;AAChC,MAAA,OAAO;AAAA,QACL,KAAA,EAAO,IAAA;AAAA,QACP,cAAc,IAAA,CAAK,YAAA;AAAA,QACnB,eAAe,IAAA,CAAK,aAAA;AAAA,QACpB,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,eAAe,IAAA,CAAK;AAAA,OACtB;AAAA,IACF,SAAS,GAAA,EAAc;AAErB,MAAA,IACE,GAAA,IACA,OAAO,GAAA,KAAQ,QAAA,IACf,YAAY,GAAA,IACX,GAAA,CAA2B,SAAS,GAAA,EACrC;AACA,QAAA,MAAM,MAAA,GAAS,GAAA;AACf,QAAA,OAAO;AAAA,UACL,KAAA,EAAO,KAAA;AAAA,UACP,KAAA,EAAO,MAAA,CAAO,IAAA,EAAM,KAAA,IAAS;AAAA,SAC/B;AAAA,MACF;AACA,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,aAAA,GAA+C;AACnD,IAAA,OAAO,IAAA,CAAK,OAAA,CAA8B,KAAA,EAAO,YAAY,CAAA;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBA,MAAM,eAAA,CACJ,UAAA,EACA,MAAA,GAA6B,EAAC,EACP;AACvB,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,MAAM,IAAI,MAAM,4CAA4C,CAAA;AAAA,IAC9D;AACA,IAAA,MAAM,EAAA,GAAK,aAAA,CAAc,WAAA,CAAY,MAAqD,CAAC,CAAA;AAC3F,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,MACV,KAAA;AAAA,MACA,CAAA,WAAA,EAAc,kBAAA,CAAmB,UAAU,CAAC,gBAAgB,EAAE,CAAA;AAAA,KAChE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,sBAAA,CACJ,SAAA,EACA,MAAA,GAA6B,EAAC,EACP;AACvB,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,MAAM,IAAI,MAAM,kDAAkD,CAAA;AAAA,IACpE;AACA,IAAA,MAAM,EAAA,GAAK,aAAA,CAAc,WAAA,CAAY,MAAqD,CAAC,CAAA;AAC3F,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,MACV,KAAA;AAAA,MACA,CAAA,UAAA,EAAa,kBAAA,CAAmB,SAAS,CAAC,gBAAgB,EAAE,CAAA;AAAA,KAC9D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,MAAM,iBAAA,CACJ,OAAA,EACA,OAAA,EAC8B;AAC9B,IAAA,IAAI,CAAC,OAAA,CAAQ,UAAA,IAAc,CAAC,QAAQ,oBAAA,EAAsB;AACxD,MAAA,MAAM,IAAI,MAAM,sEAAsE,CAAA;AAAA,IACxF;AACA,IAAA,MAAM,cAAA,GAAiB,OAAA,EAAS,cAAA,IAAkB,IAAA,EAAK;AAGvD,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,IAAA,CAAK,UAAA,EAAY,CAAA,oBAAA,CAAA;AAEhC,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,MACpC,MAAA,EAAQ,kBAAA;AAAA,MACR,cAAA,EAAgB,kBAAA;AAAA,MAChB,iBAAA,EAAmB;AAAA,KACrB;AAEA,IAAA,MAAM,IAAA,GAAoB;AAAA,MACxB,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAC9B;AAEA,IAAA,IAAI,SAAA;AAEJ,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,IAAA,CAAK,YAAY,OAAA,EAAA,EAAW;AAC3D,MAAA,IAAI,UAAU,CAAA,EAAG;AACf,QAAA,MAAM,OAAA,GAAU,IAAA,CAAK,gBAAA,CAAiB,OAAA,EAAS,SAAS,CAAA;AACxD,QAAA,MAAM,MAAM,OAAO,CAAA;AAAA,MACrB;AAEA,MAAA,IAAI,QAAA;AACJ,MAAA,IAAI;AACF,QAAA,QAAA,GAAW,MAAM,IAAA,CAAK,MAAA,CAAO,GAAA,EAAK,IAAI,CAAA;AAAA,MACxC,SAAS,GAAA,EAAK;AACZ,QAAA,SAAA,GAAY,IAAI,kBAAA;AAAA,UACd,2BAA2B,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AAAA,UAC3E;AAAA,SACF;AACA,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,SAAS,EAAA,EAAI;AACf,QAAA,MAAM,GAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AAEjC,QAAA,MAAM,OAAA,GAAW,GAAA,CAAI,WAAA,IAAe,GAAA,CAAI,WAAW,EAAC;AAIpD,QAAA,MAAM,WAAA,GAA2B;AAAA,UAC/B,EAAA,EAAK,QAAQ,EAAA,IAAiB,EAAA;AAAA,UAC9B,UAAA,EAAa,OAAA,CAAQ,UAAA,IAAyB,OAAA,CAAQ,UAAA;AAAA,UACtD,MAAA,EAAS,QAAQ,MAAA,IAAqB,SAAA;AAAA,UACtC,SAAA,EAAY,OAAA,CAAQ,SAAA,IAAwB,OAAA,CAAQ,SAAA;AAAA,UACpD,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAsB,OAAA,CAAQ,OAAA;AAAA,UAChD,SAAA,EAAY,OAAA,CAAQ,SAAA,IAAwB,OAAA,CAAQ,SAAA;AAAA,UACpD,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAsB,OAAA,CAAQ,OAAA;AAAA,UAChD,aAAA,EAAgB,OAAA,CAAQ,aAAA,IAA4B,OAAA,CAAQ,SAAA;AAAA,UAC5D,WAAA,EAAc,OAAA,CAAQ,WAAA,IAA0B,OAAA,CAAQ,OAAA;AAAA,UACxD,SAAA,EAAY,OAAA,CAAQ,SAAA,IAAwB,OAAA,CAAQ,SAAA;AAAA,UACpD,WAAY,OAAA,CAAQ,SAAA,IAAyB,OAAA,CAAQ,MAAA,IAAqB,QAAQ,SAAA,IAAa,CAAA;AAAA,UAC/F,UAAA,EAAa,QAAQ,UAAA,IAAyB,CAAA;AAAA,UAC9C,QAAA,EAAW,QAAQ,QAAA,IAAuB,KAAA;AAAA,UAC1C,WAAY,OAAA,CAAQ,SAAA,IAAA,iBAAwB,IAAI,IAAA,IAAO,WAAA;AAAY,SACrE;AAEA,QAAA,OAAO,EAAE,WAAA,EAAY;AAAA,MACvB;AAEA,MAAA,IAAI,SAAA;AACJ,MAAA,IAAI;AACF,QAAA,SAAA,GAAa,MAAM,SAAS,IAAA,EAAK;AAAA,MACnC,CAAA,CAAA,MAAQ;AACN,QAAA,SAAA,GAAY,EAAE,KAAA,EAAO,QAAA,CAAS,cAAc,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAA,EAAG;AAAA,MACxE;AAEA,MAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,QAAA,SAAA,GAAY,IAAI,oBAAA,CAAqB,SAAA,EAAW,QAAQ,CAAA;AACxD,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AAC1B,QAAA,SAAA,GAAY,IAAI,cAAA,CAAe,QAAA,CAAS,QAAQ,QAAA,CAAS,UAAA,EAAY,WAAW,QAAQ,CAAA;AACxF,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,IAAI,cAAA,CAAe,QAAA,CAAS,QAAQ,QAAA,CAAS,UAAA,EAAY,WAAW,QAAQ,CAAA;AAAA,IACpF;AAEA,IAAA,MAAM,SAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,gBAAA,CACJ,UAAA,EACA,MAAA,GAAiC,EAAC,EACF;AAChC,IAAA,MAAM,EAAA,GAAK,cAAc,MAAqD,CAAA;AAC9E,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,MACV,KAAA;AAAA,MACA,CAAA,WAAA,EAAc,kBAAA,CAAmB,UAAU,CAAC,gBAAgB,EAAE,CAAA;AAAA,KAChE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,cAAA,CACJ,UAAA,EACA,aAAA,EAC8B;AAC9B,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,MACV,KAAA;AAAA,MACA,cAAc,kBAAA,CAAmB,UAAU,CAAC,CAAA,cAAA,EAAiB,kBAAA,CAAmB,aAAa,CAAC,CAAA;AAAA,KAChG;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,YAAA,GAA6C;AACjD,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,IAAA,CAAK,OAAA,CAA6B,KAAA,EAAO,WAAW,CAAA;AAAA,IACnE,SAAS,GAAA,EAAc;AAGrB,MAAA,IACE,GAAA,IACA,OAAO,GAAA,KAAQ,QAAA,IACf,YAAY,GAAA,IACX,GAAA,CAA2B,WAAW,GAAA,EACvC;AACA,QAAA,MAAM,gBAAA,GAAmB,MAAM,IAAA,CAAK,aAAA,EAAc;AAClD,QAAA,MAAM,QAAA,GAAW,gBAAA,CAAiB,SAAA,CAAU,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,UACtD,IAAI,CAAA,CAAE,EAAA;AAAA,UACN,MAAM,CAAA,CAAE,IAAA;AAAA,UACR,aAAa,CAAA,CAAE,WAAA;AAAA,UACf,eAAA,EAAiB,EAAE,eAAA,IAAmB,EAAA;AAAA,UACtC,UAAA,EAAY,EAAE,eAAA,IAAmB,CAAA;AAAA,UACjC,QAAA,EAAU,EAAE,QAAA,IAAY,KAAA;AAAA,UACxB,UAAU,CAAA,CAAE,QAAA;AAAA,UACZ,QAAQ,CAAA,CAAE,MAAA;AAAA,UACV,SAAA,EAAW,CAAA;AAAA,UACX,YAAA,EAAc,aAAA;AAAA,UACd,YAAA,EAAc,CAAC,CAAA,CAAE,EAAE,CAAA;AAAA,UACnB,cAAA,EAAgB,CAAC,CAAA,CAAE,IAAI;AAAA,SACzB,CAAE,CAAA;AACF,QAAA,OAAO,EAAE,QAAA,EAAU,KAAA,EAAO,QAAA,CAAS,MAAA,EAAO;AAAA,MAC5C;AACA,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,UAAA,GAAwC;AAC5C,IAAA,OAAO,IAAA,CAAK,OAAA,CAA0B,KAAA,EAAO,SAAS,CAAA;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,QAAQ,MAAA,EAAuC;AACnD,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,IAClD;AACA,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,MACV,KAAA;AAAA,MACA,CAAA,QAAA,EAAW,kBAAA,CAAmB,MAAM,CAAC,CAAA;AAAA,KACvC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,mBAAmB,KAAA,EAAiD;AACxE,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,MAAM,IAAI,MAAM,0CAA0C,CAAA;AAAA,IAC5D;AACA,IAAA,MAAM,GAAA,GAAM,GAAG,IAAA,CAAK,UAAA,EAAY,CAAA,6BAAA,EAAgC,kBAAA,CAAmB,KAAK,CAAC,CAAA,CAAA;AAEzF,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,MACpC,MAAA,EAAQ;AAAA,KACV;AAEA,IAAA,IAAI,SAAA;AAEJ,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,IAAA,CAAK,YAAY,OAAA,EAAA,EAAW;AAC3D,MAAA,IAAI,UAAU,CAAA,EAAG;AACf,QAAA,MAAM,OAAA,GAAU,IAAA,CAAK,gBAAA,CAAiB,OAAA,EAAS,SAAS,CAAA;AACxD,QAAA,MAAM,MAAM,OAAO,CAAA;AAAA,MACrB;AAEA,MAAA,IAAI,QAAA;AACJ,MAAA,IAAI;AACF,QAAA,QAAA,GAAW,MAAM,KAAK,MAAA,CAAO,GAAA,EAAK,EAAE,MAAA,EAAQ,KAAA,EAAO,SAAS,CAAA;AAAA,MAC9D,SAAS,GAAA,EAAK;AACZ,QAAA,SAAA,GAAY,IAAI,kBAAA;AAAA,UACd,2BAA2B,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AAAA,UAC3E;AAAA,SACF;AACA,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,SAAS,EAAA,EAAI;AACf,QAAA,MAAM,GAAA,GAAM,MAAM,QAAA,CAAS,IAAA,EAAK;AAChC,QAAA,OAAO,gBAAgB,GAAG,CAAA;AAAA,MAC5B;AAEA,MAAA,IAAI,SAAA;AACJ,MAAA,IAAI;AACF,QAAA,SAAA,GAAa,MAAM,SAAS,IAAA,EAAK;AAAA,MACnC,CAAA,CAAA,MAAQ;AACN,QAAA,SAAA,GAAY,EAAE,KAAA,EAAO,QAAA,CAAS,cAAc,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAA,EAAG;AAAA,MACxE;AAEA,MAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,QAAA,SAAA,GAAY,IAAI,oBAAA,CAAqB,SAAA,EAAW,QAAQ,CAAA;AACxD,QAAA;AAAA,MACF;AACA,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AAC1B,QAAA,SAAA,GAAY,IAAI,cAAA,CAAe,QAAA,CAAS,QAAQ,QAAA,CAAS,UAAA,EAAY,WAAW,QAAQ,CAAA;AACxF,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,IAAI,cAAA,CAAe,QAAA,CAAS,QAAQ,QAAA,CAAS,UAAA,EAAY,WAAW,QAAQ,CAAA;AAAA,IACpF;AAEA,IAAA,MAAM,SAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA,MAAM,qBAAA,CACJ,OAAA,EACA,OAAA,EACwC;AACxC,IAAA,MAAM,cAAA,GAAiB,OAAA,EAAS,cAAA,IAAkB,IAAA,EAAK;AACvD,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,IAAA,CAAK,UAAA,EAAY,CAAA,4BAAA,CAAA;AAEhC,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,MACpC,MAAA,EAAQ,kBAAA;AAAA,MACR,cAAA,EAAgB,kBAAA;AAAA,MAChB,iBAAA,EAAmB;AAAA,KACrB;AAEA,IAAA,MAAM,IAAA,GAAoB;AAAA,MACxB,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,2BAAA,CAA4B,OAAO,CAAC;AAAA,KAC3D;AAEA,IAAA,IAAI,SAAA;AAEJ,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,IAAA,CAAK,YAAY,OAAA,EAAA,EAAW;AAC3D,MAAA,IAAI,UAAU,CAAA,EAAG;AACf,QAAA,MAAM,OAAA,GAAU,IAAA,CAAK,gBAAA,CAAiB,OAAA,EAAS,SAAS,CAAA;AACxD,QAAA,MAAM,MAAM,OAAO,CAAA;AAAA,MACrB;AAEA,MAAA,IAAI,QAAA;AACJ,MAAA,IAAI;AACF,QAAA,QAAA,GAAW,MAAM,IAAA,CAAK,MAAA,CAAO,GAAA,EAAK,IAAI,CAAA;AAAA,MACxC,SAAS,GAAA,EAAK;AACZ,QAAA,SAAA,GAAY,IAAI,kBAAA;AAAA,UACd,2BAA2B,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AAAA,UAC3E;AAAA,SACF;AACA,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,SAAS,EAAA,EAAI;AACf,QAAA,MAAM,GAAA,GAAM,MAAM,QAAA,CAAS,IAAA,EAAK;AAChC,QAAA,OAAO,gBAAgB,GAAG,CAAA;AAAA,MAC5B;AAEA,MAAA,IAAI,SAAA;AACJ,MAAA,IAAI;AACF,QAAA,SAAA,GAAa,MAAM,SAAS,IAAA,EAAK;AAAA,MACnC,CAAA,CAAA,MAAQ;AACN,QAAA,SAAA,GAAY,EAAE,KAAA,EAAO,QAAA,CAAS,cAAc,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAA,EAAG;AAAA,MACxE;AAEA,MAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,QAAA,SAAA,GAAY,IAAI,oBAAA,CAAqB,SAAA,EAAW,QAAQ,CAAA;AACxD,QAAA;AAAA,MACF;AACA,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AAC1B,QAAA,SAAA,GAAY,IAAI,cAAA,CAAe,QAAA,CAAS,QAAQ,QAAA,CAAS,UAAA,EAAY,WAAW,QAAQ,CAAA;AACxF,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,IAAI,cAAA,CAAe,QAAA,CAAS,QAAQ,QAAA,CAAS,UAAA,EAAY,WAAW,QAAQ,CAAA;AAAA,IACpF;AAEA,IAAA,MAAM,SAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBA,MAAM,mBAAA,CACJ,OAAA,EACA,OAAA,EACgC;AAChC,IAAA,MAAM,cAAA,GAAiB,OAAA,EAAS,cAAA,IAAkB,IAAA,EAAK;AACvD,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,OAAA;AAAA,MACrB,MAAA;AAAA,MACA,yBAAA;AAAA,MACA,4BAA4B,OAAO,CAAA;AAAA,MACnC,EAAE,mBAAmB,cAAA;AAAe,KACtC;AAEA,IAAA,MAAM,IAAA,GAAO,gBAAgB,GAAG,CAAA;AAIhC,IAAA,MAAM,WAAA,GAAe,IAAA,CAAK,WAAA,IAA2B,IAAA,CAAK,UAAA,IAAyB,CAAA;AACnF,IAAA,MAAM,SAAA,GAAa,IAAA,CAAK,SAAA,IAAyB,IAAA,CAAK,SAAA,IAAwB,WAAA;AAC9E,IAAA,MAAM,aAAA,GAAiB,IAAA,CAAK,aAAA,IAA6B,WAAA,GAAc,SAAA;AACvE,IAAA,OAAO;AAAA,MACL,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,iBAAiB,IAAA,CAAK,eAAA;AAAA,MACtB,SAAA;AAAA,MACA,aAAA;AAAA,MACA,WAAA;AAAA,MACA,QAAA,EAAW,KAAK,QAAA,IAAuB,KAAA;AAAA,MACvC,eAAe,IAAA,CAAK,aAAA;AAAA,MACpB,eAAe,IAAA,CAAK,aAAA;AAAA,MACpB,cAAA,EAAiB,KAAK,cAAA,IAA6B,MAAA;AAAA,MACnD,aAAA,EAAgB,KAAK,aAAA,IAA4B,MAAA;AAAA,MACjD,gBAAA,EAAmB,KAAK,gBAAA,IAA+B;AAAA,KACzD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,eACJ,OAAA,EACiC;AACjC,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,OAAA;AAAA,MACrB,MAAA;AAAA,MACA,mBAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,OAAO,gBAAgB,GAAG,CAAA;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAc,OAAA,CACZ,MAAA,EACA,IAAA,EACA,MACA,YAAA,EACY;AACZ,IAAA,MAAM,GAAA,GAAM,GAAG,IAAA,CAAK,UAAA,EAAY,CAAA,EAAG,UAAU,GAAG,IAAI,CAAA,CAAA;AAEpD,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,MACpC,MAAA,EAAQ,kBAAA;AAAA,MACR,GAAG;AAAA,KACL;AAEA,IAAA,IAAI,SAAS,MAAA,EAAW;AACtB,MAAA,OAAA,CAAQ,cAAc,CAAA,GAAI,kBAAA;AAAA,IAC5B;AAEA,IAAA,MAAM,IAAA,GAAoB;AAAA,MACxB,MAAA;AAAA,MACA,OAAA;AAAA,MACA,MAAM,IAAA,KAAS,MAAA,GAAY,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,GAAI;AAAA,KACpD;AAEA,IAAA,IAAI,SAAA;AAEJ,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,IAAA,CAAK,YAAY,OAAA,EAAA,EAAW;AAE3D,MAAA,IAAI,UAAU,CAAA,EAAG;AACf,QAAA,MAAM,OAAA,GAAU,IAAA,CAAK,gBAAA,CAAiB,OAAA,EAAS,SAAS,CAAA;AACxD,QAAA,MAAM,MAAM,OAAO,CAAA;AAAA,MACrB;AAGA,MAAA,IAAI,QAAA;AACJ,MAAA,IAAI;AACF,QAAA,QAAA,GAAW,MAAM,IAAA,CAAK,MAAA,CAAO,GAAA,EAAK,IAAI,CAAA;AAAA,MACxC,SAAS,GAAA,EAAK;AACZ,QAAA,SAAA,GAAY,IAAI,kBAAA;AAAA,UACd,2BAA2B,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AAAA,UAC3E;AAAA,SACF;AAEA,QAAA;AAAA,MACF;AAGA,MAAA,IAAI,SAAS,EAAA,EAAI;AACf,QAAA,OAAQ,MAAM,SAAS,IAAA,EAAK;AAAA,MAC9B;AAGA,MAAA,IAAI,SAAA;AACJ,MAAA,IAAI;AACF,QAAA,SAAA,GAAa,MAAM,SAAS,IAAA,EAAK;AAAA,MACnC,CAAA,CAAA,MAAQ;AACN,QAAA,SAAA,GAAY,EAAE,KAAA,EAAO,QAAA,CAAS,cAAc,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAA,EAAG;AAAA,MACxE;AAGA,MAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,QAAA,SAAA,GAAY,IAAI,oBAAA,CAAqB,SAAA,EAAW,QAAQ,CAAA;AAExD,QAAA;AAAA,MACF;AAGA,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AAC1B,QAAA,SAAA,GAAY,IAAI,cAAA;AAAA,UACd,QAAA,CAAS,MAAA;AAAA,UACT,QAAA,CAAS,UAAA;AAAA,UACT,SAAA;AAAA,UACA;AAAA,SACF;AACA,QAAA;AAAA,MACF;AAGA,MAAA,MAAM,IAAI,cAAA;AAAA,QACR,QAAA,CAAS,MAAA;AAAA,QACT,QAAA,CAAS,UAAA;AAAA,QACT,SAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAGA,IAAA,MAAM,SAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,gBAAA,CACN,SACA,SAAA,EACQ;AACR,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,cAAA,GAAiB,CAAA,KAAM,OAAA,GAAU,CAAA,CAAA;AAC1D,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,EAAO,GAAI,WAAA;AAGjC,IAAA,IAAI,qBAAqB,oBAAA,EAAsB;AAC7C,MAAA,MAAM,WAAA,GAAc,UAAU,UAAA,GAAa,GAAA;AAC3C,MAAA,OAAO,IAAA,CAAK,GAAA,CAAI,WAAA,EAAa,QAAQ,CAAA;AAAA,IACvC;AAEA,IAAA,OAAO,QAAA;AAAA,EACT;AAEF","file":"index.js","sourcesContent":["import type { ApiErrorBody } from \"./types.js\";\n\n// ═══════════════════════════════════════════════════════════════\n// Base error\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Base error class for all SDK errors.\n *\n * Use `instanceof` checks to distinguish error types:\n *\n * ```ts\n * try { … } catch (e) {\n * if (e instanceof ResiraRateLimitError) { … }\n * if (e instanceof ResiraApiError) { … }\n * if (e instanceof ResiraNetworkError) { … }\n * }\n * ```\n */\nexport class ResiraError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ResiraError\";\n // Fix prototype chain for instanceof to work after transpilation\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// API error (4xx / 5xx with a parsed body)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Thrown when the API returns a non-2xx response with a JSON body.\n *\n * ```ts\n * err.status // 400, 404, 409, 422, 500, …\n * err.code // HTTP status text (e.g. \"Not Found\")\n * err.body // Parsed `{ error: \"…\" }` from the server\n * ```\n */\nexport class ResiraApiError extends ResiraError {\n /** HTTP status code. */\n readonly status: number;\n /** HTTP status text (e.g. `\"Bad Request\"`). */\n readonly code: string;\n /** Parsed error body from the API. */\n readonly body: ApiErrorBody;\n /** The full `Response` object (headers are still accessible). */\n readonly response: Response;\n\n constructor(status: number, code: string, body: ApiErrorBody, response: Response) {\n super(body.error || `API error ${status}`);\n this.name = \"ResiraApiError\";\n this.status = status;\n this.code = code;\n this.body = body;\n this.response = response;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n /** Whether this error is retryable (5xx or 429). */\n get retryable(): boolean {\n return this.status === 429 || this.status >= 500;\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Rate limit error (429)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Thrown when the API returns 429 Too Many Requests.\n *\n * ```ts\n * err.retryAfter // Seconds until the client should retry\n * ```\n */\nexport class ResiraRateLimitError extends ResiraApiError {\n /** Seconds to wait before retrying (from `Retry-After` header). */\n readonly retryAfter: number;\n\n constructor(body: ApiErrorBody, response: Response) {\n super(429, \"Too Many Requests\", body, response);\n this.name = \"ResiraRateLimitError\";\n this.retryAfter =\n body.retryAfter ??\n (Number.parseInt(response.headers.get(\"retry-after\") ?? \"60\", 10) ||\n 60);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Network error (fetch failed, DNS, timeout, etc.)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Thrown when the request never reached the server.\n *\n * This wraps the underlying `TypeError` or `DOMException` from\n * `fetch()` failures (DNS resolution, TLS, network offline, etc.).\n */\nexport class ResiraNetworkError extends ResiraError {\n /** The original error thrown by `fetch`. */\n readonly cause: unknown;\n\n constructor(message: string, cause: unknown) {\n super(message);\n this.name = \"ResiraNetworkError\";\n this.cause = cause;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import type { ResiraConfig, WeightedBaseUrl } from \"./types.js\";\n\ninterface ResolvedBaseUrl {\n url: string;\n weight: number;\n}\n\nconst DEFAULT_LOCAL_BASE_URLS: ResolvedBaseUrl[] = [\n { url: \"http://localhost:3001\", weight: 100 },\n];\n\nconst DEFAULT_PRODUCTION_BASE_URLS: ResolvedBaseUrl[] = [\n { url: \"https://api.resira.app\", weight: 100 },\n];\n\nfunction readEnv(name: string): string | undefined {\n if (typeof process === \"undefined\") return undefined;\n return process.env?.[name];\n}\n\n\nfunction normalizeUrl(url: string): string {\n return url.trim().replace(/\\/+$/, \"\");\n}\n\nfunction isPositiveNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\nfunction toResolvedBaseUrl(value: string | WeightedBaseUrl): ResolvedBaseUrl | null {\n if (typeof value === \"string\") {\n const url = normalizeUrl(value);\n return url ? { url, weight: 1 } : null;\n }\n\n const url = normalizeUrl(value.url);\n if (!url) return null;\n\n return {\n url,\n weight: isPositiveNumber(value.weight) ? value.weight : 1,\n };\n}\n\nfunction parseJsonBaseUrls(value: string): ResolvedBaseUrl[] {\n const parsed = JSON.parse(value) as unknown;\n if (!Array.isArray(parsed)) return [];\n\n return parsed.flatMap((entry) => {\n const resolved =\n typeof entry === \"string\"\n ? toResolvedBaseUrl(entry)\n : entry && typeof entry === \"object\"\n ? toResolvedBaseUrl(entry as WeightedBaseUrl)\n : null;\n\n return resolved ? [resolved] : [];\n });\n}\n\nfunction parseDelimitedBaseUrls(value: string): ResolvedBaseUrl[] {\n return value\n .split(\",\")\n .flatMap((entry) => {\n const [rawUrl, rawWeight] = entry.split(\"|\");\n const url = normalizeUrl(rawUrl ?? \"\");\n if (!url) return [];\n\n const parsedWeight = rawWeight ? Number(rawWeight.trim()) : 1;\n return [{\n url,\n weight: isPositiveNumber(parsedWeight) ? parsedWeight : 1,\n }];\n });\n}\n\nfunction parseEnvBaseUrls(value: string | undefined): ResolvedBaseUrl[] {\n if (!value) return [];\n\n try {\n const parsed = parseJsonBaseUrls(value);\n if (parsed.length > 0) return parsed;\n } catch {\n // Fall back to delimiter parsing.\n }\n\n return parseDelimitedBaseUrls(value);\n}\n\nexport function resolveBaseUrls(config: ResiraConfig): ResolvedBaseUrl[] {\n if (config.baseUrl) {\n return [{ url: normalizeUrl(config.baseUrl), weight: 100 }];\n }\n\n if (config.baseUrls?.length) {\n const explicit = config.baseUrls.flatMap((entry) => {\n const resolved = toResolvedBaseUrl(entry);\n return resolved ? [resolved] : [];\n });\n\n if (explicit.length > 0) return explicit;\n }\n\n const envBaseUrls = parseEnvBaseUrls(readEnv(\"RESIRA_API_BASE_URLS\"));\n if (envBaseUrls.length > 0) {\n return envBaseUrls;\n }\n\n if (readEnv(\"NODE_ENV\") === \"development\") {\n return DEFAULT_LOCAL_BASE_URLS;\n }\n\n return DEFAULT_PRODUCTION_BASE_URLS;\n}\n\nexport function pickBaseUrl(baseUrls: ResolvedBaseUrl[]): string {\n return baseUrls[0]?.url ?? DEFAULT_PRODUCTION_BASE_URLS[0].url;\n}\n\nexport function getRoutingStats(): Record<string, never> {\n return {};\n}","import { ResiraApiError, ResiraNetworkError, ResiraRateLimitError } from \"./errors.js\";\nimport { pickBaseUrl, resolveBaseUrls } from \"./routing.js\";\nimport type {\n ApiErrorBody,\n Availability,\n AvailabilityParams,\n CheckoutSessionResponse,\n ConfirmPaymentRequest,\n ConfirmPaymentResponse,\n CreateCheckoutSessionRequest,\n CreateCheckoutSessionResponse,\n CreatePaymentIntentRequest,\n CreateReservationRequest,\n Dish,\n DishListResponse,\n DishResponse,\n ListReservationsParams,\n PaginatedReservations,\n PaymentIntentResponse,\n ProductListResponse,\n PropertyConfig,\n Reservation,\n ReservationResponse,\n ResiraConfig,\n ResourceListResponse,\n ValidatePromoCodeResponse,\n} from \"./types.js\";\n\n// ═══════════════════════════════════════════════════════════════\n// Constants\n// ═══════════════════════════════════════════════════════════════\n\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_RETRY_BASE_DELAY = 500; // ms\nconst API_PREFIX = \"/v1/public\";\n\n// ═══════════════════════════════════════════════════════════════\n// Helpers\n// ═══════════════════════════════════════════════════════════════\n\n/** Generate a random UUID v4 for idempotency keys. */\nfunction uuid(): string {\n // Use crypto.randomUUID when available (Node 19+, all modern browsers)\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID();\n }\n // Fallback: manual v4 UUID\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n return (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n });\n}\n\n/** Build a query string from a flat params object. Skips `undefined` values. */\nfunction toQueryString(params: Record<string, string | number | boolean | undefined>): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n }\n }\n return parts.length > 0 ? `?${parts.join(\"&\")}` : \"\";\n}\n\n/** Sleep for `ms` milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Convert camelCase keys to snake_case for query parameters.\n * The API expects snake_case query params (`start_date`, `party_size`).\n */\nfunction camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/** Convert an object's keys from camelCase to snake_case. */\nfunction keysToSnake(\n obj: Record<string, string | number | boolean | undefined>,\n): Record<string, string | number | boolean | undefined> {\n const result: Record<string, string | number | boolean | undefined> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[camelToSnake(key)] = value;\n }\n return result;\n}\n\n/** Convert snake_case string to camelCase. */\nfunction snakeToCamel(str: string): string {\n return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\n}\n\n/** Deep-convert all keys in an object/array from camelCase to snake_case. */\nfunction deepKeysToSnake(obj: unknown): unknown {\n if (Array.isArray(obj)) return obj.map(deepKeysToSnake);\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[camelToSnake(key)] = deepKeysToSnake(value);\n }\n return result;\n }\n return obj;\n}\n\n/** Deep-convert all keys in an object/array from snake_case to camelCase. */\nfunction deepKeysToCamel(obj: unknown): unknown {\n if (Array.isArray(obj)) return obj.map(deepKeysToCamel);\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[snakeToCamel(key)] = deepKeysToCamel(value);\n }\n return result;\n }\n return obj;\n}\n\nfunction toIsoIfValid(value: unknown): string | null {\n if (typeof value !== \"string\" || !value.trim()) return null;\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return null;\n return date.toISOString();\n}\n\nfunction normalizeDurationMinutes(value: unknown): number | null {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return null;\n const rounded = Math.round(value);\n return rounded > 0 ? rounded : null;\n}\n\nfunction withCanonicalDurationWindow<T extends {\n durationMinutes?: number;\n durationHours?: number;\n startTime?: string;\n endTime?: string;\n}>(payload: T): T {\n const next = { ...payload };\n const hoursAsMinutes = normalizeDurationMinutes(next.durationHours)\n ? Math.round((next.durationHours as number) * 60)\n : null;\n const durationMinutes =\n normalizeDurationMinutes(next.durationMinutes) ?? hoursAsMinutes;\n\n if (durationMinutes) {\n next.durationMinutes = durationMinutes;\n next.durationHours = Number((durationMinutes / 60).toFixed(6));\n }\n\n const startIso = toIsoIfValid(next.startTime);\n const endIso = toIsoIfValid(next.endTime);\n\n if (startIso) next.startTime = startIso;\n if (durationMinutes && startIso) {\n const computedEnd = new Date(\n new Date(startIso).getTime() + durationMinutes * 60_000,\n ).toISOString();\n if (!endIso) {\n next.endTime = computedEnd;\n } else {\n const mismatch =\n new Date(endIso).getTime() - new Date(startIso).getTime() !==\n durationMinutes * 60_000;\n if (mismatch) {\n next.endTime = computedEnd;\n } else {\n next.endTime = endIso;\n }\n }\n } else if (endIso) {\n next.endTime = endIso;\n }\n\n return next;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Client\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Resira SDK client.\n *\n * ```ts\n * const resira = new Resira({\n * apiKey: \"resira_live_abc123…\",\n * baseUrl: \"https://api.example.com\", // optional\n * });\n *\n * const availability = await resira.getAvailability(\"prop-1\", {\n * startDate: \"2026-07-01\",\n * endDate: \"2026-07-07\",\n * });\n * ```\n */\nexport class Resira {\n private readonly apiKey: string;\n private readonly baseUrls: ReturnType<typeof resolveBaseUrls>;\n private readonly maxRetries: number;\n private readonly retryBaseDelay: number;\n private readonly _fetch: typeof globalThis.fetch;\n\n constructor(config: ResiraConfig) {\n if (!config.apiKey) {\n throw new Error(\"Resira: apiKey is required\");\n }\n this.apiKey = config.apiKey;\n this.baseUrls = resolveBaseUrls(config);\n this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n this.retryBaseDelay = config.retryBaseDelay ?? DEFAULT_RETRY_BASE_DELAY;\n this._fetch = config.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n /** The resolved API origin used by this client instance. */\n getBaseUrl(): string {\n return pickBaseUrl(this.baseUrls);\n }\n\n // ─────────────────────────────────────────────────────────────\n // Public API methods\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Fetch the public property configuration.\n *\n * Returns non-sensitive settings such as the Stripe publishable\n * key, deposit percentage, currency, and branding info.\n *\n * ```ts\n * const config = await resira.getConfig();\n * console.log(config.stripePublishableKey); // \"pk_test_…\"\n * ```\n */\n async getConfig(): Promise<PropertyConfig> {\n return this.request<PropertyConfig>(\"GET\", \"/config\");\n }\n\n /**\n * Validate a promo/discount code.\n *\n * Returns discount details if valid, or an error message if not.\n *\n * ```ts\n * const result = await resira.validatePromoCode(\"SUMMER20\");\n * if (result.valid) {\n * console.log(result.discountType, result.discountValue);\n * }\n * ```\n */\n async validatePromoCode(code: string): Promise<ValidatePromoCodeResponse> {\n try {\n const raw = await this.request<Record<string, unknown>>(\n \"POST\",\n \"/promo-codes/validate\",\n { code },\n );\n const data = deepKeysToCamel(raw) as Record<string, unknown>;\n return {\n valid: true,\n discountType: data.discountType as \"percent\" | \"fixed\" | undefined,\n discountValue: data.discountValue as number | undefined,\n currency: data.currency as string | undefined,\n minOrderCents: data.minOrderCents as number | undefined,\n };\n } catch (err: unknown) {\n // 4xx errors mean invalid code\n if (\n err &&\n typeof err === \"object\" &&\n \"status\" in err &&\n (err as { status: number }).status < 500\n ) {\n const apiErr = err as { body?: { error?: string } };\n return {\n valid: false,\n error: apiErr.body?.error ?? \"Invalid promo code\",\n };\n }\n throw err;\n }\n }\n\n /**\n * List all active resources for the organization.\n *\n * Returns resource cards with name, description, price, duration,\n * image, and type — suitable for building a resource picker.\n *\n * ```ts\n * const { resources } = await resira.listResources();\n * ```\n */\n async listResources(): Promise<ResourceListResponse> {\n return this.request<ResourceListResponse>(\"GET\", \"/resources\");\n }\n\n /**\n * Query availability for a resource.\n *\n * **Properties** (date-based):\n * ```ts\n * await resira.getAvailability(\"prop-1\", {\n * startDate: \"2026-07-01\",\n * endDate: \"2026-07-07\",\n * });\n * ```\n *\n * **Restaurants** (time-slot):\n * ```ts\n * await resira.getAvailability(\"table-5\", {\n * date: \"2026-07-01\",\n * partySize: 4,\n * });\n * ```\n *\n * Omit params to get all blocked dates (for calendar rendering).\n */\n async getAvailability(\n resourceId: string,\n params: AvailabilityParams = {},\n ): Promise<Availability> {\n if (!resourceId) {\n throw new Error(\"resourceId is required for getAvailability\");\n }\n const qs = toQueryString(keysToSnake(params as Record<string, string | number | undefined>));\n return this.request<Availability>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/availability${qs}`,\n );\n }\n\n /**\n * Query availability for a product/service.\n *\n * Aggregates capacity across all linked equipment. If a product\n * has 2 jet skis (each capacity=1), slots show capacity: 2.\n * Both pending and confirmed reservations count as occupied.\n *\n * ```ts\n * await resira.getProductAvailability(\"prod-123\", {\n * date: \"2026-07-01\",\n * durationMinutes: 30,\n * });\n * ```\n */\n async getProductAvailability(\n productId: string,\n params: AvailabilityParams = {},\n ): Promise<Availability> {\n if (!productId) {\n throw new Error(\"productId is required for getProductAvailability\");\n }\n const qs = toQueryString(keysToSnake(params as Record<string, string | number | undefined>));\n return this.request<Availability>(\n \"GET\",\n `/products/${encodeURIComponent(productId)}/availability${qs}`,\n );\n }\n\n /**\n * Create a reservation.\n *\n * Uses `POST /v2/api/reservations` — the `resourceId` is sent in\n * the request body, **not** in the URL path.\n *\n * An `Idempotency-Key` header is automatically attached so that\n * retries (including those from exponential backoff) are safe.\n *\n * ```ts\n * const { reservation } = await resira.createReservation({\n * resourceId: \"prop-1\",\n * guestName: \"Jane Doe\",\n * guestEmail: \"jane@example.com\",\n * startDate: \"2026-07-01\",\n * endDate: \"2026-07-07\",\n * partySize: 3,\n * });\n * ```\n */\n async createReservation(\n payload: CreateReservationRequest,\n options?: { idempotencyKey?: string },\n ): Promise<ReservationResponse> {\n if (!payload.resourceId && !payload.checkoutSessionToken) {\n throw new Error(\"resourceId or checkoutSessionToken is required for createReservation\");\n }\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n\n // Note: uses /v2/api prefix, not /v1/public\n const url = `${this.getBaseUrl()}/v2/api/reservations`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n };\n\n const init: RequestInit = {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | ResiraRateLimitError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n let response: Response;\n try {\n response = await this._fetch(url, init);\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n continue;\n }\n\n if (response.ok) {\n const raw = (await response.json()) as Record<string, unknown>;\n // The API may nest under \"reservation\" or \"booking\" depending on endpoint\n const resData = (raw.reservation ?? raw.booking ?? {}) as Record<string, unknown>;\n\n // Augment with request data: API response doesn't include\n // startTime/endTime/startDate/endDate/resourceId for v2 reservations\n const reservation: Reservation = {\n id: (resData.id as string) ?? \"\",\n resourceId: (resData.resourceId as string) ?? payload.resourceId,\n status: (resData.status as string) ?? \"pending\",\n startDate: (resData.startDate as string) ?? payload.startDate,\n endDate: (resData.endDate as string) ?? payload.endDate,\n startTime: (resData.startTime as string) ?? payload.startTime,\n endTime: (resData.endTime as string) ?? payload.endTime,\n startDatetime: (resData.startDatetime as string) ?? payload.startTime,\n endDatetime: (resData.endDatetime as string) ?? payload.endTime,\n guestName: (resData.guestName as string) ?? payload.guestName,\n partySize: (resData.partySize as number) ?? (resData.guests as number) ?? payload.partySize ?? 2,\n totalPrice: (resData.totalPrice as number) ?? 0,\n currency: (resData.currency as string) ?? \"EUR\",\n createdAt: (resData.createdAt as string) ?? new Date().toISOString(),\n };\n\n return { reservation };\n }\n\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n continue;\n }\n\n if (response.status >= 500) {\n lastError = new ResiraApiError(response.status, response.statusText, errorBody, response);\n continue;\n }\n\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n\n throw lastError!;\n }\n\n /**\n * List reservations for a resource (paginated).\n *\n * ```ts\n * const page = await resira.listReservations(\"prop-1\", {\n * status: \"confirmed\",\n * page: 1,\n * limit: 50,\n * });\n * console.log(page.data); // Reservation[]\n * console.log(page.totalPages); // number\n * ```\n */\n async listReservations(\n resourceId: string,\n params: ListReservationsParams = {},\n ): Promise<PaginatedReservations> {\n const qs = toQueryString(params as Record<string, string | number | undefined>);\n return this.request<PaginatedReservations>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/reservations${qs}`,\n );\n }\n\n /**\n * Get a single reservation by ID.\n *\n * ```ts\n * const { reservation } = await resira.getReservation(\"prop-1\", \"res-uuid\");\n * ```\n */\n async getReservation(\n resourceId: string,\n reservationId: string,\n ): Promise<ReservationResponse> {\n return this.request<ReservationResponse>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/reservations/${encodeURIComponent(reservationId)}`,\n );\n }\n\n /**\n * List all active products/services for the organisation.\n *\n * Calls `GET /v1/public/products` which returns products with\n * pricing, duration, and linked equipment.\n *\n * Falls back to mapping resources → products if the endpoint\n * returns 404 (backend hasn't been updated yet).\n *\n * ```ts\n * const { products } = await resira.listProducts();\n * ```\n */\n async listProducts(): Promise<ProductListResponse> {\n try {\n return await this.request<ProductListResponse>(\"GET\", \"/products\");\n } catch (err: unknown) {\n // Fallback: if /products endpoint doesn't exist yet (404),\n // map resources → products shape\n if (\n err &&\n typeof err === \"object\" &&\n \"status\" in err &&\n (err as { status: number }).status === 404\n ) {\n const resourceResponse = await this.listResources();\n const products = resourceResponse.resources.map((r) => ({\n id: r.id,\n name: r.name,\n description: r.description,\n durationMinutes: r.durationMinutes ?? 60,\n priceCents: r.pricePerSession ?? 0,\n currency: r.currency ?? \"EUR\",\n imageUrl: r.imageUrl,\n active: r.active,\n sortOrder: 0,\n pricingModel: \"per_session\" as const,\n equipmentIds: [r.id],\n equipmentNames: [r.name],\n }));\n return { products, count: products.length };\n }\n throw err;\n }\n }\n\n /**\n * List all dishes with 3D model data for the organisation.\n *\n * Returns dishes with name, description, price, image, and\n * 3D model URLs for AR/preview rendering.\n *\n * ```ts\n * const { dishes } = await resira.listDishes();\n * ```\n */\n async listDishes(): Promise<DishListResponse> {\n return this.request<DishListResponse>(\"GET\", \"/dishes\");\n }\n\n /**\n * Get a single dish by ID.\n *\n * ```ts\n * const { dish } = await resira.getDish(\"dish-uuid\");\n * console.log(dish.name, dish.model?.glbUrl);\n * ```\n */\n async getDish(dishId: string): Promise<DishResponse> {\n if (!dishId) {\n throw new Error(\"dishId is required for getDish\");\n }\n return this.request<DishResponse>(\n \"GET\",\n `/dishes/${encodeURIComponent(dishId)}`,\n );\n }\n\n /**\n * Retrieve a checkout session by its token.\n *\n * Used to hydrate the checkout screen when opening the widget\n * with a pre-created session token (skip service selection).\n *\n * ```ts\n * const { session } = await resira.getCheckoutSession(\"cs_ab12cd34ef56\");\n * console.log(session.productName, session.priceCents);\n * ```\n */\n async getCheckoutSession(token: string): Promise<CheckoutSessionResponse> {\n if (!token) {\n throw new Error(\"token is required for getCheckoutSession\");\n }\n const url = `${this.getBaseUrl()}/v2/public/checkout-sessions/${encodeURIComponent(token)}`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n let response: Response;\n try {\n response = await this._fetch(url, { method: \"GET\", headers });\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n continue;\n }\n\n if (response.ok) {\n const raw = await response.json();\n return deepKeysToCamel(raw) as CheckoutSessionResponse;\n }\n\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n continue;\n }\n if (response.status >= 500) {\n lastError = new ResiraApiError(response.status, response.statusText, errorBody, response);\n continue;\n }\n\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n\n throw lastError!;\n }\n\n /**\n * Create a new checkout session.\n *\n * External sites can create a session with product, slot, and guest\n * details, then pass the returned token to the widget to skip\n * directly to checkout.\n *\n * ```ts\n * const { sessionToken } = await resira.createCheckoutSession({\n * productId: \"prod-123\",\n * durationMinutes: 30,\n * partySize: 2,\n * date: \"2026-07-01\",\n * startTime: \"2026-07-01T10:00:00Z\",\n * endTime: \"2026-07-01T10:30:00Z\",\n * });\n * ```\n */\n async createCheckoutSession(\n payload: CreateCheckoutSessionRequest,\n options?: { idempotencyKey?: string },\n ): Promise<CreateCheckoutSessionResponse> {\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n const url = `${this.getBaseUrl()}/v2/public/checkout-sessions`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n };\n\n const init: RequestInit = {\n method: \"POST\",\n headers,\n body: JSON.stringify(withCanonicalDurationWindow(payload)),\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n let response: Response;\n try {\n response = await this._fetch(url, init);\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n continue;\n }\n\n if (response.ok) {\n const raw = await response.json();\n return deepKeysToCamel(raw) as CreateCheckoutSessionResponse;\n }\n\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n continue;\n }\n if (response.status >= 500) {\n lastError = new ResiraApiError(response.status, response.statusText, errorBody, response);\n continue;\n }\n\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n\n throw lastError!;\n }\n\n /**\n * Create a Stripe payment intent for a booking.\n *\n * The server creates the payment intent, calculates the amount,\n * and returns a `clientSecret` to confirm payment on the frontend\n * using Stripe Elements.\n *\n * ```ts\n * const { clientSecret, amountNow, amountAtVenue } =\n * await resira.createPaymentIntent({\n * productId: \"prod-123\",\n * resourceId: \"res-456\",\n * partySize: 2,\n * startDate: \"2026-07-01\",\n * startTime: \"2026-07-01T10:00:00Z\",\n * endTime: \"2026-07-01T11:00:00Z\",\n * guestName: \"Jane Doe\",\n * guestEmail: \"jane@example.com\",\n * });\n * ```\n */\n async createPaymentIntent(\n payload: CreatePaymentIntentRequest,\n options?: { idempotencyKey?: string },\n ): Promise<PaymentIntentResponse> {\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n const raw = await this.request<Record<string, unknown>>(\n \"POST\",\n \"/payments/create-intent\",\n withCanonicalDurationWindow(payload),\n { \"Idempotency-Key\": idempotencyKey },\n );\n // Normalize response keys to camelCase\n const data = deepKeysToCamel(raw) as Record<string, unknown>;\n // Map backend field names to SDK field names:\n // backend: amountDue, totalPrice\n // SDK: amountNow, totalAmount, amountAtVenue\n const totalAmount = (data.totalAmount as number) ?? (data.totalPrice as number) ?? 0;\n const amountNow = (data.amountNow as number) ?? (data.amountDue as number) ?? totalAmount;\n const amountAtVenue = (data.amountAtVenue as number) ?? (totalAmount - amountNow);\n return {\n clientSecret: data.clientSecret as string,\n paymentIntentId: data.paymentIntentId as string,\n amountNow,\n amountAtVenue,\n totalAmount,\n currency: (data.currency as string) ?? \"EUR\",\n paymentOption: data.paymentOption as string | undefined,\n reservationId: data.reservationId as string | undefined,\n discountAmount: (data.discountAmount as number) ?? undefined,\n originalPrice: (data.originalPrice as number) ?? undefined,\n promoCodeApplied: (data.promoCodeApplied as string) ?? undefined,\n };\n }\n\n /**\n * Confirm that a payment was successful after the guest\n * completes the Stripe payment flow.\n *\n * This transitions the reservation from `pending` to `confirmed`.\n *\n * ```ts\n * const { reservation, paymentStatus } =\n * await resira.confirmPayment({\n * paymentIntentId: \"pi_xxx\",\n * reservationId: \"res-uuid\",\n * });\n * ```\n */\n async confirmPayment(\n payload: ConfirmPaymentRequest,\n ): Promise<ConfirmPaymentResponse> {\n const raw = await this.request<Record<string, unknown>>(\n \"POST\",\n \"/payments/confirm\",\n payload,\n );\n // Normalize response keys to camelCase in case backend returns snake_case\n return deepKeysToCamel(raw) as ConfirmPaymentResponse;\n }\n\n // ─────────────────────────────────────────────────────────────\n // Internal HTTP layer\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Execute an HTTP request with retry logic and error normalization.\n *\n * - Attaches `Authorization: Bearer <apiKey>` on every request.\n * - Retries on 429 and 5xx with exponential backoff + jitter.\n * - Parses error bodies and throws typed error classes.\n */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n extraHeaders?: Record<string, string>,\n ): Promise<T> {\n const url = `${this.getBaseUrl()}${API_PREFIX}${path}`;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n ...extraHeaders,\n };\n\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n const init: RequestInit = {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n };\n\n let lastError: ResiraApiError | ResiraNetworkError | undefined;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n // ── Wait before retry ────────────────────────────────\n if (attempt > 0) {\n const backoff = this.calculateBackoff(attempt, lastError);\n await sleep(backoff);\n }\n\n // ── Execute the request ──────────────────────────────\n let response: Response;\n try {\n response = await this._fetch(url, init);\n } catch (err) {\n lastError = new ResiraNetworkError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n err,\n );\n // Network errors are always retryable\n continue;\n }\n\n // ── Success ──────────────────────────────────────────\n if (response.ok) {\n return (await response.json()) as T;\n }\n\n // ── Parse error body ─────────────────────────────────\n let errorBody: ApiErrorBody;\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n errorBody = { error: response.statusText || `HTTP ${response.status}` };\n }\n\n // ── Rate limit ───────────────────────────────────────\n if (response.status === 429) {\n lastError = new ResiraRateLimitError(errorBody, response);\n // Always retry 429s (up to maxRetries)\n continue;\n }\n\n // ── Server error (5xx) — retryable ───────────────────\n if (response.status >= 500) {\n lastError = new ResiraApiError(\n response.status,\n response.statusText,\n errorBody,\n response,\n );\n continue;\n }\n\n // ── Client error (4xx) — NOT retryable ───────────────\n throw new ResiraApiError(\n response.status,\n response.statusText,\n errorBody,\n response,\n );\n }\n\n // All retries exhausted — throw the last error\n throw lastError!;\n }\n\n /**\n * Calculate backoff delay in milliseconds for a given retry attempt.\n *\n * Uses exponential backoff with full jitter:\n * delay = random(0, base * 2^attempt)\n *\n * For 429 responses, respects the `Retry-After` header as a minimum.\n */\n private calculateBackoff(\n attempt: number,\n lastError?: ResiraApiError | ResiraNetworkError,\n ): number {\n const exponential = this.retryBaseDelay * 2 ** (attempt - 1);\n const jittered = Math.random() * exponential;\n\n // If the server told us to wait, use that as the floor\n if (lastError instanceof ResiraRateLimitError) {\n const serverDelay = lastError.retryAfter * 1000;\n return Math.max(serverDelay, jittered);\n }\n\n return jittered;\n }\n\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@resira/sdk",
3
- "version": "0.4.16",
3
+ "version": "0.4.18",
4
4
  "description": "TypeScript SDK for the Resira public reservation API",
5
5
  "license": "MIT",
6
6
  "type": "module",