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 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) throw new Error("No refresh token available.");
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}/auth/refresh`,
51
- { refresh_token: currentTokens.refreshToken },
52
- { withCredentials: config.withCredentials }
61
+ `${config.baseURL}${path}`,
62
+ requestBody,
63
+ {
64
+ headers: requestHeaders,
65
+ withCredentials: config.withCredentials
66
+ }
53
67
  );
54
- const { access_token, refresh_token, expires_in, token_type } = response.data;
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: access_token,
57
- refreshToken: refresh_token || currentTokens.refreshToken,
58
- expiresAt: Date.now() + expires_in * 1e3,
59
- tokenType: token_type || "Bearer"
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) throw new Error("No refresh token available.");
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}/auth/refresh`,
10
- { refresh_token: currentTokens.refreshToken },
11
- { withCredentials: config.withCredentials }
20
+ `${config.baseURL}${path}`,
21
+ requestBody,
22
+ {
23
+ headers: requestHeaders,
24
+ withCredentials: config.withCredentials
25
+ }
12
26
  );
13
- const { access_token, refresh_token, expires_in, token_type } = response.data;
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: access_token,
16
- refreshToken: refresh_token || currentTokens.refreshToken,
17
- expiresAt: Date.now() + expires_in * 1e3,
18
- tokenType: token_type || "Bearer"
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-core-lib",
3
- "version": "2.2.1",
3
+ "version": "3.2.2",
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",