api-core-lib 2.2.1 → 3.2.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 +54 -14
- package/dist/index.d.ts +54 -14
- package/dist/index.js +30 -12
- package/dist/index.mjs +30 -12
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
@@ -83,19 +83,6 @@ interface RequestConfig extends AxiosRequestConfig {
|
|
83
83
|
onUploadProgress?: (progressEvent: AxiosProgressEvent) => void;
|
84
84
|
onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void;
|
85
85
|
}
|
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
86
|
/**
|
100
87
|
* يمثل خيارات الاستعلام للترقيم والبحث والفرز.
|
101
88
|
*/
|
@@ -122,6 +109,59 @@ interface UseApiConfig<T> {
|
|
122
109
|
onSuccess?: (message: string, data?: T) => void;
|
123
110
|
onError?: (message: string, error?: ApiError) => void;
|
124
111
|
}
|
112
|
+
/**
|
113
|
+
* واجهة لتخصيص عملية تجديد التوكن بشكل كامل.
|
114
|
+
*/
|
115
|
+
interface RefreshTokenConfig {
|
116
|
+
/**
|
117
|
+
* المسار الذي يتم استخدامه لتجديد التوكن (e.g., '/auth/refresh').
|
118
|
+
* @default '/auth/refresh'
|
119
|
+
*/
|
120
|
+
path: string;
|
121
|
+
/**
|
122
|
+
* دالة لتحديد كيفية بناء جسم (body) طلب التجديد.
|
123
|
+
* @param refreshToken - التوكن المستخدم للتجديد.
|
124
|
+
* @returns كائن يمثل جسم الطلب.
|
125
|
+
* @default (refreshToken) => ({ refresh_token: refreshToken })
|
126
|
+
*/
|
127
|
+
buildRequestBody?: (refreshToken: string) => Record<string, any>;
|
128
|
+
/**
|
129
|
+
* دالة لتحديد كيفية بناء الهيدرز (headers) الخاصة بطلب التجديد.
|
130
|
+
* @param currentTokens - التوكنات الحالية.
|
131
|
+
* @returns كائن يمثل الهيدرز الإضافية.
|
132
|
+
* @default () => ({})
|
133
|
+
*/
|
134
|
+
buildRequestHeaders?: (currentTokens: Tokens) => Record<string, string>;
|
135
|
+
/**
|
136
|
+
* دالة مخصصة لاستخلاص التوكنات الجديدة من استجابة الـ API.
|
137
|
+
* @param responseData - البيانات التي تم إرجاعها من الـ API.
|
138
|
+
* @returns كائن من نوع Tokens.
|
139
|
+
* @default (data) => ({ accessToken: data.access_token, ... })
|
140
|
+
*/
|
141
|
+
extractTokens: (responseData: any) => {
|
142
|
+
accessToken: string;
|
143
|
+
refreshToken?: string;
|
144
|
+
expiresIn: number;
|
145
|
+
tokenType?: string;
|
146
|
+
};
|
147
|
+
}
|
148
|
+
/**
|
149
|
+
* الواجهة الرئيسية لتهيئة عميل الـ API.
|
150
|
+
*/
|
151
|
+
interface ApiClientConfig {
|
152
|
+
baseURL?: string;
|
153
|
+
tokenManager: TokenManager;
|
154
|
+
timeout?: number;
|
155
|
+
headers?: Record<string, string>;
|
156
|
+
withCredentials?: boolean;
|
157
|
+
responseType?: ResponseType;
|
158
|
+
/**
|
159
|
+
* إعدادات مخصصة لعملية تجديد التوكن.
|
160
|
+
* إذا لم يتم توفيرها، ستتوقف محاولات التجديد التلقائي.
|
161
|
+
*/
|
162
|
+
refreshTokenConfig?: RefreshTokenConfig;
|
163
|
+
onRefreshError?: (error: any) => void;
|
164
|
+
}
|
125
165
|
|
126
166
|
/**
|
127
167
|
* @file src/core/client.ts
|
@@ -195,4 +235,4 @@ declare function useApi<T extends {
|
|
195
235
|
};
|
196
236
|
};
|
197
237
|
|
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 };
|
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 };
|
package/dist/index.d.ts
CHANGED
@@ -83,19 +83,6 @@ interface RequestConfig extends AxiosRequestConfig {
|
|
83
83
|
onUploadProgress?: (progressEvent: AxiosProgressEvent) => void;
|
84
84
|
onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void;
|
85
85
|
}
|
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
86
|
/**
|
100
87
|
* يمثل خيارات الاستعلام للترقيم والبحث والفرز.
|
101
88
|
*/
|
@@ -122,6 +109,59 @@ interface UseApiConfig<T> {
|
|
122
109
|
onSuccess?: (message: string, data?: T) => void;
|
123
110
|
onError?: (message: string, error?: ApiError) => void;
|
124
111
|
}
|
112
|
+
/**
|
113
|
+
* واجهة لتخصيص عملية تجديد التوكن بشكل كامل.
|
114
|
+
*/
|
115
|
+
interface RefreshTokenConfig {
|
116
|
+
/**
|
117
|
+
* المسار الذي يتم استخدامه لتجديد التوكن (e.g., '/auth/refresh').
|
118
|
+
* @default '/auth/refresh'
|
119
|
+
*/
|
120
|
+
path: string;
|
121
|
+
/**
|
122
|
+
* دالة لتحديد كيفية بناء جسم (body) طلب التجديد.
|
123
|
+
* @param refreshToken - التوكن المستخدم للتجديد.
|
124
|
+
* @returns كائن يمثل جسم الطلب.
|
125
|
+
* @default (refreshToken) => ({ refresh_token: refreshToken })
|
126
|
+
*/
|
127
|
+
buildRequestBody?: (refreshToken: string) => Record<string, any>;
|
128
|
+
/**
|
129
|
+
* دالة لتحديد كيفية بناء الهيدرز (headers) الخاصة بطلب التجديد.
|
130
|
+
* @param currentTokens - التوكنات الحالية.
|
131
|
+
* @returns كائن يمثل الهيدرز الإضافية.
|
132
|
+
* @default () => ({})
|
133
|
+
*/
|
134
|
+
buildRequestHeaders?: (currentTokens: Tokens) => Record<string, string>;
|
135
|
+
/**
|
136
|
+
* دالة مخصصة لاستخلاص التوكنات الجديدة من استجابة الـ API.
|
137
|
+
* @param responseData - البيانات التي تم إرجاعها من الـ API.
|
138
|
+
* @returns كائن من نوع Tokens.
|
139
|
+
* @default (data) => ({ accessToken: data.access_token, ... })
|
140
|
+
*/
|
141
|
+
extractTokens: (responseData: any) => {
|
142
|
+
accessToken: string;
|
143
|
+
refreshToken?: string;
|
144
|
+
expiresIn: number;
|
145
|
+
tokenType?: string;
|
146
|
+
};
|
147
|
+
}
|
148
|
+
/**
|
149
|
+
* الواجهة الرئيسية لتهيئة عميل الـ API.
|
150
|
+
*/
|
151
|
+
interface ApiClientConfig {
|
152
|
+
baseURL?: string;
|
153
|
+
tokenManager: TokenManager;
|
154
|
+
timeout?: number;
|
155
|
+
headers?: Record<string, string>;
|
156
|
+
withCredentials?: boolean;
|
157
|
+
responseType?: ResponseType;
|
158
|
+
/**
|
159
|
+
* إعدادات مخصصة لعملية تجديد التوكن.
|
160
|
+
* إذا لم يتم توفيرها، ستتوقف محاولات التجديد التلقائي.
|
161
|
+
*/
|
162
|
+
refreshTokenConfig?: RefreshTokenConfig;
|
163
|
+
onRefreshError?: (error: any) => void;
|
164
|
+
}
|
125
165
|
|
126
166
|
/**
|
127
167
|
* @file src/core/client.ts
|
@@ -195,4 +235,4 @@ declare function useApi<T extends {
|
|
195
235
|
};
|
196
236
|
};
|
197
237
|
|
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 };
|
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 };
|
package/dist/index.js
CHANGED
@@ -43,26 +43,44 @@ module.exports = __toCommonJS(index_exports);
|
|
43
43
|
var import_axios = __toESM(require("axios"));
|
44
44
|
var import_uuid = require("uuid");
|
45
45
|
async function refreshToken(config, tokenManager) {
|
46
|
+
const { refreshTokenConfig } = config;
|
47
|
+
if (!refreshTokenConfig) {
|
48
|
+
console.warn("[API Core] Refresh token process is disabled (refreshTokenConfig is not provided).");
|
49
|
+
await tokenManager.clearTokens();
|
50
|
+
return null;
|
51
|
+
}
|
46
52
|
try {
|
47
53
|
const currentTokens = await tokenManager.getTokens();
|
48
|
-
if (!currentTokens.refreshToken)
|
54
|
+
if (!currentTokens.refreshToken) {
|
55
|
+
throw new Error("No refresh token available to perform refresh.");
|
56
|
+
}
|
57
|
+
const { path, buildRequestBody, buildRequestHeaders, extractTokens } = refreshTokenConfig;
|
58
|
+
const requestBody = buildRequestBody ? buildRequestBody(currentTokens.refreshToken) : { refresh_token: currentTokens.refreshToken };
|
59
|
+
const requestHeaders = buildRequestHeaders ? buildRequestHeaders(currentTokens) : {};
|
49
60
|
const response = await import_axios.default.post(
|
50
|
-
`${config.baseURL}
|
51
|
-
|
52
|
-
{
|
61
|
+
`${config.baseURL}${path}`,
|
62
|
+
requestBody,
|
63
|
+
{
|
64
|
+
headers: requestHeaders,
|
65
|
+
withCredentials: config.withCredentials
|
66
|
+
}
|
53
67
|
);
|
54
|
-
const
|
68
|
+
const extracted = extractTokens(response.data);
|
69
|
+
if (!extracted || !extracted.accessToken || typeof extracted.expiresIn !== "number") {
|
70
|
+
throw new Error("extractTokens function failed to return a valid token structure.");
|
71
|
+
}
|
55
72
|
const newTokens = {
|
56
|
-
accessToken:
|
57
|
-
refreshToken:
|
58
|
-
|
59
|
-
|
73
|
+
accessToken: extracted.accessToken,
|
74
|
+
refreshToken: extracted.refreshToken || currentTokens.refreshToken,
|
75
|
+
// احتفظ بالقديم إذا لم يأتِ جديد
|
76
|
+
expiresAt: Date.now() + extracted.expiresIn * 1e3,
|
77
|
+
tokenType: extracted.tokenType || "Bearer"
|
60
78
|
};
|
61
79
|
await tokenManager.setTokens(newTokens);
|
62
80
|
console.log("[API Core] Tokens refreshed successfully.");
|
63
81
|
return newTokens;
|
64
82
|
} catch (err) {
|
65
|
-
console.error("[API Core] Failed to refresh token.", err);
|
83
|
+
console.error("[API Core] Failed to refresh token.", err.response?.data || err.message);
|
66
84
|
if (config.onRefreshError) {
|
67
85
|
config.onRefreshError(err);
|
68
86
|
}
|
@@ -95,7 +113,7 @@ function createApiClient(config) {
|
|
95
113
|
const now = Date.now();
|
96
114
|
const tokenBuffer = 60 * 1e3;
|
97
115
|
if (tokens.accessToken && tokens.expiresAt && tokens.expiresAt - now < tokenBuffer) {
|
98
|
-
if (!tokenRefreshPromise) {
|
116
|
+
if (!tokenRefreshPromise && config.refreshTokenConfig) {
|
99
117
|
console.log("[API Core] Proactive token refresh initiated.");
|
100
118
|
tokenRefreshPromise = refreshToken(config, tokenManager);
|
101
119
|
}
|
@@ -115,7 +133,7 @@ function createApiClient(config) {
|
|
115
133
|
const originalRequest = error.config;
|
116
134
|
if (error.response?.status === 401 && !originalRequest._retry) {
|
117
135
|
originalRequest._retry = true;
|
118
|
-
if (!tokenRefreshPromise) {
|
136
|
+
if (!tokenRefreshPromise && config.refreshTokenConfig) {
|
119
137
|
console.log("[API Core] Reactive token refresh initiated due to 401.");
|
120
138
|
tokenRefreshPromise = refreshToken(config, tokenManager);
|
121
139
|
}
|
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
|
}
|