api-core-lib 2.2.2 → 3.3.2
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 +129 -41
- package/dist/index.d.ts +129 -41
- package/dist/index.js +81 -30
- package/dist/index.mjs +80 -30
- package/package.json +1 -1
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
|
*/
|
@@ -83,19 +62,6 @@ interface RequestConfig extends AxiosRequestConfig {
|
|
83
62
|
onUploadProgress?: (progressEvent: AxiosProgressEvent) => void;
|
84
63
|
onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void;
|
85
64
|
}
|
86
|
-
/**
|
87
|
-
* الواجهة الرئيسية لتهيئة عميل الـ API.
|
88
|
-
*/
|
89
|
-
interface ApiClientConfig {
|
90
|
-
baseURL?: string;
|
91
|
-
tokenManager: TokenManager;
|
92
|
-
timeout?: number;
|
93
|
-
headers?: Record<string, string>;
|
94
|
-
withCredentials?: boolean;
|
95
|
-
responseType?: ResponseType;
|
96
|
-
pathRefreshToken?: string;
|
97
|
-
onRefreshError?: (error: any) => void;
|
98
|
-
}
|
99
65
|
/**
|
100
66
|
* يمثل خيارات الاستعلام للترقيم والبحث والفرز.
|
101
67
|
*/
|
@@ -122,6 +88,92 @@ interface UseApiConfig<T> {
|
|
122
88
|
onSuccess?: (message: string, data?: T) => void;
|
123
89
|
onError?: (message: string, error?: ApiError) => void;
|
124
90
|
}
|
91
|
+
/**
|
92
|
+
* واجهة لتخصيص عملية تجديد التوكن بشكل كامل.
|
93
|
+
*/
|
94
|
+
interface RefreshTokenConfig {
|
95
|
+
/**
|
96
|
+
* المسار الذي يتم استخدامه لتجديد التوكن (e.g., '/auth/refresh').
|
97
|
+
* @default '/auth/refresh'
|
98
|
+
*/
|
99
|
+
path: string;
|
100
|
+
/**
|
101
|
+
* دالة لتحديد كيفية بناء جسم (body) طلب التجديد.
|
102
|
+
* @param refreshToken - التوكن المستخدم للتجديد.
|
103
|
+
* @returns كائن يمثل جسم الطلب.
|
104
|
+
* @default (refreshToken) => ({ refresh_token: refreshToken })
|
105
|
+
*/
|
106
|
+
buildRequestBody?: (refreshToken: string) => Record<string, any>;
|
107
|
+
/**
|
108
|
+
* دالة لتحديد كيفية بناء الهيدرز (headers) الخاصة بطلب التجديد.
|
109
|
+
* @param currentTokens - التوكنات الحالية.
|
110
|
+
* @returns كائن يمثل الهيدرز الإضافية.
|
111
|
+
* @default () => ({})
|
112
|
+
*/
|
113
|
+
buildRequestHeaders?: (currentTokens: Tokens) => Record<string, string>;
|
114
|
+
/**
|
115
|
+
* دالة مخصصة لاستخلاص التوكنات الجديدة من استجابة الـ API.
|
116
|
+
* @param responseData - البيانات التي تم إرجاعها من الـ API.
|
117
|
+
* @returns كائن من نوع Tokens.
|
118
|
+
* @default (data) => ({ accessToken: data.access_token, ... })
|
119
|
+
*/
|
120
|
+
extractTokens: (responseData: any) => {
|
121
|
+
accessToken: string;
|
122
|
+
refreshToken?: string;
|
123
|
+
expiresIn: number;
|
124
|
+
tokenType?: string;
|
125
|
+
};
|
126
|
+
}
|
127
|
+
/**
|
128
|
+
* الواجهة الرئيسية لتهيئة عميل الـ API.
|
129
|
+
*/
|
130
|
+
interface ApiClientConfig {
|
131
|
+
baseURL?: string;
|
132
|
+
tokenManager: TokenManager;
|
133
|
+
timeout?: number;
|
134
|
+
headers?: Record<string, string>;
|
135
|
+
withCredentials?: boolean;
|
136
|
+
responseType?: ResponseType;
|
137
|
+
/**
|
138
|
+
* إعدادات مخصصة لعملية تجديد التوكن.
|
139
|
+
* إذا لم يتم توفيرها، ستتوقف محاولات التجديد التلقائي.
|
140
|
+
*/
|
141
|
+
refreshTokenConfig?: RefreshTokenConfig;
|
142
|
+
onRefreshError?: (error: any) => void;
|
143
|
+
}
|
144
|
+
/**
|
145
|
+
* يمثل بنية الاستجابة القياسية من الـ API.
|
146
|
+
* @template T نوع البيانات الأساسية في الاستجابة.
|
147
|
+
*/
|
148
|
+
interface ApiResponse<T = any> {
|
149
|
+
data: T;
|
150
|
+
message?: string;
|
151
|
+
meta?: PaginationMeta;
|
152
|
+
}
|
153
|
+
/**
|
154
|
+
* يمثل بنية الاستجابة القياسية المغلفة التي قد تأتي من بعض نقاط الـ API.
|
155
|
+
* @template T نوع البيانات الأساسية في الاستجابة.
|
156
|
+
*/
|
157
|
+
interface ApiResponse<T = any> {
|
158
|
+
data: T;
|
159
|
+
message?: string;
|
160
|
+
meta?: PaginationMeta;
|
161
|
+
success?: boolean;
|
162
|
+
}
|
163
|
+
/**
|
164
|
+
* يمثل كائن الاستجابة الموحد والنهائي الذي يرجعه كل طلب.
|
165
|
+
* هذا هو النوع الذي ستتعامل معه دائمًا.
|
166
|
+
* @template T نوع البيانات النهائية التي تريد الوصول إليها.
|
167
|
+
*/
|
168
|
+
interface StandardResponse<T> {
|
169
|
+
data: T | null;
|
170
|
+
rawResponse: any;
|
171
|
+
error: ApiError | null;
|
172
|
+
loading: boolean;
|
173
|
+
success: boolean;
|
174
|
+
message?: string;
|
175
|
+
validationErrors?: ValidationError[];
|
176
|
+
}
|
125
177
|
|
126
178
|
/**
|
127
179
|
* @file src/core/client.ts
|
@@ -151,6 +203,39 @@ declare function createApiServices<T>(axiosInstance: AxiosInstance, endpoint: st
|
|
151
203
|
|
152
204
|
declare function buildPaginateQuery(query: PaginateQueryOptions): string;
|
153
205
|
|
206
|
+
/**
|
207
|
+
* Defines a single custom API action.
|
208
|
+
* @template TRequest - The type of the data sent in the request body/params.
|
209
|
+
* @template TResponse - The type of the data expected in the successful API response.
|
210
|
+
*/
|
211
|
+
type ApiAction<TRequest, TResponse> = (payload: TRequest, config?: RequestConfig) => Promise<StandardResponse<TResponse>>;
|
212
|
+
/**
|
213
|
+
* A factory function to create a collection of typed, custom API actions.
|
214
|
+
*
|
215
|
+
* @template TActions - An object type where keys are action names and values are objects
|
216
|
+
* defining the endpoint, method, and types for that action.
|
217
|
+
* @param axiosInstance - The configured Axios instance from `createApiClient`.
|
218
|
+
* @param actionsConfig - An object defining the configuration for each custom action.
|
219
|
+
* @returns A fully-typed object of executable API action functions.
|
220
|
+
*
|
221
|
+
* @example
|
222
|
+
* const authActions = createApiActions(apiClient, {
|
223
|
+
* login: { method: 'POST', endpoint: '/auth/login', requestType: {} as LoginCredentials, responseType: {} as AuthResponse },
|
224
|
+
* getProfile: { method: 'GET', endpoint: '/user/profile', requestType: {} as void, responseType: {} as UserProfile }
|
225
|
+
* });
|
226
|
+
*
|
227
|
+
* // Usage:
|
228
|
+
* const result = await authActions.login({ email: '..', password: '..' });
|
229
|
+
*/
|
230
|
+
declare function createApiActions<TActions extends Record<string, {
|
231
|
+
method: Method;
|
232
|
+
endpoint: string;
|
233
|
+
requestType: any;
|
234
|
+
responseType: any;
|
235
|
+
}>>(axiosInstance: AxiosInstance, actionsConfig: TActions): {
|
236
|
+
[K in keyof TActions]: ApiAction<TActions[K]['requestType'], TActions[K]['responseType']>;
|
237
|
+
};
|
238
|
+
|
154
239
|
declare class CacheManager {
|
155
240
|
private cache;
|
156
241
|
private defaultDuration;
|
@@ -162,12 +247,15 @@ declare class CacheManager {
|
|
162
247
|
declare const cacheManager: CacheManager;
|
163
248
|
|
164
249
|
/**
|
165
|
-
*
|
166
|
-
*
|
167
|
-
* ...
|
250
|
+
* A smart response processor that normalizes API responses.
|
251
|
+
* It intelligently unwraps nested data from standard API envelopes
|
252
|
+
* (like { success: true, data: {...} }) and provides direct access
|
253
|
+
* to the core data, while still handling errors consistently.
|
254
|
+
*
|
255
|
+
* @param responseOrError The raw Axios response or a pre-processed ApiError.
|
256
|
+
* @returns A standardized `StandardResponse` object with direct access to `.data`.
|
168
257
|
*/
|
169
|
-
|
170
|
-
declare const processResponse: <T>(responseOrError: AxiosResponse<ApiResponse<T>> | ApiError) => StandardResponse<T>;
|
258
|
+
declare const processResponse: <T>(responseOrError: AxiosResponse<any> | ApiError) => StandardResponse<T>;
|
171
259
|
|
172
260
|
declare function useApi<T extends {
|
173
261
|
id?: string | number;
|
@@ -195,4 +283,4 @@ declare function useApi<T extends {
|
|
195
283
|
};
|
196
284
|
};
|
197
285
|
|
198
|
-
export { type ApiClientConfig, type ApiError, type ApiResponse, type PaginateQueryOptions, type PaginationMeta, type RequestConfig, type StandardResponse, type TokenManager, type Tokens, type UseApiConfig, type ValidationError, buildPaginateQuery, cacheManager, createApiClient, createApiServices, processResponse, useApi };
|
286
|
+
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, 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
|
*/
|
@@ -83,19 +62,6 @@ interface RequestConfig extends AxiosRequestConfig {
|
|
83
62
|
onUploadProgress?: (progressEvent: AxiosProgressEvent) => void;
|
84
63
|
onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void;
|
85
64
|
}
|
86
|
-
/**
|
87
|
-
* الواجهة الرئيسية لتهيئة عميل الـ API.
|
88
|
-
*/
|
89
|
-
interface ApiClientConfig {
|
90
|
-
baseURL?: string;
|
91
|
-
tokenManager: TokenManager;
|
92
|
-
timeout?: number;
|
93
|
-
headers?: Record<string, string>;
|
94
|
-
withCredentials?: boolean;
|
95
|
-
responseType?: ResponseType;
|
96
|
-
pathRefreshToken?: string;
|
97
|
-
onRefreshError?: (error: any) => void;
|
98
|
-
}
|
99
65
|
/**
|
100
66
|
* يمثل خيارات الاستعلام للترقيم والبحث والفرز.
|
101
67
|
*/
|
@@ -122,6 +88,92 @@ interface UseApiConfig<T> {
|
|
122
88
|
onSuccess?: (message: string, data?: T) => void;
|
123
89
|
onError?: (message: string, error?: ApiError) => void;
|
124
90
|
}
|
91
|
+
/**
|
92
|
+
* واجهة لتخصيص عملية تجديد التوكن بشكل كامل.
|
93
|
+
*/
|
94
|
+
interface RefreshTokenConfig {
|
95
|
+
/**
|
96
|
+
* المسار الذي يتم استخدامه لتجديد التوكن (e.g., '/auth/refresh').
|
97
|
+
* @default '/auth/refresh'
|
98
|
+
*/
|
99
|
+
path: string;
|
100
|
+
/**
|
101
|
+
* دالة لتحديد كيفية بناء جسم (body) طلب التجديد.
|
102
|
+
* @param refreshToken - التوكن المستخدم للتجديد.
|
103
|
+
* @returns كائن يمثل جسم الطلب.
|
104
|
+
* @default (refreshToken) => ({ refresh_token: refreshToken })
|
105
|
+
*/
|
106
|
+
buildRequestBody?: (refreshToken: string) => Record<string, any>;
|
107
|
+
/**
|
108
|
+
* دالة لتحديد كيفية بناء الهيدرز (headers) الخاصة بطلب التجديد.
|
109
|
+
* @param currentTokens - التوكنات الحالية.
|
110
|
+
* @returns كائن يمثل الهيدرز الإضافية.
|
111
|
+
* @default () => ({})
|
112
|
+
*/
|
113
|
+
buildRequestHeaders?: (currentTokens: Tokens) => Record<string, string>;
|
114
|
+
/**
|
115
|
+
* دالة مخصصة لاستخلاص التوكنات الجديدة من استجابة الـ API.
|
116
|
+
* @param responseData - البيانات التي تم إرجاعها من الـ API.
|
117
|
+
* @returns كائن من نوع Tokens.
|
118
|
+
* @default (data) => ({ accessToken: data.access_token, ... })
|
119
|
+
*/
|
120
|
+
extractTokens: (responseData: any) => {
|
121
|
+
accessToken: string;
|
122
|
+
refreshToken?: string;
|
123
|
+
expiresIn: number;
|
124
|
+
tokenType?: string;
|
125
|
+
};
|
126
|
+
}
|
127
|
+
/**
|
128
|
+
* الواجهة الرئيسية لتهيئة عميل الـ API.
|
129
|
+
*/
|
130
|
+
interface ApiClientConfig {
|
131
|
+
baseURL?: string;
|
132
|
+
tokenManager: TokenManager;
|
133
|
+
timeout?: number;
|
134
|
+
headers?: Record<string, string>;
|
135
|
+
withCredentials?: boolean;
|
136
|
+
responseType?: ResponseType;
|
137
|
+
/**
|
138
|
+
* إعدادات مخصصة لعملية تجديد التوكن.
|
139
|
+
* إذا لم يتم توفيرها، ستتوقف محاولات التجديد التلقائي.
|
140
|
+
*/
|
141
|
+
refreshTokenConfig?: RefreshTokenConfig;
|
142
|
+
onRefreshError?: (error: any) => void;
|
143
|
+
}
|
144
|
+
/**
|
145
|
+
* يمثل بنية الاستجابة القياسية من الـ API.
|
146
|
+
* @template T نوع البيانات الأساسية في الاستجابة.
|
147
|
+
*/
|
148
|
+
interface ApiResponse<T = any> {
|
149
|
+
data: T;
|
150
|
+
message?: string;
|
151
|
+
meta?: PaginationMeta;
|
152
|
+
}
|
153
|
+
/**
|
154
|
+
* يمثل بنية الاستجابة القياسية المغلفة التي قد تأتي من بعض نقاط الـ API.
|
155
|
+
* @template T نوع البيانات الأساسية في الاستجابة.
|
156
|
+
*/
|
157
|
+
interface ApiResponse<T = any> {
|
158
|
+
data: T;
|
159
|
+
message?: string;
|
160
|
+
meta?: PaginationMeta;
|
161
|
+
success?: boolean;
|
162
|
+
}
|
163
|
+
/**
|
164
|
+
* يمثل كائن الاستجابة الموحد والنهائي الذي يرجعه كل طلب.
|
165
|
+
* هذا هو النوع الذي ستتعامل معه دائمًا.
|
166
|
+
* @template T نوع البيانات النهائية التي تريد الوصول إليها.
|
167
|
+
*/
|
168
|
+
interface StandardResponse<T> {
|
169
|
+
data: T | null;
|
170
|
+
rawResponse: any;
|
171
|
+
error: ApiError | null;
|
172
|
+
loading: boolean;
|
173
|
+
success: boolean;
|
174
|
+
message?: string;
|
175
|
+
validationErrors?: ValidationError[];
|
176
|
+
}
|
125
177
|
|
126
178
|
/**
|
127
179
|
* @file src/core/client.ts
|
@@ -151,6 +203,39 @@ declare function createApiServices<T>(axiosInstance: AxiosInstance, endpoint: st
|
|
151
203
|
|
152
204
|
declare function buildPaginateQuery(query: PaginateQueryOptions): string;
|
153
205
|
|
206
|
+
/**
|
207
|
+
* Defines a single custom API action.
|
208
|
+
* @template TRequest - The type of the data sent in the request body/params.
|
209
|
+
* @template TResponse - The type of the data expected in the successful API response.
|
210
|
+
*/
|
211
|
+
type ApiAction<TRequest, TResponse> = (payload: TRequest, config?: RequestConfig) => Promise<StandardResponse<TResponse>>;
|
212
|
+
/**
|
213
|
+
* A factory function to create a collection of typed, custom API actions.
|
214
|
+
*
|
215
|
+
* @template TActions - An object type where keys are action names and values are objects
|
216
|
+
* defining the endpoint, method, and types for that action.
|
217
|
+
* @param axiosInstance - The configured Axios instance from `createApiClient`.
|
218
|
+
* @param actionsConfig - An object defining the configuration for each custom action.
|
219
|
+
* @returns A fully-typed object of executable API action functions.
|
220
|
+
*
|
221
|
+
* @example
|
222
|
+
* const authActions = createApiActions(apiClient, {
|
223
|
+
* login: { method: 'POST', endpoint: '/auth/login', requestType: {} as LoginCredentials, responseType: {} as AuthResponse },
|
224
|
+
* getProfile: { method: 'GET', endpoint: '/user/profile', requestType: {} as void, responseType: {} as UserProfile }
|
225
|
+
* });
|
226
|
+
*
|
227
|
+
* // Usage:
|
228
|
+
* const result = await authActions.login({ email: '..', password: '..' });
|
229
|
+
*/
|
230
|
+
declare function createApiActions<TActions extends Record<string, {
|
231
|
+
method: Method;
|
232
|
+
endpoint: string;
|
233
|
+
requestType: any;
|
234
|
+
responseType: any;
|
235
|
+
}>>(axiosInstance: AxiosInstance, actionsConfig: TActions): {
|
236
|
+
[K in keyof TActions]: ApiAction<TActions[K]['requestType'], TActions[K]['responseType']>;
|
237
|
+
};
|
238
|
+
|
154
239
|
declare class CacheManager {
|
155
240
|
private cache;
|
156
241
|
private defaultDuration;
|
@@ -162,12 +247,15 @@ declare class CacheManager {
|
|
162
247
|
declare const cacheManager: CacheManager;
|
163
248
|
|
164
249
|
/**
|
165
|
-
*
|
166
|
-
*
|
167
|
-
* ...
|
250
|
+
* A smart response processor that normalizes API responses.
|
251
|
+
* It intelligently unwraps nested data from standard API envelopes
|
252
|
+
* (like { success: true, data: {...} }) and provides direct access
|
253
|
+
* to the core data, while still handling errors consistently.
|
254
|
+
*
|
255
|
+
* @param responseOrError The raw Axios response or a pre-processed ApiError.
|
256
|
+
* @returns A standardized `StandardResponse` object with direct access to `.data`.
|
168
257
|
*/
|
169
|
-
|
170
|
-
declare const processResponse: <T>(responseOrError: AxiosResponse<ApiResponse<T>> | ApiError) => StandardResponse<T>;
|
258
|
+
declare const processResponse: <T>(responseOrError: AxiosResponse<any> | ApiError) => StandardResponse<T>;
|
171
259
|
|
172
260
|
declare function useApi<T extends {
|
173
261
|
id?: string | number;
|
@@ -195,4 +283,4 @@ declare function useApi<T extends {
|
|
195
283
|
};
|
196
284
|
};
|
197
285
|
|
198
|
-
export { type ApiClientConfig, type ApiError, type ApiResponse, type PaginateQueryOptions, type PaginationMeta, type RequestConfig, type StandardResponse, type TokenManager, type Tokens, type UseApiConfig, type ValidationError, buildPaginateQuery, cacheManager, createApiClient, createApiServices, processResponse, useApi };
|
286
|
+
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, 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,
|
@@ -43,26 +44,44 @@ module.exports = __toCommonJS(index_exports);
|
|
43
44
|
var import_axios = __toESM(require("axios"));
|
44
45
|
var import_uuid = require("uuid");
|
45
46
|
async function refreshToken(config, tokenManager) {
|
47
|
+
const { refreshTokenConfig } = config;
|
48
|
+
if (!refreshTokenConfig) {
|
49
|
+
console.warn("[API Core] Refresh token process is disabled (refreshTokenConfig is not provided).");
|
50
|
+
await tokenManager.clearTokens();
|
51
|
+
return null;
|
52
|
+
}
|
46
53
|
try {
|
47
54
|
const currentTokens = await tokenManager.getTokens();
|
48
|
-
if (!currentTokens.refreshToken)
|
55
|
+
if (!currentTokens.refreshToken) {
|
56
|
+
throw new Error("No refresh token available to perform refresh.");
|
57
|
+
}
|
58
|
+
const { path, buildRequestBody, buildRequestHeaders, extractTokens } = refreshTokenConfig;
|
59
|
+
const requestBody = buildRequestBody ? buildRequestBody(currentTokens.refreshToken) : { refresh_token: currentTokens.refreshToken };
|
60
|
+
const requestHeaders = buildRequestHeaders ? buildRequestHeaders(currentTokens) : {};
|
49
61
|
const response = await import_axios.default.post(
|
50
|
-
`${config.baseURL}${
|
51
|
-
|
52
|
-
{
|
62
|
+
`${config.baseURL}${path}`,
|
63
|
+
requestBody,
|
64
|
+
{
|
65
|
+
headers: requestHeaders,
|
66
|
+
withCredentials: config.withCredentials
|
67
|
+
}
|
53
68
|
);
|
54
|
-
const
|
69
|
+
const extracted = extractTokens(response.data);
|
70
|
+
if (!extracted || !extracted.accessToken || typeof extracted.expiresIn !== "number") {
|
71
|
+
throw new Error("extractTokens function failed to return a valid token structure.");
|
72
|
+
}
|
55
73
|
const newTokens = {
|
56
|
-
accessToken:
|
57
|
-
refreshToken:
|
58
|
-
|
59
|
-
|
74
|
+
accessToken: extracted.accessToken,
|
75
|
+
refreshToken: extracted.refreshToken || currentTokens.refreshToken,
|
76
|
+
// احتفظ بالقديم إذا لم يأتِ جديد
|
77
|
+
expiresAt: Date.now() + extracted.expiresIn * 1e3,
|
78
|
+
tokenType: extracted.tokenType || "Bearer"
|
60
79
|
};
|
61
80
|
await tokenManager.setTokens(newTokens);
|
62
81
|
console.log("[API Core] Tokens refreshed successfully.");
|
63
82
|
return newTokens;
|
64
83
|
} catch (err) {
|
65
|
-
console.error("[API Core] Failed to refresh token.", err);
|
84
|
+
console.error("[API Core] Failed to refresh token.", err.response?.data || err.message);
|
66
85
|
if (config.onRefreshError) {
|
67
86
|
config.onRefreshError(err);
|
68
87
|
}
|
@@ -95,7 +114,7 @@ function createApiClient(config) {
|
|
95
114
|
const now = Date.now();
|
96
115
|
const tokenBuffer = 60 * 1e3;
|
97
116
|
if (tokens.accessToken && tokens.expiresAt && tokens.expiresAt - now < tokenBuffer) {
|
98
|
-
if (!tokenRefreshPromise) {
|
117
|
+
if (!tokenRefreshPromise && config.refreshTokenConfig) {
|
99
118
|
console.log("[API Core] Proactive token refresh initiated.");
|
100
119
|
tokenRefreshPromise = refreshToken(config, tokenManager);
|
101
120
|
}
|
@@ -115,7 +134,7 @@ function createApiClient(config) {
|
|
115
134
|
const originalRequest = error.config;
|
116
135
|
if (error.response?.status === 401 && !originalRequest._retry) {
|
117
136
|
originalRequest._retry = true;
|
118
|
-
if (!tokenRefreshPromise) {
|
137
|
+
if (!tokenRefreshPromise && config.refreshTokenConfig) {
|
119
138
|
console.log("[API Core] Reactive token refresh initiated due to 401.");
|
120
139
|
tokenRefreshPromise = refreshToken(config, tokenManager);
|
121
140
|
}
|
@@ -170,37 +189,38 @@ function isAxiosResponse(obj) {
|
|
170
189
|
var processResponse = (responseOrError) => {
|
171
190
|
if (isApiError(responseOrError)) {
|
172
191
|
return {
|
173
|
-
|
192
|
+
data: null,
|
193
|
+
rawResponse: void 0,
|
174
194
|
error: responseOrError,
|
175
195
|
validationErrors: responseOrError.errors || [],
|
176
|
-
// الخطأ الآن صحيح
|
177
196
|
success: false,
|
178
197
|
loading: false,
|
179
198
|
message: responseOrError.message
|
180
199
|
};
|
181
200
|
}
|
182
201
|
if (isAxiosResponse(responseOrError)) {
|
183
|
-
const
|
202
|
+
const rawData = responseOrError.data;
|
203
|
+
const isWrappedResponse = rawData && typeof rawData.success === "boolean" && rawData.data !== void 0;
|
204
|
+
const finalData = isWrappedResponse ? rawData.data : rawData;
|
205
|
+
const message = isWrappedResponse ? rawData.message : "Request successful.";
|
184
206
|
return {
|
185
|
-
|
207
|
+
data: finalData,
|
208
|
+
// <-- وصول مباشر للبيانات النهائية!
|
209
|
+
rawResponse: rawData,
|
210
|
+
// احتفظ بالاستجابة الكاملة إذا احتجت إليها
|
186
211
|
loading: false,
|
187
212
|
success: true,
|
188
213
|
error: null,
|
189
|
-
message
|
214
|
+
message,
|
190
215
|
validationErrors: []
|
191
|
-
// <-- أضف قيمة افتراضية هنا للاتساق
|
192
216
|
};
|
193
217
|
}
|
194
218
|
return {
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
status: 500
|
199
|
-
},
|
219
|
+
data: null,
|
220
|
+
rawResponse: void 0,
|
221
|
+
error: { message: "An unknown error occurred during response processing.", status: 500 },
|
200
222
|
success: false,
|
201
|
-
loading: false
|
202
|
-
validationErrors: []
|
203
|
-
// <-- أضف قيمة افتراضية هنا أيضًا
|
223
|
+
loading: false
|
204
224
|
};
|
205
225
|
};
|
206
226
|
|
@@ -250,6 +270,34 @@ function createApiServices(axiosInstance, endpoint) {
|
|
250
270
|
return { get, getWithQuery, post, patch, remove };
|
251
271
|
}
|
252
272
|
|
273
|
+
// src/services/actions.ts
|
274
|
+
function createAction(axiosInstance, method, endpoint) {
|
275
|
+
return async (payload, config) => {
|
276
|
+
try {
|
277
|
+
const response = await axiosInstance.request({
|
278
|
+
// <--- غيرنا النوع إلى any
|
279
|
+
url: endpoint,
|
280
|
+
method,
|
281
|
+
...method.toUpperCase() === "GET" ? { params: payload } : { data: payload },
|
282
|
+
...config
|
283
|
+
});
|
284
|
+
return processResponse(response);
|
285
|
+
} catch (error) {
|
286
|
+
return processResponse(error);
|
287
|
+
}
|
288
|
+
};
|
289
|
+
}
|
290
|
+
function createApiActions(axiosInstance, actionsConfig) {
|
291
|
+
const actions = {};
|
292
|
+
for (const actionName in actionsConfig) {
|
293
|
+
if (Object.prototype.hasOwnProperty.call(actionsConfig, actionName)) {
|
294
|
+
const { method, endpoint } = actionsConfig[actionName];
|
295
|
+
actions[actionName] = createAction(axiosInstance, method, endpoint);
|
296
|
+
}
|
297
|
+
}
|
298
|
+
return actions;
|
299
|
+
}
|
300
|
+
|
253
301
|
// src/core/cache.ts
|
254
302
|
var CacheManager = class {
|
255
303
|
cache = /* @__PURE__ */ new Map();
|
@@ -294,7 +342,9 @@ function useApi(axiosInstance, config) {
|
|
294
342
|
onError
|
295
343
|
} = config;
|
296
344
|
const [state, setState] = (0, import_react.useState)({
|
297
|
-
|
345
|
+
data: initialData || null,
|
346
|
+
// <--- التغيير هنا
|
347
|
+
rawResponse: null,
|
298
348
|
loading: enabled,
|
299
349
|
error: null,
|
300
350
|
success: false
|
@@ -302,7 +352,7 @@ function useApi(axiosInstance, config) {
|
|
302
352
|
const [queryOptions, setQueryOptions] = (0, import_react.useState)(initialQuery);
|
303
353
|
const apiServices = (0, import_react.useRef)(createApiServices(axiosInstance, endpoint)).current;
|
304
354
|
const fetchData = (0, import_react.useCallback)(async () => {
|
305
|
-
setState((prev) => ({ ...prev, loading: true, error: null }));
|
355
|
+
setState((prev) => ({ ...prev, data: null, loading: true, error: null }));
|
306
356
|
const queryString = buildPaginateQuery(queryOptions);
|
307
357
|
const result = await apiServices.getWithQuery(queryString, { cancelTokenKey: endpoint });
|
308
358
|
setState(result);
|
@@ -321,7 +371,7 @@ function useApi(axiosInstance, config) {
|
|
321
371
|
if (result.success) {
|
322
372
|
if (refetchAfterChange) await fetchData();
|
323
373
|
else setState((prev) => ({ ...prev, loading: false }));
|
324
|
-
if (onSuccess) onSuccess(result.message || "Item created successfully!", result.
|
374
|
+
if (onSuccess) onSuccess(result.message || "Item created successfully!", result.data);
|
325
375
|
} else {
|
326
376
|
setState((prev) => ({ ...prev, loading: false, error: result.error }));
|
327
377
|
if (onError) onError(result.message || "Create failed", result.error || void 0);
|
@@ -334,7 +384,7 @@ function useApi(axiosInstance, config) {
|
|
334
384
|
if (result.success) {
|
335
385
|
if (refetchAfterChange) await fetchData();
|
336
386
|
else setState((prev) => ({ ...prev, loading: false }));
|
337
|
-
if (onSuccess) onSuccess(result.message || "Item updated successfully!", result.
|
387
|
+
if (onSuccess) onSuccess(result.message || "Item updated successfully!", result.data);
|
338
388
|
} else {
|
339
389
|
setState((prev) => ({ ...prev, loading: false, error: result.error }));
|
340
390
|
if (onError) onError(result.message || "Update failed", result.error || void 0);
|
@@ -386,6 +436,7 @@ function useApi(axiosInstance, config) {
|
|
386
436
|
0 && (module.exports = {
|
387
437
|
buildPaginateQuery,
|
388
438
|
cacheManager,
|
439
|
+
createApiActions,
|
389
440
|
createApiClient,
|
390
441
|
createApiServices,
|
391
442
|
processResponse,
|
package/dist/index.mjs
CHANGED
@@ -2,26 +2,44 @@
|
|
2
2
|
import axios from "axios";
|
3
3
|
import { v4 as uuidv4 } from "uuid";
|
4
4
|
async function refreshToken(config, tokenManager) {
|
5
|
+
const { refreshTokenConfig } = config;
|
6
|
+
if (!refreshTokenConfig) {
|
7
|
+
console.warn("[API Core] Refresh token process is disabled (refreshTokenConfig is not provided).");
|
8
|
+
await tokenManager.clearTokens();
|
9
|
+
return null;
|
10
|
+
}
|
5
11
|
try {
|
6
12
|
const currentTokens = await tokenManager.getTokens();
|
7
|
-
if (!currentTokens.refreshToken)
|
13
|
+
if (!currentTokens.refreshToken) {
|
14
|
+
throw new Error("No refresh token available to perform refresh.");
|
15
|
+
}
|
16
|
+
const { path, buildRequestBody, buildRequestHeaders, extractTokens } = refreshTokenConfig;
|
17
|
+
const requestBody = buildRequestBody ? buildRequestBody(currentTokens.refreshToken) : { refresh_token: currentTokens.refreshToken };
|
18
|
+
const requestHeaders = buildRequestHeaders ? buildRequestHeaders(currentTokens) : {};
|
8
19
|
const response = await axios.post(
|
9
|
-
`${config.baseURL}${
|
10
|
-
|
11
|
-
{
|
20
|
+
`${config.baseURL}${path}`,
|
21
|
+
requestBody,
|
22
|
+
{
|
23
|
+
headers: requestHeaders,
|
24
|
+
withCredentials: config.withCredentials
|
25
|
+
}
|
12
26
|
);
|
13
|
-
const
|
27
|
+
const extracted = extractTokens(response.data);
|
28
|
+
if (!extracted || !extracted.accessToken || typeof extracted.expiresIn !== "number") {
|
29
|
+
throw new Error("extractTokens function failed to return a valid token structure.");
|
30
|
+
}
|
14
31
|
const newTokens = {
|
15
|
-
accessToken:
|
16
|
-
refreshToken:
|
17
|
-
|
18
|
-
|
32
|
+
accessToken: extracted.accessToken,
|
33
|
+
refreshToken: extracted.refreshToken || currentTokens.refreshToken,
|
34
|
+
// احتفظ بالقديم إذا لم يأتِ جديد
|
35
|
+
expiresAt: Date.now() + extracted.expiresIn * 1e3,
|
36
|
+
tokenType: extracted.tokenType || "Bearer"
|
19
37
|
};
|
20
38
|
await tokenManager.setTokens(newTokens);
|
21
39
|
console.log("[API Core] Tokens refreshed successfully.");
|
22
40
|
return newTokens;
|
23
41
|
} catch (err) {
|
24
|
-
console.error("[API Core] Failed to refresh token.", err);
|
42
|
+
console.error("[API Core] Failed to refresh token.", err.response?.data || err.message);
|
25
43
|
if (config.onRefreshError) {
|
26
44
|
config.onRefreshError(err);
|
27
45
|
}
|
@@ -54,7 +72,7 @@ function createApiClient(config) {
|
|
54
72
|
const now = Date.now();
|
55
73
|
const tokenBuffer = 60 * 1e3;
|
56
74
|
if (tokens.accessToken && tokens.expiresAt && tokens.expiresAt - now < tokenBuffer) {
|
57
|
-
if (!tokenRefreshPromise) {
|
75
|
+
if (!tokenRefreshPromise && config.refreshTokenConfig) {
|
58
76
|
console.log("[API Core] Proactive token refresh initiated.");
|
59
77
|
tokenRefreshPromise = refreshToken(config, tokenManager);
|
60
78
|
}
|
@@ -74,7 +92,7 @@ function createApiClient(config) {
|
|
74
92
|
const originalRequest = error.config;
|
75
93
|
if (error.response?.status === 401 && !originalRequest._retry) {
|
76
94
|
originalRequest._retry = true;
|
77
|
-
if (!tokenRefreshPromise) {
|
95
|
+
if (!tokenRefreshPromise && config.refreshTokenConfig) {
|
78
96
|
console.log("[API Core] Reactive token refresh initiated due to 401.");
|
79
97
|
tokenRefreshPromise = refreshToken(config, tokenManager);
|
80
98
|
}
|
@@ -129,37 +147,38 @@ function isAxiosResponse(obj) {
|
|
129
147
|
var processResponse = (responseOrError) => {
|
130
148
|
if (isApiError(responseOrError)) {
|
131
149
|
return {
|
132
|
-
|
150
|
+
data: null,
|
151
|
+
rawResponse: void 0,
|
133
152
|
error: responseOrError,
|
134
153
|
validationErrors: responseOrError.errors || [],
|
135
|
-
// الخطأ الآن صحيح
|
136
154
|
success: false,
|
137
155
|
loading: false,
|
138
156
|
message: responseOrError.message
|
139
157
|
};
|
140
158
|
}
|
141
159
|
if (isAxiosResponse(responseOrError)) {
|
142
|
-
const
|
160
|
+
const rawData = responseOrError.data;
|
161
|
+
const isWrappedResponse = rawData && typeof rawData.success === "boolean" && rawData.data !== void 0;
|
162
|
+
const finalData = isWrappedResponse ? rawData.data : rawData;
|
163
|
+
const message = isWrappedResponse ? rawData.message : "Request successful.";
|
143
164
|
return {
|
144
|
-
|
165
|
+
data: finalData,
|
166
|
+
// <-- وصول مباشر للبيانات النهائية!
|
167
|
+
rawResponse: rawData,
|
168
|
+
// احتفظ بالاستجابة الكاملة إذا احتجت إليها
|
145
169
|
loading: false,
|
146
170
|
success: true,
|
147
171
|
error: null,
|
148
|
-
message
|
172
|
+
message,
|
149
173
|
validationErrors: []
|
150
|
-
// <-- أضف قيمة افتراضية هنا للاتساق
|
151
174
|
};
|
152
175
|
}
|
153
176
|
return {
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
status: 500
|
158
|
-
},
|
177
|
+
data: null,
|
178
|
+
rawResponse: void 0,
|
179
|
+
error: { message: "An unknown error occurred during response processing.", status: 500 },
|
159
180
|
success: false,
|
160
|
-
loading: false
|
161
|
-
validationErrors: []
|
162
|
-
// <-- أضف قيمة افتراضية هنا أيضًا
|
181
|
+
loading: false
|
163
182
|
};
|
164
183
|
};
|
165
184
|
|
@@ -209,6 +228,34 @@ function createApiServices(axiosInstance, endpoint) {
|
|
209
228
|
return { get, getWithQuery, post, patch, remove };
|
210
229
|
}
|
211
230
|
|
231
|
+
// src/services/actions.ts
|
232
|
+
function createAction(axiosInstance, method, endpoint) {
|
233
|
+
return async (payload, config) => {
|
234
|
+
try {
|
235
|
+
const response = await axiosInstance.request({
|
236
|
+
// <--- غيرنا النوع إلى any
|
237
|
+
url: endpoint,
|
238
|
+
method,
|
239
|
+
...method.toUpperCase() === "GET" ? { params: payload } : { data: payload },
|
240
|
+
...config
|
241
|
+
});
|
242
|
+
return processResponse(response);
|
243
|
+
} catch (error) {
|
244
|
+
return processResponse(error);
|
245
|
+
}
|
246
|
+
};
|
247
|
+
}
|
248
|
+
function createApiActions(axiosInstance, actionsConfig) {
|
249
|
+
const actions = {};
|
250
|
+
for (const actionName in actionsConfig) {
|
251
|
+
if (Object.prototype.hasOwnProperty.call(actionsConfig, actionName)) {
|
252
|
+
const { method, endpoint } = actionsConfig[actionName];
|
253
|
+
actions[actionName] = createAction(axiosInstance, method, endpoint);
|
254
|
+
}
|
255
|
+
}
|
256
|
+
return actions;
|
257
|
+
}
|
258
|
+
|
212
259
|
// src/core/cache.ts
|
213
260
|
var CacheManager = class {
|
214
261
|
cache = /* @__PURE__ */ new Map();
|
@@ -253,7 +300,9 @@ function useApi(axiosInstance, config) {
|
|
253
300
|
onError
|
254
301
|
} = config;
|
255
302
|
const [state, setState] = useState({
|
256
|
-
|
303
|
+
data: initialData || null,
|
304
|
+
// <--- التغيير هنا
|
305
|
+
rawResponse: null,
|
257
306
|
loading: enabled,
|
258
307
|
error: null,
|
259
308
|
success: false
|
@@ -261,7 +310,7 @@ function useApi(axiosInstance, config) {
|
|
261
310
|
const [queryOptions, setQueryOptions] = useState(initialQuery);
|
262
311
|
const apiServices = useRef(createApiServices(axiosInstance, endpoint)).current;
|
263
312
|
const fetchData = useCallback(async () => {
|
264
|
-
setState((prev) => ({ ...prev, loading: true, error: null }));
|
313
|
+
setState((prev) => ({ ...prev, data: null, loading: true, error: null }));
|
265
314
|
const queryString = buildPaginateQuery(queryOptions);
|
266
315
|
const result = await apiServices.getWithQuery(queryString, { cancelTokenKey: endpoint });
|
267
316
|
setState(result);
|
@@ -280,7 +329,7 @@ function useApi(axiosInstance, config) {
|
|
280
329
|
if (result.success) {
|
281
330
|
if (refetchAfterChange) await fetchData();
|
282
331
|
else setState((prev) => ({ ...prev, loading: false }));
|
283
|
-
if (onSuccess) onSuccess(result.message || "Item created successfully!", result.
|
332
|
+
if (onSuccess) onSuccess(result.message || "Item created successfully!", result.data);
|
284
333
|
} else {
|
285
334
|
setState((prev) => ({ ...prev, loading: false, error: result.error }));
|
286
335
|
if (onError) onError(result.message || "Create failed", result.error || void 0);
|
@@ -293,7 +342,7 @@ function useApi(axiosInstance, config) {
|
|
293
342
|
if (result.success) {
|
294
343
|
if (refetchAfterChange) await fetchData();
|
295
344
|
else setState((prev) => ({ ...prev, loading: false }));
|
296
|
-
if (onSuccess) onSuccess(result.message || "Item updated successfully!", result.
|
345
|
+
if (onSuccess) onSuccess(result.message || "Item updated successfully!", result.data);
|
297
346
|
} else {
|
298
347
|
setState((prev) => ({ ...prev, loading: false, error: result.error }));
|
299
348
|
if (onError) onError(result.message || "Update failed", result.error || void 0);
|
@@ -344,6 +393,7 @@ function useApi(axiosInstance, config) {
|
|
344
393
|
export {
|
345
394
|
buildPaginateQuery,
|
346
395
|
cacheManager,
|
396
|
+
createApiActions,
|
347
397
|
createApiClient,
|
348
398
|
createApiServices,
|
349
399
|
processResponse,
|