api-core-lib 3.2.2 → 3.3.3

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.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { ResponseType, AxiosRequestConfig, AxiosProgressEvent, AxiosInstance, AxiosResponse } from 'axios';
1
+ import { ResponseType, AxiosRequestConfig, AxiosProgressEvent, AxiosInstance, Method, AxiosResponse } from 'axios';
2
2
  import * as react from 'react';
3
3
 
4
4
  /**
@@ -18,15 +18,6 @@ interface PaginationMeta {
18
18
  currentPage: number;
19
19
  totalPages: number;
20
20
  }
21
- /**
22
- * يمثل بنية الاستجابة القياسية من الـ API.
23
- * @template T نوع البيانات الأساسية في الاستجابة.
24
- */
25
- interface ApiResponse<T = any> {
26
- data: T;
27
- message?: string;
28
- meta?: PaginationMeta;
29
- }
30
21
  /**
31
22
  * يمثل خطأ التحقق من صحة حقل معين.
32
23
  */
@@ -44,18 +35,6 @@ interface ApiError {
44
35
  errors?: ValidationError[];
45
36
  requestId?: string;
46
37
  }
47
- /**
48
- * يمثل كائن الاستجابة الموحد الذي يرجعه كل طلب.
49
- * @template T نوع البيانات المتوقعة في حالة النجاح.
50
- */
51
- interface StandardResponse<T> {
52
- response?: ApiResponse<T> | T;
53
- error: ApiError | null;
54
- loading: boolean;
55
- success: boolean;
56
- message?: string;
57
- validationErrors?: ValidationError[];
58
- }
59
38
  /**
60
39
  * يمثل مجموعة التوكنات التي يتم إدارتها.
61
40
  */
@@ -96,19 +75,6 @@ interface PaginateQueryOptions {
96
75
  }[];
97
76
  filter?: Record<string, any>;
98
77
  }
99
- /**
100
- * واجهة لتهيئة الهوك `useApi`.
101
- * @template T نوع البيانات التي يتعامل معها الهوك.
102
- */
103
- interface UseApiConfig<T> {
104
- endpoint: string;
105
- initialData?: T | T[];
106
- initialQuery?: PaginateQueryOptions;
107
- enabled?: boolean;
108
- refetchAfterChange?: boolean;
109
- onSuccess?: (message: string, data?: T) => void;
110
- onError?: (message: string, error?: ApiError) => void;
111
- }
112
78
  /**
113
79
  * واجهة لتخصيص عملية تجديد التوكن بشكل كامل.
114
80
  */
@@ -162,6 +128,82 @@ interface ApiClientConfig {
162
128
  refreshTokenConfig?: RefreshTokenConfig;
163
129
  onRefreshError?: (error: any) => void;
164
130
  }
131
+ /**
132
+ * يمثل بنية الاستجابة القياسية من الـ API.
133
+ * @template T نوع البيانات الأساسية في الاستجابة.
134
+ */
135
+ interface ApiResponse<T = any> {
136
+ data: T;
137
+ message?: string;
138
+ meta?: PaginationMeta;
139
+ }
140
+ /**
141
+ * يمثل بنية الاستجابة القياسية المغلفة التي قد تأتي من بعض نقاط الـ API.
142
+ * @template T نوع البيانات الأساسية في الاستجابة.
143
+ */
144
+ interface ApiResponse<T = any> {
145
+ data: T;
146
+ message?: string;
147
+ meta?: PaginationMeta;
148
+ success?: boolean;
149
+ }
150
+ /**
151
+ * يمثل كائن الاستجابة الموحد والنهائي الذي يرجعه كل طلب.
152
+ * هذا هو النوع الذي ستتعامل معه دائمًا.
153
+ * @template T نوع البيانات النهائية التي تريد الوصول إليها.
154
+ */
155
+ interface StandardResponse<T> {
156
+ data: T | null;
157
+ rawResponse: any;
158
+ error: ApiError | null;
159
+ loading: boolean;
160
+ success: boolean;
161
+ message?: string;
162
+ validationErrors?: ValidationError[];
163
+ }
164
+ /**
165
+ * NEW: واجهة استعلام مرنة تسمح بالبارامترات القياسية (للفلترة والترقيم)
166
+ * بالإضافة إلى أي بارامترات مخصصة أخرى عبر الـ index signature.
167
+ * @example
168
+ * { page: 1, limit: 10, search: 'term', status: 'published', authorId: 123 }
169
+ */
170
+ interface QueryOptions {
171
+ page?: number;
172
+ limit?: number;
173
+ search?: string;
174
+ sortBy?: {
175
+ key: string;
176
+ direction: 'asc' | 'desc';
177
+ }[];
178
+ filter?: Record<string, any>;
179
+ [key: string]: any;
180
+ }
181
+ /**
182
+ * NEW: واجهة لتمرير خيارات إضافية لدوال الأكشن (create, update, remove).
183
+ */
184
+ interface ActionOptions {
185
+ /**
186
+ * يسمح لك بتجاوز الـ endpoint الافتراضي المحدد في الهوك.
187
+ * مفيد لإرسال طلبات لنقاط نهاية متخصصة.
188
+ * @example
189
+ * // لتحديث عنصر وتغيير حالته عبر مسار مختلف
190
+ * update('123', { status: 'active' }, { endpoint: '/items/123/activate' })
191
+ */
192
+ endpoint?: string;
193
+ }
194
+ /**
195
+ * واجهة لتهيئة الهوك `useApi`.
196
+ * @template T نوع البيانات التي يتعامل معها الهوك.
197
+ */
198
+ interface UseApiConfig<T> {
199
+ endpoint: string;
200
+ initialData?: T | T[];
201
+ initialQuery?: QueryOptions;
202
+ enabled?: boolean;
203
+ refetchAfterChange?: boolean;
204
+ onSuccess?: (message: string, data?: T) => void;
205
+ onError?: (message: string, error?: ApiError) => void;
206
+ }
165
207
 
166
208
  /**
167
209
  * @file src/core/client.ts
@@ -173,12 +215,13 @@ interface ApiClientConfig {
173
215
 
174
216
  declare function createApiClient(config: ApiClientConfig): AxiosInstance;
175
217
 
218
+ type CrudRequestConfig = RequestConfig & ActionOptions;
176
219
  declare function createApiServices<T>(axiosInstance: AxiosInstance, endpoint: string): {
177
220
  get: (id?: string, config?: RequestConfig) => Promise<StandardResponse<T | T[]>>;
178
221
  getWithQuery: (query: string, config?: RequestConfig) => Promise<StandardResponse<T[]>>;
179
- post: (data: Partial<T>, config?: RequestConfig) => Promise<StandardResponse<T>>;
180
- patch: (id: string, data: Partial<T>, config?: RequestConfig) => Promise<StandardResponse<T>>;
181
- remove: (id: string, config?: RequestConfig) => Promise<StandardResponse<any>>;
222
+ post: (data: Partial<T>, config?: CrudRequestConfig) => Promise<StandardResponse<T>>;
223
+ patch: (id: string, data: Partial<T>, config?: CrudRequestConfig) => Promise<StandardResponse<T>>;
224
+ remove: (id: string, config?: CrudRequestConfig) => Promise<StandardResponse<any>>;
182
225
  };
183
226
 
184
227
  /**
@@ -189,7 +232,46 @@ declare function createApiServices<T>(axiosInstance: AxiosInstance, endpoint: st
189
232
  * بالإضافة إلى دوال التحقق من الأنواع (type guards).
190
233
  */
191
234
 
192
- declare function buildPaginateQuery(query: PaginateQueryOptions): string;
235
+ /**
236
+ * يبني سلسلة استعلام (query string) من كائن خيارات مرن.
237
+ * يتعامل مع البارامترات القياسية والمخصصة.
238
+ * @param query - كائن من نوع QueryOptions.
239
+ * @returns سلسلة استعلام جاهزة للإضافة للرابط.
240
+ */
241
+ declare function buildPaginateQuery(query: QueryOptions): string;
242
+
243
+ /**
244
+ * Defines a single custom API action.
245
+ * @template TRequest - The type of the data sent in the request body/params.
246
+ * @template TResponse - The type of the data expected in the successful API response.
247
+ */
248
+ type ApiAction<TRequest, TResponse> = (payload: TRequest, config?: RequestConfig) => Promise<StandardResponse<TResponse>>;
249
+ /**
250
+ * A factory function to create a collection of typed, custom API actions.
251
+ *
252
+ * @template TActions - An object type where keys are action names and values are objects
253
+ * defining the endpoint, method, and types for that action.
254
+ * @param axiosInstance - The configured Axios instance from `createApiClient`.
255
+ * @param actionsConfig - An object defining the configuration for each custom action.
256
+ * @returns A fully-typed object of executable API action functions.
257
+ *
258
+ * @example
259
+ * const authActions = createApiActions(apiClient, {
260
+ * login: { method: 'POST', endpoint: '/auth/login', requestType: {} as LoginCredentials, responseType: {} as AuthResponse },
261
+ * getProfile: { method: 'GET', endpoint: '/user/profile', requestType: {} as void, responseType: {} as UserProfile }
262
+ * });
263
+ *
264
+ * // Usage:
265
+ * const result = await authActions.login({ email: '..', password: '..' });
266
+ */
267
+ declare function createApiActions<TActions extends Record<string, {
268
+ method: Method;
269
+ endpoint: string;
270
+ requestType: any;
271
+ responseType: any;
272
+ }>>(axiosInstance: AxiosInstance, actionsConfig: TActions): {
273
+ [K in keyof TActions]: ApiAction<TActions[K]['requestType'], TActions[K]['responseType']>;
274
+ };
193
275
 
194
276
  declare class CacheManager {
195
277
  private cache;
@@ -202,12 +284,15 @@ declare class CacheManager {
202
284
  declare const cacheManager: CacheManager;
203
285
 
204
286
  /**
205
- * @file src/core/processor.ts
206
- * @description
207
- * ...
287
+ * A smart response processor that normalizes API responses.
288
+ * It intelligently unwraps nested data from standard API envelopes
289
+ * (like { success: true, data: {...} }) and provides direct access
290
+ * to the core data, while still handling errors consistently.
291
+ *
292
+ * @param responseOrError The raw Axios response or a pre-processed ApiError.
293
+ * @returns A standardized `StandardResponse` object with direct access to `.data`.
208
294
  */
209
-
210
- declare const processResponse: <T>(responseOrError: AxiosResponse<ApiResponse<T>> | ApiError) => StandardResponse<T>;
295
+ declare const processResponse: <T>(responseOrError: AxiosResponse<any> | ApiError) => StandardResponse<T>;
211
296
 
212
297
  declare function useApi<T extends {
213
298
  id?: string | number;
@@ -215,14 +300,14 @@ declare function useApi<T extends {
215
300
  state: StandardResponse<T | T[]>;
216
301
  setState: react.Dispatch<react.SetStateAction<StandardResponse<T | T[]>>>;
217
302
  actions: {
218
- fetch: () => Promise<void>;
219
- create: (newItem: Partial<T>) => Promise<StandardResponse<T>>;
220
- update: (id: string, updatedItem: Partial<T>) => Promise<StandardResponse<T>>;
221
- remove: (id: string) => Promise<StandardResponse<any>>;
303
+ fetch: (options?: QueryOptions) => Promise<void>;
304
+ create: (newItem: Partial<T>, options?: ActionOptions) => Promise<StandardResponse<T>>;
305
+ update: (id: string, updatedItem: Partial<T>, options?: ActionOptions) => Promise<StandardResponse<T>>;
306
+ remove: (id: string, options?: ActionOptions) => Promise<StandardResponse<any>>;
222
307
  };
223
308
  query: {
224
- options: PaginateQueryOptions;
225
- setOptions: react.Dispatch<react.SetStateAction<PaginateQueryOptions>>;
309
+ options: QueryOptions;
310
+ setOptions: react.Dispatch<react.SetStateAction<QueryOptions>>;
226
311
  setPage: (page: number) => void;
227
312
  setLimit: (limit: number) => void;
228
313
  setSearchTerm: (search: string) => void;
@@ -231,8 +316,9 @@ declare function useApi<T extends {
231
316
  direction: "asc" | "desc";
232
317
  }[]) => void;
233
318
  setFilters: (filter: Record<string, any>) => void;
319
+ setQueryParam: (key: string, value: any) => void;
234
320
  reset: () => void;
235
321
  };
236
322
  };
237
323
 
238
- export { type ApiClientConfig, type ApiError, type ApiResponse, type PaginateQueryOptions, type PaginationMeta, type RefreshTokenConfig, type RequestConfig, type StandardResponse, type TokenManager, type Tokens, type UseApiConfig, type ValidationError, buildPaginateQuery, cacheManager, createApiClient, createApiServices, processResponse, useApi };
324
+ export { type ActionOptions, type ApiClientConfig, type ApiError, type ApiResponse, type PaginateQueryOptions, type PaginationMeta, type QueryOptions, type RefreshTokenConfig, type RequestConfig, type StandardResponse, type TokenManager, type Tokens, type UseApiConfig, type ValidationError, buildPaginateQuery, cacheManager, createApiActions, createApiClient, createApiServices, processResponse, useApi };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ResponseType, AxiosRequestConfig, AxiosProgressEvent, AxiosInstance, AxiosResponse } from 'axios';
1
+ import { ResponseType, AxiosRequestConfig, AxiosProgressEvent, AxiosInstance, Method, AxiosResponse } from 'axios';
2
2
  import * as react from 'react';
3
3
 
4
4
  /**
@@ -18,15 +18,6 @@ interface PaginationMeta {
18
18
  currentPage: number;
19
19
  totalPages: number;
20
20
  }
21
- /**
22
- * يمثل بنية الاستجابة القياسية من الـ API.
23
- * @template T نوع البيانات الأساسية في الاستجابة.
24
- */
25
- interface ApiResponse<T = any> {
26
- data: T;
27
- message?: string;
28
- meta?: PaginationMeta;
29
- }
30
21
  /**
31
22
  * يمثل خطأ التحقق من صحة حقل معين.
32
23
  */
@@ -44,18 +35,6 @@ interface ApiError {
44
35
  errors?: ValidationError[];
45
36
  requestId?: string;
46
37
  }
47
- /**
48
- * يمثل كائن الاستجابة الموحد الذي يرجعه كل طلب.
49
- * @template T نوع البيانات المتوقعة في حالة النجاح.
50
- */
51
- interface StandardResponse<T> {
52
- response?: ApiResponse<T> | T;
53
- error: ApiError | null;
54
- loading: boolean;
55
- success: boolean;
56
- message?: string;
57
- validationErrors?: ValidationError[];
58
- }
59
38
  /**
60
39
  * يمثل مجموعة التوكنات التي يتم إدارتها.
61
40
  */
@@ -96,19 +75,6 @@ interface PaginateQueryOptions {
96
75
  }[];
97
76
  filter?: Record<string, any>;
98
77
  }
99
- /**
100
- * واجهة لتهيئة الهوك `useApi`.
101
- * @template T نوع البيانات التي يتعامل معها الهوك.
102
- */
103
- interface UseApiConfig<T> {
104
- endpoint: string;
105
- initialData?: T | T[];
106
- initialQuery?: PaginateQueryOptions;
107
- enabled?: boolean;
108
- refetchAfterChange?: boolean;
109
- onSuccess?: (message: string, data?: T) => void;
110
- onError?: (message: string, error?: ApiError) => void;
111
- }
112
78
  /**
113
79
  * واجهة لتخصيص عملية تجديد التوكن بشكل كامل.
114
80
  */
@@ -162,6 +128,82 @@ interface ApiClientConfig {
162
128
  refreshTokenConfig?: RefreshTokenConfig;
163
129
  onRefreshError?: (error: any) => void;
164
130
  }
131
+ /**
132
+ * يمثل بنية الاستجابة القياسية من الـ API.
133
+ * @template T نوع البيانات الأساسية في الاستجابة.
134
+ */
135
+ interface ApiResponse<T = any> {
136
+ data: T;
137
+ message?: string;
138
+ meta?: PaginationMeta;
139
+ }
140
+ /**
141
+ * يمثل بنية الاستجابة القياسية المغلفة التي قد تأتي من بعض نقاط الـ API.
142
+ * @template T نوع البيانات الأساسية في الاستجابة.
143
+ */
144
+ interface ApiResponse<T = any> {
145
+ data: T;
146
+ message?: string;
147
+ meta?: PaginationMeta;
148
+ success?: boolean;
149
+ }
150
+ /**
151
+ * يمثل كائن الاستجابة الموحد والنهائي الذي يرجعه كل طلب.
152
+ * هذا هو النوع الذي ستتعامل معه دائمًا.
153
+ * @template T نوع البيانات النهائية التي تريد الوصول إليها.
154
+ */
155
+ interface StandardResponse<T> {
156
+ data: T | null;
157
+ rawResponse: any;
158
+ error: ApiError | null;
159
+ loading: boolean;
160
+ success: boolean;
161
+ message?: string;
162
+ validationErrors?: ValidationError[];
163
+ }
164
+ /**
165
+ * NEW: واجهة استعلام مرنة تسمح بالبارامترات القياسية (للفلترة والترقيم)
166
+ * بالإضافة إلى أي بارامترات مخصصة أخرى عبر الـ index signature.
167
+ * @example
168
+ * { page: 1, limit: 10, search: 'term', status: 'published', authorId: 123 }
169
+ */
170
+ interface QueryOptions {
171
+ page?: number;
172
+ limit?: number;
173
+ search?: string;
174
+ sortBy?: {
175
+ key: string;
176
+ direction: 'asc' | 'desc';
177
+ }[];
178
+ filter?: Record<string, any>;
179
+ [key: string]: any;
180
+ }
181
+ /**
182
+ * NEW: واجهة لتمرير خيارات إضافية لدوال الأكشن (create, update, remove).
183
+ */
184
+ interface ActionOptions {
185
+ /**
186
+ * يسمح لك بتجاوز الـ endpoint الافتراضي المحدد في الهوك.
187
+ * مفيد لإرسال طلبات لنقاط نهاية متخصصة.
188
+ * @example
189
+ * // لتحديث عنصر وتغيير حالته عبر مسار مختلف
190
+ * update('123', { status: 'active' }, { endpoint: '/items/123/activate' })
191
+ */
192
+ endpoint?: string;
193
+ }
194
+ /**
195
+ * واجهة لتهيئة الهوك `useApi`.
196
+ * @template T نوع البيانات التي يتعامل معها الهوك.
197
+ */
198
+ interface UseApiConfig<T> {
199
+ endpoint: string;
200
+ initialData?: T | T[];
201
+ initialQuery?: QueryOptions;
202
+ enabled?: boolean;
203
+ refetchAfterChange?: boolean;
204
+ onSuccess?: (message: string, data?: T) => void;
205
+ onError?: (message: string, error?: ApiError) => void;
206
+ }
165
207
 
166
208
  /**
167
209
  * @file src/core/client.ts
@@ -173,12 +215,13 @@ interface ApiClientConfig {
173
215
 
174
216
  declare function createApiClient(config: ApiClientConfig): AxiosInstance;
175
217
 
218
+ type CrudRequestConfig = RequestConfig & ActionOptions;
176
219
  declare function createApiServices<T>(axiosInstance: AxiosInstance, endpoint: string): {
177
220
  get: (id?: string, config?: RequestConfig) => Promise<StandardResponse<T | T[]>>;
178
221
  getWithQuery: (query: string, config?: RequestConfig) => Promise<StandardResponse<T[]>>;
179
- post: (data: Partial<T>, config?: RequestConfig) => Promise<StandardResponse<T>>;
180
- patch: (id: string, data: Partial<T>, config?: RequestConfig) => Promise<StandardResponse<T>>;
181
- remove: (id: string, config?: RequestConfig) => Promise<StandardResponse<any>>;
222
+ post: (data: Partial<T>, config?: CrudRequestConfig) => Promise<StandardResponse<T>>;
223
+ patch: (id: string, data: Partial<T>, config?: CrudRequestConfig) => Promise<StandardResponse<T>>;
224
+ remove: (id: string, config?: CrudRequestConfig) => Promise<StandardResponse<any>>;
182
225
  };
183
226
 
184
227
  /**
@@ -189,7 +232,46 @@ declare function createApiServices<T>(axiosInstance: AxiosInstance, endpoint: st
189
232
  * بالإضافة إلى دوال التحقق من الأنواع (type guards).
190
233
  */
191
234
 
192
- declare function buildPaginateQuery(query: PaginateQueryOptions): string;
235
+ /**
236
+ * يبني سلسلة استعلام (query string) من كائن خيارات مرن.
237
+ * يتعامل مع البارامترات القياسية والمخصصة.
238
+ * @param query - كائن من نوع QueryOptions.
239
+ * @returns سلسلة استعلام جاهزة للإضافة للرابط.
240
+ */
241
+ declare function buildPaginateQuery(query: QueryOptions): string;
242
+
243
+ /**
244
+ * Defines a single custom API action.
245
+ * @template TRequest - The type of the data sent in the request body/params.
246
+ * @template TResponse - The type of the data expected in the successful API response.
247
+ */
248
+ type ApiAction<TRequest, TResponse> = (payload: TRequest, config?: RequestConfig) => Promise<StandardResponse<TResponse>>;
249
+ /**
250
+ * A factory function to create a collection of typed, custom API actions.
251
+ *
252
+ * @template TActions - An object type where keys are action names and values are objects
253
+ * defining the endpoint, method, and types for that action.
254
+ * @param axiosInstance - The configured Axios instance from `createApiClient`.
255
+ * @param actionsConfig - An object defining the configuration for each custom action.
256
+ * @returns A fully-typed object of executable API action functions.
257
+ *
258
+ * @example
259
+ * const authActions = createApiActions(apiClient, {
260
+ * login: { method: 'POST', endpoint: '/auth/login', requestType: {} as LoginCredentials, responseType: {} as AuthResponse },
261
+ * getProfile: { method: 'GET', endpoint: '/user/profile', requestType: {} as void, responseType: {} as UserProfile }
262
+ * });
263
+ *
264
+ * // Usage:
265
+ * const result = await authActions.login({ email: '..', password: '..' });
266
+ */
267
+ declare function createApiActions<TActions extends Record<string, {
268
+ method: Method;
269
+ endpoint: string;
270
+ requestType: any;
271
+ responseType: any;
272
+ }>>(axiosInstance: AxiosInstance, actionsConfig: TActions): {
273
+ [K in keyof TActions]: ApiAction<TActions[K]['requestType'], TActions[K]['responseType']>;
274
+ };
193
275
 
194
276
  declare class CacheManager {
195
277
  private cache;
@@ -202,12 +284,15 @@ declare class CacheManager {
202
284
  declare const cacheManager: CacheManager;
203
285
 
204
286
  /**
205
- * @file src/core/processor.ts
206
- * @description
207
- * ...
287
+ * A smart response processor that normalizes API responses.
288
+ * It intelligently unwraps nested data from standard API envelopes
289
+ * (like { success: true, data: {...} }) and provides direct access
290
+ * to the core data, while still handling errors consistently.
291
+ *
292
+ * @param responseOrError The raw Axios response or a pre-processed ApiError.
293
+ * @returns A standardized `StandardResponse` object with direct access to `.data`.
208
294
  */
209
-
210
- declare const processResponse: <T>(responseOrError: AxiosResponse<ApiResponse<T>> | ApiError) => StandardResponse<T>;
295
+ declare const processResponse: <T>(responseOrError: AxiosResponse<any> | ApiError) => StandardResponse<T>;
211
296
 
212
297
  declare function useApi<T extends {
213
298
  id?: string | number;
@@ -215,14 +300,14 @@ declare function useApi<T extends {
215
300
  state: StandardResponse<T | T[]>;
216
301
  setState: react.Dispatch<react.SetStateAction<StandardResponse<T | T[]>>>;
217
302
  actions: {
218
- fetch: () => Promise<void>;
219
- create: (newItem: Partial<T>) => Promise<StandardResponse<T>>;
220
- update: (id: string, updatedItem: Partial<T>) => Promise<StandardResponse<T>>;
221
- remove: (id: string) => Promise<StandardResponse<any>>;
303
+ fetch: (options?: QueryOptions) => Promise<void>;
304
+ create: (newItem: Partial<T>, options?: ActionOptions) => Promise<StandardResponse<T>>;
305
+ update: (id: string, updatedItem: Partial<T>, options?: ActionOptions) => Promise<StandardResponse<T>>;
306
+ remove: (id: string, options?: ActionOptions) => Promise<StandardResponse<any>>;
222
307
  };
223
308
  query: {
224
- options: PaginateQueryOptions;
225
- setOptions: react.Dispatch<react.SetStateAction<PaginateQueryOptions>>;
309
+ options: QueryOptions;
310
+ setOptions: react.Dispatch<react.SetStateAction<QueryOptions>>;
226
311
  setPage: (page: number) => void;
227
312
  setLimit: (limit: number) => void;
228
313
  setSearchTerm: (search: string) => void;
@@ -231,8 +316,9 @@ declare function useApi<T extends {
231
316
  direction: "asc" | "desc";
232
317
  }[]) => void;
233
318
  setFilters: (filter: Record<string, any>) => void;
319
+ setQueryParam: (key: string, value: any) => void;
234
320
  reset: () => void;
235
321
  };
236
322
  };
237
323
 
238
- export { type ApiClientConfig, type ApiError, type ApiResponse, type PaginateQueryOptions, type PaginationMeta, type RefreshTokenConfig, type RequestConfig, type StandardResponse, type TokenManager, type Tokens, type UseApiConfig, type ValidationError, buildPaginateQuery, cacheManager, createApiClient, createApiServices, processResponse, useApi };
324
+ export { type ActionOptions, type ApiClientConfig, type ApiError, type ApiResponse, type PaginateQueryOptions, type PaginationMeta, type QueryOptions, type RefreshTokenConfig, type RequestConfig, type StandardResponse, type TokenManager, type Tokens, type UseApiConfig, type ValidationError, buildPaginateQuery, cacheManager, createApiActions, createApiClient, createApiServices, processResponse, useApi };
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  buildPaginateQuery: () => buildPaginateQuery,
34
34
  cacheManager: () => cacheManager,
35
+ createApiActions: () => createApiActions,
35
36
  createApiClient: () => createApiClient,
36
37
  createApiServices: () => createApiServices,
37
38
  processResponse: () => processResponse,
@@ -163,6 +164,7 @@ var import_axios2 = __toESM(require("axios"));
163
164
  function buildPaginateQuery(query) {
164
165
  if (!query) return "";
165
166
  const params = new URLSearchParams();
167
+ const standardKeys = /* @__PURE__ */ new Set(["page", "limit", "search", "sortBy", "filter"]);
166
168
  if (query.page) params.append("page", query.page.toString());
167
169
  if (query.limit) params.append("limit", query.limit.toString());
168
170
  if (query.search) params.append("search", query.search);
@@ -174,6 +176,14 @@ function buildPaginateQuery(query) {
174
176
  params.append(`filter.${field}`, String(value));
175
177
  });
176
178
  }
179
+ for (const key in query) {
180
+ if (Object.prototype.hasOwnProperty.call(query, key) && !standardKeys.has(key)) {
181
+ const value = query[key];
182
+ if (value !== void 0 && value !== null) {
183
+ params.append(key, String(value));
184
+ }
185
+ }
186
+ }
177
187
  const queryString = params.toString();
178
188
  return queryString ? `?${queryString}` : "";
179
189
  }
@@ -188,37 +198,38 @@ function isAxiosResponse(obj) {
188
198
  var processResponse = (responseOrError) => {
189
199
  if (isApiError(responseOrError)) {
190
200
  return {
191
- response: void 0,
201
+ data: null,
202
+ rawResponse: void 0,
192
203
  error: responseOrError,
193
204
  validationErrors: responseOrError.errors || [],
194
- // الخطأ الآن صحيح
195
205
  success: false,
196
206
  loading: false,
197
207
  message: responseOrError.message
198
208
  };
199
209
  }
200
210
  if (isAxiosResponse(responseOrError)) {
201
- const response = responseOrError;
211
+ const rawData = responseOrError.data;
212
+ const isWrappedResponse = rawData && typeof rawData.success === "boolean" && rawData.data !== void 0;
213
+ const finalData = isWrappedResponse ? rawData.data : rawData;
214
+ const message = isWrappedResponse ? rawData.message : "Request successful.";
202
215
  return {
203
- response: response.data,
216
+ data: finalData,
217
+ // <-- وصول مباشر للبيانات النهائية!
218
+ rawResponse: rawData,
219
+ // احتفظ بالاستجابة الكاملة إذا احتجت إليها
204
220
  loading: false,
205
221
  success: true,
206
222
  error: null,
207
- message: response.data.message || "Request successful.",
223
+ message,
208
224
  validationErrors: []
209
- // <-- أضف قيمة افتراضية هنا للاتساق
210
225
  };
211
226
  }
212
227
  return {
213
- response: void 0,
214
- error: {
215
- message: "An unknown error occurred during response processing.",
216
- status: 500
217
- },
228
+ data: null,
229
+ rawResponse: void 0,
230
+ error: { message: "An unknown error occurred during response processing.", status: 500 },
218
231
  success: false,
219
- loading: false,
220
- validationErrors: []
221
- // <-- أضف قيمة افتراضية هنا أيضًا
232
+ loading: false
222
233
  };
223
234
  };
224
235
 
@@ -242,24 +253,27 @@ function createApiServices(axiosInstance, endpoint) {
242
253
  }
243
254
  };
244
255
  const post = async (data, config) => {
256
+ const finalUrl = config?.endpoint || endpoint;
245
257
  try {
246
- const response = await axiosInstance.post(endpoint, data, config);
258
+ const response = await axiosInstance.post(finalUrl, data, config);
247
259
  return processResponse(response);
248
260
  } catch (error) {
249
261
  return processResponse(error);
250
262
  }
251
263
  };
252
264
  const patch = async (id, data, config) => {
265
+ const finalUrl = config?.endpoint || `${endpoint}/${id}`;
253
266
  try {
254
- const response = await axiosInstance.patch(`${endpoint}/${id}`, data, config);
267
+ const response = await axiosInstance.patch(finalUrl, data, config);
255
268
  return processResponse(response);
256
269
  } catch (error) {
257
270
  return processResponse(error);
258
271
  }
259
272
  };
260
273
  const remove = async (id, config) => {
274
+ const finalUrl = config?.endpoint || `${endpoint}/${id}`;
261
275
  try {
262
- const response = await axiosInstance.delete(`${endpoint}/${id}`, config);
276
+ const response = await axiosInstance.delete(finalUrl, config);
263
277
  return processResponse(response);
264
278
  } catch (error) {
265
279
  return processResponse(error);
@@ -268,6 +282,34 @@ function createApiServices(axiosInstance, endpoint) {
268
282
  return { get, getWithQuery, post, patch, remove };
269
283
  }
270
284
 
285
+ // src/services/actions.ts
286
+ function createAction(axiosInstance, method, endpoint) {
287
+ return async (payload, config) => {
288
+ try {
289
+ const response = await axiosInstance.request({
290
+ // <--- غيرنا النوع إلى any
291
+ url: endpoint,
292
+ method,
293
+ ...method.toUpperCase() === "GET" ? { params: payload } : { data: payload },
294
+ ...config
295
+ });
296
+ return processResponse(response);
297
+ } catch (error) {
298
+ return processResponse(error);
299
+ }
300
+ };
301
+ }
302
+ function createApiActions(axiosInstance, actionsConfig) {
303
+ const actions = {};
304
+ for (const actionName in actionsConfig) {
305
+ if (Object.prototype.hasOwnProperty.call(actionsConfig, actionName)) {
306
+ const { method, endpoint } = actionsConfig[actionName];
307
+ actions[actionName] = createAction(axiosInstance, method, endpoint);
308
+ }
309
+ }
310
+ return actions;
311
+ }
312
+
271
313
  // src/core/cache.ts
272
314
  var CacheManager = class {
273
315
  cache = /* @__PURE__ */ new Map();
@@ -305,23 +347,26 @@ function useApi(axiosInstance, config) {
305
347
  const {
306
348
  endpoint,
307
349
  initialData,
308
- initialQuery = { page: 1, limit: 10 },
350
+ initialQuery = { limit: 10 },
309
351
  enabled = true,
310
352
  refetchAfterChange = true,
353
+ // تم تعديل القيمة الافتراضية لتكون أكثر شيوعًا
311
354
  onSuccess,
312
355
  onError
313
356
  } = config;
314
357
  const [state, setState] = (0, import_react.useState)({
315
- response: initialData || void 0,
358
+ data: initialData || null,
359
+ rawResponse: null,
316
360
  loading: enabled,
317
361
  error: null,
318
362
  success: false
319
363
  });
320
364
  const [queryOptions, setQueryOptions] = (0, import_react.useState)(initialQuery);
321
365
  const apiServices = (0, import_react.useRef)(createApiServices(axiosInstance, endpoint)).current;
322
- const fetchData = (0, import_react.useCallback)(async () => {
323
- setState((prev) => ({ ...prev, loading: true, error: null }));
324
- const queryString = buildPaginateQuery(queryOptions);
366
+ const fetchData = (0, import_react.useCallback)(async (options) => {
367
+ const currentQuery = options || queryOptions;
368
+ setState((prev) => ({ ...prev, data: null, loading: true, error: null }));
369
+ const queryString = buildPaginateQuery(currentQuery);
325
370
  const result = await apiServices.getWithQuery(queryString, { cancelTokenKey: endpoint });
326
371
  setState(result);
327
372
  if (!result.success && onError) {
@@ -333,35 +378,35 @@ function useApi(axiosInstance, config) {
333
378
  fetchData();
334
379
  }
335
380
  }, [enabled, queryOptions]);
336
- const createItem = async (newItem) => {
381
+ const createItem = async (newItem, options) => {
337
382
  setState((prev) => ({ ...prev, loading: true }));
338
- const result = await apiServices.post(newItem);
383
+ const result = await apiServices.post(newItem, options);
339
384
  if (result.success) {
340
385
  if (refetchAfterChange) await fetchData();
341
386
  else setState((prev) => ({ ...prev, loading: false }));
342
- if (onSuccess) onSuccess(result.message || "Item created successfully!", result.response);
387
+ if (onSuccess) onSuccess(result.message || "Item created successfully!", result.data);
343
388
  } else {
344
389
  setState((prev) => ({ ...prev, loading: false, error: result.error }));
345
390
  if (onError) onError(result.message || "Create failed", result.error || void 0);
346
391
  }
347
392
  return result;
348
393
  };
349
- const updateItem = async (id, updatedItem) => {
394
+ const updateItem = async (id, updatedItem, options) => {
350
395
  setState((prev) => ({ ...prev, loading: true }));
351
- const result = await apiServices.patch(id, updatedItem);
396
+ const result = await apiServices.patch(id, updatedItem, options);
352
397
  if (result.success) {
353
398
  if (refetchAfterChange) await fetchData();
354
399
  else setState((prev) => ({ ...prev, loading: false }));
355
- if (onSuccess) onSuccess(result.message || "Item updated successfully!", result.response);
400
+ if (onSuccess) onSuccess(result.message || "Item updated successfully!", result.data);
356
401
  } else {
357
402
  setState((prev) => ({ ...prev, loading: false, error: result.error }));
358
403
  if (onError) onError(result.message || "Update failed", result.error || void 0);
359
404
  }
360
405
  return result;
361
406
  };
362
- const deleteItem = async (id) => {
407
+ const deleteItem = async (id, options) => {
363
408
  setState((prev) => ({ ...prev, loading: true }));
364
- const result = await apiServices.remove(id);
409
+ const result = await apiServices.remove(id, options);
365
410
  if (result.success) {
366
411
  if (refetchAfterChange) await fetchData();
367
412
  else setState((prev) => ({ ...prev, loading: false }));
@@ -377,11 +422,19 @@ function useApi(axiosInstance, config) {
377
422
  const setSearchTerm = (search) => setQueryOptions((prev) => ({ ...prev, search, page: 1 }));
378
423
  const setSorting = (sortBy) => setQueryOptions((prev) => ({ ...prev, sortBy }));
379
424
  const setFilters = (filter) => setQueryOptions((prev) => ({ ...prev, filter, page: 1 }));
425
+ const setQueryParam = (key, value) => {
426
+ setQueryOptions((prev) => {
427
+ const newQuery = { ...prev, [key]: value };
428
+ if (key !== "page") {
429
+ newQuery.page = 1;
430
+ }
431
+ return newQuery;
432
+ });
433
+ };
380
434
  const resetQuery = () => setQueryOptions(initialQuery);
381
435
  return {
382
436
  state,
383
437
  setState,
384
- // Exposing setState for direct manipulation or connection to Redux
385
438
  actions: {
386
439
  fetch: fetchData,
387
440
  create: createItem,
@@ -396,6 +449,8 @@ function useApi(axiosInstance, config) {
396
449
  setSearchTerm,
397
450
  setSorting,
398
451
  setFilters,
452
+ setQueryParam,
453
+ // <-- NEW
399
454
  reset: resetQuery
400
455
  }
401
456
  };
@@ -404,6 +459,7 @@ function useApi(axiosInstance, config) {
404
459
  0 && (module.exports = {
405
460
  buildPaginateQuery,
406
461
  cacheManager,
462
+ createApiActions,
407
463
  createApiClient,
408
464
  createApiServices,
409
465
  processResponse,
package/dist/index.mjs CHANGED
@@ -122,6 +122,7 @@ import axios2 from "axios";
122
122
  function buildPaginateQuery(query) {
123
123
  if (!query) return "";
124
124
  const params = new URLSearchParams();
125
+ const standardKeys = /* @__PURE__ */ new Set(["page", "limit", "search", "sortBy", "filter"]);
125
126
  if (query.page) params.append("page", query.page.toString());
126
127
  if (query.limit) params.append("limit", query.limit.toString());
127
128
  if (query.search) params.append("search", query.search);
@@ -133,6 +134,14 @@ function buildPaginateQuery(query) {
133
134
  params.append(`filter.${field}`, String(value));
134
135
  });
135
136
  }
137
+ for (const key in query) {
138
+ if (Object.prototype.hasOwnProperty.call(query, key) && !standardKeys.has(key)) {
139
+ const value = query[key];
140
+ if (value !== void 0 && value !== null) {
141
+ params.append(key, String(value));
142
+ }
143
+ }
144
+ }
136
145
  const queryString = params.toString();
137
146
  return queryString ? `?${queryString}` : "";
138
147
  }
@@ -147,37 +156,38 @@ function isAxiosResponse(obj) {
147
156
  var processResponse = (responseOrError) => {
148
157
  if (isApiError(responseOrError)) {
149
158
  return {
150
- response: void 0,
159
+ data: null,
160
+ rawResponse: void 0,
151
161
  error: responseOrError,
152
162
  validationErrors: responseOrError.errors || [],
153
- // الخطأ الآن صحيح
154
163
  success: false,
155
164
  loading: false,
156
165
  message: responseOrError.message
157
166
  };
158
167
  }
159
168
  if (isAxiosResponse(responseOrError)) {
160
- const response = responseOrError;
169
+ const rawData = responseOrError.data;
170
+ const isWrappedResponse = rawData && typeof rawData.success === "boolean" && rawData.data !== void 0;
171
+ const finalData = isWrappedResponse ? rawData.data : rawData;
172
+ const message = isWrappedResponse ? rawData.message : "Request successful.";
161
173
  return {
162
- response: response.data,
174
+ data: finalData,
175
+ // <-- وصول مباشر للبيانات النهائية!
176
+ rawResponse: rawData,
177
+ // احتفظ بالاستجابة الكاملة إذا احتجت إليها
163
178
  loading: false,
164
179
  success: true,
165
180
  error: null,
166
- message: response.data.message || "Request successful.",
181
+ message,
167
182
  validationErrors: []
168
- // <-- أضف قيمة افتراضية هنا للاتساق
169
183
  };
170
184
  }
171
185
  return {
172
- response: void 0,
173
- error: {
174
- message: "An unknown error occurred during response processing.",
175
- status: 500
176
- },
186
+ data: null,
187
+ rawResponse: void 0,
188
+ error: { message: "An unknown error occurred during response processing.", status: 500 },
177
189
  success: false,
178
- loading: false,
179
- validationErrors: []
180
- // <-- أضف قيمة افتراضية هنا أيضًا
190
+ loading: false
181
191
  };
182
192
  };
183
193
 
@@ -201,24 +211,27 @@ function createApiServices(axiosInstance, endpoint) {
201
211
  }
202
212
  };
203
213
  const post = async (data, config) => {
214
+ const finalUrl = config?.endpoint || endpoint;
204
215
  try {
205
- const response = await axiosInstance.post(endpoint, data, config);
216
+ const response = await axiosInstance.post(finalUrl, data, config);
206
217
  return processResponse(response);
207
218
  } catch (error) {
208
219
  return processResponse(error);
209
220
  }
210
221
  };
211
222
  const patch = async (id, data, config) => {
223
+ const finalUrl = config?.endpoint || `${endpoint}/${id}`;
212
224
  try {
213
- const response = await axiosInstance.patch(`${endpoint}/${id}`, data, config);
225
+ const response = await axiosInstance.patch(finalUrl, data, config);
214
226
  return processResponse(response);
215
227
  } catch (error) {
216
228
  return processResponse(error);
217
229
  }
218
230
  };
219
231
  const remove = async (id, config) => {
232
+ const finalUrl = config?.endpoint || `${endpoint}/${id}`;
220
233
  try {
221
- const response = await axiosInstance.delete(`${endpoint}/${id}`, config);
234
+ const response = await axiosInstance.delete(finalUrl, config);
222
235
  return processResponse(response);
223
236
  } catch (error) {
224
237
  return processResponse(error);
@@ -227,6 +240,34 @@ function createApiServices(axiosInstance, endpoint) {
227
240
  return { get, getWithQuery, post, patch, remove };
228
241
  }
229
242
 
243
+ // src/services/actions.ts
244
+ function createAction(axiosInstance, method, endpoint) {
245
+ return async (payload, config) => {
246
+ try {
247
+ const response = await axiosInstance.request({
248
+ // <--- غيرنا النوع إلى any
249
+ url: endpoint,
250
+ method,
251
+ ...method.toUpperCase() === "GET" ? { params: payload } : { data: payload },
252
+ ...config
253
+ });
254
+ return processResponse(response);
255
+ } catch (error) {
256
+ return processResponse(error);
257
+ }
258
+ };
259
+ }
260
+ function createApiActions(axiosInstance, actionsConfig) {
261
+ const actions = {};
262
+ for (const actionName in actionsConfig) {
263
+ if (Object.prototype.hasOwnProperty.call(actionsConfig, actionName)) {
264
+ const { method, endpoint } = actionsConfig[actionName];
265
+ actions[actionName] = createAction(axiosInstance, method, endpoint);
266
+ }
267
+ }
268
+ return actions;
269
+ }
270
+
230
271
  // src/core/cache.ts
231
272
  var CacheManager = class {
232
273
  cache = /* @__PURE__ */ new Map();
@@ -264,23 +305,26 @@ function useApi(axiosInstance, config) {
264
305
  const {
265
306
  endpoint,
266
307
  initialData,
267
- initialQuery = { page: 1, limit: 10 },
308
+ initialQuery = { limit: 10 },
268
309
  enabled = true,
269
310
  refetchAfterChange = true,
311
+ // تم تعديل القيمة الافتراضية لتكون أكثر شيوعًا
270
312
  onSuccess,
271
313
  onError
272
314
  } = config;
273
315
  const [state, setState] = useState({
274
- response: initialData || void 0,
316
+ data: initialData || null,
317
+ rawResponse: null,
275
318
  loading: enabled,
276
319
  error: null,
277
320
  success: false
278
321
  });
279
322
  const [queryOptions, setQueryOptions] = useState(initialQuery);
280
323
  const apiServices = useRef(createApiServices(axiosInstance, endpoint)).current;
281
- const fetchData = useCallback(async () => {
282
- setState((prev) => ({ ...prev, loading: true, error: null }));
283
- const queryString = buildPaginateQuery(queryOptions);
324
+ const fetchData = useCallback(async (options) => {
325
+ const currentQuery = options || queryOptions;
326
+ setState((prev) => ({ ...prev, data: null, loading: true, error: null }));
327
+ const queryString = buildPaginateQuery(currentQuery);
284
328
  const result = await apiServices.getWithQuery(queryString, { cancelTokenKey: endpoint });
285
329
  setState(result);
286
330
  if (!result.success && onError) {
@@ -292,35 +336,35 @@ function useApi(axiosInstance, config) {
292
336
  fetchData();
293
337
  }
294
338
  }, [enabled, queryOptions]);
295
- const createItem = async (newItem) => {
339
+ const createItem = async (newItem, options) => {
296
340
  setState((prev) => ({ ...prev, loading: true }));
297
- const result = await apiServices.post(newItem);
341
+ const result = await apiServices.post(newItem, options);
298
342
  if (result.success) {
299
343
  if (refetchAfterChange) await fetchData();
300
344
  else setState((prev) => ({ ...prev, loading: false }));
301
- if (onSuccess) onSuccess(result.message || "Item created successfully!", result.response);
345
+ if (onSuccess) onSuccess(result.message || "Item created successfully!", result.data);
302
346
  } else {
303
347
  setState((prev) => ({ ...prev, loading: false, error: result.error }));
304
348
  if (onError) onError(result.message || "Create failed", result.error || void 0);
305
349
  }
306
350
  return result;
307
351
  };
308
- const updateItem = async (id, updatedItem) => {
352
+ const updateItem = async (id, updatedItem, options) => {
309
353
  setState((prev) => ({ ...prev, loading: true }));
310
- const result = await apiServices.patch(id, updatedItem);
354
+ const result = await apiServices.patch(id, updatedItem, options);
311
355
  if (result.success) {
312
356
  if (refetchAfterChange) await fetchData();
313
357
  else setState((prev) => ({ ...prev, loading: false }));
314
- if (onSuccess) onSuccess(result.message || "Item updated successfully!", result.response);
358
+ if (onSuccess) onSuccess(result.message || "Item updated successfully!", result.data);
315
359
  } else {
316
360
  setState((prev) => ({ ...prev, loading: false, error: result.error }));
317
361
  if (onError) onError(result.message || "Update failed", result.error || void 0);
318
362
  }
319
363
  return result;
320
364
  };
321
- const deleteItem = async (id) => {
365
+ const deleteItem = async (id, options) => {
322
366
  setState((prev) => ({ ...prev, loading: true }));
323
- const result = await apiServices.remove(id);
367
+ const result = await apiServices.remove(id, options);
324
368
  if (result.success) {
325
369
  if (refetchAfterChange) await fetchData();
326
370
  else setState((prev) => ({ ...prev, loading: false }));
@@ -336,11 +380,19 @@ function useApi(axiosInstance, config) {
336
380
  const setSearchTerm = (search) => setQueryOptions((prev) => ({ ...prev, search, page: 1 }));
337
381
  const setSorting = (sortBy) => setQueryOptions((prev) => ({ ...prev, sortBy }));
338
382
  const setFilters = (filter) => setQueryOptions((prev) => ({ ...prev, filter, page: 1 }));
383
+ const setQueryParam = (key, value) => {
384
+ setQueryOptions((prev) => {
385
+ const newQuery = { ...prev, [key]: value };
386
+ if (key !== "page") {
387
+ newQuery.page = 1;
388
+ }
389
+ return newQuery;
390
+ });
391
+ };
339
392
  const resetQuery = () => setQueryOptions(initialQuery);
340
393
  return {
341
394
  state,
342
395
  setState,
343
- // Exposing setState for direct manipulation or connection to Redux
344
396
  actions: {
345
397
  fetch: fetchData,
346
398
  create: createItem,
@@ -355,6 +407,8 @@ function useApi(axiosInstance, config) {
355
407
  setSearchTerm,
356
408
  setSorting,
357
409
  setFilters,
410
+ setQueryParam,
411
+ // <-- NEW
358
412
  reset: resetQuery
359
413
  }
360
414
  };
@@ -362,6 +416,7 @@ function useApi(axiosInstance, config) {
362
416
  export {
363
417
  buildPaginateQuery,
364
418
  cacheManager,
419
+ createApiActions,
365
420
  createApiClient,
366
421
  createApiServices,
367
422
  processResponse,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-core-lib",
3
- "version": "3.2.2",
3
+ "version": "3.3.3",
4
4
  "description": "A flexible and powerful API client library for modern web applications.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",