@krymskyimaksym/react-api-client 1.0.0

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.js ADDED
@@ -0,0 +1,418 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var react = require('react');
6
+
7
+ // src/config.ts
8
+ var globalConfig = null;
9
+ function configureApiClient(config) {
10
+ globalConfig = config;
11
+ }
12
+ function getConfig() {
13
+ if (!globalConfig) {
14
+ throw new Error(
15
+ "API client is not configured. Call configureApiClient() first."
16
+ );
17
+ }
18
+ return globalConfig;
19
+ }
20
+ function isConfigured() {
21
+ return globalConfig !== null;
22
+ }
23
+
24
+ // src/utils.ts
25
+ function buildEndpoint(endpoint, params) {
26
+ if (typeof endpoint === "function" && typeof params !== "undefined") {
27
+ return endpoint(params);
28
+ }
29
+ return endpoint;
30
+ }
31
+ async function executeRequest(endpoint, fetchConfig, params) {
32
+ const url = buildEndpoint(endpoint, params);
33
+ const config = getConfig();
34
+ try {
35
+ const requestConfig = { ...fetchConfig };
36
+ let response;
37
+ if (requestConfig.method?.toUpperCase() === "GET" || !requestConfig.method) {
38
+ response = await config.httpClient.get(url, {
39
+ params: {
40
+ ...requestConfig.requestParams,
41
+ ...params
42
+ }
43
+ });
44
+ } else {
45
+ response = await config.httpClient.request(url, {
46
+ method: requestConfig.method,
47
+ data: {
48
+ ...requestConfig.requestParams,
49
+ ...params
50
+ }
51
+ });
52
+ }
53
+ return { ...response, status: true };
54
+ } catch (e) {
55
+ const error = e;
56
+ if (error.response?.status === 401 && config.onUnauthorized) {
57
+ await config.onUnauthorized();
58
+ }
59
+ if (error.response?.data) {
60
+ return {
61
+ ...error.response.data,
62
+ status: false
63
+ };
64
+ }
65
+ return {
66
+ status: false,
67
+ message: error instanceof Error ? error.message : "Request error"
68
+ };
69
+ }
70
+ }
71
+ function handleResponse(result, onSuccess, onError) {
72
+ if (result.status && onSuccess) {
73
+ onSuccess(result);
74
+ } else if (!result.status && onError) {
75
+ const err = new Error(result.message ?? "Request failed");
76
+ onError(err);
77
+ }
78
+ }
79
+ function createUseFetch(endpoint, fetchConfig) {
80
+ return (params, options = {}) => {
81
+ const {
82
+ enabled = true,
83
+ refetchOnMount = true,
84
+ onSuccess,
85
+ onError
86
+ } = options;
87
+ const [data, setData] = react.useState(null);
88
+ const [isLoading, setIsLoading] = react.useState(enabled && refetchOnMount);
89
+ const [isRefetching, setIsRefetching] = react.useState(false);
90
+ const [error, setError] = react.useState(null);
91
+ const isMountedRef = react.useRef(true);
92
+ const serializedParams = react.useMemo(
93
+ () => params ? JSON.stringify(params) : null,
94
+ [params]
95
+ );
96
+ const fetchData = react.useCallback(
97
+ async (isRefetch = false) => {
98
+ if (!enabled) return;
99
+ try {
100
+ if (isRefetch) {
101
+ setIsRefetching(true);
102
+ } else {
103
+ setIsLoading(true);
104
+ }
105
+ setError(null);
106
+ const parsedParams = serializedParams ? JSON.parse(serializedParams) : void 0;
107
+ const result = await executeRequest(endpoint, fetchConfig, parsedParams);
108
+ if (isMountedRef.current) {
109
+ setData(result);
110
+ handleResponse(
111
+ result,
112
+ onSuccess,
113
+ onError
114
+ );
115
+ }
116
+ } catch (err) {
117
+ const error2 = err;
118
+ if (isMountedRef.current) {
119
+ setError(error2);
120
+ if (onError) {
121
+ onError(error2);
122
+ }
123
+ }
124
+ } finally {
125
+ if (isMountedRef.current) {
126
+ if (isRefetch) {
127
+ setIsRefetching(false);
128
+ } else {
129
+ setIsLoading(false);
130
+ }
131
+ }
132
+ }
133
+ },
134
+ [enabled, serializedParams, onSuccess, onError]
135
+ );
136
+ const refetch = react.useCallback(async () => {
137
+ await fetchData(true);
138
+ }, [fetchData]);
139
+ react.useEffect(() => {
140
+ isMountedRef.current = true;
141
+ if (enabled && refetchOnMount) {
142
+ void fetchData(false);
143
+ }
144
+ return () => {
145
+ isMountedRef.current = false;
146
+ };
147
+ }, [enabled, refetchOnMount, fetchData]);
148
+ return {
149
+ data,
150
+ isLoading,
151
+ isRefetching,
152
+ error,
153
+ refetch
154
+ };
155
+ };
156
+ }
157
+ function createUseMutation(endpoint, fetchConfig) {
158
+ return (options = {}) => {
159
+ const { onMutate, onSuccess, onError, onSettled } = options;
160
+ const [data, setData] = react.useState(null);
161
+ const [error, setError] = react.useState(null);
162
+ const [isLoading, setIsLoading] = react.useState(false);
163
+ const [isSuccess, setIsSuccess] = react.useState(false);
164
+ const [isError, setIsError] = react.useState(false);
165
+ const reset = react.useCallback(() => {
166
+ setData(null);
167
+ setError(null);
168
+ setIsLoading(false);
169
+ setIsSuccess(false);
170
+ setIsError(false);
171
+ }, []);
172
+ const mutateAsync = react.useCallback(
173
+ async (variables) => {
174
+ setIsLoading(true);
175
+ setIsSuccess(false);
176
+ setIsError(false);
177
+ setError(null);
178
+ try {
179
+ if (onMutate) {
180
+ await onMutate(variables);
181
+ }
182
+ const result = await executeRequest(endpoint, fetchConfig, variables);
183
+ setData(result);
184
+ if (result.status) {
185
+ setIsSuccess(true);
186
+ if (onSuccess) {
187
+ await onSuccess(result, variables);
188
+ }
189
+ } else {
190
+ const err = new Error(result.message ?? "Mutation failed");
191
+ setIsError(true);
192
+ setError(err);
193
+ if (onError) {
194
+ await onError(err, variables);
195
+ }
196
+ }
197
+ if (onSettled) {
198
+ await onSettled(result, null, variables);
199
+ }
200
+ return result;
201
+ } catch (err) {
202
+ const error2 = err;
203
+ setError(error2);
204
+ setIsError(true);
205
+ setIsSuccess(false);
206
+ if (onError) {
207
+ await onError(error2, variables);
208
+ }
209
+ if (onSettled) {
210
+ await onSettled(null, error2, variables);
211
+ }
212
+ throw error2;
213
+ } finally {
214
+ setIsLoading(false);
215
+ }
216
+ },
217
+ [onMutate, onSuccess, onError, onSettled]
218
+ );
219
+ const mutateSync = react.useCallback(
220
+ (variables) => {
221
+ void mutateAsync(variables);
222
+ },
223
+ [mutateAsync]
224
+ );
225
+ return {
226
+ data,
227
+ error,
228
+ isLoading,
229
+ isSuccess,
230
+ isError,
231
+ mutate: mutateSync,
232
+ mutateAsync,
233
+ reset
234
+ };
235
+ };
236
+ }
237
+ function createUsePaginate(endpoint, fetchConfig, options) {
238
+ return (params, hookOptions = {}) => {
239
+ const {
240
+ enabled = true,
241
+ initialPage = 1,
242
+ initialLimit = 20,
243
+ onSuccess,
244
+ onError
245
+ } = hookOptions;
246
+ const [data, setData] = react.useState([]);
247
+ const [currentPage, setCurrentPage] = react.useState(initialPage);
248
+ const [totalPages, setTotalPages] = react.useState(null);
249
+ const [total, setTotal] = react.useState(null);
250
+ const [isLoading, setIsLoading] = react.useState(enabled);
251
+ const [isFetchingNextPage, setIsFetchingNextPage] = react.useState(false);
252
+ const [error, setError] = react.useState(null);
253
+ const isMountedRef = react.useRef(true);
254
+ const limit = initialLimit;
255
+ const dataExtractor = react.useMemo(
256
+ () => options?.dataExtractor || ((response) => response.data),
257
+ []
258
+ );
259
+ const totalExtractor = react.useMemo(
260
+ () => options?.totalExtractor || ((response) => response.total ?? 0),
261
+ []
262
+ );
263
+ const serializedParams = react.useMemo(
264
+ () => params ? JSON.stringify(params) : null,
265
+ [params]
266
+ );
267
+ const fetchPage = react.useCallback(
268
+ async (page, append = false) => {
269
+ if (!enabled) return;
270
+ try {
271
+ if (append) {
272
+ setIsFetchingNextPage(true);
273
+ } else {
274
+ setIsLoading(true);
275
+ }
276
+ setError(null);
277
+ const parsedParams = serializedParams ? JSON.parse(serializedParams) : {};
278
+ const requestParams = {
279
+ ...parsedParams,
280
+ page,
281
+ limit
282
+ };
283
+ const result = await executeRequest(endpoint, fetchConfig, requestParams);
284
+ if (isMountedRef.current) {
285
+ handleResponse(
286
+ result,
287
+ onSuccess,
288
+ onError
289
+ );
290
+ if (!result.status) {
291
+ const err = new Error(result.message ?? "Request failed");
292
+ setError(err);
293
+ return;
294
+ }
295
+ const newData = dataExtractor(result);
296
+ const totalCount = totalExtractor(result);
297
+ if (append) {
298
+ setData((prevData) => [...prevData, ...newData]);
299
+ } else {
300
+ setData(newData);
301
+ }
302
+ setCurrentPage(page);
303
+ setTotal(totalCount);
304
+ setTotalPages(Math.ceil(totalCount / limit));
305
+ }
306
+ } catch (err) {
307
+ const error2 = err;
308
+ if (isMountedRef.current) {
309
+ setError(error2);
310
+ if (onError) {
311
+ onError(error2);
312
+ }
313
+ }
314
+ } finally {
315
+ if (isMountedRef.current) {
316
+ if (append) {
317
+ setIsFetchingNextPage(false);
318
+ } else {
319
+ setIsLoading(false);
320
+ }
321
+ }
322
+ }
323
+ },
324
+ [
325
+ enabled,
326
+ serializedParams,
327
+ limit,
328
+ onSuccess,
329
+ onError,
330
+ dataExtractor,
331
+ totalExtractor
332
+ ]
333
+ );
334
+ const hasNextPage = totalPages !== null && currentPage < totalPages;
335
+ const hasPreviousPage = currentPage > 1;
336
+ const fetchNextPage = react.useCallback(async () => {
337
+ if (!hasNextPage) return;
338
+ await fetchPage(currentPage + 1, true);
339
+ }, [hasNextPage, currentPage, fetchPage]);
340
+ const fetchPreviousPage = react.useCallback(async () => {
341
+ if (!hasPreviousPage) return;
342
+ await fetchPage(currentPage - 1, false);
343
+ }, [hasPreviousPage, currentPage, fetchPage]);
344
+ const refetch = react.useCallback(async () => {
345
+ await fetchPage(currentPage, false);
346
+ }, [currentPage, fetchPage]);
347
+ const reset = react.useCallback(() => {
348
+ setData([]);
349
+ setCurrentPage(initialPage);
350
+ setTotalPages(null);
351
+ setTotal(null);
352
+ setError(null);
353
+ void fetchPage(initialPage, false);
354
+ }, [initialPage, fetchPage]);
355
+ react.useEffect(() => {
356
+ isMountedRef.current = true;
357
+ if (enabled) {
358
+ void fetchPage(initialPage, false);
359
+ }
360
+ return () => {
361
+ isMountedRef.current = false;
362
+ };
363
+ }, [enabled, serializedParams, fetchPage, initialPage]);
364
+ return {
365
+ data,
366
+ currentPage,
367
+ totalPages,
368
+ total,
369
+ hasNextPage,
370
+ hasPreviousPage,
371
+ isLoading,
372
+ isFetchingNextPage,
373
+ error,
374
+ fetchNextPage,
375
+ fetchPreviousPage,
376
+ refetch,
377
+ reset
378
+ };
379
+ };
380
+ }
381
+
382
+ // src/index.ts
383
+ function apiClient(endpoint, fetchConfig = {}) {
384
+ const fetch = async (params) => {
385
+ return executeRequest(
386
+ endpoint,
387
+ fetchConfig,
388
+ params
389
+ );
390
+ };
391
+ const useFetch = createUseFetch(endpoint, fetchConfig);
392
+ return { fetch, useFetch };
393
+ }
394
+ function apiMutation(endpoint, fetchConfig = {}) {
395
+ const mutate = async (params) => {
396
+ return executeRequest(
397
+ endpoint,
398
+ fetchConfig,
399
+ params
400
+ );
401
+ };
402
+ const useMutation = createUseMutation(endpoint, fetchConfig);
403
+ return { mutate, useMutation };
404
+ }
405
+ function apiPaginate(endpoint, fetchConfig = {}, options) {
406
+ const usePaginate = createUsePaginate(endpoint, fetchConfig, options);
407
+ return { usePaginate };
408
+ }
409
+ var index_default = apiClient;
410
+
411
+ exports.apiMutation = apiMutation;
412
+ exports.apiPaginate = apiPaginate;
413
+ exports.configureApiClient = configureApiClient;
414
+ exports.default = index_default;
415
+ exports.getConfig = getConfig;
416
+ exports.isConfigured = isConfigured;
417
+ //# sourceMappingURL=index.js.map
418
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts","../src/utils.ts","../src/hooks/use-fetch.ts","../src/hooks/use-mutation.ts","../src/hooks/use-paginate.ts","../src/index.ts"],"names":["useState","useRef","useMemo","useCallback","error","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import type { ApiClientConfig } from './types';\n\nlet globalConfig: ApiClientConfig | null = null;\n\n/**\n * Configure the API client globally\n * @param config - API client configuration\n *\n * @example\n * import { configureApiClient } from '@krymskyimaksym/react-api-client';\n * import { router } from 'expo-router';\n *\n * configureApiClient({\n * httpClient: myHttpClient,\n * onUnauthorized: () => router.replace('/login')\n * });\n */\nexport function configureApiClient(config: ApiClientConfig): void {\n globalConfig = config;\n}\n\n/**\n * Get the current global configuration\n * @throws Error if configuration is not set\n */\nexport function getConfig(): ApiClientConfig {\n if (!globalConfig) {\n throw new Error(\n 'API client is not configured. Call configureApiClient() first.',\n );\n }\n return globalConfig;\n}\n\n/**\n * Check if the API client is configured\n */\nexport function isConfigured(): boolean {\n return globalConfig !== null;\n}\n","import { getConfig } from './config';\n\nimport type { RequestConfig, ResponseWrapper } from './types';\n\n/**\n * Builds the endpoint URL from a string or function\n */\nexport function buildEndpoint<RequestParamsType>(\n endpoint: string | ((arg0: RequestParamsType) => string),\n params?: RequestParamsType,\n): string {\n if (typeof endpoint === 'function' && typeof params !== 'undefined') {\n return endpoint(params);\n }\n return endpoint as string;\n}\n\n/**\n * Executes an HTTP request with error handling and response wrapping\n */\nexport async function executeRequest<\n ResponseType,\n RequestParamsType,\n ErrorResponseType,\n>(\n endpoint: string | ((arg0: RequestParamsType) => string),\n fetchConfig: RequestConfig,\n params?: RequestParamsType,\n): Promise<ResponseWrapper<ResponseType, ErrorResponseType>> {\n type RT = ResponseWrapper<ResponseType, ErrorResponseType>;\n const url = buildEndpoint(endpoint, params);\n const config = getConfig();\n\n try {\n const requestConfig = { ...fetchConfig };\n let response: ResponseType;\n\n if (\n requestConfig.method?.toUpperCase() === 'GET' ||\n !requestConfig.method\n ) {\n response = await config.httpClient.get<ResponseType>(url, {\n params: {\n ...requestConfig.requestParams,\n ...(params as Record<string, string>),\n },\n });\n } else {\n response = await config.httpClient.request<ResponseType>(url, {\n method: requestConfig.method,\n data: {\n ...requestConfig.requestParams,\n ...(params as Record<string, unknown>),\n },\n });\n }\n\n return { ...response, status: true } as RT;\n } catch (e) {\n const error = e as {\n response?: { status: number; data: ErrorResponseType };\n };\n\n if (error.response?.status === 401 && config.onUnauthorized) {\n await config.onUnauthorized();\n }\n\n if (error.response?.data) {\n return {\n ...(error.response.data as Record<string, unknown>),\n status: false,\n } as unknown as RT;\n }\n\n return {\n status: false,\n message: error instanceof Error ? error.message : 'Request error',\n } as unknown as RT;\n }\n}\n\n/**\n * Handles response success and error callbacks\n */\nexport function handleResponse<T, E = unknown>(\n result: ResponseWrapper<T, E>,\n onSuccess?: (data: ResponseWrapper<T, E>) => void,\n onError?: (error: Error) => void,\n): void {\n if (result.status && onSuccess) {\n onSuccess(result);\n } else if (!result.status && onError) {\n const err = new Error(result.message ?? 'Request failed');\n onError(err);\n }\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { executeRequest, handleResponse } from '../utils';\n\nimport type {\n RequestConfig,\n ResponseWrapper,\n UseFetchOptions,\n UseFetchResult,\n} from '../types/index';\n\n/**\n * Hook for fetching data (GET requests)\n */\nexport function createUseFetch<\n ResponseType,\n RequestParamsType,\n ErrorResponseType,\n>(\n endpoint: string | ((arg0: RequestParamsType) => string),\n fetchConfig: RequestConfig,\n) {\n type RT = ResponseWrapper<ResponseType, ErrorResponseType>;\n\n return (\n params?: RequestParamsType,\n options: UseFetchOptions<RT> = {},\n ): UseFetchResult<RT> => {\n const {\n enabled = true,\n refetchOnMount = true,\n onSuccess,\n onError,\n } = options;\n\n const [data, setData] = useState<RT | null>(null);\n const [isLoading, setIsLoading] = useState(enabled && refetchOnMount);\n const [isRefetching, setIsRefetching] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const isMountedRef = useRef(true);\n\n // Serialize params to avoid unnecessary re-renders\n const serializedParams = useMemo(\n () => (params ? JSON.stringify(params) : null),\n [params],\n );\n\n const fetchData = useCallback(\n async (isRefetch = false) => {\n if (!enabled) return;\n\n try {\n if (isRefetch) {\n setIsRefetching(true);\n } else {\n setIsLoading(true);\n }\n setError(null);\n\n const parsedParams = serializedParams\n ? JSON.parse(serializedParams)\n : undefined;\n\n const result = await executeRequest<\n ResponseType,\n RequestParamsType,\n ErrorResponseType\n >(endpoint, fetchConfig, parsedParams);\n\n if (isMountedRef.current) {\n setData(result);\n handleResponse<ResponseType, ErrorResponseType>(\n result,\n onSuccess,\n onError,\n );\n }\n } catch (err) {\n const error = err as Error;\n if (isMountedRef.current) {\n setError(error);\n if (onError) {\n onError(error);\n }\n }\n } finally {\n if (isMountedRef.current) {\n if (isRefetch) {\n setIsRefetching(false);\n } else {\n setIsLoading(false);\n }\n }\n }\n },\n [enabled, serializedParams, onSuccess, onError],\n );\n\n const refetch = useCallback(async () => {\n await fetchData(true);\n }, [fetchData]);\n\n useEffect(() => {\n isMountedRef.current = true;\n\n if (enabled && refetchOnMount) {\n void fetchData(false);\n }\n\n return () => {\n isMountedRef.current = false;\n };\n }, [enabled, refetchOnMount, fetchData]);\n\n return {\n data,\n isLoading,\n isRefetching,\n error,\n refetch,\n };\n };\n}\n","import { useCallback, useState } from 'react';\n\nimport { executeRequest } from '../utils';\n\nimport type {\n RequestConfig,\n ResponseWrapper,\n UseMutationOptions,\n UseMutationResult,\n} from '../types/index';\n\n/**\n * Hook for mutations (POST/PUT/PATCH/DELETE requests)\n */\nexport function createUseMutation<\n ResponseType,\n RequestParamsType,\n ErrorResponseType,\n>(\n endpoint: string | ((arg0: RequestParamsType) => string),\n fetchConfig: RequestConfig,\n) {\n type RT = ResponseWrapper<ResponseType, ErrorResponseType>;\n\n return (\n options: UseMutationOptions<RT, RequestParamsType> = {},\n ): UseMutationResult<RT, RequestParamsType> => {\n const { onMutate, onSuccess, onError, onSettled } = options;\n\n const [data, setData] = useState<RT | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [isSuccess, setIsSuccess] = useState(false);\n const [isError, setIsError] = useState(false);\n\n const reset = useCallback(() => {\n setData(null);\n setError(null);\n setIsLoading(false);\n setIsSuccess(false);\n setIsError(false);\n }, []);\n\n const mutateAsync = useCallback(\n async (variables: RequestParamsType): Promise<RT> => {\n setIsLoading(true);\n setIsSuccess(false);\n setIsError(false);\n setError(null);\n\n try {\n // onMutate callback\n if (onMutate) {\n await onMutate(variables);\n }\n\n const result = await executeRequest<\n ResponseType,\n RequestParamsType,\n ErrorResponseType\n >(endpoint, fetchConfig, variables);\n\n setData(result);\n\n if (result.status) {\n setIsSuccess(true);\n // onSuccess callback\n if (onSuccess) {\n await onSuccess(result, variables);\n }\n } else {\n const err = new Error(result.message ?? 'Mutation failed');\n setIsError(true);\n setError(err);\n // onError callback\n if (onError) {\n await onError(err, variables);\n }\n }\n\n // onSettled callback (always called)\n if (onSettled) {\n await onSettled(result, null, variables);\n }\n\n return result;\n } catch (err) {\n const error = err as Error;\n setError(error);\n setIsError(true);\n setIsSuccess(false);\n\n // onError callback\n if (onError) {\n await onError(error, variables);\n }\n\n // onSettled callback (always called)\n if (onSettled) {\n await onSettled(null, error, variables);\n }\n\n throw error;\n } finally {\n setIsLoading(false);\n }\n },\n [onMutate, onSuccess, onError, onSettled],\n );\n\n const mutateSync = useCallback(\n (variables: RequestParamsType) => {\n void mutateAsync(variables);\n },\n [mutateAsync],\n );\n\n return {\n data,\n error,\n isLoading,\n isSuccess,\n isError,\n mutate: mutateSync,\n mutateAsync,\n reset,\n };\n };\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { executeRequest, handleResponse } from '../utils';\n\nimport type {\n RequestConfig,\n ResponseWrapper,\n UsePaginateOptions,\n UsePaginateResult,\n} from '../types/index';\n\n/**\n * Hook for paginated data fetching\n */\nexport function createUsePaginate<\n ResponseType extends { data: TData; total?: number; page?: number },\n TData extends unknown[],\n RequestParamsType,\n ErrorResponseType,\n>(\n endpoint: string | ((arg0: RequestParamsType) => string),\n fetchConfig: RequestConfig,\n options?: {\n dataExtractor?: (response: ResponseType) => TData;\n totalExtractor?: (response: ResponseType) => number;\n },\n) {\n return (\n params?: Omit<RequestParamsType, 'page' | 'limit'>,\n hookOptions: UsePaginateOptions<\n ResponseWrapper<ResponseType, ErrorResponseType>\n > = {},\n ): UsePaginateResult<TData> => {\n const {\n enabled = true,\n initialPage = 1,\n initialLimit = 20,\n onSuccess,\n onError,\n } = hookOptions;\n\n const [data, setData] = useState<TData>([] as unknown as TData);\n const [currentPage, setCurrentPage] = useState(initialPage);\n const [totalPages, setTotalPages] = useState<number | null>(null);\n const [total, setTotal] = useState<number | null>(null);\n const [isLoading, setIsLoading] = useState(enabled);\n const [isFetchingNextPage, setIsFetchingNextPage] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const isMountedRef = useRef(true);\n const limit = initialLimit;\n\n const dataExtractor = useMemo(\n () =>\n options?.dataExtractor || ((response: ResponseType) => response.data),\n [],\n );\n\n const totalExtractor = useMemo(\n () =>\n options?.totalExtractor ||\n ((response: ResponseType) => response.total ?? 0),\n [],\n );\n\n const serializedParams = useMemo(\n () => (params ? JSON.stringify(params) : null),\n [params],\n );\n\n const fetchPage = useCallback(\n async (page: number, append = false) => {\n if (!enabled) return;\n\n try {\n if (append) {\n setIsFetchingNextPage(true);\n } else {\n setIsLoading(true);\n }\n setError(null);\n\n const parsedParams = serializedParams\n ? JSON.parse(serializedParams)\n : {};\n const requestParams = {\n ...parsedParams,\n page,\n limit,\n } as RequestParamsType;\n\n const result = await executeRequest<\n ResponseType,\n RequestParamsType,\n ErrorResponseType\n >(endpoint, fetchConfig, requestParams);\n\n if (isMountedRef.current) {\n handleResponse<ResponseType, ErrorResponseType>(\n result,\n onSuccess,\n onError,\n );\n\n if (!result.status) {\n const err = new Error(result.message ?? 'Request failed');\n setError(err);\n return;\n }\n\n const newData = dataExtractor(result as ResponseType);\n const totalCount = totalExtractor(result as ResponseType);\n\n if (append) {\n setData(prevData => [...prevData, ...newData] as TData);\n } else {\n setData(newData);\n }\n\n setCurrentPage(page);\n setTotal(totalCount);\n setTotalPages(Math.ceil(totalCount / limit));\n }\n } catch (err) {\n const error = err as Error;\n if (isMountedRef.current) {\n setError(error);\n if (onError) {\n onError(error);\n }\n }\n } finally {\n if (isMountedRef.current) {\n if (append) {\n setIsFetchingNextPage(false);\n } else {\n setIsLoading(false);\n }\n }\n }\n },\n [\n enabled,\n serializedParams,\n limit,\n onSuccess,\n onError,\n dataExtractor,\n totalExtractor,\n ],\n );\n\n const hasNextPage = totalPages !== null && currentPage < totalPages;\n const hasPreviousPage = currentPage > 1;\n\n const fetchNextPage = useCallback(async () => {\n if (!hasNextPage) return;\n await fetchPage(currentPage + 1, true);\n }, [hasNextPage, currentPage, fetchPage]);\n\n const fetchPreviousPage = useCallback(async () => {\n if (!hasPreviousPage) return;\n await fetchPage(currentPage - 1, false);\n }, [hasPreviousPage, currentPage, fetchPage]);\n\n const refetch = useCallback(async () => {\n await fetchPage(currentPage, false);\n }, [currentPage, fetchPage]);\n\n const reset = useCallback(() => {\n setData([] as unknown as TData);\n setCurrentPage(initialPage);\n setTotalPages(null);\n setTotal(null);\n setError(null);\n void fetchPage(initialPage, false);\n }, [initialPage, fetchPage]);\n\n useEffect(() => {\n isMountedRef.current = true;\n\n if (enabled) {\n void fetchPage(initialPage, false);\n }\n\n return () => {\n isMountedRef.current = false;\n };\n }, [enabled, serializedParams, fetchPage, initialPage]);\n\n return {\n data,\n currentPage,\n totalPages,\n total,\n hasNextPage,\n hasPreviousPage,\n isLoading,\n isFetchingNextPage,\n error,\n fetchNextPage,\n fetchPreviousPage,\n refetch,\n reset,\n };\n };\n}\n","import { executeRequest } from './utils';\n\nimport { createUseFetch, createUseMutation, createUsePaginate } from './hooks';\n\nimport type {\n ApiClientReturn,\n ApiMutationReturn,\n ApiPaginateReturn,\n RequestConfig,\n ResponseWrapper,\n} from './types';\n\n/**\n * Creates an API client for GET requests\n * @param endpoint - URL string or function that generates URL from params\n * @param fetchConfig - Request configuration\n * @returns Object with fetch method and useFetch hook\n *\n * @example\n * const userApi = apiClient<User, { id: string }>('/api/users/:id')\n * const { data } = userApi.useFetch({ id: '123' })\n */\nfunction apiClient<\n ResponseType = void,\n RequestParamsType = void,\n ErrorResponseType = unknown,\n>(\n endpoint: string | ((arg0: RequestParamsType) => string),\n fetchConfig: RequestConfig = {},\n): ApiClientReturn<ResponseType, RequestParamsType, ErrorResponseType> {\n type RT = ResponseWrapper<ResponseType, ErrorResponseType>;\n\n const fetch = async (params?: RequestParamsType): Promise<RT> => {\n return executeRequest<ResponseType, RequestParamsType, ErrorResponseType>(\n endpoint,\n fetchConfig,\n params,\n );\n };\n\n const useFetch = createUseFetch<\n ResponseType,\n RequestParamsType,\n ErrorResponseType\n >(endpoint, fetchConfig);\n\n return { fetch, useFetch };\n}\n\n/**\n * Creates an API client for mutation requests (POST/PUT/PATCH/DELETE)\n * @param endpoint - URL string or function that generates URL from params\n * @param fetchConfig - Request configuration\n * @returns Object with mutate method and useMutation hook\n *\n * @example\n * const createUserApi = apiMutation<User, CreateUserRequest>('/api/users', { method: 'POST' })\n * const { mutate, isLoading } = createUserApi.useMutation()\n */\nfunction apiMutation<\n ResponseType = void,\n RequestParamsType = void,\n ErrorResponseType = unknown,\n>(\n endpoint: string | ((arg0: RequestParamsType) => string),\n fetchConfig: RequestConfig = {},\n): ApiMutationReturn<ResponseType, RequestParamsType, ErrorResponseType> {\n type RT = ResponseWrapper<ResponseType, ErrorResponseType>;\n\n const mutate = async (params?: RequestParamsType): Promise<RT> => {\n return executeRequest<ResponseType, RequestParamsType, ErrorResponseType>(\n endpoint,\n fetchConfig,\n params,\n );\n };\n\n const useMutation = createUseMutation<\n ResponseType,\n RequestParamsType,\n ErrorResponseType\n >(endpoint, fetchConfig);\n\n return { mutate, useMutation };\n}\n\n/**\n * Creates an API client for paginated requests\n * @param endpoint - URL string or function that generates URL from params\n * @param fetchConfig - Request configuration\n * @param options - Pagination options (data/total extractors)\n * @returns Object with usePaginate hook\n *\n * @example\n * const usersApi = apiPaginate<UsersResponse, User[], { search?: string }>('/api/users')\n * const { data, fetchNextPage, hasNextPage } = usersApi.usePaginate()\n */\nfunction apiPaginate<\n ResponseType extends { data: TData; total?: number; page?: number },\n TData extends unknown[],\n RequestParamsType = void,\n ErrorResponseType = unknown,\n>(\n endpoint: string | ((arg0: RequestParamsType) => string),\n fetchConfig: RequestConfig = {},\n options?: {\n dataExtractor?: (response: ResponseType) => TData;\n totalExtractor?: (response: ResponseType) => number;\n },\n): ApiPaginateReturn<\n ResponseType,\n RequestParamsType,\n TData,\n ErrorResponseType\n> {\n const usePaginate = createUsePaginate<\n ResponseType,\n TData,\n RequestParamsType,\n ErrorResponseType\n >(endpoint, fetchConfig, options);\n\n return { usePaginate };\n}\n\nexport default apiClient;\nexport { apiMutation, apiPaginate };\n\n// Export configuration\nexport { configureApiClient, getConfig, isConfigured } from './config';\n\n// Re-export types for convenience\nexport type {\n ResponseWrapper,\n UseFetchOptions,\n UseFetchResult,\n UseMutationOptions,\n UseMutationResult,\n UsePaginateOptions,\n UsePaginateResult,\n ApiClientConfig,\n IHttpClient,\n} from './types';\n"]}