{"version":3,"file":"api-clients.mjs","sources":["../../../src/lib/services/api-clients.ts"],"sourcesContent":["/**\n * @file Resource API Clients\n * @description Domain-specific resource client factories for CRUD operations.\n *\n * **IMPORTANT**: This module provides `createResourceClient` for building domain-specific\n * API clients with caching. For the core HTTP client infrastructure, use `createApiClient`\n * from `@/lib/api` instead.\n *\n * **MIGRATION NOTICE**: This module currently uses the deprecated `httpClient` from './http'.\n * A future version will migrate to use `apiClient` from `@/lib/api` for consistency.\n * New code should prefer using `apiClient` directly or the hooks from `@/lib/api/hooks`.\n *\n * @example\n * ```typescript\n * import { createResourceClient } from '@/lib/services';\n *\n * interface User {\n *   id: string;\n *   name: string;\n *   email: string;\n * }\n *\n * const userClient = createResourceClient<User>({\n *   basePath: '/api/users',\n *   cacheTtl: 5 * 60 * 1000,\n * });\n *\n * // CRUD operations\n * const users = await userClient.getAll({ page: 1 });\n * const user = await userClient.getById('123');\n * ```\n *\n * @see {@link @/lib/api} for the recommended API client\n */\n\n/**\n * @deprecated Use `apiClient` from `@/lib/api` instead.\n * This import is maintained for backward compatibility with existing resource clients.\n */\nimport { type HttpRequestConfig } from './http';\nimport { requestCache, type RequestCache } from './cache';\nimport { apiClient } from '@/lib/api';\n\n/**\n * Resource API response wrapper\n */\nexport interface ResourceApiResponse<T> {\n  data: T;\n  meta?: {\n    total?: number;\n    page?: number;\n    pageSize?: number;\n    [key: string]: unknown;\n  };\n}\n\n/**\n * Paginated response\n */\nexport interface PaginatedResponse<T> {\n  items: T[];\n  total: number;\n  page: number;\n  pageSize: number;\n  hasMore: boolean;\n}\n\n/**\n * List query parameters\n */\nexport interface ListQueryParams {\n  page?: number;\n  pageSize?: number;\n  sort?: string;\n  order?: 'asc' | 'desc';\n  search?: string;\n  filter?: Record<string, unknown>;\n}\n\n/**\n * Resource client configuration\n *\n * **Note**: This is distinct from `ApiClientConfig` in `@/lib/api/types.ts` which\n * configures the core HTTP client. This interface configures domain-specific\n * resource clients with caching capabilities.\n */\nexport interface ResourceClientConfig {\n  /** Base path for all endpoints */\n  basePath: string;\n\n  /** Request cache instance */\n  cache?: RequestCache;\n\n  /** Default cache TTL */\n  cacheTtl?: number;\n\n  /** Enable caching by default */\n  enableCache?: boolean;\n}\n\n/**\n * Resource client interface returned by createResourceClient\n *\n * Provides CRUD operations for a specific resource type with built-in caching.\n *\n * **Note**: This is distinct from `ApiClient` class in `@/lib/api` which is the\n * core HTTP client. This interface represents a domain-specific resource client.\n */\nexport interface ResourceClient<T extends { id: string | number }> {\n  getAll(params?: ListQueryParams, options?: { cache?: boolean }): Promise<PaginatedResponse<T>>;\n  getById(id: string | number, options?: { cache?: boolean }): Promise<T>;\n  create(data: Omit<T, 'id'>): Promise<T>;\n  update(id: string | number, data: Partial<T>): Promise<T>;\n  replace(id: string | number, data: Omit<T, 'id'>): Promise<T>;\n  delete(id: string | number): Promise<void>;\n  batchDelete(ids: (string | number)[]): Promise<void>;\n  customGet<R>(\n    path: string,\n    params?: Record<string, string | number | boolean | undefined>,\n    options?: { cache?: boolean }\n  ): Promise<R>;\n  customPost<R>(path: string, body?: unknown, config?: Partial<HttpRequestConfig>): Promise<R>;\n  invalidateCache(): void;\n}\n\n/**\n * @deprecated Use `createResourceClient` instead. The name `createApiClient` conflicts\n * with `@/lib/api/api-client.ts`. This alias will be removed in a future version.\n */\nexport const createApiClient = createResourceClient;\n\n/**\n * Create a domain-specific resource client with CRUD operations and caching\n *\n * This factory creates clients for specific API resources (users, posts, etc.)\n * with built-in caching, pagination support, and standard CRUD methods.\n *\n * For the core HTTP client with interceptors, retry logic, and token refresh,\n * use `createApiClient` from `@/lib/api` instead.\n *\n * @param config - Resource client configuration\n * @returns Configured resource client with CRUD operations\n *\n * @example\n * ```typescript\n * const userClient = createResourceClient<User>({\n *   basePath: '/api/users',\n *   cacheTtl: 5 * 60 * 1000, // 5 minutes\n *   enableCache: true,\n * });\n *\n * // Fetch all users with pagination\n * const { items, total, hasMore } = await userClient.getAll({ page: 1, pageSize: 20 });\n *\n * // Fetch single user\n * const user = await userClient.getById('123');\n *\n * // Create new user\n * const newUser = await userClient.create({ name: 'John', email: 'john@example.com' });\n * ```\n */\nexport function createResourceClient<T extends { id: string | number }>(\n  config: ResourceClientConfig\n): ResourceClient<T> {\n  const { basePath, cache = requestCache, cacheTtl = 5 * 60 * 1000, enableCache = true } = config;\n\n  /**\n   * Build full URL\n   */\n  function buildUrl(path: string = ''): string {\n    return `${basePath}${path}`;\n  }\n\n  /**\n   * Build cache key\n   */\n  function buildCacheKey(path: string, params?: unknown): string {\n    return cache.generateKey(buildUrl(path), params as Record<string, unknown>);\n  }\n\n  return {\n    /**\n     * Get all items using apiClient\n     * @throws {ApiError} When the request fails\n     */\n    async getAll(\n      params?: ListQueryParams,\n      options?: { cache?: boolean }\n    ): Promise<PaginatedResponse<T>> {\n      const useCache = options?.cache ?? enableCache;\n      const cacheKey = buildCacheKey('', params);\n\n      if (useCache) {\n        const cached = cache.get<PaginatedResponse<T>>(cacheKey);\n        if (cached !== null && cached !== undefined) return cached;\n      }\n\n      const response = await apiClient.get<ResourceApiResponse<T[]>>(buildUrl(), {\n        params: params as Record<string, string | number | boolean | undefined>,\n      });\n\n      const result: PaginatedResponse<T> = {\n        items: response.data.data,\n        total: response.data.meta?.total ?? response.data.data.length,\n        page: response.data.meta?.page ?? params?.page ?? 1,\n        pageSize: response.data.meta?.pageSize ?? params?.pageSize ?? 20,\n        hasMore:\n          response.data.meta?.total != null &&\n          (params?.page ?? 1) * (params?.pageSize ?? 20) < response.data.meta.total,\n      };\n\n      if (useCache) {\n        cache.set(cacheKey, result, cacheTtl);\n      }\n\n      return result;\n    },\n\n    /**\n     * Get single item by ID using apiClient\n     * @throws {ApiError} When the request fails\n     */\n    async getById(id: string | number, options?: { cache?: boolean }): Promise<T> {\n      const useCache = options?.cache ?? enableCache;\n      const cacheKey = buildCacheKey(`/${id}`);\n\n      if (useCache) {\n        const cached = cache.get<T>(cacheKey);\n        if (cached !== null && cached !== undefined) return cached;\n      }\n\n      const response = await apiClient.get<ResourceApiResponse<T>>(buildUrl(`/${id}`));\n      const { data } = response.data;\n\n      if (useCache) {\n        cache.set(cacheKey, data, cacheTtl);\n      }\n\n      return data;\n    },\n\n    /**\n     * Create new item using apiClient\n     * @throws {ApiError} When the request fails\n     */\n    async create(data: Omit<T, 'id'>): Promise<T> {\n      const response = await apiClient.post<ResourceApiResponse<T>>(buildUrl(), data);\n\n      // Invalidate list cache\n      cache.invalidatePattern(new RegExp(`^${basePath}$`));\n\n      return response.data.data;\n    },\n\n    /**\n     * Update existing item using apiClient\n     * @throws {ApiError} When the request fails\n     */\n    async update(id: string | number, data: Partial<T>): Promise<T> {\n      const response = await apiClient.patch<ResourceApiResponse<T>>(buildUrl(`/${id}`), data);\n\n      // Invalidate caches\n      cache.delete(buildCacheKey(`/${id}`));\n      cache.invalidatePattern(new RegExp(`^${basePath}$`));\n\n      return response.data.data;\n    },\n\n    /**\n     * Replace existing item using apiClient\n     * @throws {ApiError} When the request fails\n     */\n    async replace(id: string | number, data: Omit<T, 'id'>): Promise<T> {\n      const response = await apiClient.put<ResourceApiResponse<T>>(buildUrl(`/${id}`), data);\n\n      // Invalidate caches\n      cache.delete(buildCacheKey(`/${id}`));\n      cache.invalidatePattern(new RegExp(`^${basePath}$`));\n\n      return response.data.data;\n    },\n\n    /**\n     * Delete item using apiClient\n     * @throws {ApiError} When the request fails\n     */\n    async delete(id: string | number): Promise<void> {\n      await apiClient.delete(buildUrl(`/${id}`));\n\n      // Invalidate caches\n      cache.delete(buildCacheKey(`/${id}`));\n      cache.invalidatePattern(new RegExp(`^${basePath}$`));\n    },\n\n    /**\n     * Batch delete items using apiClient\n     * @throws {ApiError} When any delete request fails\n     */\n    async batchDelete(ids: (string | number)[]): Promise<void> {\n      await Promise.all(ids.map(async (id) => apiClient.delete(buildUrl(`/${id}`))));\n\n      // Invalidate caches\n      ids.forEach((id) => cache.delete(buildCacheKey(`/${id}`)));\n      cache.invalidatePattern(new RegExp(`^${basePath}$`));\n    },\n\n    /**\n     * Custom GET request using apiClient\n     * @throws {ApiError} When the request fails\n     */\n    async customGet<R>(\n      path: string,\n      params?: Record<string, string | number | boolean | undefined>,\n      options?: { cache?: boolean }\n    ): Promise<R> {\n      const useCache = options?.cache ?? enableCache;\n      const cacheKey = buildCacheKey(path, params);\n\n      if (useCache) {\n        const cached = cache.get<R>(cacheKey);\n        if (cached !== null && cached !== undefined) return cached;\n      }\n\n      const response = await apiClient.get<ResourceApiResponse<R>>(buildUrl(path), {\n        params,\n      });\n      const { data } = response.data;\n\n      if (useCache) {\n        cache.set(cacheKey, data, cacheTtl);\n      }\n\n      return data;\n    },\n\n    /**\n     * Custom POST request using apiClient\n     * @throws {ApiError} When the request fails\n     */\n    async customPost<R>(\n      path: string,\n      body?: unknown,\n      _config?: Partial<HttpRequestConfig>\n    ): Promise<R> {\n      const response = await apiClient.post<ResourceApiResponse<R>>(buildUrl(path), body);\n      return response.data.data;\n    },\n\n    /**\n     * Invalidate all caches for this client\n     */\n    invalidateCache(): void {\n      cache.invalidatePattern(new RegExp(`^${basePath}`));\n    },\n  };\n}\n\n/**\n * Pre-configured resource clients for common domains\n */\nexport const resourceClients = {\n  users: createResourceClient<{ id: string; email: string; name: string }>({\n    basePath: '/api/users',\n  }),\n\n  reports: createResourceClient<{ id: string; title: string; type: string }>({\n    basePath: '/api/reports',\n  }),\n\n  settings: createResourceClient<{ id: string; key: string; value: unknown }>({\n    basePath: '/api/settings',\n    cacheTtl: 10 * 60 * 1000, // 10 minutes\n  }),\n};\n\n/**\n * @deprecated Use `resourceClients` instead. This alias will be removed in a future version.\n */\nexport const apiClients = resourceClients;\n\n// =============================================================================\n// BACKWARD COMPATIBILITY TYPE ALIASES\n// =============================================================================\n\n/**\n * @deprecated Use `ResourceApiResponse` instead.\n */\nexport type ApiResponse<T> = ResourceApiResponse<T>;\n\n/**\n * @deprecated Use `ResourceClientConfig` instead.\n */\nexport type ApiClientConfig = ResourceClientConfig;\n\n/**\n * @deprecated Use `ResourceClient` instead.\n */\nexport type ApiClient<T extends { id: string | number }> = ResourceClient<T>;\n"],"names":["createApiClient","createResourceClient","config","basePath","cache","requestCache","cacheTtl","enableCache","buildUrl","path","buildCacheKey","params","options","useCache","cacheKey","cached","response","apiClient","result","id","data","ids","body","_config","resourceClients","apiClients"],"mappings":"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"}