@resira/sdk 0.4.19 → 0.4.21

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
@@ -324,10 +324,11 @@ var Resira = class {
324
324
  throw new Error("resourceId is required for getAvailability");
325
325
  }
326
326
  const qs = toQueryString(keysToSnake(params));
327
- return this.request(
327
+ const raw = await this.request(
328
328
  "GET",
329
329
  `/resources/${encodeURIComponent(resourceId)}/availability${qs}`
330
330
  );
331
+ return deepKeysToCamel(raw);
331
332
  }
332
333
  /**
333
334
  * Query availability for a product/service.
@@ -348,10 +349,83 @@ var Resira = class {
348
349
  throw new Error("productId is required for getProductAvailability");
349
350
  }
350
351
  const qs = toQueryString(keysToSnake(params));
351
- return this.request(
352
+ const raw = await this.request(
352
353
  "GET",
353
354
  `/products/${encodeURIComponent(productId)}/availability${qs}`
354
355
  );
356
+ return deepKeysToCamel(raw);
357
+ }
358
+ /**
359
+ * Create a short-lived hold on a product time slot (typically ~5 minutes).
360
+ * Uses `POST /v2/public/products/{productId}/slot-holds`.
361
+ */
362
+ async createSlotHold(productId, payload, options) {
363
+ if (!productId) {
364
+ throw new Error("productId is required for createSlotHold");
365
+ }
366
+ const idempotencyKey = options?.idempotencyKey ?? uuid();
367
+ const url = `${this.getBaseUrl()}/v2/public/products/${encodeURIComponent(productId)}/slot-holds`;
368
+ const body = {
369
+ ...payload,
370
+ ...payload.durationMinutes != null && payload.durationHours == null ? { durationHours: Number((payload.durationMinutes / 60).toFixed(6)) } : {}
371
+ };
372
+ const init = {
373
+ method: "POST",
374
+ headers: {
375
+ Authorization: `Bearer ${this.apiKey}`,
376
+ Accept: "application/json",
377
+ "Content-Type": "application/json",
378
+ "Idempotency-Key": idempotencyKey
379
+ },
380
+ body: JSON.stringify(body)
381
+ };
382
+ const response = await this._fetch(url, init);
383
+ if (!response.ok) {
384
+ let errorBody = { error: response.statusText || `HTTP ${response.status}` };
385
+ try {
386
+ errorBody = await response.json();
387
+ } catch {
388
+ }
389
+ throw new ResiraApiError(response.status, response.statusText, errorBody, response);
390
+ }
391
+ const raw = await response.json();
392
+ return deepKeysToCamel(raw);
393
+ }
394
+ /**
395
+ * Release an active slot hold (user abandoned checkout or changed slot).
396
+ * Uses `DELETE /v2/public/slot-holds/{holdId}`.
397
+ */
398
+ async releaseSlotHold(holdId) {
399
+ if (!holdId) {
400
+ throw new Error("holdId is required for releaseSlotHold");
401
+ }
402
+ const url = `${this.getBaseUrl()}/v2/public/slot-holds/${encodeURIComponent(holdId)}`;
403
+ const init = {
404
+ method: "DELETE",
405
+ headers: {
406
+ Authorization: `Bearer ${this.apiKey}`,
407
+ Accept: "application/json"
408
+ }
409
+ };
410
+ const response = await this._fetch(url, init);
411
+ if (!response.ok) {
412
+ let errorBody = { error: response.statusText || `HTTP ${response.status}` };
413
+ try {
414
+ errorBody = await response.json();
415
+ } catch {
416
+ }
417
+ throw new ResiraApiError(response.status, response.statusText, errorBody, response);
418
+ }
419
+ const text = await response.text();
420
+ if (!text.trim()) {
421
+ return { holdId, status: "released", serverNow: (/* @__PURE__ */ new Date()).toISOString() };
422
+ }
423
+ try {
424
+ const raw = JSON.parse(text);
425
+ return deepKeysToCamel(raw);
426
+ } catch {
427
+ return { holdId, status: "released", serverNow: (/* @__PURE__ */ new Date()).toISOString() };
428
+ }
355
429
  }
356
430
  /**
357
431
  * Create a reservation.
@@ -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\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"]}
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;;;ACtFA,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,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,OAAA;AAAA,MACrB,KAAA;AAAA,MACA,CAAA,WAAA,EAAc,kBAAA,CAAmB,UAAU,CAAC,gBAAgB,EAAE,CAAA;AAAA,KAChE;AACA,IAAA,OAAO,gBAAgB,GAAG,CAAA;AAAA,EAC5B;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,MAA+D,CAAC,CAAA;AACrG,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,OAAA;AAAA,MACrB,KAAA;AAAA,MACA,CAAA,UAAA,EAAa,kBAAA,CAAmB,SAAS,CAAC,gBAAgB,EAAE,CAAA;AAAA,KAC9D;AACA,IAAA,OAAO,gBAAgB,GAAG,CAAA;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAA,CACJ,SAAA,EACA,OAAA,EACA,OAAA,EAC2B;AAC3B,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,MAAM,IAAI,MAAM,0CAA0C,CAAA;AAAA,IAC5D;AACA,IAAA,MAAM,cAAA,GAAiB,OAAA,EAAS,cAAA,IAAkB,IAAA,EAAK;AACvD,IAAA,MAAM,GAAA,GAAM,GAAG,IAAA,CAAK,UAAA,EAAY,CAAA,oBAAA,EAAuB,kBAAA,CAAmB,SAAS,CAAC,CAAA,WAAA,CAAA;AACpF,IAAA,MAAM,IAAA,GAA8B;AAAA,MAClC,GAAG,OAAA;AAAA,MACH,GAAI,OAAA,CAAQ,eAAA,IAAmB,QAAQ,OAAA,CAAQ,aAAA,IAAiB,OAC5D,EAAE,aAAA,EAAe,MAAA,CAAA,CAAQ,OAAA,CAAQ,kBAAkB,EAAA,EAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,KACjE;AAAC,KACP;AAEA,IAAA,MAAM,IAAA,GAAoB;AAAA,MACxB,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,QACpC,MAAA,EAAQ,kBAAA;AAAA,QACR,cAAA,EAAgB,kBAAA;AAAA,QAChB,iBAAA,EAAmB;AAAA,OACrB;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAI;AAAA,KAC3B;AAEA,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,MAAA,CAAO,KAAK,IAAI,CAAA;AAC5C,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,IAAI,SAAA,GAA0B,EAAE,KAAA,EAAO,QAAA,CAAS,cAAc,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAA,EAAG;AACxF,MAAA,IAAI;AACF,QAAA,SAAA,GAAa,MAAM,SAAS,IAAA,EAAK;AAAA,MACnC,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,MAAM,IAAI,cAAA,CAAe,QAAA,CAAS,QAAQ,QAAA,CAAS,UAAA,EAAY,WAAW,QAAQ,CAAA;AAAA,IACpF;AACA,IAAA,MAAM,GAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO,gBAAgB,GAAG,CAAA;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAgB,MAAA,EAAkD;AACtE,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,IAAI,MAAM,wCAAwC,CAAA;AAAA,IAC1D;AACA,IAAA,MAAM,GAAA,GAAM,GAAG,IAAA,CAAK,UAAA,EAAY,CAAA,sBAAA,EAAyB,kBAAA,CAAmB,MAAM,CAAC,CAAA,CAAA;AACnF,IAAA,MAAM,IAAA,GAAoB;AAAA,MACxB,MAAA,EAAQ,QAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,QACpC,MAAA,EAAQ;AAAA;AACV,KACF;AACA,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,MAAA,CAAO,KAAK,IAAI,CAAA;AAC5C,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,IAAI,SAAA,GAA0B,EAAE,KAAA,EAAO,QAAA,CAAS,cAAc,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAA,EAAG;AACxF,MAAA,IAAI;AACF,QAAA,SAAA,GAAa,MAAM,SAAS,IAAA,EAAK;AAAA,MACnC,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,MAAM,IAAI,cAAA,CAAe,QAAA,CAAS,QAAQ,QAAA,CAAS,UAAA,EAAY,WAAW,QAAQ,CAAA;AAAA,IACpF;AACA,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,IAAI,CAAC,IAAA,CAAK,IAAA,EAAK,EAAG;AAChB,MAAA,OAAO,EAAE,QAAQ,MAAA,EAAQ,UAAA,EAAY,4BAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY,EAAE;AAAA,IAC3E;AACA,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAC3B,MAAA,OAAO,gBAAgB,GAAG,CAAA;AAAA,IAC5B,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,EAAE,QAAQ,MAAA,EAAQ,UAAA,EAAY,4BAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY,EAAE;AAAA,IAC3E;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.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 CreateSlotHoldRequest,\n ReleaseSlotHoldResponse,\n SlotHoldResponse,\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 const raw = await this.request<Record<string, unknown>>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/availability${qs}`,\n );\n return deepKeysToCamel(raw) as Availability;\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 | boolean | undefined>));\n const raw = await this.request<Record<string, unknown>>(\n \"GET\",\n `/products/${encodeURIComponent(productId)}/availability${qs}`,\n );\n return deepKeysToCamel(raw) as Availability;\n }\n\n /**\n * Create a short-lived hold on a product time slot (typically ~5 minutes).\n * Uses `POST /v2/public/products/{productId}/slot-holds`.\n */\n async createSlotHold(\n productId: string,\n payload: CreateSlotHoldRequest,\n options?: { idempotencyKey?: string },\n ): Promise<SlotHoldResponse> {\n if (!productId) {\n throw new Error(\"productId is required for createSlotHold\");\n }\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n const url = `${this.getBaseUrl()}/v2/public/products/${encodeURIComponent(productId)}/slot-holds`;\n const body: CreateSlotHoldRequest = {\n ...payload,\n ...(payload.durationMinutes != null && payload.durationHours == null\n ? { durationHours: Number((payload.durationMinutes / 60).toFixed(6)) }\n : {}),\n };\n\n const init: RequestInit = {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n },\n body: JSON.stringify(body),\n };\n\n const response = await this._fetch(url, init);\n if (!response.ok) {\n let errorBody: ApiErrorBody = { error: response.statusText || `HTTP ${response.status}` };\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n /* ignore */\n }\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n const raw = (await response.json()) as Record<string, unknown>;\n return deepKeysToCamel(raw) as SlotHoldResponse;\n }\n\n /**\n * Release an active slot hold (user abandoned checkout or changed slot).\n * Uses `DELETE /v2/public/slot-holds/{holdId}`.\n */\n async releaseSlotHold(holdId: string): Promise<ReleaseSlotHoldResponse> {\n if (!holdId) {\n throw new Error(\"holdId is required for releaseSlotHold\");\n }\n const url = `${this.getBaseUrl()}/v2/public/slot-holds/${encodeURIComponent(holdId)}`;\n const init: RequestInit = {\n method: \"DELETE\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n },\n };\n const response = await this._fetch(url, init);\n if (!response.ok) {\n let errorBody: ApiErrorBody = { error: response.statusText || `HTTP ${response.status}` };\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n /* ignore */\n }\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n const text = await response.text();\n if (!text.trim()) {\n return { holdId, status: \"released\", serverNow: new Date().toISOString() };\n }\n try {\n const raw = JSON.parse(text) as Record<string, unknown>;\n return deepKeysToCamel(raw) as ReleaseSlotHoldResponse;\n } catch {\n return { holdId, status: \"released\", serverNow: new Date().toISOString() };\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
@@ -62,6 +62,16 @@ interface AvailabilityParams {
62
62
  partySize?: number;
63
63
  /** Session duration in minutes (watersport/service: controls slot intervals). */
64
64
  durationMinutes?: number;
65
+ /**
66
+ * Product availability: scope to one linked resource (physical asset).
67
+ * Omit to use pooled capacity across all `equipmentIds`.
68
+ */
69
+ resourceId?: string;
70
+ /**
71
+ * Product availability: request per-linked-resource remaining/capacity per slot
72
+ * (matches public `include_per_resource` query param).
73
+ */
74
+ includePerResource?: boolean;
65
75
  }
66
76
  /**
67
77
  * A reservation as returned by the public API.
@@ -132,10 +142,26 @@ interface TimeSlotAvailability {
132
142
  capacity: number;
133
143
  /** Number of confirmed/pending reservations in this slot. */
134
144
  reserved: number;
145
+ /** Seats temporarily held (soft lock) for in-progress checkouts. */
146
+ held?: number;
135
147
  /** Remaining seats (`capacity - reserved`). */
136
148
  remaining: number;
137
149
  /** Whether the slot has any remaining capacity. */
138
150
  available: boolean;
151
+ /** Per-slot hold TTL echo (seconds), when API provides it. */
152
+ holdTtlSeconds?: number;
153
+ /**
154
+ * When `includePerResource` was requested on product availability:
155
+ * per-asset breakdown for this slot.
156
+ */
157
+ perResource?: Array<{
158
+ resourceId: string;
159
+ resourceName?: string;
160
+ capacity?: number;
161
+ reserved?: number;
162
+ remaining?: number;
163
+ held?: number;
164
+ }>;
139
165
  }
140
166
  /**
141
167
  * Availability response — domain-agnostic.
@@ -149,11 +175,57 @@ interface Availability {
149
175
  resourceId: string;
150
176
  /** ISO 4217 currency code. */
151
177
  currency: string;
178
+ /** Server time (ISO) for countdown sync with slot holds. */
179
+ serverNow?: string;
180
+ /** Default hold TTL in seconds (e.g. 300). */
181
+ holdTtlSeconds?: number;
152
182
  /** Date-level availability (properties). */
153
183
  dates?: DateAvailability;
154
184
  /** Time-slot availability (restaurants). */
155
185
  timeSlots?: TimeSlotAvailability[];
156
186
  }
187
+ /** Body for `POST /v2/public/products/{productId}/slot-holds`. */
188
+ interface CreateSlotHoldRequest {
189
+ startTime: string;
190
+ durationMinutes: number;
191
+ /** Optional hours for older backends; prefer `durationMinutes`. */
192
+ durationHours?: number;
193
+ partySize: number;
194
+ resourceId?: string;
195
+ sessionToken?: string;
196
+ }
197
+ interface SlotHoldResourceSnapshot {
198
+ resourceCapacity?: number;
199
+ resourceReserved?: number;
200
+ resourceHeld?: number;
201
+ }
202
+ interface SlotHoldCapacitySnapshot {
203
+ total?: number;
204
+ reserved?: number;
205
+ held?: number;
206
+ availableAfterHold?: number;
207
+ }
208
+ /** Response from creating a slot hold. */
209
+ interface SlotHoldResponse {
210
+ holdId: string;
211
+ resourceId: string;
212
+ status: string;
213
+ expiresAt: string;
214
+ ttlSeconds: number;
215
+ slotStart: string;
216
+ slotEnd: string;
217
+ durationMinutes: number;
218
+ partySize: number;
219
+ resourceSnapshot?: SlotHoldResourceSnapshot;
220
+ capacitySnapshot?: SlotHoldCapacitySnapshot;
221
+ serverNow: string;
222
+ }
223
+ /** Response from releasing a slot hold. */
224
+ interface ReleaseSlotHoldResponse {
225
+ holdId: string;
226
+ status: string;
227
+ serverNow: string;
228
+ }
157
229
  /** Configuration for the Resira SDK client. */
158
230
  interface WeightedBaseUrl {
159
231
  /** Base URL for an API origin. */
@@ -243,6 +315,8 @@ interface ResourceListResponse {
243
315
  /** Raw error body returned by the API (`{ "error": "..." }`). */
244
316
  interface ApiErrorBody {
245
317
  error: string;
318
+ /** Machine-readable code when API provides it (e.g. `HOLD_EXPIRED`, `SLOT_UNAVAILABLE`). */
319
+ code?: string;
246
320
  retryAfter?: number;
247
321
  }
248
322
  /** Pricing model for a product/service. */
@@ -439,6 +513,11 @@ interface CreatePaymentIntentRequest {
439
513
  waiverAccepted?: boolean;
440
514
  /** Checkout session token. When provided, session data is merged with the payload. */
441
515
  checkoutSessionToken?: string;
516
+ /**
517
+ * Active slot hold from `createSlotHold`. Recommended when holds are enabled
518
+ * so the server can validate capacity in the same transaction as payment.
519
+ */
520
+ holdId?: string;
442
521
  }
443
522
  /** Response from creating a payment intent. */
444
523
  interface PaymentIntentResponse {
@@ -636,6 +715,8 @@ interface CheckoutSession {
636
715
  promoCode?: string;
637
716
  /** Checkout-specific configuration. */
638
717
  checkoutConfig: CheckoutConfig;
718
+ /** Slot hold bound to this session, when applicable. */
719
+ holdId?: string;
639
720
  }
640
721
  /** Response wrapper for a checkout session. */
641
722
  interface CheckoutSessionResponse {
@@ -663,6 +744,8 @@ interface CreateCheckoutSessionRequest {
663
744
  guestEmail?: string;
664
745
  /** Promo code (optional). */
665
746
  promoCode?: string;
747
+ /** Optional slot hold to associate with this session. */
748
+ holdId?: string;
666
749
  }
667
750
  /** Response from creating a checkout session. */
668
751
  interface CreateCheckoutSessionResponse {
@@ -776,6 +859,18 @@ declare class Resira {
776
859
  * ```
777
860
  */
778
861
  getProductAvailability(productId: string, params?: AvailabilityParams): Promise<Availability>;
862
+ /**
863
+ * Create a short-lived hold on a product time slot (typically ~5 minutes).
864
+ * Uses `POST /v2/public/products/{productId}/slot-holds`.
865
+ */
866
+ createSlotHold(productId: string, payload: CreateSlotHoldRequest, options?: {
867
+ idempotencyKey?: string;
868
+ }): Promise<SlotHoldResponse>;
869
+ /**
870
+ * Release an active slot hold (user abandoned checkout or changed slot).
871
+ * Uses `DELETE /v2/public/slot-holds/{holdId}`.
872
+ */
873
+ releaseSlotHold(holdId: string): Promise<ReleaseSlotHoldResponse>;
779
874
  /**
780
875
  * Create a reservation.
781
876
  *
@@ -1010,4 +1105,4 @@ declare class ResiraNetworkError extends ResiraError {
1010
1105
  constructor(message: string, cause: unknown);
1011
1106
  }
1012
1107
 
1013
- export { type ApiErrorBody, type Availability, type AvailabilityParams, type CheckoutConfig, type CheckoutSession, type CheckoutSessionResponse, type ConfirmPaymentRequest, type ConfirmPaymentResponse, type CreateCheckoutSessionRequest, type CreateCheckoutSessionResponse, type CreatePaymentIntentRequest, type CreateReservationRequest, type DateAvailability, type Dish, type DishListResponse, type DishModel, type DishResponse, type DurationPrice, type ListReservationsParams, type PaginatedReservations, type PaymentIntentResponse, type PricingModel, type Product, type ProductCategory, type ProductImage, type ProductListResponse, type ProductVariant, type PromoCode, type PropertyConfig, type PublicResource, type RefundRule, type Reservation, type ReservationResponse, Resira, ResiraApiError, type ResiraConfig, ResiraError, ResiraNetworkError, ResiraRateLimitError, type ResourceImage, type ResourceImageDisplaySettings, type ResourceListResponse, type RiderTierPrice, type TimeSlotAvailability, type ValidatePromoCodeResponse, type WeightedBaseUrl, getRoutingStats };
1108
+ export { type ApiErrorBody, type Availability, type AvailabilityParams, type CheckoutConfig, type CheckoutSession, type CheckoutSessionResponse, type ConfirmPaymentRequest, type ConfirmPaymentResponse, type CreateCheckoutSessionRequest, type CreateCheckoutSessionResponse, type CreatePaymentIntentRequest, type CreateReservationRequest, type CreateSlotHoldRequest, type DateAvailability, type Dish, type DishListResponse, type DishModel, type DishResponse, type DurationPrice, type ListReservationsParams, type PaginatedReservations, type PaymentIntentResponse, type PricingModel, type Product, type ProductCategory, type ProductImage, type ProductListResponse, type ProductVariant, type PromoCode, type PropertyConfig, type PublicResource, type RefundRule, type ReleaseSlotHoldResponse, type Reservation, type ReservationResponse, Resira, ResiraApiError, type ResiraConfig, ResiraError, ResiraNetworkError, ResiraRateLimitError, type ResourceImage, type ResourceImageDisplaySettings, type ResourceListResponse, type RiderTierPrice, type SlotHoldCapacitySnapshot, type SlotHoldResourceSnapshot, type SlotHoldResponse, type TimeSlotAvailability, type ValidatePromoCodeResponse, type WeightedBaseUrl, getRoutingStats };
package/dist/index.d.ts CHANGED
@@ -62,6 +62,16 @@ interface AvailabilityParams {
62
62
  partySize?: number;
63
63
  /** Session duration in minutes (watersport/service: controls slot intervals). */
64
64
  durationMinutes?: number;
65
+ /**
66
+ * Product availability: scope to one linked resource (physical asset).
67
+ * Omit to use pooled capacity across all `equipmentIds`.
68
+ */
69
+ resourceId?: string;
70
+ /**
71
+ * Product availability: request per-linked-resource remaining/capacity per slot
72
+ * (matches public `include_per_resource` query param).
73
+ */
74
+ includePerResource?: boolean;
65
75
  }
66
76
  /**
67
77
  * A reservation as returned by the public API.
@@ -132,10 +142,26 @@ interface TimeSlotAvailability {
132
142
  capacity: number;
133
143
  /** Number of confirmed/pending reservations in this slot. */
134
144
  reserved: number;
145
+ /** Seats temporarily held (soft lock) for in-progress checkouts. */
146
+ held?: number;
135
147
  /** Remaining seats (`capacity - reserved`). */
136
148
  remaining: number;
137
149
  /** Whether the slot has any remaining capacity. */
138
150
  available: boolean;
151
+ /** Per-slot hold TTL echo (seconds), when API provides it. */
152
+ holdTtlSeconds?: number;
153
+ /**
154
+ * When `includePerResource` was requested on product availability:
155
+ * per-asset breakdown for this slot.
156
+ */
157
+ perResource?: Array<{
158
+ resourceId: string;
159
+ resourceName?: string;
160
+ capacity?: number;
161
+ reserved?: number;
162
+ remaining?: number;
163
+ held?: number;
164
+ }>;
139
165
  }
140
166
  /**
141
167
  * Availability response — domain-agnostic.
@@ -149,11 +175,57 @@ interface Availability {
149
175
  resourceId: string;
150
176
  /** ISO 4217 currency code. */
151
177
  currency: string;
178
+ /** Server time (ISO) for countdown sync with slot holds. */
179
+ serverNow?: string;
180
+ /** Default hold TTL in seconds (e.g. 300). */
181
+ holdTtlSeconds?: number;
152
182
  /** Date-level availability (properties). */
153
183
  dates?: DateAvailability;
154
184
  /** Time-slot availability (restaurants). */
155
185
  timeSlots?: TimeSlotAvailability[];
156
186
  }
187
+ /** Body for `POST /v2/public/products/{productId}/slot-holds`. */
188
+ interface CreateSlotHoldRequest {
189
+ startTime: string;
190
+ durationMinutes: number;
191
+ /** Optional hours for older backends; prefer `durationMinutes`. */
192
+ durationHours?: number;
193
+ partySize: number;
194
+ resourceId?: string;
195
+ sessionToken?: string;
196
+ }
197
+ interface SlotHoldResourceSnapshot {
198
+ resourceCapacity?: number;
199
+ resourceReserved?: number;
200
+ resourceHeld?: number;
201
+ }
202
+ interface SlotHoldCapacitySnapshot {
203
+ total?: number;
204
+ reserved?: number;
205
+ held?: number;
206
+ availableAfterHold?: number;
207
+ }
208
+ /** Response from creating a slot hold. */
209
+ interface SlotHoldResponse {
210
+ holdId: string;
211
+ resourceId: string;
212
+ status: string;
213
+ expiresAt: string;
214
+ ttlSeconds: number;
215
+ slotStart: string;
216
+ slotEnd: string;
217
+ durationMinutes: number;
218
+ partySize: number;
219
+ resourceSnapshot?: SlotHoldResourceSnapshot;
220
+ capacitySnapshot?: SlotHoldCapacitySnapshot;
221
+ serverNow: string;
222
+ }
223
+ /** Response from releasing a slot hold. */
224
+ interface ReleaseSlotHoldResponse {
225
+ holdId: string;
226
+ status: string;
227
+ serverNow: string;
228
+ }
157
229
  /** Configuration for the Resira SDK client. */
158
230
  interface WeightedBaseUrl {
159
231
  /** Base URL for an API origin. */
@@ -243,6 +315,8 @@ interface ResourceListResponse {
243
315
  /** Raw error body returned by the API (`{ "error": "..." }`). */
244
316
  interface ApiErrorBody {
245
317
  error: string;
318
+ /** Machine-readable code when API provides it (e.g. `HOLD_EXPIRED`, `SLOT_UNAVAILABLE`). */
319
+ code?: string;
246
320
  retryAfter?: number;
247
321
  }
248
322
  /** Pricing model for a product/service. */
@@ -439,6 +513,11 @@ interface CreatePaymentIntentRequest {
439
513
  waiverAccepted?: boolean;
440
514
  /** Checkout session token. When provided, session data is merged with the payload. */
441
515
  checkoutSessionToken?: string;
516
+ /**
517
+ * Active slot hold from `createSlotHold`. Recommended when holds are enabled
518
+ * so the server can validate capacity in the same transaction as payment.
519
+ */
520
+ holdId?: string;
442
521
  }
443
522
  /** Response from creating a payment intent. */
444
523
  interface PaymentIntentResponse {
@@ -636,6 +715,8 @@ interface CheckoutSession {
636
715
  promoCode?: string;
637
716
  /** Checkout-specific configuration. */
638
717
  checkoutConfig: CheckoutConfig;
718
+ /** Slot hold bound to this session, when applicable. */
719
+ holdId?: string;
639
720
  }
640
721
  /** Response wrapper for a checkout session. */
641
722
  interface CheckoutSessionResponse {
@@ -663,6 +744,8 @@ interface CreateCheckoutSessionRequest {
663
744
  guestEmail?: string;
664
745
  /** Promo code (optional). */
665
746
  promoCode?: string;
747
+ /** Optional slot hold to associate with this session. */
748
+ holdId?: string;
666
749
  }
667
750
  /** Response from creating a checkout session. */
668
751
  interface CreateCheckoutSessionResponse {
@@ -776,6 +859,18 @@ declare class Resira {
776
859
  * ```
777
860
  */
778
861
  getProductAvailability(productId: string, params?: AvailabilityParams): Promise<Availability>;
862
+ /**
863
+ * Create a short-lived hold on a product time slot (typically ~5 minutes).
864
+ * Uses `POST /v2/public/products/{productId}/slot-holds`.
865
+ */
866
+ createSlotHold(productId: string, payload: CreateSlotHoldRequest, options?: {
867
+ idempotencyKey?: string;
868
+ }): Promise<SlotHoldResponse>;
869
+ /**
870
+ * Release an active slot hold (user abandoned checkout or changed slot).
871
+ * Uses `DELETE /v2/public/slot-holds/{holdId}`.
872
+ */
873
+ releaseSlotHold(holdId: string): Promise<ReleaseSlotHoldResponse>;
779
874
  /**
780
875
  * Create a reservation.
781
876
  *
@@ -1010,4 +1105,4 @@ declare class ResiraNetworkError extends ResiraError {
1010
1105
  constructor(message: string, cause: unknown);
1011
1106
  }
1012
1107
 
1013
- export { type ApiErrorBody, type Availability, type AvailabilityParams, type CheckoutConfig, type CheckoutSession, type CheckoutSessionResponse, type ConfirmPaymentRequest, type ConfirmPaymentResponse, type CreateCheckoutSessionRequest, type CreateCheckoutSessionResponse, type CreatePaymentIntentRequest, type CreateReservationRequest, type DateAvailability, type Dish, type DishListResponse, type DishModel, type DishResponse, type DurationPrice, type ListReservationsParams, type PaginatedReservations, type PaymentIntentResponse, type PricingModel, type Product, type ProductCategory, type ProductImage, type ProductListResponse, type ProductVariant, type PromoCode, type PropertyConfig, type PublicResource, type RefundRule, type Reservation, type ReservationResponse, Resira, ResiraApiError, type ResiraConfig, ResiraError, ResiraNetworkError, ResiraRateLimitError, type ResourceImage, type ResourceImageDisplaySettings, type ResourceListResponse, type RiderTierPrice, type TimeSlotAvailability, type ValidatePromoCodeResponse, type WeightedBaseUrl, getRoutingStats };
1108
+ export { type ApiErrorBody, type Availability, type AvailabilityParams, type CheckoutConfig, type CheckoutSession, type CheckoutSessionResponse, type ConfirmPaymentRequest, type ConfirmPaymentResponse, type CreateCheckoutSessionRequest, type CreateCheckoutSessionResponse, type CreatePaymentIntentRequest, type CreateReservationRequest, type CreateSlotHoldRequest, type DateAvailability, type Dish, type DishListResponse, type DishModel, type DishResponse, type DurationPrice, type ListReservationsParams, type PaginatedReservations, type PaymentIntentResponse, type PricingModel, type Product, type ProductCategory, type ProductImage, type ProductListResponse, type ProductVariant, type PromoCode, type PropertyConfig, type PublicResource, type RefundRule, type ReleaseSlotHoldResponse, type Reservation, type ReservationResponse, Resira, ResiraApiError, type ResiraConfig, ResiraError, ResiraNetworkError, ResiraRateLimitError, type ResourceImage, type ResourceImageDisplaySettings, type ResourceListResponse, type RiderTierPrice, type SlotHoldCapacitySnapshot, type SlotHoldResourceSnapshot, type SlotHoldResponse, type TimeSlotAvailability, type ValidatePromoCodeResponse, type WeightedBaseUrl, getRoutingStats };
package/dist/index.js CHANGED
@@ -322,10 +322,11 @@ var Resira = class {
322
322
  throw new Error("resourceId is required for getAvailability");
323
323
  }
324
324
  const qs = toQueryString(keysToSnake(params));
325
- return this.request(
325
+ const raw = await this.request(
326
326
  "GET",
327
327
  `/resources/${encodeURIComponent(resourceId)}/availability${qs}`
328
328
  );
329
+ return deepKeysToCamel(raw);
329
330
  }
330
331
  /**
331
332
  * Query availability for a product/service.
@@ -346,10 +347,83 @@ var Resira = class {
346
347
  throw new Error("productId is required for getProductAvailability");
347
348
  }
348
349
  const qs = toQueryString(keysToSnake(params));
349
- return this.request(
350
+ const raw = await this.request(
350
351
  "GET",
351
352
  `/products/${encodeURIComponent(productId)}/availability${qs}`
352
353
  );
354
+ return deepKeysToCamel(raw);
355
+ }
356
+ /**
357
+ * Create a short-lived hold on a product time slot (typically ~5 minutes).
358
+ * Uses `POST /v2/public/products/{productId}/slot-holds`.
359
+ */
360
+ async createSlotHold(productId, payload, options) {
361
+ if (!productId) {
362
+ throw new Error("productId is required for createSlotHold");
363
+ }
364
+ const idempotencyKey = options?.idempotencyKey ?? uuid();
365
+ const url = `${this.getBaseUrl()}/v2/public/products/${encodeURIComponent(productId)}/slot-holds`;
366
+ const body = {
367
+ ...payload,
368
+ ...payload.durationMinutes != null && payload.durationHours == null ? { durationHours: Number((payload.durationMinutes / 60).toFixed(6)) } : {}
369
+ };
370
+ const init = {
371
+ method: "POST",
372
+ headers: {
373
+ Authorization: `Bearer ${this.apiKey}`,
374
+ Accept: "application/json",
375
+ "Content-Type": "application/json",
376
+ "Idempotency-Key": idempotencyKey
377
+ },
378
+ body: JSON.stringify(body)
379
+ };
380
+ const response = await this._fetch(url, init);
381
+ if (!response.ok) {
382
+ let errorBody = { error: response.statusText || `HTTP ${response.status}` };
383
+ try {
384
+ errorBody = await response.json();
385
+ } catch {
386
+ }
387
+ throw new ResiraApiError(response.status, response.statusText, errorBody, response);
388
+ }
389
+ const raw = await response.json();
390
+ return deepKeysToCamel(raw);
391
+ }
392
+ /**
393
+ * Release an active slot hold (user abandoned checkout or changed slot).
394
+ * Uses `DELETE /v2/public/slot-holds/{holdId}`.
395
+ */
396
+ async releaseSlotHold(holdId) {
397
+ if (!holdId) {
398
+ throw new Error("holdId is required for releaseSlotHold");
399
+ }
400
+ const url = `${this.getBaseUrl()}/v2/public/slot-holds/${encodeURIComponent(holdId)}`;
401
+ const init = {
402
+ method: "DELETE",
403
+ headers: {
404
+ Authorization: `Bearer ${this.apiKey}`,
405
+ Accept: "application/json"
406
+ }
407
+ };
408
+ const response = await this._fetch(url, init);
409
+ if (!response.ok) {
410
+ let errorBody = { error: response.statusText || `HTTP ${response.status}` };
411
+ try {
412
+ errorBody = await response.json();
413
+ } catch {
414
+ }
415
+ throw new ResiraApiError(response.status, response.statusText, errorBody, response);
416
+ }
417
+ const text = await response.text();
418
+ if (!text.trim()) {
419
+ return { holdId, status: "released", serverNow: (/* @__PURE__ */ new Date()).toISOString() };
420
+ }
421
+ try {
422
+ const raw = JSON.parse(text);
423
+ return deepKeysToCamel(raw);
424
+ } catch {
425
+ return { holdId, status: "released", serverNow: (/* @__PURE__ */ new Date()).toISOString() };
426
+ }
353
427
  }
354
428
  /**
355
429
  * Create a reservation.
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\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"]}
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 CreateSlotHoldRequest,\n ReleaseSlotHoldResponse,\n SlotHoldResponse,\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 const raw = await this.request<Record<string, unknown>>(\n \"GET\",\n `/resources/${encodeURIComponent(resourceId)}/availability${qs}`,\n );\n return deepKeysToCamel(raw) as Availability;\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 | boolean | undefined>));\n const raw = await this.request<Record<string, unknown>>(\n \"GET\",\n `/products/${encodeURIComponent(productId)}/availability${qs}`,\n );\n return deepKeysToCamel(raw) as Availability;\n }\n\n /**\n * Create a short-lived hold on a product time slot (typically ~5 minutes).\n * Uses `POST /v2/public/products/{productId}/slot-holds`.\n */\n async createSlotHold(\n productId: string,\n payload: CreateSlotHoldRequest,\n options?: { idempotencyKey?: string },\n ): Promise<SlotHoldResponse> {\n if (!productId) {\n throw new Error(\"productId is required for createSlotHold\");\n }\n const idempotencyKey = options?.idempotencyKey ?? uuid();\n const url = `${this.getBaseUrl()}/v2/public/products/${encodeURIComponent(productId)}/slot-holds`;\n const body: CreateSlotHoldRequest = {\n ...payload,\n ...(payload.durationMinutes != null && payload.durationHours == null\n ? { durationHours: Number((payload.durationMinutes / 60).toFixed(6)) }\n : {}),\n };\n\n const init: RequestInit = {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n },\n body: JSON.stringify(body),\n };\n\n const response = await this._fetch(url, init);\n if (!response.ok) {\n let errorBody: ApiErrorBody = { error: response.statusText || `HTTP ${response.status}` };\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n /* ignore */\n }\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n const raw = (await response.json()) as Record<string, unknown>;\n return deepKeysToCamel(raw) as SlotHoldResponse;\n }\n\n /**\n * Release an active slot hold (user abandoned checkout or changed slot).\n * Uses `DELETE /v2/public/slot-holds/{holdId}`.\n */\n async releaseSlotHold(holdId: string): Promise<ReleaseSlotHoldResponse> {\n if (!holdId) {\n throw new Error(\"holdId is required for releaseSlotHold\");\n }\n const url = `${this.getBaseUrl()}/v2/public/slot-holds/${encodeURIComponent(holdId)}`;\n const init: RequestInit = {\n method: \"DELETE\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: \"application/json\",\n },\n };\n const response = await this._fetch(url, init);\n if (!response.ok) {\n let errorBody: ApiErrorBody = { error: response.statusText || `HTTP ${response.status}` };\n try {\n errorBody = (await response.json()) as ApiErrorBody;\n } catch {\n /* ignore */\n }\n throw new ResiraApiError(response.status, response.statusText, errorBody, response);\n }\n const text = await response.text();\n if (!text.trim()) {\n return { holdId, status: \"released\", serverNow: new Date().toISOString() };\n }\n try {\n const raw = JSON.parse(text) as Record<string, unknown>;\n return deepKeysToCamel(raw) as ReleaseSlotHoldResponse;\n } catch {\n return { holdId, status: \"released\", serverNow: new Date().toISOString() };\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.19",
3
+ "version": "0.4.21",
4
4
  "description": "TypeScript SDK for the Resira public reservation API",
5
5
  "license": "MIT",
6
6
  "type": "module",