@slotchain/sdk 1.1.3 → 1.1.4

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.js CHANGED
@@ -365,10 +365,79 @@ var ServiceClient = class {
365
365
  );
366
366
  return response.data;
367
367
  }
368
+ /**
369
+ * Get services for a tenant (full list with optional filters)
370
+ * GET /api/v1/services
371
+ *
372
+ * @param options - Query options
373
+ * @param options.tenantId - Tenant ID (UUID) - required if tenantSlug not provided
374
+ * @param options.tenantSlug - Tenant slug - required if tenantId not provided
375
+ * @param options.slotId - Slot ID (DEPRECATED - accepted but ignored for API compatibility)
376
+ * @param options.isActive - Filter by active status
377
+ * @param options.includeItems - Include nested service items (default: false)
378
+ * @param options.page - Page number (default: 1)
379
+ * @param options.limit - Items per page (default: 20, max: 100)
380
+ * @returns Services with optional pagination metadata
381
+ */
382
+ async getServicesByTenant(options) {
383
+ if (!options.tenantId && !options.tenantSlug) {
384
+ return {
385
+ success: false,
386
+ error: {
387
+ code: "MISSING_TENANT_ID",
388
+ message: "tenantId or tenantSlug is required"
389
+ }
390
+ };
391
+ }
392
+ const params = {};
393
+ if (options.tenantId) {
394
+ params.tenant_id = options.tenantId;
395
+ }
396
+ if (options.tenantSlug) {
397
+ params.tenantSlug = options.tenantSlug;
398
+ }
399
+ if (options.slotId) {
400
+ params.slot_id = options.slotId;
401
+ }
402
+ if (options.isActive !== void 0) {
403
+ params.is_active = options.isActive;
404
+ }
405
+ if (options.includeItems) {
406
+ params.includeItems = true;
407
+ }
408
+ if (options.page !== void 0) {
409
+ params.page = options.page;
410
+ }
411
+ if (options.limit !== void 0) {
412
+ params.limit = Math.min(options.limit, 100);
413
+ }
414
+ const response = await this.client.get(
415
+ "/api/v1/services",
416
+ { params }
417
+ );
418
+ return response.data;
419
+ }
420
+ /**
421
+ * Get services for a specific slot
422
+ * GET /api/v1/slots/:id/services
423
+ *
424
+ * Note: Services are tenant-level entities. This endpoint returns all active services
425
+ * for the slot's tenant with items included. The response uses 'items' property (not 'serviceItems').
426
+ *
427
+ * @param slotId - Slot ID (UUID)
428
+ * @returns Services with nested items (always includes items, only active services)
429
+ */
430
+ async getServicesBySlot(slotId) {
431
+ const response = await this.client.get(
432
+ `/api/v1/slots/${slotId}/services`
433
+ );
434
+ return response.data;
435
+ }
368
436
  /**
369
437
  * List services by tenant slug
370
438
  * GET /api/v1/services?tenantSlug=:slug
371
439
  *
440
+ * @deprecated Consider using getServicesByTenant() for better type safety and validation
372
441
  * @param slug - Tenant slug (or use tenant_id in list() method)
373
442
  * @param params - Optional parameters (includeItems, page, limit, is_active)
374
443
  * @returns List of services for the tenant
@@ -384,6 +453,7 @@ var ServiceClient = class {
384
453
  * List services with optional filters
385
454
  * GET /api/v1/services
386
455
  *
456
+ * @deprecated Consider using getServicesByTenant() for better type safety and validation
387
457
  * @param params - Query parameters (tenant_id, tenantSlug, slot_id, page, limit, is_active, includeItems)
388
458
  * @returns Paginated list of services
389
459
  */
@@ -700,8 +770,11 @@ var SlotClient = class {
700
770
  * Get all active services for a slot with their items
701
771
  * GET /api/v1/slots/:id/services
702
772
  *
703
- * @param id - Slot ID
704
- * @returns Services with nested service items
773
+ * Note: Services are tenant-level entities. This endpoint returns all active services
774
+ * for the slot's tenant with items included. The response uses 'items' property (not 'serviceItems').
775
+ *
776
+ * @param id - Slot ID (UUID)
777
+ * @returns Services with nested items (always includes items, only active services)
705
778
  */
706
779
  async getServices(id) {
707
780
  const response = await this.client.get(
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/clients/tenant-client.ts","../src/clients/booking-client.ts","../src/clients/service-client.ts","../src/clients/service-item-client.ts","../src/clients/slot-client.ts","../src/clients/customer-client.ts","../src/clients/flow-client.ts","../src/clients/studio-client.ts","../src/clients/notification-client.ts","../src/clients/data-quality-client.ts","../src/clients/organization-client.ts","../src/errors.ts","../src/interceptors.ts","../src/retry.ts","../src/middleware/validateSlotlyRequest.ts"],"sourcesContent":["import axios, { AxiosInstance, InternalAxiosRequestConfig } from 'axios';\nimport { TenantClient } from './clients/tenant-client';\nimport { BookingClient } from './clients/booking-client';\nimport { ServiceClient } from './clients/service-client';\nimport { ServiceItemClient } from './clients/service-item-client';\nimport { SlotClient } from './clients/slot-client';\nimport { CustomerClient } from './clients/customer-client';\nimport { FlowClient } from './clients/flow-client';\nimport { StudioClient } from './clients/studio-client';\nimport { NotificationClient } from './clients/notification-client';\nimport { DataQualityClient } from './clients/data-quality-client';\nimport { OrganizationClient } from './clients/organization-client';\nimport { setupRequestInterceptor, setupResponseInterceptor, setupErrorInterceptor } from './interceptors';\nimport { setupRetryInterceptor } from './retry';\nimport { SlotlyConfigurationError } from './errors';\n\n// Re-export types\nexport type {\n ApiResponse,\n Tenant,\n TenantFullConfig,\n TenantBranding,\n Booking,\n BookingWithSlot,\n ListBookingsOptions,\n Service,\n ServiceItem,\n ServiceWithItems,\n ServiceItemWithService,\n Category,\n Slot,\n Customer,\n Flow,\n FlowStep,\n Studio,\n Notification,\n DataQualityIssue,\n Organization,\n OrganizationFullConfig,\n GetOrganizationOptions,\n} from './types/api';\n\n// Re-export errors\nexport {\n SlotlyApiError,\n SlotlyAuthError,\n SlotlyNetworkError,\n SlotlyConfigurationError,\n} from './errors';\n\n// Re-export middleware\nexport {\n validateSlotlyRequest,\n getSlotlyContext,\n type SlotlyAuthContext,\n type SlotlyRequest,\n} from './middleware/validateSlotlyRequest';\n\nexport interface SlotlyClientOptions {\n /**\n * Required: Function that returns the API key or service token.\n * This must return a non-empty string.\n */\n getClientKey: () => Promise<string>;\n /**\n * Optional: Function that returns a Clerk JWT for user traceability.\n * If provided and returns a token, it will be included in the Authorization header.\n */\n getUserToken?: () => Promise<string | null>;\n /**\n * Optional: Custom base URL for the API.\n * Defaults to process.env.SLOTLY_API_URL or 'https://api.slotly.dev'\n */\n baseURL?: string;\n /**\n * Optional: Additional headers to include with every request.\n */\n headers?: Record<string, string>;\n /**\n * Optional: Retry configuration.\n */\n retry?: {\n maxRetries?: number;\n retryDelay?: number;\n };\n}\n\n/**\n * Unified Slotly API client\n * Provides typed access to all Slotly API domains\n * \n * Note: RegisterClient has been moved to @slotly/studio-sdk\n * for studio-specific booking register operations.\n */\nexport interface SlotlyApi {\n tenant: TenantClient;\n booking: BookingClient;\n service: ServiceClient;\n serviceItem: ServiceItemClient;\n slot: SlotClient;\n customer: CustomerClient;\n flow: FlowClient;\n studio: StudioClient;\n notification: NotificationClient;\n dataQuality: DataQualityClient;\n organization: OrganizationClient;\n}\n\nconst defaultBaseURL = typeof process !== 'undefined' && process.env?.SLOTLY_API_URL \n ? process.env.SLOTLY_API_URL \n : 'https://api.slotly.dev';\n\n/**\n * Creates a new isolated Axios instance with authentication interceptors.\n * Client isolation per instantiation ensures:\n * - No cross-contamination between different auth contexts\n * - SSR safety (each request gets its own client instance)\n * - Proper isolation for scoped keys/roles in the future\n */\nfunction createAuthenticatedClient(options: SlotlyClientOptions): AxiosInstance {\n const client = axios.create({\n baseURL: options.baseURL || defaultBaseURL,\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n timeout: 30000, // 30 seconds\n });\n\n // Request interceptor: Add authentication headers\n // This interceptor runs once per request and fetches fresh tokens\n client.interceptors.request.use(\n async (config: InternalAxiosRequestConfig) => {\n try {\n // Fetch both credentials in parallel for performance\n const [clientKeyPromise, userTokenPromise] = [\n options.getClientKey(),\n options.getUserToken?.() ?? Promise.resolve(null),\n ];\n\n const [clientKey, userToken] = await Promise.all([\n clientKeyPromise,\n userTokenPromise,\n ]);\n\n // Validate that clientKey is provided and non-empty\n if (!clientKey || typeof clientKey !== 'string' || clientKey.trim().length === 0) {\n throw new SlotlyConfigurationError(\n 'getClientKey() must return a non-empty string. API key is required for all requests.',\n { received: clientKey }\n );\n }\n\n // Always set the API key header\n config.headers['x-slotly-api-key'] = clientKey;\n\n // Conditionally set Authorization header if user token is provided\n if (userToken && typeof userToken === 'string' && userToken.trim().length > 0) {\n config.headers['Authorization'] = `Bearer ${userToken}`;\n }\n\n return config;\n } catch (error) {\n // If it's already a SlotlyConfigurationError, re-throw it\n if (error instanceof SlotlyConfigurationError) {\n throw error;\n }\n\n // Handle errors from getClientKey() or getUserToken()\n // If getClientKey fails, this is critical\n if (error && typeof error === 'object' && 'message' in error) {\n // eslint-disable-next-line no-console\n console.error('[Slotly SDK] Failed to retrieve authentication credentials:', error);\n \n throw new SlotlyConfigurationError(\n `Failed to retrieve authentication credentials: ${error.message}`,\n { originalError: error }\n );\n }\n\n throw error;\n }\n },\n (error: Error) => Promise.reject(error)\n );\n\n // Request interceptor: Logging\n client.interceptors.request.use(setupRequestInterceptor());\n\n // Response interceptor: Logging and error shaping\n client.interceptors.response.use(\n (response: any) => setupResponseInterceptor()(response),\n (error: any) => setupErrorInterceptor()(error)\n );\n\n // Error interceptor: Retry logic\n client.interceptors.response.use(\n (response: any) => response,\n setupRetryInterceptor({\n maxRetries: options.retry?.maxRetries ?? 3,\n retryDelay: options.retry?.retryDelay ?? 1000,\n })\n );\n\n return client;\n}\n\n/**\n * Initialize and configure a new Slotly API client with dual authentication.\n * \n * This function creates an isolated Axios instance per call, ensuring:\n * - SSR safety: Each request/context gets its own client instance\n * - No cross-contamination: Different auth contexts don't interfere\n * - Scalable: Supports future expansion for scoped keys, roles, or per-request tokens\n * \n * Authentication model:\n * - **getClientKey()**: Required. Always sets `x-slotly-api-key` header.\n * Identifies the SDK/application making the request.\n * - **getUserToken()**: Optional. Sets `Authorization: Bearer <token>` header if provided.\n * Provides user traceability and authorization scoping.\n *\n * @example Basic usage with API key (public SDK client):\n * ```ts\n * import { useSlotly } from '@slotly/sdk';\n *\n * const slotly = useSlotly({\n * getClientKey: async () => process.env.SLOTLY_SDK_KEY!,\n * });\n * ```\n *\n * @example Server-side with Clerk (authenticated, user-scoped):\n * ```ts\n * import { getToken } from '@clerk/clerk-sdk-node';\n * import { useSlotly } from '@slotly/sdk';\n *\n * // In an API route or server action\n * const slotly = useSlotly({\n * getClientKey: async () => process.env.SLOTLY_SDK_KEY!,\n * getUserToken: async () => await getToken(req),\n * });\n * ```\n *\n * @example Client-side with Clerk (Next.js):\n * ```ts\n * import { useAuth } from '@clerk/nextjs';\n * import { useSlotly } from '@slotly/sdk';\n *\n * function MyComponent() {\n * const { getToken } = useAuth();\n * \n * const slotly = useSlotly({\n * getClientKey: async () => process.env.NEXT_PUBLIC_SLOTLY_SDK_KEY!,\n * getUserToken: getToken,\n * });\n * }\n * ```\n *\n * @example Future: Scoped keys or role-based access\n * ```ts\n * // Future enhancement: Per-request scoping\n * const slotly = useSlotly({\n * getClientKey: async () => getScopedKey(role, tenantId),\n * getUserToken: async () => getToken(),\n * });\n * ```\n *\n * @throws {SlotlyConfigurationError} If getClientKey is missing, returns null, undefined, or empty string.\n */\nexport const useSlotly = (options: SlotlyClientOptions): SlotlyApi => {\n // Validate required options\n if (!options || typeof options !== 'object') {\n throw new SlotlyConfigurationError(\n 'useSlotly() requires an options object with getClientKey function'\n );\n }\n\n if (!options.getClientKey || typeof options.getClientKey !== 'function') {\n throw new SlotlyConfigurationError(\n 'getClientKey must be a function that returns Promise<string>'\n );\n }\n\n // Create a new isolated client instance for this configuration\n // This ensures SSR safety and prevents cross-contamination\n const client = createAuthenticatedClient(options);\n\n // Return the unified API object with all domain clients\n return {\n tenant: new TenantClient(client),\n booking: new BookingClient(client),\n service: new ServiceClient(client),\n serviceItem: new ServiceItemClient(client),\n slot: new SlotClient(client),\n customer: new CustomerClient(client),\n flow: new FlowClient(client),\n studio: new StudioClient(client),\n notification: new NotificationClient(client),\n dataQuality: new DataQualityClient(client),\n organization: new OrganizationClient(client),\n };\n};\n\n// Default export for convenience\nexport default useSlotly;\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Tenant, TenantFullConfig } from '../types/api';\n\nexport class TenantClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get tenant configuration by slug\n * GET /api/v1/tenant-config/:slug\n */\n async getBySlug(slug: string): Promise<ApiResponse<Tenant>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Tenant>>(\n `/api/v1/tenant-config/${slug}`\n );\n return response.data;\n }\n\n /**\n * Get tenant by ID\n * GET /api/v1/tenants/:id\n */\n async getById(id: string): Promise<ApiResponse<Tenant>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Tenant>>(\n `/api/v1/tenants/${id}`\n );\n return response.data;\n }\n\n /**\n * List tenants with optional filters\n * GET /api/v1/tenants\n *\n * @param params - Query parameters\n * - organization_id (optional) - Filter tenants by organization ID\n * - org_id (optional) - Alias for organization_id\n * - page (optional) - Page number for pagination\n * - limit (optional) - Items per page\n * @returns Paginated list of tenants\n *\n * @example\n * ```typescript\n * // List all tenants\n * const allTenants = await slotly.tenant.list();\n *\n * // List tenants for a specific organization\n * const orgTenants = await slotly.tenant.list({\n * organization_id: 'org-123',\n * page: 1,\n * limit: 20\n * });\n * ```\n */\n async list(params?: {\n organization_id?: string;\n org_id?: string;\n page?: number;\n limit?: number;\n }): Promise<ApiResponse<Tenant[]>> {\n // Normalize org_id to organization_id if provided\n const queryParams: Record<string, any> = {};\n if (params?.organization_id) {\n queryParams.organization_id = params.organization_id;\n } else if (params?.org_id) {\n queryParams.organization_id = params.org_id;\n }\n if (params?.page !== undefined) queryParams.page = params.page;\n if (params?.limit !== undefined) queryParams.limit = params.limit;\n\n const response = await this.client.get<ApiResponse<Tenant[]>>(\n '/api/v1/tenants',\n { params: queryParams }\n );\n return response.data;\n }\n\n /**\n * Create a new tenant\n * POST /api/v1/tenants\n */\n async create(data: Partial<Tenant>): Promise<ApiResponse<Tenant>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<Tenant>>(\n '/api/v1/tenants',\n data\n );\n return response.data;\n }\n\n /**\n * Update tenant by ID\n * PATCH /api/v1/tenants/:id\n */\n async update(id: string, data: Partial<Tenant>): Promise<ApiResponse<Tenant>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.patch<ApiResponse<Tenant>>(\n `/api/v1/tenants/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete tenant by ID\n * DELETE /api/v1/tenants/:id\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/tenants/${id}`\n );\n return response.data;\n }\n\n /**\n * Get full tenant configuration including branding, services, and service items\n * GET /api/v1/tenants/:slug\n * \n * This method returns the complete tenant configuration including:\n * - Tenant basic info (id, slug, name)\n * - Branding configuration (logo, colors, etc.)\n * - All services associated with the tenant (with nested service items)\n * - Feature flags and subscription level\n * \n * Note: Service items are nested within each service object (not as a separate top-level array).\n * The endpoint returns full config by default (includes services with nested items).\n * \n * @param slug - Tenant slug identifier (required, non-nullable)\n * @param includeServices - Include services with nested items (default: true)\n * @returns Promise resolving to ApiResponse<TenantFullConfig>\n * \n * @example\n * ```typescript\n * const result = await slotly.tenant.getFullConfig('bright-accountants');\n * if (result.success && result.data) {\n * const config = result.data;\n * console.log('Tenant:', config.name);\n * console.log('Logo:', config.branding?.logoUrl);\n * console.log('Services:', config.services.length);\n * \n * // Service items are nested within each service\n * config.services.forEach(service => {\n * console.log(`Service: ${service.name}`);\n * if (service.serviceItems) {\n * console.log(` Items: ${service.serviceItems.length}`);\n * }\n * });\n * }\n * ```\n * \n * **Guaranteed fields (non-nullable):**\n * - `id`: string\n * - `slug`: string\n * - `name`: string\n * - `services`: ServiceWithItems[] (may be empty array, each service may have nested `serviceItems`)\n * \n * **Optional fields:**\n * - `branding`: TenantBranding | undefined\n * - `services[].serviceItems`: ServiceItem[] | undefined (nested within each service)\n * - `featuresEnabled`: string[] | undefined\n * - `subscriptionLevel`: string | undefined\n * - `config`: Record<string, any> | undefined\n * \n * **Error Codes:**\n * - `TENANT_NOT_FOUND` - Tenant with slug not found\n * - `AUTH_ERROR` - Authentication failed\n * - `PERMISSION_DENIED` - Insufficient permissions\n * - `NETWORK_ERROR` - Network request failed\n */\n async getFullConfig(slug: string, includeServices: boolean = true): Promise<ApiResponse<TenantFullConfig>> {\n const response = await this.client.get<ApiResponse<TenantFullConfig>>(\n `/api/v1/tenants/${slug}`,\n { params: { includeServices } }\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Booking, BookingWithSlot, ListBookingsOptions } from '../types/api';\n\nexport class BookingClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get booking by ID\n * GET /api/v1/bookings/:id\n */\n async getById(id: string): Promise<ApiResponse<Booking>> {\n const response = await this.client.get<ApiResponse<Booking>>(\n `/api/v1/bookings/${id}`\n );\n return response.data;\n }\n\n /**\n * List bookings with enhanced filtering\n * GET /api/v1/bookings\n *\n * Supports filtering by tenant_id, slot_id, customer_id, status, and optional nested slot information.\n *\n * @param params - Query options (tenant_id, slot_id, customer_id, status, includeSlot, page, limit)\n * @returns Bookings or BookingsWithSlot based on includeSlot parameter\n *\n * @example\n * ```typescript\n * // List bookings by tenant (single query - fast!)\n * const bookings = await slotly.booking.list({\n * tenant_id: 'tenant-123',\n * includeSlot: true,\n * page: 1,\n * limit: 20\n * });\n *\n * // List bookings by slot\n * const slotBookings = await slotly.booking.list({\n * slot_id: 'slot-456',\n * status: 'confirmed'\n * });\n * ```\n */\n async list(params?: ListBookingsOptions): Promise<ApiResponse<Booking[] | BookingWithSlot[]>> {\n const response = await this.client.get<ApiResponse<Booking[] | BookingWithSlot[]>>(\n '/api/v1/bookings',\n { params }\n );\n return response.data;\n }\n\n /**\n * List bookings by tenant (convenience method)\n * GET /api/v1/bookings?tenant_id=:id\n *\n * @param tenantId - Tenant ID\n * @param options - Additional options (includeSlot, page, limit, status)\n * @returns Bookings or BookingsWithSlot based on includeSlot parameter\n *\n * @example\n * ```typescript\n * const bookings = await slotly.booking.listByTenant('tenant-123', {\n * page: 1,\n * limit: 20,\n * status: 'confirmed'\n * });\n * ```\n */\n async listByTenant(\n tenantId: string,\n options?: Omit<ListBookingsOptions, 'tenant_id'>\n ): Promise<ApiResponse<Booking[] | BookingWithSlot[]>> {\n return this.list({\n tenant_id: tenantId,\n ...options,\n });\n }\n\n /**\n * List bookings by tenant with nested slot information (convenience method)\n * GET /api/v1/bookings?tenant_id=:id&includeSlot=true\n *\n * @param tenantId - Tenant ID\n * @param options - Additional options (page, limit, status)\n * @returns BookingsWithSlot (includes nested slot information)\n *\n * @example\n * ```typescript\n * const bookings = await slotly.booking.listByTenantWithSlots('tenant-123', {\n * page: 1,\n * limit: 20\n * });\n *\n * // Access slot information\n * bookings.data.forEach(booking => {\n * if (booking.slots) {\n * console.log('Slot name:', booking.slots.name);\n * }\n * });\n * ```\n */\n async listByTenantWithSlots(\n tenantId: string,\n options?: Omit<ListBookingsOptions, 'tenant_id' | 'includeSlot'>\n ): Promise<ApiResponse<BookingWithSlot[]>> {\n return this.list({\n tenant_id: tenantId,\n includeSlot: true,\n ...options,\n }) as Promise<ApiResponse<BookingWithSlot[]>>;\n }\n\n /**\n * Create a new booking (publishes booking.created event)\n * POST /api/v1/bookings\n */\n async create(data: {\n slot_id: string;\n customer_info: {\n name: string;\n email: string;\n phone?: string;\n address?: string;\n city?: string;\n state?: string;\n zipCode?: string;\n isGuestCheckout?: boolean;\n };\n booking_data?: Record<string, unknown>;\n }): Promise<ApiResponse<Booking>> {\n const response = await this.client.post<ApiResponse<Booking>>(\n '/api/v1/bookings',\n data\n );\n return response.data;\n }\n\n /**\n * Update booking by ID\n * PUT /api/v1/bookings/:id\n */\n async update(id: string, data: {\n status?: string;\n customer_info?: Record<string, unknown>;\n booking_data?: Record<string, unknown>;\n }): Promise<ApiResponse<Booking>> {\n const response = await this.client.put<ApiResponse<Booking>>(\n `/api/v1/bookings/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Cancel booking by ID\n * Note: Cancel is typically done via update with status change\n * If dedicated cancel endpoint exists, update this method\n */\n async cancel(id: string): Promise<ApiResponse<Booking>> {\n // Use update to change status to cancelled\n return this.update(id, { status: 'cancelled' });\n }\n\n /**\n * Delete booking by ID (soft delete)\n * DELETE /api/v1/bookings/:id\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/bookings/${id}`\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Service, ServiceWithItems, Category } from '../types/api';\n\nexport class ServiceClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get service by ID\n * GET /api/v1/services/:id\n * \n * @param id - Service ID\n * @param includeItems - Include nested service items (default: false)\n * @returns Service details (with items if includeItems=true)\n */\n async getById(id: string, includeItems: boolean = false): Promise<ApiResponse<Service | ServiceWithItems>> {\n const response = await this.client.get<ApiResponse<Service | ServiceWithItems>>(\n `/api/v1/services/${id}`,\n includeItems ? { params: { includeItems: true } } : undefined\n );\n return response.data;\n }\n\n /**\n * List services by tenant slug\n * GET /api/v1/services?tenantSlug=:slug\n * \n * @param slug - Tenant slug (or use tenant_id in list() method)\n * @param params - Optional parameters (includeItems, page, limit, is_active)\n * @returns List of services for the tenant\n */\n async listServices(\n slug: string,\n params?: {\n includeItems?: boolean;\n page?: number;\n limit?: number;\n is_active?: boolean;\n }\n ): Promise<ApiResponse<Service[] | ServiceWithItems[]>> {\n const response = await this.client.get<ApiResponse<Service[] | ServiceWithItems[]>>(\n '/api/v1/services',\n { params: { tenantSlug: slug, ...params } }\n );\n return response.data;\n }\n\n /**\n * List services with optional filters\n * GET /api/v1/services\n * \n * @param params - Query parameters (tenant_id, tenantSlug, slot_id, page, limit, is_active, includeItems)\n * @returns Paginated list of services\n */\n async list(params?: {\n tenant_id?: string;\n tenantSlug?: string;\n slot_id?: string;\n page?: number;\n limit?: number;\n is_active?: boolean;\n includeItems?: boolean;\n }): Promise<ApiResponse<Service[] | ServiceWithItems[]>> {\n const response = await this.client.get<ApiResponse<Service[] | ServiceWithItems[]>>(\n '/api/v1/services',\n { params }\n );\n return response.data;\n }\n\n /**\n * Create a new service\n * POST /api/v1/services\n * \n * @param data - Service creation data (tenant_id, name required)\n * @returns Created service\n */\n async create(data: Partial<Service>): Promise<ApiResponse<Service>> {\n const response = await this.client.post<ApiResponse<Service>>(\n '/api/v1/services',\n data\n );\n return response.data;\n }\n\n /**\n * Update service by ID\n * PUT /api/v1/services/:id\n * \n * @param id - Service ID\n * @param data - Service update data\n * @returns Updated service\n */\n async update(id: string, data: Partial<Service>): Promise<ApiResponse<Service>> {\n const response = await this.client.put<ApiResponse<Service>>(\n `/api/v1/services/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete service by ID\n * DELETE /api/v1/services/:id\n * \n * @param id - Service ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/services/${id}`\n );\n return response.data;\n }\n\n /**\n * Bulk create services\n * POST /api/v1/services/bulk (if available)\n * \n * @param services - Array of services to create\n * @returns Created services\n */\n async bulkCreate(services: Partial<Service>[]): Promise<ApiResponse<Service[]>> {\n // Note: Verify if bulk endpoint exists in API\n const response = await this.client.post<ApiResponse<Service[]>>(\n '/api/v1/services/bulk',\n { services }\n );\n return response.data;\n }\n\n /**\n * Get service with its service items nested\n * GET /api/v1/services/:id?includeItems=true\n * \n * @param id - Service ID\n * @returns Service with nested service items\n */\n async getWithItems(id: string): Promise<ApiResponse<ServiceWithItems>> {\n const response = await this.client.get<ApiResponse<ServiceWithItems>>(\n `/api/v1/services/${id}`,\n { params: { includeItems: true } }\n );\n return response.data;\n }\n\n /**\n * List services with their service items nested\n * GET /api/v1/services?includeItems=true\n * \n * @param params - Query parameters (tenant_id, tenantSlug, slot_id, page, limit, is_active)\n * @returns Paginated list of services with nested service items\n */\n async listWithItems(params?: {\n tenant_id?: string;\n tenantSlug?: string;\n slot_id?: string;\n page?: number;\n limit?: number;\n is_active?: boolean;\n }): Promise<ApiResponse<ServiceWithItems[]>> {\n const response = await this.client.get<ApiResponse<ServiceWithItems[]>>(\n '/api/v1/services',\n { params: { includeItems: true, ...params } }\n );\n return response.data;\n }\n\n /**\n * List all categories for a tenant (extracted from services)\n * GET /api/v1/categories?tenantSlug=:slug\n * \n * @param tenantSlug - Tenant slug (or use tenant_id in params)\n * @param params - Optional query parameters (tenant_id, includeServices)\n * @returns List of categories for the tenant\n */\n async listCategories(\n tenantSlug?: string,\n params?: {\n tenant_id?: string;\n includeServices?: boolean;\n }\n ): Promise<ApiResponse<Category[]>> {\n const response = await this.client.get<ApiResponse<Category[]>>(\n '/api/v1/categories',\n { params: { tenantSlug, ...params } }\n );\n return response.data;\n }\n\n /**\n * Get category by ID (category name, lowercase)\n * GET /api/v1/categories/:id?tenantSlug=:slug\n * \n * @param categoryId - Category ID (lowercase category name, e.g., \"consulting\")\n * @param tenantSlug - Tenant slug (or use tenant_id in params)\n * @param params - Optional query parameters (tenant_id, includeServices, includeItems)\n * @returns Category details\n */\n async getCategory(\n categoryId: string,\n tenantSlug?: string,\n params?: {\n tenant_id?: string;\n includeServices?: boolean;\n includeItems?: boolean;\n }\n ): Promise<ApiResponse<Category>> {\n const response = await this.client.get<ApiResponse<Category>>(\n `/api/v1/categories/${categoryId}`,\n { params: { tenantSlug, ...params } }\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, ServiceItem, ServiceItemWithService } from '../types/api';\n\n/**\n * ServiceItemClient provides methods for managing service items independently\n * or in relation to their parent services.\n */\nexport class ServiceItemClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get service item by ID\n * GET /api/v1/service-items/:id\n * \n * @param id - Service item ID\n * @returns Service item details\n */\n async getById(id: string): Promise<ApiResponse<ServiceItem>> {\n const response = await this.client.get<ApiResponse<ServiceItem>>(\n `/api/v1/service-items/${id}`\n );\n return response.data;\n }\n\n /**\n * List all service items for a service\n * GET /api/v1/services/:serviceId/items\n * \n * @param serviceId - Service ID\n * @returns List of service items for the specified service\n */\n async listByService(serviceId: string): Promise<ApiResponse<ServiceItem[]>> {\n const response = await this.client.get<ApiResponse<ServiceItem[]>>(\n `/api/v1/services/${serviceId}/items`\n );\n return response.data;\n }\n\n /**\n * Create a new service item for a service\n * POST /api/v1/services/:serviceId/items\n * \n * @param serviceId - Service ID\n * @param data - Service item creation data\n * @returns Created service item\n */\n async createForService(\n serviceId: string,\n data: Partial<ServiceItem>\n ): Promise<ApiResponse<ServiceItem>> {\n const response = await this.client.post<ApiResponse<ServiceItem>>(\n `/api/v1/services/${serviceId}/items`,\n { ...data, service_id: serviceId }\n );\n return response.data;\n }\n\n /**\n * Create a new service item\n * POST /api/v1/service-items (alternative to createForService)\n * \n * @param data - Service item creation data (must include service_id)\n * @returns Created service item\n */\n async create(data: Partial<ServiceItem>): Promise<ApiResponse<ServiceItem>> {\n const response = await this.client.post<ApiResponse<ServiceItem>>(\n '/api/v1/service-items',\n data\n );\n return response.data;\n }\n\n /**\n * Update service item by ID\n * PUT /api/v1/service-items/:id\n * \n * @param id - Service item ID\n * @param data - Service item update data\n * @returns Updated service item\n */\n async update(id: string, data: Partial<ServiceItem>): Promise<ApiResponse<ServiceItem>> {\n const response = await this.client.put<ApiResponse<ServiceItem>>(\n `/api/v1/service-items/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete service item by ID\n * DELETE /api/v1/service-items/:id\n * \n * @param id - Service item ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/service-items/${id}`\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Slot, ServiceWithItems, Tenant } from '../types/api';\n\nexport class SlotClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get slot by ID\n * GET /api/v1/slots/:id\n * \n * @param id - Slot ID\n * @returns Slot details\n */\n async getById(id: string): Promise<ApiResponse<Slot>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Slot>>(\n `/api/v1/slots/${id}`\n );\n return response.data;\n }\n\n /**\n * List available slots\n * GET /api/v1/slots\n * \n * @param params - Query parameters (tenant_id required, status, is_active, page, limit)\n * @returns Paginated list of slots\n */\n async list(params: {\n tenant_id: string;\n status?: string;\n is_active?: boolean;\n page?: number;\n limit?: number;\n }): Promise<ApiResponse<Slot[]>> {\n const response = await this.client.get<ApiResponse<Slot[]>>(\n '/api/v1/slots',\n { params }\n );\n return response.data;\n }\n\n /**\n * Create a new slot\n * POST /api/v1/slots\n * \n * @param data - Slot creation data (tenant_id, name required)\n * @returns Created slot\n */\n async create(data: Partial<Slot>): Promise<ApiResponse<Slot>> {\n const response = await this.client.post<ApiResponse<Slot>>(\n '/api/v1/slots',\n data\n );\n return response.data;\n }\n\n /**\n * Update slot by ID\n * PUT /api/v1/slots/:id\n * \n * @param id - Slot ID\n * @param data - Slot update data\n * @returns Updated slot\n */\n async update(id: string, data: Partial<Slot>): Promise<ApiResponse<Slot>> {\n const response = await this.client.put<ApiResponse<Slot>>(\n `/api/v1/slots/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete slot by ID\n * DELETE /api/v1/slots/:id\n * \n * @param id - Slot ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/slots/${id}`\n );\n return response.data;\n }\n\n /**\n * Bulk create slots\n * POST /api/v1/slots/bulk (verify if available)\n * \n * @param slots - Array of slots to create\n * @returns Created slots\n */\n async bulkCreate(slots: Partial<Slot>[]): Promise<ApiResponse<Slot[]>> {\n // Note: Verify if bulk endpoint exists in API\n const response = await this.client.post<ApiResponse<Slot[]>>(\n '/api/v1/slots/bulk',\n { slots }\n );\n return response.data;\n }\n\n /**\n * Mark slot as available/unavailable\n * Note: Use update() method with status or other fields\n */\n async setAvailability(id: string, available: boolean): Promise<ApiResponse<Slot>> {\n return this.update(id, { status: available ? 'active' : 'inactive' } as Partial<Slot>);\n }\n\n /**\n * Get all active services for a slot with their items\n * GET /api/v1/slots/:id/services\n * \n * @param id - Slot ID\n * @returns Services with nested service items\n */\n async getServices(id: string): Promise<ApiResponse<ServiceWithItems[]>> {\n const response = await this.client.get<ApiResponse<ServiceWithItems[]>>(\n `/api/v1/slots/${id}/services`\n );\n return response.data;\n }\n\n /**\n * Get slot with tenant information\n * GET /api/v1/slots/:id/tenant-info\n * \n * @param id - Slot ID\n * @returns Slot with tenant data\n */\n async getWithTenant(id: string): Promise<ApiResponse<Slot & { tenant: Tenant }>> {\n const response = await this.client.get<ApiResponse<Slot & { tenant: Tenant }>>(\n `/api/v1/slots/${id}/tenant-info`\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Customer, Booking } from '../types/api';\n\nexport class CustomerClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get customer by ID\n * GET /api/v1/customers/:id\n * \n * @param id - Customer ID\n * @returns Customer details\n */\n async getById(id: string): Promise<ApiResponse<Customer>> {\n const response = await this.client.get<ApiResponse<Customer>>(\n `/api/v1/customers/${id}`\n );\n return response.data;\n }\n\n /**\n * Get customer by email\n * GET /api/v1/customers?email=:email&tenant_id=:id\n * \n * @param email - Customer email\n * @param tenantId - Required tenant ID for scoping\n * @returns Customer details\n */\n async getByEmail(email: string, tenantId: string): Promise<ApiResponse<Customer>> {\n const response = await this.client.get<ApiResponse<Customer>>(\n '/api/v1/customers',\n { params: { email, tenant_id: tenantId } }\n );\n return response.data;\n }\n\n /**\n * List customers with optional filters\n * GET /api/v1/customers\n * \n * @param params - Query parameters (tenant_id required, page, limit, search, is_guest)\n * @returns Paginated list of customers\n */\n async list(params: {\n tenant_id: string;\n page?: number;\n limit?: number;\n search?: string;\n is_guest?: boolean;\n }): Promise<ApiResponse<Customer[]>> {\n const response = await this.client.get<ApiResponse<Customer[]>>(\n '/api/v1/customers',\n { params }\n );\n return response.data;\n }\n\n /**\n * Create a new customer\n * POST /api/v1/customers\n * \n * @param data - Customer creation data (tenant_id, name, email required)\n * @returns Created customer\n */\n async create(data: Partial<Customer>): Promise<ApiResponse<Customer>> {\n const response = await this.client.post<ApiResponse<Customer>>(\n '/api/v1/customers',\n data\n );\n return response.data;\n }\n\n /**\n * Update customer by ID\n * PUT /api/v1/customers/:id\n * \n * @param id - Customer ID\n * @param data - Customer update data\n * @returns Updated customer\n */\n async update(id: string, data: Partial<Customer>): Promise<ApiResponse<Customer>> {\n const response = await this.client.put<ApiResponse<Customer>>(\n `/api/v1/customers/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete customer by ID\n * DELETE /api/v1/customers/:id\n * \n * @param id - Customer ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/customers/${id}`\n );\n return response.data;\n }\n\n /**\n * Lookup customer by userId or tenantId\n * GET /api/v1/customers/lookup\n * \n * @param params - Query parameters (userId optional, tenantId required)\n * @returns Customer or null\n */\n async lookup(params: {\n userId?: string;\n tenantId: string;\n }): Promise<ApiResponse<Customer | null>> {\n const response = await this.client.get<ApiResponse<Customer | null>>(\n '/api/v1/customers/lookup',\n { params: { userId: params.userId, tenantId: params.tenantId } }\n );\n return response.data;\n }\n\n /**\n * Get autocomplete data from existing customers and bookings\n * GET /api/v1/customers/autocomplete\n * \n * @param tenantId - Tenant ID (required)\n * @returns Autocomplete data\n */\n async autocomplete(tenantId: string): Promise<ApiResponse<any>> {\n const response = await this.client.get<ApiResponse<any>>(\n '/api/v1/customers/autocomplete',\n { params: { tenantId } }\n );\n return response.data;\n }\n\n /**\n * Get all bookings for a customer\n * GET /api/v1/customers/bookings\n * \n * @param params - Query parameters (email optional, userId optional, tenantId required)\n * @returns Customer bookings data\n */\n async getBookings(params: {\n email?: string;\n userId?: string;\n tenantId: string;\n }): Promise<ApiResponse<{\n customer: Customer | null;\n bookings: Booking[];\n groupedBySlot: Record<string, Booking[]>;\n total: number;\n }>> {\n const response = await this.client.get<ApiResponse<{\n customer: Customer | null;\n bookings: Booking[];\n groupedBySlot: Record<string, Booking[]>;\n total: number;\n }>>(\n '/api/v1/customers/bookings',\n { params }\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Flow } from '../types/api';\n\nexport class FlowClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get flow by ID\n * GET /api/v1/flows/:id\n * \n * @param id - Flow ID\n * @returns Flow details\n */\n async getById(id: string): Promise<ApiResponse<Flow>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Flow>>(\n `/api/v1/flows/${id}`\n );\n return response.data;\n }\n\n /**\n * List flows with optional filters\n * GET /api/v1/flows\n * \n * @param params - Query parameters (tenantId, page, limit)\n * @returns Paginated list of flows\n */\n async list(params?: {\n tenantId?: string;\n page?: number;\n limit?: number;\n }): Promise<ApiResponse<Flow[]>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Flow[]>>(\n '/api/v1/flows',\n { params }\n );\n return response.data;\n }\n\n /**\n * Create a new flow\n * POST /api/v1/flows\n * \n * @param data - Flow creation data\n * @returns Created flow\n */\n async create(data: Partial<Flow>): Promise<ApiResponse<Flow>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<Flow>>(\n '/api/v1/flows',\n data\n );\n return response.data;\n }\n\n /**\n * Update flow by ID\n * PATCH /api/v1/flows/:id\n * \n * @param id - Flow ID\n * @param data - Flow update data\n * @returns Updated flow\n */\n async update(id: string, data: Partial<Flow>): Promise<ApiResponse<Flow>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.patch<ApiResponse<Flow>>(\n `/api/v1/flows/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete flow by ID\n * DELETE /api/v1/flows/:id\n * \n * @param id - Flow ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/flows/${id}`\n );\n return response.data;\n }\n\n /**\n * Execute a flow\n * POST /api/v1/flows/:id/execute\n * \n * @param id - Flow ID\n * @param input - Optional input data for flow execution\n * @returns Flow execution result\n */\n async execute(id: string, input?: Record<string, any>): Promise<ApiResponse<any>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<any>>(\n `/api/v1/flows/${id}/execute`,\n { input }\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Studio } from '../types/api';\n\nexport class StudioClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get studio by ID\n * GET /api/v1/studios/:id\n * \n * @param id - Studio ID\n * @returns Studio details\n */\n async getById(id: string): Promise<ApiResponse<Studio>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Studio>>(\n `/api/v1/studios/${id}`\n );\n return response.data;\n }\n\n /**\n * Get studio by slug\n * GET /api/v1/studios/slug/:slug\n * \n * @param slug - Studio slug\n * @returns Studio details\n */\n async getBySlug(slug: string): Promise<ApiResponse<Studio>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Studio>>(\n `/api/v1/studios/slug/${slug}`\n );\n return response.data;\n }\n\n /**\n * List studios with optional filters\n * GET /api/v1/studios\n * \n * @param params - Query parameters (page, limit, search)\n * @returns Paginated list of studios\n */\n async list(params?: {\n page?: number;\n limit?: number;\n search?: string;\n }): Promise<ApiResponse<Studio[]>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Studio[]>>(\n '/api/v1/studios',\n { params }\n );\n return response.data;\n }\n\n /**\n * Create a new studio\n * POST /api/v1/studios\n * \n * @param data - Studio creation data\n * @returns Created studio\n */\n async create(data: Partial<Studio>): Promise<ApiResponse<Studio>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<Studio>>(\n '/api/v1/studios',\n data\n );\n return response.data;\n }\n\n /**\n * Update studio by ID\n * PATCH /api/v1/studios/:id\n * \n * @param id - Studio ID\n * @param data - Studio update data\n * @returns Updated studio\n */\n async update(id: string, data: Partial<Studio>): Promise<ApiResponse<Studio>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.patch<ApiResponse<Studio>>(\n `/api/v1/studios/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete studio by ID\n * DELETE /api/v1/studios/:id\n * \n * @param id - Studio ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/studios/${id}`\n );\n return response.data;\n }\n\n /**\n * Get data quality issues for a studio\n * GET /api/v1/studios/:id/data-quality\n * \n * @param id - Studio ID\n * @param params - Query parameters (resolved, severity)\n * @returns List of data quality issues\n */\n async getDataQualityIssues(\n id: string,\n params?: {\n resolved?: boolean;\n severity?: 'low' | 'medium' | 'high';\n }\n ): Promise<ApiResponse<any[]>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<any[]>>(\n `/api/v1/studios/${id}/data-quality`,\n { params }\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Notification } from '../types/api';\n\nexport class NotificationClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get notification by ID\n * GET /api/v1/notifications/:id\n * \n * @param id - Notification ID\n * @returns Notification details\n */\n async getById(id: string): Promise<ApiResponse<Notification>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Notification>>(\n `/api/v1/notifications/${id}`\n );\n return response.data;\n }\n\n /**\n * List notifications with optional filters\n * GET /api/v1/notifications\n * \n * @param params - Query parameters (tenantId, type, recipient, page, limit)\n * @returns Paginated list of notifications\n */\n async list(params?: {\n tenantId?: string;\n type?: string;\n recipient?: string;\n page?: number;\n limit?: number;\n }): Promise<ApiResponse<Notification[]>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Notification[]>>(\n '/api/v1/notifications',\n { params }\n );\n return response.data;\n }\n\n /**\n * Create a new notification\n * POST /api/v1/notifications\n * \n * @param data - Notification creation data\n * @returns Created notification\n */\n async create(data: Partial<Notification>): Promise<ApiResponse<Notification>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<Notification>>(\n '/api/v1/notifications',\n data\n );\n return response.data;\n }\n\n /**\n * Send notification immediately\n * POST /api/v1/notifications/send\n * \n * @param data - Notification data to send\n * @returns Sent notification\n */\n async send(data: Partial<Notification>): Promise<ApiResponse<Notification>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<Notification>>(\n '/api/v1/notifications/send',\n data\n );\n return response.data;\n }\n\n /**\n * Update notification by ID\n * PATCH /api/v1/notifications/:id\n * \n * @param id - Notification ID\n * @param data - Notification update data\n * @returns Updated notification\n */\n async update(id: string, data: Partial<Notification>): Promise<ApiResponse<Notification>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.patch<ApiResponse<Notification>>(\n `/api/v1/notifications/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete notification by ID\n * DELETE /api/v1/notifications/:id\n * \n * @param id - Notification ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/notifications/${id}`\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, DataQualityIssue } from '../types/api';\n\nexport class DataQualityClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get data quality issue by ID\n * GET /api/v1/data-quality/:id\n * \n * @param id - Issue ID\n * @returns Data quality issue details\n */\n async getById(id: string): Promise<ApiResponse<DataQualityIssue>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<DataQualityIssue>>(\n `/api/v1/data-quality/${id}`\n );\n return response.data;\n }\n\n /**\n * List data quality issues with optional filters\n * GET /api/v1/data-quality\n * \n * @param params - Query parameters (tenantId, type, severity, resolved, page, limit)\n * @returns Paginated list of data quality issues\n */\n async list(params?: {\n tenantId?: string;\n type?: string;\n severity?: 'low' | 'medium' | 'high';\n resolved?: boolean;\n page?: number;\n limit?: number;\n }): Promise<ApiResponse<DataQualityIssue[]>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<DataQualityIssue[]>>(\n '/api/v1/data-quality',\n { params }\n );\n return response.data;\n }\n\n /**\n * Run data quality check for a tenant\n * POST /api/v1/data-quality/check\n * \n * @param tenantId - Tenant ID to check\n * @returns List of detected issues\n */\n async runCheck(tenantId: string): Promise<ApiResponse<DataQualityIssue[]>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<DataQualityIssue[]>>(\n '/api/v1/data-quality/check',\n { tenantId }\n );\n return response.data;\n }\n\n /**\n * Resolve a data quality issue\n * PATCH /api/v1/data-quality/:id/resolve\n * \n * @param id - Issue ID\n * @returns Resolved issue\n */\n async resolve(id: string): Promise<ApiResponse<DataQualityIssue>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.patch<ApiResponse<DataQualityIssue>>(\n `/api/v1/data-quality/${id}/resolve`,\n { resolved: true }\n );\n return response.data;\n }\n\n /**\n * Get data quality summary for a tenant\n * GET /api/v1/data-quality/summary?tenantId=:id\n * \n * @param tenantId - Tenant ID\n * @returns Summary of data quality issues\n */\n async getSummary(tenantId: string): Promise<ApiResponse<any>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<any>>(\n '/api/v1/data-quality/summary',\n { params: { tenantId } }\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Organization, OrganizationFullConfig, GetOrganizationOptions } from '../types/api';\n\n/**\n * OrganizationClient provides methods for managing organizations\n */\nexport class OrganizationClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get organization by ID or slug\n * GET /api/v1/organizations/:id\n *\n * @param identifier - Organization ID or slug\n * @param options - Query options (includeTenants, page, limit, is_public)\n * @returns Organization or OrganizationFullConfig (with nested tenants if includeTenants=true)\n *\n * @example\n * ```typescript\n * // Get organization only\n * const org = await slotly.organization.getById('org-123');\n *\n * // Get organization with tenants\n * const orgWithTenants = await slotly.organization.getById('org-123', {\n * includeTenants: true,\n * page: 1,\n * limit: 10,\n * is_public: true\n * });\n * ```\n */\n async getById(\n identifier: string,\n options?: GetOrganizationOptions\n ): Promise<ApiResponse<Organization | OrganizationFullConfig>> {\n const params: Record<string, any> = {};\n\n if (options?.includeTenants) {\n params.includeTenants = 'true';\n }\n\n if (options?.page !== undefined) {\n params.page = options.page;\n }\n\n if (options?.limit !== undefined) {\n params.limit = options.limit;\n }\n\n if (options?.is_public !== undefined) {\n params.is_public = options.is_public;\n }\n\n const response = await this.client.get<ApiResponse<Organization | OrganizationFullConfig>>(\n `/api/v1/organizations/${identifier}`,\n { params }\n );\n return response.data;\n }\n\n /**\n * Get organization by slug (alias for getById)\n * GET /api/v1/organizations/:slug\n *\n * @param slug - Organization slug\n * @param options - Query options (includeTenants, page, limit, is_public)\n * @returns Organization or OrganizationFullConfig (with nested tenants if includeTenants=true)\n *\n * @example\n * ```typescript\n * const org = await slotly.organization.getBySlug('acme-corp', {\n * includeTenants: true\n * });\n * ```\n */\n async getBySlug(\n slug: string,\n options?: GetOrganizationOptions\n ): Promise<ApiResponse<Organization | OrganizationFullConfig>> {\n return this.getById(slug, options);\n }\n}\n\n","/**\n * Custom error classes for Slotly SDK\n */\n\nexport class SlotlyApiError extends Error {\n constructor(\n public code: string,\n message: string,\n public statusCode?: number,\n public details?: any\n ) {\n super(message);\n this.name = 'SlotlyApiError';\n Object.setPrototypeOf(this, SlotlyApiError.prototype);\n }\n}\n\nexport class SlotlyAuthError extends SlotlyApiError {\n constructor(message: string, details?: any) {\n super('AUTH_ERROR', message, 401, details);\n this.name = 'SlotlyAuthError';\n Object.setPrototypeOf(this, SlotlyAuthError.prototype);\n }\n}\n\nexport class SlotlyNetworkError extends Error {\n constructor(message: string, public originalError?: any) {\n super(message);\n this.name = 'SlotlyNetworkError';\n Object.setPrototypeOf(this, SlotlyNetworkError.prototype);\n }\n}\n\nexport class SlotlyConfigurationError extends Error {\n constructor(message: string, public details?: any) {\n super(message);\n this.name = 'SlotlyConfigurationError';\n Object.setPrototypeOf(this, SlotlyConfigurationError.prototype);\n }\n}\n\n","import { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';\nimport { SlotlyApiError, SlotlyAuthError, SlotlyNetworkError } from './errors';\nimport { ApiResponse } from './types/api';\n\n/**\n * Request interceptor for logging\n */\nexport function setupRequestInterceptor() {\n return (config: InternalAxiosRequestConfig) => {\n // TODO: Add request logging if needed\n // console.log(`[Slotly SDK] ${config.method?.toUpperCase()} ${config.url}`);\n return config;\n };\n}\n\n/**\n * Response interceptor for error shaping and logging\n */\nexport function setupResponseInterceptor() {\n return (response: AxiosResponse) => {\n // TODO: Add response logging if needed\n // console.log(`[Slotly SDK] Response: ${response.status} ${response.config.url}`);\n return response;\n };\n}\n\n/**\n * Error interceptor for shaping errors into SlotlyApiError\n */\nexport function setupErrorInterceptor() {\n return (error: AxiosError<ApiResponse<any>>) => {\n // Network errors (no response)\n if (!error.response) {\n const networkError = new SlotlyNetworkError(\n error.message || 'Network error occurred',\n error\n );\n // TODO: Add error logging\n // console.error('[Slotly SDK] Network error:', networkError);\n return Promise.reject(networkError);\n }\n\n const { status, data } = error.response;\n\n // Handle authentication errors\n if (status === 401 || status === 403) {\n const authError = new SlotlyAuthError(\n data?.error?.message || 'Authentication failed',\n data?.error?.details\n );\n // TODO: Add error logging\n // console.error('[Slotly SDK] Auth error:', authError);\n return Promise.reject(authError);\n }\n\n // Handle API errors with structured error format\n if (data?.error) {\n const apiError = new SlotlyApiError(\n data.error.code || 'API_ERROR',\n data.error.message || 'An error occurred',\n status,\n data.error.details\n );\n // TODO: Add error logging\n // console.error('[Slotly SDK] API error:', apiError);\n return Promise.reject(apiError);\n }\n\n // Handle other HTTP errors\n const apiError = new SlotlyApiError(\n 'HTTP_ERROR',\n error.message || `Request failed with status ${status}`,\n status,\n data\n );\n // TODO: Add error logging\n // console.error('[Slotly SDK] HTTP error:', apiError);\n return Promise.reject(apiError);\n };\n}\n\n","import axios, { AxiosError, InternalAxiosRequestConfig } from 'axios';\n\n/**\n * Exponential backoff retry configuration\n */\nexport interface RetryConfig {\n maxRetries: number;\n retryDelay: number; // Base delay in milliseconds\n retryCondition?: (error: AxiosError) => boolean;\n}\n\nconst defaultRetryConfig: RetryConfig = {\n maxRetries: 3,\n retryDelay: 1000, // 1 second\n retryCondition: (error: AxiosError) => {\n // Retry on network errors and 5xx server errors\n if (!error.response) {\n return true; // Network error\n }\n const status = error.response.status;\n return status >= 500 && status < 600;\n },\n};\n\n/**\n * Calculate exponential backoff delay with jitter\n */\nfunction calculateRetryDelay(attempt: number, baseDelay: number): number {\n const exponentialDelay = baseDelay * Math.pow(2, attempt);\n const jitter = Math.random() * 0.3 * exponentialDelay; // Add up to 30% jitter\n return exponentialDelay + jitter;\n}\n\n/**\n * Axios interceptor for retry logic\n */\nexport function setupRetryInterceptor(\n config: RetryConfig = defaultRetryConfig\n) {\n return async (error: AxiosError) => {\n const requestConfig = error.config as InternalAxiosRequestConfig & {\n _retry?: boolean;\n _retryCount?: number;\n };\n\n // If no config, reject\n if (!requestConfig) {\n return Promise.reject(error);\n }\n\n // Initialize retry count\n if (requestConfig._retryCount === undefined) {\n requestConfig._retryCount = 0;\n }\n\n // Check if we should retry\n const shouldRetry =\n requestConfig._retryCount < config.maxRetries &&\n (!config.retryCondition || config.retryCondition(error));\n\n if (!shouldRetry) {\n return Promise.reject(error);\n }\n\n // Mark as retrying\n requestConfig._retry = true;\n requestConfig._retryCount += 1;\n\n // Calculate delay\n const delay = calculateRetryDelay(\n requestConfig._retryCount - 1,\n config.retryDelay\n );\n\n // Wait before retrying\n await new Promise((resolve) => setTimeout(resolve, delay));\n\n // Retry the request\n return axios(requestConfig);\n };\n}\n\n","import type { NextApiRequest, NextApiResponse } from 'next';\nimport { jwtDecode } from 'jwt-decode';\nimport { SlotlyAuthError } from '../errors';\n\n/**\n * Authentication context extracted from validated Slotly request\n */\nexport interface SlotlyAuthContext {\n clientKey: string;\n userId?: string;\n tenantId?: string;\n permissions?: string[];\n tokenClaims?: Record<string, any>;\n}\n\n/**\n * Extended Next.js request with Slotly context\n */\nexport interface SlotlyRequest extends NextApiRequest {\n slotlyContext: SlotlyAuthContext;\n}\n\n/**\n * Next.js API route handler type\n */\nexport type NextApiHandler = (\n req: NextApiRequest,\n res: NextApiResponse\n) => Promise<void> | void;\n\n/**\n * Mock allowlist for client keys\n * \n * ⚠️ DEVELOPMENT ONLY: This is a mock allowlist for development/testing purposes.\n * \n * In production, this MUST be replaced with:\n * - A secure database lookup (e.g., PostgreSQL, DynamoDB)\n * - A secrets management system (e.g., AWS Secrets Manager, HashiCorp Vault)\n * - A Redis cache with appropriate TTL for high-throughput scenarios\n * - Rate limiting per client key to prevent abuse\n * \n * Consider implementing:\n * - Key rotation policies\n * - Per-key rate limiting (especially important for public booking flows)\n * - Audit logging of key usage\n * - Revocation mechanisms\n * \n * TODO: Replace with actual database or cache lookup\n */\nconst allowedKeys: Record<\n string,\n { tenantId: string; permissions: string[] }\n> = {\n 'test-key-123': {\n tenantId: 'bright-accountants',\n permissions: ['booking:create'],\n },\n 'admin-ui': {\n tenantId: 'slotly-core',\n permissions: ['*'],\n },\n};\n\n/**\n * Validates an API key against the allowlist\n * Returns the associated tenant and permissions if valid\n */\nfunction validateApiKey(clientKey: string): {\n tenantId: string;\n permissions: string[];\n} | null {\n if (!clientKey || typeof clientKey !== 'string') {\n return null;\n }\n\n const keyInfo = allowedKeys[clientKey];\n if (!keyInfo) {\n return null;\n }\n\n return {\n tenantId: keyInfo.tenantId,\n permissions: keyInfo.permissions,\n };\n}\n\n/**\n * Extracts and decodes JWT token from Authorization header\n * \n * If present, extracts user identity from the token. This is optional:\n * - Anonymous/client-only flows: Authorization header not required\n * - User-authenticated flows: Authorization header provides user traceability\n * \n * Returns userId from 'sub' claim and full token claims for additional context.\n * Note: Currently decodes without signature validation (development).\n * TODO: Add signature validation in production using Clerk or JWT library.\n */\nfunction extractUserToken(authHeader?: string): {\n userId?: string;\n tokenClaims?: Record<string, any>;\n} | null {\n if (!authHeader || typeof authHeader !== 'string') {\n return null;\n }\n\n // Extract Bearer token\n const bearerMatch = authHeader.match(/^Bearer\\s+(.+)$/i);\n if (!bearerMatch || !bearerMatch[1]) {\n return null;\n }\n\n const token = bearerMatch[1];\n\n try {\n // Decode JWT without signature validation\n // WARNING: This is for development only. Production should validate signatures.\n // TODO: Add signature validation in production (e.g., using Clerk's verifyToken or jsonwebtoken)\n const claims = jwtDecode(token) as Record<string, any>;\n\n if (!claims || typeof claims !== 'object') {\n // eslint-disable-next-line no-console\n console.error('[Slotly SDK] Invalid JWT token: claims is not an object');\n return null;\n }\n\n // Extract userId from 'sub' claim\n const userId = claims.sub || claims.user_id || claims.userId;\n\n return {\n userId: typeof userId === 'string' ? userId : undefined,\n tokenClaims: claims,\n };\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Slotly SDK] Failed to decode JWT token:', error);\n return null;\n }\n}\n\n/**\n * Validates Slotly request headers and extracts authentication context\n * \n * Validates:\n * - `x-slotly-api-key`: Required header identifying the client/application\n * - `Authorization: Bearer ...`: Optional header providing user identity (if present, extracts user identity)\n * \n * Throws SlotlyAuthError if validation fails. Error includes code, message, and details\n * fields that align with the ApiResponse<T> error shape for consistent error handling.\n * \n * @throws {SlotlyAuthError} If x-slotly-api-key is missing, invalid, or not in allowlist\n */\nfunction validateAndExtractContext(req: NextApiRequest): SlotlyAuthContext {\n // Extract x-slotly-api-key header (required)\n // Support both lowercase and mixed case headers\n const clientKey =\n (req.headers['x-slotly-api-key'] as string) ||\n (req.headers['X-Slotly-Api-Key'] as string) ||\n (req.headers['x-slotly-api-key'] as string);\n\n if (!clientKey || typeof clientKey !== 'string' || clientKey.trim().length === 0) {\n const error = new SlotlyAuthError(\n 'Missing or invalid x-slotly-api-key header. API key is required.',\n { header: 'x-slotly-api-key' }\n );\n // eslint-disable-next-line no-console\n console.error('[Slotly SDK] Validation failed:', error.message);\n throw error;\n }\n\n // Validate API key against allowlist\n const keyInfo = validateApiKey(clientKey);\n if (!keyInfo) {\n const error = new SlotlyAuthError(\n 'Invalid API key. Client key not found in allowlist.',\n { clientKey: clientKey.substring(0, 8) + '...' }\n );\n // eslint-disable-next-line no-console\n console.error('[Slotly SDK] Validation failed:', error.message);\n throw error;\n }\n\n // Extract Authorization header (optional)\n // Support both lowercase and mixed case headers\n const authHeader =\n (req.headers.authorization as string) ||\n (req.headers.Authorization as string);\n\n const tokenInfo = authHeader ? extractUserToken(authHeader) : null;\n\n // Build context\n const context: SlotlyAuthContext = {\n clientKey,\n tenantId: keyInfo.tenantId,\n permissions: keyInfo.permissions,\n ...(tokenInfo?.userId && { userId: tokenInfo.userId }),\n ...(tokenInfo?.tokenClaims && { tokenClaims: tokenInfo.tokenClaims }),\n };\n\n return context;\n}\n\n/**\n * Safely extracts Slotly context from Next.js request\n * \n * Use this helper when you need to access the context outside of the middleware wrapper,\n * or to check if the context exists.\n * \n * **Important:** Other route handlers should guard user-required flows:\n * ```ts\n * const context = getSlotlyContext(req);\n * if (!context?.userId) {\n * return res.status(403).json({\n * success: false,\n * error: { code: 'USER_REQUIRED', message: 'User authentication required' }\n * });\n * }\n * ```\n * \n * @param req Next.js API request\n * @returns SlotlyAuthContext if present, null otherwise\n */\nexport function getSlotlyContext(\n req: NextApiRequest\n): SlotlyAuthContext | null {\n const slotlyReq = req as SlotlyRequest;\n return slotlyReq.slotlyContext || null;\n}\n\n/**\n * Middleware wrapper for Next.js API routes and Edge Functions\n * Validates Slotly authentication headers and injects context into request\n * \n * **Supported Environments:**\n * - Next.js API Routes (serverless functions)\n * - Next.js Edge Functions (Edge Runtime)\n * - Vercel Edge Functions\n * \n * **Note on Edge Functions:**\n * Header names are normalized, but edge runtime may have different header casing.\n * This middleware handles both `x-slotly-api-key` and `X-Slotly-Api-Key` variants.\n *\n * **Error Response Format:**\n * All error responses follow the `ApiResponse<T>` format for consistency:\n * ```ts\n * {\n * success: false,\n * error: {\n * code: string, // Error code (e.g., 'AUTH_ERROR', 'INTERNAL_ERROR')\n * message: string, // Human-readable error message\n * details?: any // Additional error details\n * }\n * }\n * ```\n * \n * **Usage:**\n * ```ts\n * import { validateSlotlyRequest } from \"@slotly/sdk/middleware/validateSlotlyRequest\";\n *\n * export default validateSlotlyRequest(async (req, res) => {\n * const { userId, clientKey, tenantId, permissions } = req.slotlyContext;\n * \n * // Check if user authentication is required for this endpoint\n * if (!userId) {\n * return res.status(403).json({\n * success: false,\n * error: { code: 'USER_REQUIRED', message: 'User authentication required' }\n * });\n * }\n * \n * // Authenticated + scoped — safe to proceed\n * res.json({ success: true, data: { userId, tenantId } });\n * });\n * ```\n *\n * **Performance Considerations:**\n * - For high-throughput scenarios (e.g., many public booking flows), consider:\n * - Caching API key lookups with TTL (Redis, in-memory cache)\n * - Rate limiting per client key\n * - Database connection pooling for key validation\n *\n * @param handler Next.js API route handler or Edge Function handler\n * @returns Wrapped handler with Slotly validation\n */\nexport function validateSlotlyRequest(\n handler: (req: SlotlyRequest, res: NextApiResponse) => Promise<void> | void\n) {\n return async (req: NextApiRequest, res: NextApiResponse): Promise<void> => {\n try {\n // Validate and extract context\n const context = validateAndExtractContext(req);\n\n // Inject context into request\n const slotlyReq = req as SlotlyRequest;\n slotlyReq.slotlyContext = context;\n\n // Call the actual handler with validated request\n await handler(slotlyReq, res);\n } catch (error) {\n // Handle SlotlyAuthError\n if (error instanceof SlotlyAuthError) {\n // eslint-disable-next-line no-console\n console.error(\n '[Slotly SDK] Authentication failed:',\n error.message,\n error.details\n );\n\n // Error response follows ApiResponse<T> format for consistency\n // SlotlyAuthError includes code, message, and details fields that align\n // with the ApiResponse<T> error shape\n res.status(error.statusCode || 401).json({\n success: false,\n error: {\n code: error.code,\n message: error.message,\n details: error.details,\n },\n });\n return;\n }\n\n // Handle other errors\n // eslint-disable-next-line no-console\n console.error('[Slotly SDK] Unexpected error:', error);\n\n // Error response follows ApiResponse<T> format for consistency\n res.status(500).json({\n success: false,\n error: {\n code: 'INTERNAL_ERROR',\n message: 'An unexpected error occurred',\n },\n });\n }\n };\n}\n\n"],"mappings":"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","names":["import_axios","apiError","axios","axios"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/clients/tenant-client.ts","../src/clients/booking-client.ts","../src/clients/service-client.ts","../src/clients/service-item-client.ts","../src/clients/slot-client.ts","../src/clients/customer-client.ts","../src/clients/flow-client.ts","../src/clients/studio-client.ts","../src/clients/notification-client.ts","../src/clients/data-quality-client.ts","../src/clients/organization-client.ts","../src/errors.ts","../src/interceptors.ts","../src/retry.ts","../src/middleware/validateSlotlyRequest.ts"],"sourcesContent":["import axios, { AxiosInstance, InternalAxiosRequestConfig } from 'axios';\nimport { TenantClient } from './clients/tenant-client';\nimport { BookingClient } from './clients/booking-client';\nimport { ServiceClient } from './clients/service-client';\nimport { ServiceItemClient } from './clients/service-item-client';\nimport { SlotClient } from './clients/slot-client';\nimport { CustomerClient } from './clients/customer-client';\nimport { FlowClient } from './clients/flow-client';\nimport { StudioClient } from './clients/studio-client';\nimport { NotificationClient } from './clients/notification-client';\nimport { DataQualityClient } from './clients/data-quality-client';\nimport { OrganizationClient } from './clients/organization-client';\nimport { setupRequestInterceptor, setupResponseInterceptor, setupErrorInterceptor } from './interceptors';\nimport { setupRetryInterceptor } from './retry';\nimport { SlotlyConfigurationError } from './errors';\n\n// Re-export types\nexport type {\n ApiResponse,\n Tenant,\n TenantFullConfig,\n TenantBranding,\n Booking,\n BookingWithSlot,\n ListBookingsOptions,\n Service,\n ServiceItem,\n ServiceWithItems,\n SlotServiceWithItems,\n ServiceItemWithService,\n Category,\n Slot,\n Customer,\n Flow,\n FlowStep,\n Studio,\n Notification,\n DataQualityIssue,\n Organization,\n OrganizationFullConfig,\n GetOrganizationOptions,\n} from './types/api';\n\n// Re-export errors\nexport {\n SlotlyApiError,\n SlotlyAuthError,\n SlotlyNetworkError,\n SlotlyConfigurationError,\n} from './errors';\n\n// Re-export middleware\nexport {\n validateSlotlyRequest,\n getSlotlyContext,\n type SlotlyAuthContext,\n type SlotlyRequest,\n} from './middleware/validateSlotlyRequest';\n\nexport interface SlotlyClientOptions {\n /**\n * Required: Function that returns the API key or service token.\n * This must return a non-empty string.\n */\n getClientKey: () => Promise<string>;\n /**\n * Optional: Function that returns a Clerk JWT for user traceability.\n * If provided and returns a token, it will be included in the Authorization header.\n */\n getUserToken?: () => Promise<string | null>;\n /**\n * Optional: Custom base URL for the API.\n * Defaults to process.env.SLOTLY_API_URL or 'https://api.slotly.dev'\n */\n baseURL?: string;\n /**\n * Optional: Additional headers to include with every request.\n */\n headers?: Record<string, string>;\n /**\n * Optional: Retry configuration.\n */\n retry?: {\n maxRetries?: number;\n retryDelay?: number;\n };\n}\n\n/**\n * Unified Slotly API client\n * Provides typed access to all Slotly API domains\n * \n * Note: RegisterClient has been moved to @slotly/studio-sdk\n * for studio-specific booking register operations.\n */\nexport interface SlotlyApi {\n tenant: TenantClient;\n booking: BookingClient;\n service: ServiceClient;\n serviceItem: ServiceItemClient;\n slot: SlotClient;\n customer: CustomerClient;\n flow: FlowClient;\n studio: StudioClient;\n notification: NotificationClient;\n dataQuality: DataQualityClient;\n organization: OrganizationClient;\n}\n\nconst defaultBaseURL = typeof process !== 'undefined' && process.env?.SLOTLY_API_URL \n ? process.env.SLOTLY_API_URL \n : 'https://api.slotly.dev';\n\n/**\n * Creates a new isolated Axios instance with authentication interceptors.\n * Client isolation per instantiation ensures:\n * - No cross-contamination between different auth contexts\n * - SSR safety (each request gets its own client instance)\n * - Proper isolation for scoped keys/roles in the future\n */\nfunction createAuthenticatedClient(options: SlotlyClientOptions): AxiosInstance {\n const client = axios.create({\n baseURL: options.baseURL || defaultBaseURL,\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n timeout: 30000, // 30 seconds\n });\n\n // Request interceptor: Add authentication headers\n // This interceptor runs once per request and fetches fresh tokens\n client.interceptors.request.use(\n async (config: InternalAxiosRequestConfig) => {\n try {\n // Fetch both credentials in parallel for performance\n const [clientKeyPromise, userTokenPromise] = [\n options.getClientKey(),\n options.getUserToken?.() ?? Promise.resolve(null),\n ];\n\n const [clientKey, userToken] = await Promise.all([\n clientKeyPromise,\n userTokenPromise,\n ]);\n\n // Validate that clientKey is provided and non-empty\n if (!clientKey || typeof clientKey !== 'string' || clientKey.trim().length === 0) {\n throw new SlotlyConfigurationError(\n 'getClientKey() must return a non-empty string. API key is required for all requests.',\n { received: clientKey }\n );\n }\n\n // Always set the API key header\n config.headers['x-slotly-api-key'] = clientKey;\n\n // Conditionally set Authorization header if user token is provided\n if (userToken && typeof userToken === 'string' && userToken.trim().length > 0) {\n config.headers['Authorization'] = `Bearer ${userToken}`;\n }\n\n return config;\n } catch (error) {\n // If it's already a SlotlyConfigurationError, re-throw it\n if (error instanceof SlotlyConfigurationError) {\n throw error;\n }\n\n // Handle errors from getClientKey() or getUserToken()\n // If getClientKey fails, this is critical\n if (error && typeof error === 'object' && 'message' in error) {\n // eslint-disable-next-line no-console\n console.error('[Slotly SDK] Failed to retrieve authentication credentials:', error);\n \n throw new SlotlyConfigurationError(\n `Failed to retrieve authentication credentials: ${error.message}`,\n { originalError: error }\n );\n }\n\n throw error;\n }\n },\n (error: Error) => Promise.reject(error)\n );\n\n // Request interceptor: Logging\n client.interceptors.request.use(setupRequestInterceptor());\n\n // Response interceptor: Logging and error shaping\n client.interceptors.response.use(\n (response: any) => setupResponseInterceptor()(response),\n (error: any) => setupErrorInterceptor()(error)\n );\n\n // Error interceptor: Retry logic\n client.interceptors.response.use(\n (response: any) => response,\n setupRetryInterceptor({\n maxRetries: options.retry?.maxRetries ?? 3,\n retryDelay: options.retry?.retryDelay ?? 1000,\n })\n );\n\n return client;\n}\n\n/**\n * Initialize and configure a new Slotly API client with dual authentication.\n * \n * This function creates an isolated Axios instance per call, ensuring:\n * - SSR safety: Each request/context gets its own client instance\n * - No cross-contamination: Different auth contexts don't interfere\n * - Scalable: Supports future expansion for scoped keys, roles, or per-request tokens\n * \n * Authentication model:\n * - **getClientKey()**: Required. Always sets `x-slotly-api-key` header.\n * Identifies the SDK/application making the request.\n * - **getUserToken()**: Optional. Sets `Authorization: Bearer <token>` header if provided.\n * Provides user traceability and authorization scoping.\n *\n * @example Basic usage with API key (public SDK client):\n * ```ts\n * import { useSlotly } from '@slotly/sdk';\n *\n * const slotly = useSlotly({\n * getClientKey: async () => process.env.SLOTLY_SDK_KEY!,\n * });\n * ```\n *\n * @example Server-side with Clerk (authenticated, user-scoped):\n * ```ts\n * import { getToken } from '@clerk/clerk-sdk-node';\n * import { useSlotly } from '@slotly/sdk';\n *\n * // In an API route or server action\n * const slotly = useSlotly({\n * getClientKey: async () => process.env.SLOTLY_SDK_KEY!,\n * getUserToken: async () => await getToken(req),\n * });\n * ```\n *\n * @example Client-side with Clerk (Next.js):\n * ```ts\n * import { useAuth } from '@clerk/nextjs';\n * import { useSlotly } from '@slotly/sdk';\n *\n * function MyComponent() {\n * const { getToken } = useAuth();\n * \n * const slotly = useSlotly({\n * getClientKey: async () => process.env.NEXT_PUBLIC_SLOTLY_SDK_KEY!,\n * getUserToken: getToken,\n * });\n * }\n * ```\n *\n * @example Future: Scoped keys or role-based access\n * ```ts\n * // Future enhancement: Per-request scoping\n * const slotly = useSlotly({\n * getClientKey: async () => getScopedKey(role, tenantId),\n * getUserToken: async () => getToken(),\n * });\n * ```\n *\n * @throws {SlotlyConfigurationError} If getClientKey is missing, returns null, undefined, or empty string.\n */\nexport const useSlotly = (options: SlotlyClientOptions): SlotlyApi => {\n // Validate required options\n if (!options || typeof options !== 'object') {\n throw new SlotlyConfigurationError(\n 'useSlotly() requires an options object with getClientKey function'\n );\n }\n\n if (!options.getClientKey || typeof options.getClientKey !== 'function') {\n throw new SlotlyConfigurationError(\n 'getClientKey must be a function that returns Promise<string>'\n );\n }\n\n // Create a new isolated client instance for this configuration\n // This ensures SSR safety and prevents cross-contamination\n const client = createAuthenticatedClient(options);\n\n // Return the unified API object with all domain clients\n return {\n tenant: new TenantClient(client),\n booking: new BookingClient(client),\n service: new ServiceClient(client),\n serviceItem: new ServiceItemClient(client),\n slot: new SlotClient(client),\n customer: new CustomerClient(client),\n flow: new FlowClient(client),\n studio: new StudioClient(client),\n notification: new NotificationClient(client),\n dataQuality: new DataQualityClient(client),\n organization: new OrganizationClient(client),\n };\n};\n\n// Default export for convenience\nexport default useSlotly;\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Tenant, TenantFullConfig } from '../types/api';\n\nexport class TenantClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get tenant configuration by slug\n * GET /api/v1/tenant-config/:slug\n */\n async getBySlug(slug: string): Promise<ApiResponse<Tenant>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Tenant>>(\n `/api/v1/tenant-config/${slug}`\n );\n return response.data;\n }\n\n /**\n * Get tenant by ID\n * GET /api/v1/tenants/:id\n */\n async getById(id: string): Promise<ApiResponse<Tenant>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Tenant>>(\n `/api/v1/tenants/${id}`\n );\n return response.data;\n }\n\n /**\n * List tenants with optional filters\n * GET /api/v1/tenants\n *\n * @param params - Query parameters\n * - organization_id (optional) - Filter tenants by organization ID\n * - org_id (optional) - Alias for organization_id\n * - page (optional) - Page number for pagination\n * - limit (optional) - Items per page\n * @returns Paginated list of tenants\n *\n * @example\n * ```typescript\n * // List all tenants\n * const allTenants = await slotly.tenant.list();\n *\n * // List tenants for a specific organization\n * const orgTenants = await slotly.tenant.list({\n * organization_id: 'org-123',\n * page: 1,\n * limit: 20\n * });\n * ```\n */\n async list(params?: {\n organization_id?: string;\n org_id?: string;\n page?: number;\n limit?: number;\n }): Promise<ApiResponse<Tenant[]>> {\n // Normalize org_id to organization_id if provided\n const queryParams: Record<string, any> = {};\n if (params?.organization_id) {\n queryParams.organization_id = params.organization_id;\n } else if (params?.org_id) {\n queryParams.organization_id = params.org_id;\n }\n if (params?.page !== undefined) queryParams.page = params.page;\n if (params?.limit !== undefined) queryParams.limit = params.limit;\n\n const response = await this.client.get<ApiResponse<Tenant[]>>(\n '/api/v1/tenants',\n { params: queryParams }\n );\n return response.data;\n }\n\n /**\n * Create a new tenant\n * POST /api/v1/tenants\n */\n async create(data: Partial<Tenant>): Promise<ApiResponse<Tenant>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<Tenant>>(\n '/api/v1/tenants',\n data\n );\n return response.data;\n }\n\n /**\n * Update tenant by ID\n * PATCH /api/v1/tenants/:id\n */\n async update(id: string, data: Partial<Tenant>): Promise<ApiResponse<Tenant>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.patch<ApiResponse<Tenant>>(\n `/api/v1/tenants/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete tenant by ID\n * DELETE /api/v1/tenants/:id\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/tenants/${id}`\n );\n return response.data;\n }\n\n /**\n * Get full tenant configuration including branding, services, and service items\n * GET /api/v1/tenants/:slug\n * \n * This method returns the complete tenant configuration including:\n * - Tenant basic info (id, slug, name)\n * - Branding configuration (logo, colors, etc.)\n * - All services associated with the tenant (with nested service items)\n * - Feature flags and subscription level\n * \n * Note: Service items are nested within each service object (not as a separate top-level array).\n * The endpoint returns full config by default (includes services with nested items).\n * \n * @param slug - Tenant slug identifier (required, non-nullable)\n * @param includeServices - Include services with nested items (default: true)\n * @returns Promise resolving to ApiResponse<TenantFullConfig>\n * \n * @example\n * ```typescript\n * const result = await slotly.tenant.getFullConfig('bright-accountants');\n * if (result.success && result.data) {\n * const config = result.data;\n * console.log('Tenant:', config.name);\n * console.log('Logo:', config.branding?.logoUrl);\n * console.log('Services:', config.services.length);\n * \n * // Service items are nested within each service\n * config.services.forEach(service => {\n * console.log(`Service: ${service.name}`);\n * if (service.serviceItems) {\n * console.log(` Items: ${service.serviceItems.length}`);\n * }\n * });\n * }\n * ```\n * \n * **Guaranteed fields (non-nullable):**\n * - `id`: string\n * - `slug`: string\n * - `name`: string\n * - `services`: ServiceWithItems[] (may be empty array, each service may have nested `serviceItems`)\n * \n * **Optional fields:**\n * - `branding`: TenantBranding | undefined\n * - `services[].serviceItems`: ServiceItem[] | undefined (nested within each service)\n * - `featuresEnabled`: string[] | undefined\n * - `subscriptionLevel`: string | undefined\n * - `config`: Record<string, any> | undefined\n * \n * **Error Codes:**\n * - `TENANT_NOT_FOUND` - Tenant with slug not found\n * - `AUTH_ERROR` - Authentication failed\n * - `PERMISSION_DENIED` - Insufficient permissions\n * - `NETWORK_ERROR` - Network request failed\n */\n async getFullConfig(slug: string, includeServices: boolean = true): Promise<ApiResponse<TenantFullConfig>> {\n const response = await this.client.get<ApiResponse<TenantFullConfig>>(\n `/api/v1/tenants/${slug}`,\n { params: { includeServices } }\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Booking, BookingWithSlot, ListBookingsOptions } from '../types/api';\n\nexport class BookingClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get booking by ID\n * GET /api/v1/bookings/:id\n */\n async getById(id: string): Promise<ApiResponse<Booking>> {\n const response = await this.client.get<ApiResponse<Booking>>(\n `/api/v1/bookings/${id}`\n );\n return response.data;\n }\n\n /**\n * List bookings with enhanced filtering\n * GET /api/v1/bookings\n *\n * Supports filtering by tenant_id, slot_id, customer_id, status, and optional nested slot information.\n *\n * @param params - Query options (tenant_id, slot_id, customer_id, status, includeSlot, page, limit)\n * @returns Bookings or BookingsWithSlot based on includeSlot parameter\n *\n * @example\n * ```typescript\n * // List bookings by tenant (single query - fast!)\n * const bookings = await slotly.booking.list({\n * tenant_id: 'tenant-123',\n * includeSlot: true,\n * page: 1,\n * limit: 20\n * });\n *\n * // List bookings by slot\n * const slotBookings = await slotly.booking.list({\n * slot_id: 'slot-456',\n * status: 'confirmed'\n * });\n * ```\n */\n async list(params?: ListBookingsOptions): Promise<ApiResponse<Booking[] | BookingWithSlot[]>> {\n const response = await this.client.get<ApiResponse<Booking[] | BookingWithSlot[]>>(\n '/api/v1/bookings',\n { params }\n );\n return response.data;\n }\n\n /**\n * List bookings by tenant (convenience method)\n * GET /api/v1/bookings?tenant_id=:id\n *\n * @param tenantId - Tenant ID\n * @param options - Additional options (includeSlot, page, limit, status)\n * @returns Bookings or BookingsWithSlot based on includeSlot parameter\n *\n * @example\n * ```typescript\n * const bookings = await slotly.booking.listByTenant('tenant-123', {\n * page: 1,\n * limit: 20,\n * status: 'confirmed'\n * });\n * ```\n */\n async listByTenant(\n tenantId: string,\n options?: Omit<ListBookingsOptions, 'tenant_id'>\n ): Promise<ApiResponse<Booking[] | BookingWithSlot[]>> {\n return this.list({\n tenant_id: tenantId,\n ...options,\n });\n }\n\n /**\n * List bookings by tenant with nested slot information (convenience method)\n * GET /api/v1/bookings?tenant_id=:id&includeSlot=true\n *\n * @param tenantId - Tenant ID\n * @param options - Additional options (page, limit, status)\n * @returns BookingsWithSlot (includes nested slot information)\n *\n * @example\n * ```typescript\n * const bookings = await slotly.booking.listByTenantWithSlots('tenant-123', {\n * page: 1,\n * limit: 20\n * });\n *\n * // Access slot information\n * bookings.data.forEach(booking => {\n * if (booking.slots) {\n * console.log('Slot name:', booking.slots.name);\n * }\n * });\n * ```\n */\n async listByTenantWithSlots(\n tenantId: string,\n options?: Omit<ListBookingsOptions, 'tenant_id' | 'includeSlot'>\n ): Promise<ApiResponse<BookingWithSlot[]>> {\n return this.list({\n tenant_id: tenantId,\n includeSlot: true,\n ...options,\n }) as Promise<ApiResponse<BookingWithSlot[]>>;\n }\n\n /**\n * Create a new booking (publishes booking.created event)\n * POST /api/v1/bookings\n */\n async create(data: {\n slot_id: string;\n customer_info: {\n name: string;\n email: string;\n phone?: string;\n address?: string;\n city?: string;\n state?: string;\n zipCode?: string;\n isGuestCheckout?: boolean;\n };\n booking_data?: Record<string, unknown>;\n }): Promise<ApiResponse<Booking>> {\n const response = await this.client.post<ApiResponse<Booking>>(\n '/api/v1/bookings',\n data\n );\n return response.data;\n }\n\n /**\n * Update booking by ID\n * PUT /api/v1/bookings/:id\n */\n async update(id: string, data: {\n status?: string;\n customer_info?: Record<string, unknown>;\n booking_data?: Record<string, unknown>;\n }): Promise<ApiResponse<Booking>> {\n const response = await this.client.put<ApiResponse<Booking>>(\n `/api/v1/bookings/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Cancel booking by ID\n * Note: Cancel is typically done via update with status change\n * If dedicated cancel endpoint exists, update this method\n */\n async cancel(id: string): Promise<ApiResponse<Booking>> {\n // Use update to change status to cancelled\n return this.update(id, { status: 'cancelled' });\n }\n\n /**\n * Delete booking by ID (soft delete)\n * DELETE /api/v1/bookings/:id\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/bookings/${id}`\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Service, ServiceWithItems, SlotServiceWithItems, Category } from '../types/api';\n\nexport class ServiceClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get service by ID\n * GET /api/v1/services/:id\n * \n * @param id - Service ID\n * @param includeItems - Include nested service items (default: false)\n * @returns Service details (with items if includeItems=true)\n */\n async getById(id: string, includeItems: boolean = false): Promise<ApiResponse<Service | ServiceWithItems>> {\n const response = await this.client.get<ApiResponse<Service | ServiceWithItems>>(\n `/api/v1/services/${id}`,\n includeItems ? { params: { includeItems: true } } : undefined\n );\n return response.data;\n }\n\n /**\n * Get services for a tenant (full list with optional filters)\n * GET /api/v1/services\n * \n * @param options - Query options\n * @param options.tenantId - Tenant ID (UUID) - required if tenantSlug not provided\n * @param options.tenantSlug - Tenant slug - required if tenantId not provided\n * @param options.slotId - Slot ID (DEPRECATED - accepted but ignored for API compatibility)\n * @param options.isActive - Filter by active status\n * @param options.includeItems - Include nested service items (default: false)\n * @param options.page - Page number (default: 1)\n * @param options.limit - Items per page (default: 20, max: 100)\n * @returns Services with optional pagination metadata\n */\n async getServicesByTenant(options: {\n tenantId?: string;\n tenantSlug?: string;\n slotId?: string; // DEPRECATED - accepted but ignored\n isActive?: boolean;\n includeItems?: boolean;\n page?: number;\n limit?: number;\n }): Promise<ApiResponse<Service[] | ServiceWithItems[]>> {\n // Validate that either tenantId or tenantSlug is provided\n if (!options.tenantId && !options.tenantSlug) {\n return {\n success: false,\n error: {\n code: 'MISSING_TENANT_ID',\n message: 'tenantId or tenantSlug is required',\n },\n };\n }\n\n // Build query parameters\n const params: Record<string, any> = {};\n \n if (options.tenantId) {\n params.tenant_id = options.tenantId;\n }\n if (options.tenantSlug) {\n params.tenantSlug = options.tenantSlug;\n }\n if (options.slotId) {\n // Include for API compatibility, even though it's ignored\n params.slot_id = options.slotId;\n }\n if (options.isActive !== undefined) {\n params.is_active = options.isActive;\n }\n if (options.includeItems) {\n params.includeItems = true;\n }\n if (options.page !== undefined) {\n params.page = options.page;\n }\n if (options.limit !== undefined) {\n params.limit = Math.min(options.limit, 100); // Enforce max limit\n }\n\n const response = await this.client.get<ApiResponse<Service[] | ServiceWithItems[]>>(\n '/api/v1/services',\n { params }\n );\n return response.data;\n }\n\n /**\n * Get services for a specific slot\n * GET /api/v1/slots/:id/services\n * \n * Note: Services are tenant-level entities. This endpoint returns all active services\n * for the slot's tenant with items included. The response uses 'items' property (not 'serviceItems').\n * \n * @param slotId - Slot ID (UUID)\n * @returns Services with nested items (always includes items, only active services)\n */\n async getServicesBySlot(slotId: string): Promise<ApiResponse<SlotServiceWithItems[]>> {\n const response = await this.client.get<ApiResponse<SlotServiceWithItems[]>>(\n `/api/v1/slots/${slotId}/services`\n );\n return response.data;\n }\n\n /**\n * List services by tenant slug\n * GET /api/v1/services?tenantSlug=:slug\n * \n * @deprecated Consider using getServicesByTenant() for better type safety and validation\n * @param slug - Tenant slug (or use tenant_id in list() method)\n * @param params - Optional parameters (includeItems, page, limit, is_active)\n * @returns List of services for the tenant\n */\n async listServices(\n slug: string,\n params?: {\n includeItems?: boolean;\n page?: number;\n limit?: number;\n is_active?: boolean;\n }\n ): Promise<ApiResponse<Service[] | ServiceWithItems[]>> {\n const response = await this.client.get<ApiResponse<Service[] | ServiceWithItems[]>>(\n '/api/v1/services',\n { params: { tenantSlug: slug, ...params } }\n );\n return response.data;\n }\n\n /**\n * List services with optional filters\n * GET /api/v1/services\n * \n * @deprecated Consider using getServicesByTenant() for better type safety and validation\n * @param params - Query parameters (tenant_id, tenantSlug, slot_id, page, limit, is_active, includeItems)\n * @returns Paginated list of services\n */\n async list(params?: {\n tenant_id?: string;\n tenantSlug?: string;\n slot_id?: string;\n page?: number;\n limit?: number;\n is_active?: boolean;\n includeItems?: boolean;\n }): Promise<ApiResponse<Service[] | ServiceWithItems[]>> {\n const response = await this.client.get<ApiResponse<Service[] | ServiceWithItems[]>>(\n '/api/v1/services',\n { params }\n );\n return response.data;\n }\n\n /**\n * Create a new service\n * POST /api/v1/services\n * \n * @param data - Service creation data (tenant_id, name required)\n * @returns Created service\n */\n async create(data: Partial<Service>): Promise<ApiResponse<Service>> {\n const response = await this.client.post<ApiResponse<Service>>(\n '/api/v1/services',\n data\n );\n return response.data;\n }\n\n /**\n * Update service by ID\n * PUT /api/v1/services/:id\n * \n * @param id - Service ID\n * @param data - Service update data\n * @returns Updated service\n */\n async update(id: string, data: Partial<Service>): Promise<ApiResponse<Service>> {\n const response = await this.client.put<ApiResponse<Service>>(\n `/api/v1/services/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete service by ID\n * DELETE /api/v1/services/:id\n * \n * @param id - Service ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/services/${id}`\n );\n return response.data;\n }\n\n /**\n * Bulk create services\n * POST /api/v1/services/bulk (if available)\n * \n * @param services - Array of services to create\n * @returns Created services\n */\n async bulkCreate(services: Partial<Service>[]): Promise<ApiResponse<Service[]>> {\n // Note: Verify if bulk endpoint exists in API\n const response = await this.client.post<ApiResponse<Service[]>>(\n '/api/v1/services/bulk',\n { services }\n );\n return response.data;\n }\n\n /**\n * Get service with its service items nested\n * GET /api/v1/services/:id?includeItems=true\n * \n * @param id - Service ID\n * @returns Service with nested service items\n */\n async getWithItems(id: string): Promise<ApiResponse<ServiceWithItems>> {\n const response = await this.client.get<ApiResponse<ServiceWithItems>>(\n `/api/v1/services/${id}`,\n { params: { includeItems: true } }\n );\n return response.data;\n }\n\n /**\n * List services with their service items nested\n * GET /api/v1/services?includeItems=true\n * \n * @param params - Query parameters (tenant_id, tenantSlug, slot_id, page, limit, is_active)\n * @returns Paginated list of services with nested service items\n */\n async listWithItems(params?: {\n tenant_id?: string;\n tenantSlug?: string;\n slot_id?: string;\n page?: number;\n limit?: number;\n is_active?: boolean;\n }): Promise<ApiResponse<ServiceWithItems[]>> {\n const response = await this.client.get<ApiResponse<ServiceWithItems[]>>(\n '/api/v1/services',\n { params: { includeItems: true, ...params } }\n );\n return response.data;\n }\n\n /**\n * List all categories for a tenant (extracted from services)\n * GET /api/v1/categories?tenantSlug=:slug\n * \n * @param tenantSlug - Tenant slug (or use tenant_id in params)\n * @param params - Optional query parameters (tenant_id, includeServices)\n * @returns List of categories for the tenant\n */\n async listCategories(\n tenantSlug?: string,\n params?: {\n tenant_id?: string;\n includeServices?: boolean;\n }\n ): Promise<ApiResponse<Category[]>> {\n const response = await this.client.get<ApiResponse<Category[]>>(\n '/api/v1/categories',\n { params: { tenantSlug, ...params } }\n );\n return response.data;\n }\n\n /**\n * Get category by ID (category name, lowercase)\n * GET /api/v1/categories/:id?tenantSlug=:slug\n * \n * @param categoryId - Category ID (lowercase category name, e.g., \"consulting\")\n * @param tenantSlug - Tenant slug (or use tenant_id in params)\n * @param params - Optional query parameters (tenant_id, includeServices, includeItems)\n * @returns Category details\n */\n async getCategory(\n categoryId: string,\n tenantSlug?: string,\n params?: {\n tenant_id?: string;\n includeServices?: boolean;\n includeItems?: boolean;\n }\n ): Promise<ApiResponse<Category>> {\n const response = await this.client.get<ApiResponse<Category>>(\n `/api/v1/categories/${categoryId}`,\n { params: { tenantSlug, ...params } }\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, ServiceItem, ServiceItemWithService } from '../types/api';\n\n/**\n * ServiceItemClient provides methods for managing service items independently\n * or in relation to their parent services.\n */\nexport class ServiceItemClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get service item by ID\n * GET /api/v1/service-items/:id\n * \n * @param id - Service item ID\n * @returns Service item details\n */\n async getById(id: string): Promise<ApiResponse<ServiceItem>> {\n const response = await this.client.get<ApiResponse<ServiceItem>>(\n `/api/v1/service-items/${id}`\n );\n return response.data;\n }\n\n /**\n * List all service items for a service\n * GET /api/v1/services/:serviceId/items\n * \n * @param serviceId - Service ID\n * @returns List of service items for the specified service\n */\n async listByService(serviceId: string): Promise<ApiResponse<ServiceItem[]>> {\n const response = await this.client.get<ApiResponse<ServiceItem[]>>(\n `/api/v1/services/${serviceId}/items`\n );\n return response.data;\n }\n\n /**\n * Create a new service item for a service\n * POST /api/v1/services/:serviceId/items\n * \n * @param serviceId - Service ID\n * @param data - Service item creation data\n * @returns Created service item\n */\n async createForService(\n serviceId: string,\n data: Partial<ServiceItem>\n ): Promise<ApiResponse<ServiceItem>> {\n const response = await this.client.post<ApiResponse<ServiceItem>>(\n `/api/v1/services/${serviceId}/items`,\n { ...data, service_id: serviceId }\n );\n return response.data;\n }\n\n /**\n * Create a new service item\n * POST /api/v1/service-items (alternative to createForService)\n * \n * @param data - Service item creation data (must include service_id)\n * @returns Created service item\n */\n async create(data: Partial<ServiceItem>): Promise<ApiResponse<ServiceItem>> {\n const response = await this.client.post<ApiResponse<ServiceItem>>(\n '/api/v1/service-items',\n data\n );\n return response.data;\n }\n\n /**\n * Update service item by ID\n * PUT /api/v1/service-items/:id\n * \n * @param id - Service item ID\n * @param data - Service item update data\n * @returns Updated service item\n */\n async update(id: string, data: Partial<ServiceItem>): Promise<ApiResponse<ServiceItem>> {\n const response = await this.client.put<ApiResponse<ServiceItem>>(\n `/api/v1/service-items/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete service item by ID\n * DELETE /api/v1/service-items/:id\n * \n * @param id - Service item ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/service-items/${id}`\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Slot, SlotServiceWithItems, Tenant } from '../types/api';\n\nexport class SlotClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get slot by ID\n * GET /api/v1/slots/:id\n * \n * @param id - Slot ID\n * @returns Slot details\n */\n async getById(id: string): Promise<ApiResponse<Slot>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Slot>>(\n `/api/v1/slots/${id}`\n );\n return response.data;\n }\n\n /**\n * List available slots\n * GET /api/v1/slots\n * \n * @param params - Query parameters (tenant_id required, status, is_active, page, limit)\n * @returns Paginated list of slots\n */\n async list(params: {\n tenant_id: string;\n status?: string;\n is_active?: boolean;\n page?: number;\n limit?: number;\n }): Promise<ApiResponse<Slot[]>> {\n const response = await this.client.get<ApiResponse<Slot[]>>(\n '/api/v1/slots',\n { params }\n );\n return response.data;\n }\n\n /**\n * Create a new slot\n * POST /api/v1/slots\n * \n * @param data - Slot creation data (tenant_id, name required)\n * @returns Created slot\n */\n async create(data: Partial<Slot>): Promise<ApiResponse<Slot>> {\n const response = await this.client.post<ApiResponse<Slot>>(\n '/api/v1/slots',\n data\n );\n return response.data;\n }\n\n /**\n * Update slot by ID\n * PUT /api/v1/slots/:id\n * \n * @param id - Slot ID\n * @param data - Slot update data\n * @returns Updated slot\n */\n async update(id: string, data: Partial<Slot>): Promise<ApiResponse<Slot>> {\n const response = await this.client.put<ApiResponse<Slot>>(\n `/api/v1/slots/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete slot by ID\n * DELETE /api/v1/slots/:id\n * \n * @param id - Slot ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/slots/${id}`\n );\n return response.data;\n }\n\n /**\n * Bulk create slots\n * POST /api/v1/slots/bulk (verify if available)\n * \n * @param slots - Array of slots to create\n * @returns Created slots\n */\n async bulkCreate(slots: Partial<Slot>[]): Promise<ApiResponse<Slot[]>> {\n // Note: Verify if bulk endpoint exists in API\n const response = await this.client.post<ApiResponse<Slot[]>>(\n '/api/v1/slots/bulk',\n { slots }\n );\n return response.data;\n }\n\n /**\n * Mark slot as available/unavailable\n * Note: Use update() method with status or other fields\n */\n async setAvailability(id: string, available: boolean): Promise<ApiResponse<Slot>> {\n return this.update(id, { status: available ? 'active' : 'inactive' } as Partial<Slot>);\n }\n\n /**\n * Get all active services for a slot with their items\n * GET /api/v1/slots/:id/services\n * \n * Note: Services are tenant-level entities. This endpoint returns all active services\n * for the slot's tenant with items included. The response uses 'items' property (not 'serviceItems').\n * \n * @param id - Slot ID (UUID)\n * @returns Services with nested items (always includes items, only active services)\n */\n async getServices(id: string): Promise<ApiResponse<SlotServiceWithItems[]>> {\n const response = await this.client.get<ApiResponse<SlotServiceWithItems[]>>(\n `/api/v1/slots/${id}/services`\n );\n return response.data;\n }\n\n /**\n * Get slot with tenant information\n * GET /api/v1/slots/:id/tenant-info\n * \n * @param id - Slot ID\n * @returns Slot with tenant data\n */\n async getWithTenant(id: string): Promise<ApiResponse<Slot & { tenant: Tenant }>> {\n const response = await this.client.get<ApiResponse<Slot & { tenant: Tenant }>>(\n `/api/v1/slots/${id}/tenant-info`\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Customer, Booking } from '../types/api';\n\nexport class CustomerClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get customer by ID\n * GET /api/v1/customers/:id\n * \n * @param id - Customer ID\n * @returns Customer details\n */\n async getById(id: string): Promise<ApiResponse<Customer>> {\n const response = await this.client.get<ApiResponse<Customer>>(\n `/api/v1/customers/${id}`\n );\n return response.data;\n }\n\n /**\n * Get customer by email\n * GET /api/v1/customers?email=:email&tenant_id=:id\n * \n * @param email - Customer email\n * @param tenantId - Required tenant ID for scoping\n * @returns Customer details\n */\n async getByEmail(email: string, tenantId: string): Promise<ApiResponse<Customer>> {\n const response = await this.client.get<ApiResponse<Customer>>(\n '/api/v1/customers',\n { params: { email, tenant_id: tenantId } }\n );\n return response.data;\n }\n\n /**\n * List customers with optional filters\n * GET /api/v1/customers\n * \n * @param params - Query parameters (tenant_id required, page, limit, search, is_guest)\n * @returns Paginated list of customers\n */\n async list(params: {\n tenant_id: string;\n page?: number;\n limit?: number;\n search?: string;\n is_guest?: boolean;\n }): Promise<ApiResponse<Customer[]>> {\n const response = await this.client.get<ApiResponse<Customer[]>>(\n '/api/v1/customers',\n { params }\n );\n return response.data;\n }\n\n /**\n * Create a new customer\n * POST /api/v1/customers\n * \n * @param data - Customer creation data (tenant_id, name, email required)\n * @returns Created customer\n */\n async create(data: Partial<Customer>): Promise<ApiResponse<Customer>> {\n const response = await this.client.post<ApiResponse<Customer>>(\n '/api/v1/customers',\n data\n );\n return response.data;\n }\n\n /**\n * Update customer by ID\n * PUT /api/v1/customers/:id\n * \n * @param id - Customer ID\n * @param data - Customer update data\n * @returns Updated customer\n */\n async update(id: string, data: Partial<Customer>): Promise<ApiResponse<Customer>> {\n const response = await this.client.put<ApiResponse<Customer>>(\n `/api/v1/customers/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete customer by ID\n * DELETE /api/v1/customers/:id\n * \n * @param id - Customer ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/customers/${id}`\n );\n return response.data;\n }\n\n /**\n * Lookup customer by userId or tenantId\n * GET /api/v1/customers/lookup\n * \n * @param params - Query parameters (userId optional, tenantId required)\n * @returns Customer or null\n */\n async lookup(params: {\n userId?: string;\n tenantId: string;\n }): Promise<ApiResponse<Customer | null>> {\n const response = await this.client.get<ApiResponse<Customer | null>>(\n '/api/v1/customers/lookup',\n { params: { userId: params.userId, tenantId: params.tenantId } }\n );\n return response.data;\n }\n\n /**\n * Get autocomplete data from existing customers and bookings\n * GET /api/v1/customers/autocomplete\n * \n * @param tenantId - Tenant ID (required)\n * @returns Autocomplete data\n */\n async autocomplete(tenantId: string): Promise<ApiResponse<any>> {\n const response = await this.client.get<ApiResponse<any>>(\n '/api/v1/customers/autocomplete',\n { params: { tenantId } }\n );\n return response.data;\n }\n\n /**\n * Get all bookings for a customer\n * GET /api/v1/customers/bookings\n * \n * @param params - Query parameters (email optional, userId optional, tenantId required)\n * @returns Customer bookings data\n */\n async getBookings(params: {\n email?: string;\n userId?: string;\n tenantId: string;\n }): Promise<ApiResponse<{\n customer: Customer | null;\n bookings: Booking[];\n groupedBySlot: Record<string, Booking[]>;\n total: number;\n }>> {\n const response = await this.client.get<ApiResponse<{\n customer: Customer | null;\n bookings: Booking[];\n groupedBySlot: Record<string, Booking[]>;\n total: number;\n }>>(\n '/api/v1/customers/bookings',\n { params }\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Flow } from '../types/api';\n\nexport class FlowClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get flow by ID\n * GET /api/v1/flows/:id\n * \n * @param id - Flow ID\n * @returns Flow details\n */\n async getById(id: string): Promise<ApiResponse<Flow>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Flow>>(\n `/api/v1/flows/${id}`\n );\n return response.data;\n }\n\n /**\n * List flows with optional filters\n * GET /api/v1/flows\n * \n * @param params - Query parameters (tenantId, page, limit)\n * @returns Paginated list of flows\n */\n async list(params?: {\n tenantId?: string;\n page?: number;\n limit?: number;\n }): Promise<ApiResponse<Flow[]>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Flow[]>>(\n '/api/v1/flows',\n { params }\n );\n return response.data;\n }\n\n /**\n * Create a new flow\n * POST /api/v1/flows\n * \n * @param data - Flow creation data\n * @returns Created flow\n */\n async create(data: Partial<Flow>): Promise<ApiResponse<Flow>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<Flow>>(\n '/api/v1/flows',\n data\n );\n return response.data;\n }\n\n /**\n * Update flow by ID\n * PATCH /api/v1/flows/:id\n * \n * @param id - Flow ID\n * @param data - Flow update data\n * @returns Updated flow\n */\n async update(id: string, data: Partial<Flow>): Promise<ApiResponse<Flow>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.patch<ApiResponse<Flow>>(\n `/api/v1/flows/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete flow by ID\n * DELETE /api/v1/flows/:id\n * \n * @param id - Flow ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/flows/${id}`\n );\n return response.data;\n }\n\n /**\n * Execute a flow\n * POST /api/v1/flows/:id/execute\n * \n * @param id - Flow ID\n * @param input - Optional input data for flow execution\n * @returns Flow execution result\n */\n async execute(id: string, input?: Record<string, any>): Promise<ApiResponse<any>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<any>>(\n `/api/v1/flows/${id}/execute`,\n { input }\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Studio } from '../types/api';\n\nexport class StudioClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get studio by ID\n * GET /api/v1/studios/:id\n * \n * @param id - Studio ID\n * @returns Studio details\n */\n async getById(id: string): Promise<ApiResponse<Studio>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Studio>>(\n `/api/v1/studios/${id}`\n );\n return response.data;\n }\n\n /**\n * Get studio by slug\n * GET /api/v1/studios/slug/:slug\n * \n * @param slug - Studio slug\n * @returns Studio details\n */\n async getBySlug(slug: string): Promise<ApiResponse<Studio>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Studio>>(\n `/api/v1/studios/slug/${slug}`\n );\n return response.data;\n }\n\n /**\n * List studios with optional filters\n * GET /api/v1/studios\n * \n * @param params - Query parameters (page, limit, search)\n * @returns Paginated list of studios\n */\n async list(params?: {\n page?: number;\n limit?: number;\n search?: string;\n }): Promise<ApiResponse<Studio[]>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Studio[]>>(\n '/api/v1/studios',\n { params }\n );\n return response.data;\n }\n\n /**\n * Create a new studio\n * POST /api/v1/studios\n * \n * @param data - Studio creation data\n * @returns Created studio\n */\n async create(data: Partial<Studio>): Promise<ApiResponse<Studio>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<Studio>>(\n '/api/v1/studios',\n data\n );\n return response.data;\n }\n\n /**\n * Update studio by ID\n * PATCH /api/v1/studios/:id\n * \n * @param id - Studio ID\n * @param data - Studio update data\n * @returns Updated studio\n */\n async update(id: string, data: Partial<Studio>): Promise<ApiResponse<Studio>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.patch<ApiResponse<Studio>>(\n `/api/v1/studios/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete studio by ID\n * DELETE /api/v1/studios/:id\n * \n * @param id - Studio ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/studios/${id}`\n );\n return response.data;\n }\n\n /**\n * Get data quality issues for a studio\n * GET /api/v1/studios/:id/data-quality\n * \n * @param id - Studio ID\n * @param params - Query parameters (resolved, severity)\n * @returns List of data quality issues\n */\n async getDataQualityIssues(\n id: string,\n params?: {\n resolved?: boolean;\n severity?: 'low' | 'medium' | 'high';\n }\n ): Promise<ApiResponse<any[]>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<any[]>>(\n `/api/v1/studios/${id}/data-quality`,\n { params }\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Notification } from '../types/api';\n\nexport class NotificationClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get notification by ID\n * GET /api/v1/notifications/:id\n * \n * @param id - Notification ID\n * @returns Notification details\n */\n async getById(id: string): Promise<ApiResponse<Notification>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Notification>>(\n `/api/v1/notifications/${id}`\n );\n return response.data;\n }\n\n /**\n * List notifications with optional filters\n * GET /api/v1/notifications\n * \n * @param params - Query parameters (tenantId, type, recipient, page, limit)\n * @returns Paginated list of notifications\n */\n async list(params?: {\n tenantId?: string;\n type?: string;\n recipient?: string;\n page?: number;\n limit?: number;\n }): Promise<ApiResponse<Notification[]>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<Notification[]>>(\n '/api/v1/notifications',\n { params }\n );\n return response.data;\n }\n\n /**\n * Create a new notification\n * POST /api/v1/notifications\n * \n * @param data - Notification creation data\n * @returns Created notification\n */\n async create(data: Partial<Notification>): Promise<ApiResponse<Notification>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<Notification>>(\n '/api/v1/notifications',\n data\n );\n return response.data;\n }\n\n /**\n * Send notification immediately\n * POST /api/v1/notifications/send\n * \n * @param data - Notification data to send\n * @returns Sent notification\n */\n async send(data: Partial<Notification>): Promise<ApiResponse<Notification>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<Notification>>(\n '/api/v1/notifications/send',\n data\n );\n return response.data;\n }\n\n /**\n * Update notification by ID\n * PATCH /api/v1/notifications/:id\n * \n * @param id - Notification ID\n * @param data - Notification update data\n * @returns Updated notification\n */\n async update(id: string, data: Partial<Notification>): Promise<ApiResponse<Notification>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.patch<ApiResponse<Notification>>(\n `/api/v1/notifications/${id}`,\n data\n );\n return response.data;\n }\n\n /**\n * Delete notification by ID\n * DELETE /api/v1/notifications/:id\n * \n * @param id - Notification ID\n * @returns Empty response on success\n */\n async delete(id: string): Promise<ApiResponse<void>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.delete<ApiResponse<void>>(\n `/api/v1/notifications/${id}`\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, DataQualityIssue } from '../types/api';\n\nexport class DataQualityClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get data quality issue by ID\n * GET /api/v1/data-quality/:id\n * \n * @param id - Issue ID\n * @returns Data quality issue details\n */\n async getById(id: string): Promise<ApiResponse<DataQualityIssue>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<DataQualityIssue>>(\n `/api/v1/data-quality/${id}`\n );\n return response.data;\n }\n\n /**\n * List data quality issues with optional filters\n * GET /api/v1/data-quality\n * \n * @param params - Query parameters (tenantId, type, severity, resolved, page, limit)\n * @returns Paginated list of data quality issues\n */\n async list(params?: {\n tenantId?: string;\n type?: string;\n severity?: 'low' | 'medium' | 'high';\n resolved?: boolean;\n page?: number;\n limit?: number;\n }): Promise<ApiResponse<DataQualityIssue[]>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<DataQualityIssue[]>>(\n '/api/v1/data-quality',\n { params }\n );\n return response.data;\n }\n\n /**\n * Run data quality check for a tenant\n * POST /api/v1/data-quality/check\n * \n * @param tenantId - Tenant ID to check\n * @returns List of detected issues\n */\n async runCheck(tenantId: string): Promise<ApiResponse<DataQualityIssue[]>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.post<ApiResponse<DataQualityIssue[]>>(\n '/api/v1/data-quality/check',\n { tenantId }\n );\n return response.data;\n }\n\n /**\n * Resolve a data quality issue\n * PATCH /api/v1/data-quality/:id/resolve\n * \n * @param id - Issue ID\n * @returns Resolved issue\n */\n async resolve(id: string): Promise<ApiResponse<DataQualityIssue>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.patch<ApiResponse<DataQualityIssue>>(\n `/api/v1/data-quality/${id}/resolve`,\n { resolved: true }\n );\n return response.data;\n }\n\n /**\n * Get data quality summary for a tenant\n * GET /api/v1/data-quality/summary?tenantId=:id\n * \n * @param tenantId - Tenant ID\n * @returns Summary of data quality issues\n */\n async getSummary(tenantId: string): Promise<ApiResponse<any>> {\n // TODO: Replace with actual endpoint when available\n const response = await this.client.get<ApiResponse<any>>(\n '/api/v1/data-quality/summary',\n { params: { tenantId } }\n );\n return response.data;\n }\n}\n\n","import { AxiosInstance } from 'axios';\nimport { ApiResponse, Organization, OrganizationFullConfig, GetOrganizationOptions } from '../types/api';\n\n/**\n * OrganizationClient provides methods for managing organizations\n */\nexport class OrganizationClient {\n constructor(private client: AxiosInstance) {}\n\n /**\n * Get organization by ID or slug\n * GET /api/v1/organizations/:id\n *\n * @param identifier - Organization ID or slug\n * @param options - Query options (includeTenants, page, limit, is_public)\n * @returns Organization or OrganizationFullConfig (with nested tenants if includeTenants=true)\n *\n * @example\n * ```typescript\n * // Get organization only\n * const org = await slotly.organization.getById('org-123');\n *\n * // Get organization with tenants\n * const orgWithTenants = await slotly.organization.getById('org-123', {\n * includeTenants: true,\n * page: 1,\n * limit: 10,\n * is_public: true\n * });\n * ```\n */\n async getById(\n identifier: string,\n options?: GetOrganizationOptions\n ): Promise<ApiResponse<Organization | OrganizationFullConfig>> {\n const params: Record<string, any> = {};\n\n if (options?.includeTenants) {\n params.includeTenants = 'true';\n }\n\n if (options?.page !== undefined) {\n params.page = options.page;\n }\n\n if (options?.limit !== undefined) {\n params.limit = options.limit;\n }\n\n if (options?.is_public !== undefined) {\n params.is_public = options.is_public;\n }\n\n const response = await this.client.get<ApiResponse<Organization | OrganizationFullConfig>>(\n `/api/v1/organizations/${identifier}`,\n { params }\n );\n return response.data;\n }\n\n /**\n * Get organization by slug (alias for getById)\n * GET /api/v1/organizations/:slug\n *\n * @param slug - Organization slug\n * @param options - Query options (includeTenants, page, limit, is_public)\n * @returns Organization or OrganizationFullConfig (with nested tenants if includeTenants=true)\n *\n * @example\n * ```typescript\n * const org = await slotly.organization.getBySlug('acme-corp', {\n * includeTenants: true\n * });\n * ```\n */\n async getBySlug(\n slug: string,\n options?: GetOrganizationOptions\n ): Promise<ApiResponse<Organization | OrganizationFullConfig>> {\n return this.getById(slug, options);\n }\n}\n\n","/**\n * Custom error classes for Slotly SDK\n */\n\nexport class SlotlyApiError extends Error {\n constructor(\n public code: string,\n message: string,\n public statusCode?: number,\n public details?: any\n ) {\n super(message);\n this.name = 'SlotlyApiError';\n Object.setPrototypeOf(this, SlotlyApiError.prototype);\n }\n}\n\nexport class SlotlyAuthError extends SlotlyApiError {\n constructor(message: string, details?: any) {\n super('AUTH_ERROR', message, 401, details);\n this.name = 'SlotlyAuthError';\n Object.setPrototypeOf(this, SlotlyAuthError.prototype);\n }\n}\n\nexport class SlotlyNetworkError extends Error {\n constructor(message: string, public originalError?: any) {\n super(message);\n this.name = 'SlotlyNetworkError';\n Object.setPrototypeOf(this, SlotlyNetworkError.prototype);\n }\n}\n\nexport class SlotlyConfigurationError extends Error {\n constructor(message: string, public details?: any) {\n super(message);\n this.name = 'SlotlyConfigurationError';\n Object.setPrototypeOf(this, SlotlyConfigurationError.prototype);\n }\n}\n\n","import { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';\nimport { SlotlyApiError, SlotlyAuthError, SlotlyNetworkError } from './errors';\nimport { ApiResponse } from './types/api';\n\n/**\n * Request interceptor for logging\n */\nexport function setupRequestInterceptor() {\n return (config: InternalAxiosRequestConfig) => {\n // TODO: Add request logging if needed\n // console.log(`[Slotly SDK] ${config.method?.toUpperCase()} ${config.url}`);\n return config;\n };\n}\n\n/**\n * Response interceptor for error shaping and logging\n */\nexport function setupResponseInterceptor() {\n return (response: AxiosResponse) => {\n // TODO: Add response logging if needed\n // console.log(`[Slotly SDK] Response: ${response.status} ${response.config.url}`);\n return response;\n };\n}\n\n/**\n * Error interceptor for shaping errors into SlotlyApiError\n */\nexport function setupErrorInterceptor() {\n return (error: AxiosError<ApiResponse<any>>) => {\n // Network errors (no response)\n if (!error.response) {\n const networkError = new SlotlyNetworkError(\n error.message || 'Network error occurred',\n error\n );\n // TODO: Add error logging\n // console.error('[Slotly SDK] Network error:', networkError);\n return Promise.reject(networkError);\n }\n\n const { status, data } = error.response;\n\n // Handle authentication errors\n if (status === 401 || status === 403) {\n const authError = new SlotlyAuthError(\n data?.error?.message || 'Authentication failed',\n data?.error?.details\n );\n // TODO: Add error logging\n // console.error('[Slotly SDK] Auth error:', authError);\n return Promise.reject(authError);\n }\n\n // Handle API errors with structured error format\n if (data?.error) {\n const apiError = new SlotlyApiError(\n data.error.code || 'API_ERROR',\n data.error.message || 'An error occurred',\n status,\n data.error.details\n );\n // TODO: Add error logging\n // console.error('[Slotly SDK] API error:', apiError);\n return Promise.reject(apiError);\n }\n\n // Handle other HTTP errors\n const apiError = new SlotlyApiError(\n 'HTTP_ERROR',\n error.message || `Request failed with status ${status}`,\n status,\n data\n );\n // TODO: Add error logging\n // console.error('[Slotly SDK] HTTP error:', apiError);\n return Promise.reject(apiError);\n };\n}\n\n","import axios, { AxiosError, InternalAxiosRequestConfig } from 'axios';\n\n/**\n * Exponential backoff retry configuration\n */\nexport interface RetryConfig {\n maxRetries: number;\n retryDelay: number; // Base delay in milliseconds\n retryCondition?: (error: AxiosError) => boolean;\n}\n\nconst defaultRetryConfig: RetryConfig = {\n maxRetries: 3,\n retryDelay: 1000, // 1 second\n retryCondition: (error: AxiosError) => {\n // Retry on network errors and 5xx server errors\n if (!error.response) {\n return true; // Network error\n }\n const status = error.response.status;\n return status >= 500 && status < 600;\n },\n};\n\n/**\n * Calculate exponential backoff delay with jitter\n */\nfunction calculateRetryDelay(attempt: number, baseDelay: number): number {\n const exponentialDelay = baseDelay * Math.pow(2, attempt);\n const jitter = Math.random() * 0.3 * exponentialDelay; // Add up to 30% jitter\n return exponentialDelay + jitter;\n}\n\n/**\n * Axios interceptor for retry logic\n */\nexport function setupRetryInterceptor(\n config: RetryConfig = defaultRetryConfig\n) {\n return async (error: AxiosError) => {\n const requestConfig = error.config as InternalAxiosRequestConfig & {\n _retry?: boolean;\n _retryCount?: number;\n };\n\n // If no config, reject\n if (!requestConfig) {\n return Promise.reject(error);\n }\n\n // Initialize retry count\n if (requestConfig._retryCount === undefined) {\n requestConfig._retryCount = 0;\n }\n\n // Check if we should retry\n const shouldRetry =\n requestConfig._retryCount < config.maxRetries &&\n (!config.retryCondition || config.retryCondition(error));\n\n if (!shouldRetry) {\n return Promise.reject(error);\n }\n\n // Mark as retrying\n requestConfig._retry = true;\n requestConfig._retryCount += 1;\n\n // Calculate delay\n const delay = calculateRetryDelay(\n requestConfig._retryCount - 1,\n config.retryDelay\n );\n\n // Wait before retrying\n await new Promise((resolve) => setTimeout(resolve, delay));\n\n // Retry the request\n return axios(requestConfig);\n };\n}\n\n","import type { NextApiRequest, NextApiResponse } from 'next';\nimport { jwtDecode } from 'jwt-decode';\nimport { SlotlyAuthError } from '../errors';\n\n/**\n * Authentication context extracted from validated Slotly request\n */\nexport interface SlotlyAuthContext {\n clientKey: string;\n userId?: string;\n tenantId?: string;\n permissions?: string[];\n tokenClaims?: Record<string, any>;\n}\n\n/**\n * Extended Next.js request with Slotly context\n */\nexport interface SlotlyRequest extends NextApiRequest {\n slotlyContext: SlotlyAuthContext;\n}\n\n/**\n * Next.js API route handler type\n */\nexport type NextApiHandler = (\n req: NextApiRequest,\n res: NextApiResponse\n) => Promise<void> | void;\n\n/**\n * Mock allowlist for client keys\n * \n * ⚠️ DEVELOPMENT ONLY: This is a mock allowlist for development/testing purposes.\n * \n * In production, this MUST be replaced with:\n * - A secure database lookup (e.g., PostgreSQL, DynamoDB)\n * - A secrets management system (e.g., AWS Secrets Manager, HashiCorp Vault)\n * - A Redis cache with appropriate TTL for high-throughput scenarios\n * - Rate limiting per client key to prevent abuse\n * \n * Consider implementing:\n * - Key rotation policies\n * - Per-key rate limiting (especially important for public booking flows)\n * - Audit logging of key usage\n * - Revocation mechanisms\n * \n * TODO: Replace with actual database or cache lookup\n */\nconst allowedKeys: Record<\n string,\n { tenantId: string; permissions: string[] }\n> = {\n 'test-key-123': {\n tenantId: 'bright-accountants',\n permissions: ['booking:create'],\n },\n 'admin-ui': {\n tenantId: 'slotly-core',\n permissions: ['*'],\n },\n};\n\n/**\n * Validates an API key against the allowlist\n * Returns the associated tenant and permissions if valid\n */\nfunction validateApiKey(clientKey: string): {\n tenantId: string;\n permissions: string[];\n} | null {\n if (!clientKey || typeof clientKey !== 'string') {\n return null;\n }\n\n const keyInfo = allowedKeys[clientKey];\n if (!keyInfo) {\n return null;\n }\n\n return {\n tenantId: keyInfo.tenantId,\n permissions: keyInfo.permissions,\n };\n}\n\n/**\n * Extracts and decodes JWT token from Authorization header\n * \n * If present, extracts user identity from the token. This is optional:\n * - Anonymous/client-only flows: Authorization header not required\n * - User-authenticated flows: Authorization header provides user traceability\n * \n * Returns userId from 'sub' claim and full token claims for additional context.\n * Note: Currently decodes without signature validation (development).\n * TODO: Add signature validation in production using Clerk or JWT library.\n */\nfunction extractUserToken(authHeader?: string): {\n userId?: string;\n tokenClaims?: Record<string, any>;\n} | null {\n if (!authHeader || typeof authHeader !== 'string') {\n return null;\n }\n\n // Extract Bearer token\n const bearerMatch = authHeader.match(/^Bearer\\s+(.+)$/i);\n if (!bearerMatch || !bearerMatch[1]) {\n return null;\n }\n\n const token = bearerMatch[1];\n\n try {\n // Decode JWT without signature validation\n // WARNING: This is for development only. Production should validate signatures.\n // TODO: Add signature validation in production (e.g., using Clerk's verifyToken or jsonwebtoken)\n const claims = jwtDecode(token) as Record<string, any>;\n\n if (!claims || typeof claims !== 'object') {\n // eslint-disable-next-line no-console\n console.error('[Slotly SDK] Invalid JWT token: claims is not an object');\n return null;\n }\n\n // Extract userId from 'sub' claim\n const userId = claims.sub || claims.user_id || claims.userId;\n\n return {\n userId: typeof userId === 'string' ? userId : undefined,\n tokenClaims: claims,\n };\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Slotly SDK] Failed to decode JWT token:', error);\n return null;\n }\n}\n\n/**\n * Validates Slotly request headers and extracts authentication context\n * \n * Validates:\n * - `x-slotly-api-key`: Required header identifying the client/application\n * - `Authorization: Bearer ...`: Optional header providing user identity (if present, extracts user identity)\n * \n * Throws SlotlyAuthError if validation fails. Error includes code, message, and details\n * fields that align with the ApiResponse<T> error shape for consistent error handling.\n * \n * @throws {SlotlyAuthError} If x-slotly-api-key is missing, invalid, or not in allowlist\n */\nfunction validateAndExtractContext(req: NextApiRequest): SlotlyAuthContext {\n // Extract x-slotly-api-key header (required)\n // Support both lowercase and mixed case headers\n const clientKey =\n (req.headers['x-slotly-api-key'] as string) ||\n (req.headers['X-Slotly-Api-Key'] as string) ||\n (req.headers['x-slotly-api-key'] as string);\n\n if (!clientKey || typeof clientKey !== 'string' || clientKey.trim().length === 0) {\n const error = new SlotlyAuthError(\n 'Missing or invalid x-slotly-api-key header. API key is required.',\n { header: 'x-slotly-api-key' }\n );\n // eslint-disable-next-line no-console\n console.error('[Slotly SDK] Validation failed:', error.message);\n throw error;\n }\n\n // Validate API key against allowlist\n const keyInfo = validateApiKey(clientKey);\n if (!keyInfo) {\n const error = new SlotlyAuthError(\n 'Invalid API key. Client key not found in allowlist.',\n { clientKey: clientKey.substring(0, 8) + '...' }\n );\n // eslint-disable-next-line no-console\n console.error('[Slotly SDK] Validation failed:', error.message);\n throw error;\n }\n\n // Extract Authorization header (optional)\n // Support both lowercase and mixed case headers\n const authHeader =\n (req.headers.authorization as string) ||\n (req.headers.Authorization as string);\n\n const tokenInfo = authHeader ? extractUserToken(authHeader) : null;\n\n // Build context\n const context: SlotlyAuthContext = {\n clientKey,\n tenantId: keyInfo.tenantId,\n permissions: keyInfo.permissions,\n ...(tokenInfo?.userId && { userId: tokenInfo.userId }),\n ...(tokenInfo?.tokenClaims && { tokenClaims: tokenInfo.tokenClaims }),\n };\n\n return context;\n}\n\n/**\n * Safely extracts Slotly context from Next.js request\n * \n * Use this helper when you need to access the context outside of the middleware wrapper,\n * or to check if the context exists.\n * \n * **Important:** Other route handlers should guard user-required flows:\n * ```ts\n * const context = getSlotlyContext(req);\n * if (!context?.userId) {\n * return res.status(403).json({\n * success: false,\n * error: { code: 'USER_REQUIRED', message: 'User authentication required' }\n * });\n * }\n * ```\n * \n * @param req Next.js API request\n * @returns SlotlyAuthContext if present, null otherwise\n */\nexport function getSlotlyContext(\n req: NextApiRequest\n): SlotlyAuthContext | null {\n const slotlyReq = req as SlotlyRequest;\n return slotlyReq.slotlyContext || null;\n}\n\n/**\n * Middleware wrapper for Next.js API routes and Edge Functions\n * Validates Slotly authentication headers and injects context into request\n * \n * **Supported Environments:**\n * - Next.js API Routes (serverless functions)\n * - Next.js Edge Functions (Edge Runtime)\n * - Vercel Edge Functions\n * \n * **Note on Edge Functions:**\n * Header names are normalized, but edge runtime may have different header casing.\n * This middleware handles both `x-slotly-api-key` and `X-Slotly-Api-Key` variants.\n *\n * **Error Response Format:**\n * All error responses follow the `ApiResponse<T>` format for consistency:\n * ```ts\n * {\n * success: false,\n * error: {\n * code: string, // Error code (e.g., 'AUTH_ERROR', 'INTERNAL_ERROR')\n * message: string, // Human-readable error message\n * details?: any // Additional error details\n * }\n * }\n * ```\n * \n * **Usage:**\n * ```ts\n * import { validateSlotlyRequest } from \"@slotly/sdk/middleware/validateSlotlyRequest\";\n *\n * export default validateSlotlyRequest(async (req, res) => {\n * const { userId, clientKey, tenantId, permissions } = req.slotlyContext;\n * \n * // Check if user authentication is required for this endpoint\n * if (!userId) {\n * return res.status(403).json({\n * success: false,\n * error: { code: 'USER_REQUIRED', message: 'User authentication required' }\n * });\n * }\n * \n * // Authenticated + scoped — safe to proceed\n * res.json({ success: true, data: { userId, tenantId } });\n * });\n * ```\n *\n * **Performance Considerations:**\n * - For high-throughput scenarios (e.g., many public booking flows), consider:\n * - Caching API key lookups with TTL (Redis, in-memory cache)\n * - Rate limiting per client key\n * - Database connection pooling for key validation\n *\n * @param handler Next.js API route handler or Edge Function handler\n * @returns Wrapped handler with Slotly validation\n */\nexport function validateSlotlyRequest(\n handler: (req: SlotlyRequest, res: NextApiResponse) => Promise<void> | void\n) {\n return async (req: NextApiRequest, res: NextApiResponse): Promise<void> => {\n try {\n // Validate and extract context\n const context = validateAndExtractContext(req);\n\n // Inject context into request\n const slotlyReq = req as SlotlyRequest;\n slotlyReq.slotlyContext = context;\n\n // Call the actual handler with validated request\n await handler(slotlyReq, res);\n } catch (error) {\n // Handle SlotlyAuthError\n if (error instanceof SlotlyAuthError) {\n // eslint-disable-next-line no-console\n console.error(\n '[Slotly SDK] Authentication failed:',\n error.message,\n error.details\n );\n\n // Error response follows ApiResponse<T> format for consistency\n // SlotlyAuthError includes code, message, and details fields that align\n // with the ApiResponse<T> error shape\n res.status(error.statusCode || 401).json({\n success: false,\n error: {\n code: error.code,\n message: error.message,\n details: error.details,\n },\n });\n return;\n }\n\n // Handle other errors\n // eslint-disable-next-line no-console\n console.error('[Slotly SDK] Unexpected error:', error);\n\n // Error response follows ApiResponse<T> format for consistency\n res.status(500).json({\n success: false,\n error: {\n code: 'INTERNAL_ERROR',\n message: 'An unexpected error occurred',\n },\n });\n }\n };\n}\n\n"],"mappings":"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","names":["import_axios","apiError","axios","axios"]}