@alba-cars/common-modules 1.10.3 → 1.10.4

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.
@@ -4,5 +4,53 @@ interface ApiRequestOptions extends RequestInit {
4
4
  timeout?: number;
5
5
  signal?: AbortSignal;
6
6
  }
7
+ type RequestInterceptor = (config: RequestInit & {
8
+ url: string;
9
+ options: ApiRequestOptions;
10
+ }) => Promise<RequestInit & {
11
+ url: string;
12
+ options: ApiRequestOptions;
13
+ }> | (RequestInit & {
14
+ url: string;
15
+ options: ApiRequestOptions;
16
+ });
17
+ type ResponseInterceptor = (response: Response, requestConfig: RequestInit & {
18
+ url: string;
19
+ }) => Promise<Response> | Response;
20
+ type ResponseErrorInterceptor = (error: any, requestConfig: RequestInit & {
21
+ url: string;
22
+ }) => Promise<Response> | Response | Promise<any> | any;
23
+ declare class InterceptorManager {
24
+ private requestInterceptors;
25
+ private responseInterceptors;
26
+ private responseErrorInterceptors;
27
+ addRequestInterceptor(interceptor: RequestInterceptor): number;
28
+ addResponseInterceptor(interceptor: ResponseInterceptor): number;
29
+ addResponseErrorInterceptor(interceptor: ResponseErrorInterceptor): number;
30
+ removeRequestInterceptor(index: number): void;
31
+ removeResponseInterceptor(index: number): void;
32
+ removeResponseErrorInterceptor(index: number): void;
33
+ clearRequestInterceptors(): void;
34
+ clearResponseInterceptors(): void;
35
+ clearResponseErrorInterceptors(): void;
36
+ clearAllInterceptors(): void;
37
+ applyRequestInterceptors(config: RequestInit & {
38
+ url: string;
39
+ options: ApiRequestOptions;
40
+ }): Promise<RequestInit & {
41
+ url: string;
42
+ options: ApiRequestOptions;
43
+ }>;
44
+ applyResponseInterceptors(response: Response, requestConfig: RequestInit & {
45
+ url: string;
46
+ }): Promise<Response>;
47
+ applyResponseErrorInterceptors(error: any, requestConfig: RequestInit & {
48
+ url: string;
49
+ }): Promise<any>;
50
+ retryRequest<T>(config: RequestInit & {
51
+ url: string;
52
+ }): Promise<T>;
53
+ }
54
+ export declare const interceptors: InterceptorManager;
7
55
  export declare function apiRequest<T>(endpoint: string, options?: ApiRequestOptions): Promise<T>;
8
56
  export {};
@@ -3,12 +3,115 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.apiRequest = void 0;
6
+ exports.apiRequest = exports.interceptors = void 0;
7
7
  const qs_1 = __importDefault(require("qs"));
8
8
  const enums_1 = require("../enums");
9
9
  const utils_1 = require("../utils");
10
10
  const BASE_URL = process.env.NEXT_PUBLIC_API_URL;
11
11
  const DEFAULT_TIMEOUT = (0, utils_1.timeAsMilliseconds)({ seconds: 30 });
12
+ // Interceptor manager
13
+ class InterceptorManager {
14
+ constructor() {
15
+ this.requestInterceptors = [];
16
+ this.responseInterceptors = [];
17
+ this.responseErrorInterceptors = [];
18
+ }
19
+ addRequestInterceptor(interceptor) {
20
+ return this.requestInterceptors.push(interceptor) - 1;
21
+ }
22
+ addResponseInterceptor(interceptor) {
23
+ return this.responseInterceptors.push(interceptor) - 1;
24
+ }
25
+ addResponseErrorInterceptor(interceptor) {
26
+ return this.responseErrorInterceptors.push(interceptor) - 1;
27
+ }
28
+ removeRequestInterceptor(index) {
29
+ if (index >= 0) {
30
+ this.requestInterceptors.splice(index, 1);
31
+ }
32
+ }
33
+ removeResponseInterceptor(index) {
34
+ if (index >= 0) {
35
+ this.responseInterceptors.splice(index, 1);
36
+ }
37
+ }
38
+ removeResponseErrorInterceptor(index) {
39
+ if (index >= 0) {
40
+ this.responseErrorInterceptors.splice(index, 1);
41
+ }
42
+ }
43
+ clearRequestInterceptors() {
44
+ this.requestInterceptors = [];
45
+ }
46
+ clearResponseInterceptors() {
47
+ this.responseInterceptors = [];
48
+ }
49
+ clearResponseErrorInterceptors() {
50
+ this.responseErrorInterceptors = [];
51
+ }
52
+ clearAllInterceptors() {
53
+ this.clearRequestInterceptors();
54
+ this.clearResponseInterceptors();
55
+ this.clearResponseErrorInterceptors();
56
+ }
57
+ async applyRequestInterceptors(config) {
58
+ let modifiedConfig = { ...config };
59
+ for (const interceptor of this.requestInterceptors) {
60
+ modifiedConfig = await interceptor(modifiedConfig);
61
+ }
62
+ return modifiedConfig;
63
+ }
64
+ async applyResponseInterceptors(response, requestConfig) {
65
+ let modifiedResponse = response;
66
+ for (const interceptor of this.responseInterceptors) {
67
+ modifiedResponse = await interceptor(modifiedResponse, requestConfig);
68
+ }
69
+ return modifiedResponse;
70
+ }
71
+ async applyResponseErrorInterceptors(error, requestConfig) {
72
+ let modifiedError = error;
73
+ for (const interceptor of this.responseErrorInterceptors) {
74
+ try {
75
+ // If an interceptor resolves the error, return the resolved value
76
+ const result = await interceptor(modifiedError, requestConfig);
77
+ if (result instanceof Response) {
78
+ return result;
79
+ }
80
+ modifiedError = result;
81
+ }
82
+ catch (newError) {
83
+ // If an interceptor rejects, continue with the new error
84
+ modifiedError = newError;
85
+ }
86
+ }
87
+ // If no interceptor handled the error, throw it
88
+ throw modifiedError;
89
+ }
90
+ async retryRequest(config) {
91
+ try {
92
+ // Make a new request with the updated config
93
+ const response = await fetch(config.url, config);
94
+ // Apply response interceptors
95
+ const interceptedResponse = await this.applyResponseInterceptors(response, config);
96
+ const contentType = interceptedResponse.headers.get("content-type");
97
+ const responseData = (contentType === null || contentType === void 0 ? void 0 : contentType.includes("application/json"))
98
+ ? await interceptedResponse.json()
99
+ : await interceptedResponse.text();
100
+ if (interceptedResponse.ok) {
101
+ return responseData;
102
+ }
103
+ // Handle errors
104
+ const apiError = createApiError(interceptedResponse.status, responseData);
105
+ throw apiError;
106
+ }
107
+ catch (error) {
108
+ // Apply response error interceptors
109
+ return this.applyResponseErrorInterceptors(error, config);
110
+ }
111
+ }
112
+ }
113
+ // Create the interceptor manager instance
114
+ exports.interceptors = new InterceptorManager();
12
115
  const buildUrl = (endpoint, query) => {
13
116
  let url = `${BASE_URL}${endpoint}`;
14
117
  if (query && Object.keys(query).length > 0) {
@@ -28,8 +131,8 @@ async function apiRequest(endpoint, options = {}) {
28
131
  // If timeout is specified, create a timeout abort controller
29
132
  if (options.timeout && controller) {
30
133
  timeoutId = setTimeout(() => {
31
- controller.abort('Request timeout');
32
- }, options.timeout);
134
+ controller.abort("Request timeout");
135
+ }, options.timeout || DEFAULT_TIMEOUT);
33
136
  }
34
137
  // Use provided signal or timeout controller's signal
35
138
  const signal = options.signal || (controller === null || controller === void 0 ? void 0 : controller.signal);
@@ -51,20 +154,46 @@ async function apiRequest(endpoint, options = {}) {
51
154
  catch (error) {
52
155
  return Promise.reject(error);
53
156
  }
157
+ finally {
158
+ if (timeoutId) {
159
+ clearTimeout(timeoutId);
160
+ }
161
+ }
54
162
  }
55
163
  exports.apiRequest = apiRequest;
56
164
  async function makeRequest(endpoint, config, options = {}) {
57
165
  const url = buildUrl(endpoint, options.query);
58
- const response = await fetch(url, config);
59
- const contentType = response.headers.get("content-type");
60
- const responseData = (contentType === null || contentType === void 0 ? void 0 : contentType.includes("application/json"))
61
- ? await response.json()
62
- : await response.text();
63
- if (response.ok) {
64
- return responseData;
65
- }
66
- // Handle other errors
67
- throw createApiError(response.status, responseData);
166
+ // Apply request interceptors
167
+ let requestConfig = await exports.interceptors.applyRequestInterceptors({
168
+ ...config,
169
+ url,
170
+ options,
171
+ });
172
+ // Extract the URL after interceptors may have modified it
173
+ const interceptedUrl = requestConfig.url;
174
+ try {
175
+ // Make the actual request
176
+ const response = await fetch(interceptedUrl, requestConfig);
177
+ // Apply response interceptors
178
+ const interceptedResponse = await exports.interceptors.applyResponseInterceptors(response, { ...requestConfig, url: interceptedUrl });
179
+ const contentType = interceptedResponse.headers.get("content-type");
180
+ const responseData = (contentType === null || contentType === void 0 ? void 0 : contentType.includes("application/json"))
181
+ ? await interceptedResponse.json()
182
+ : await interceptedResponse.text();
183
+ if (interceptedResponse.ok) {
184
+ return responseData;
185
+ }
186
+ // Handle other errors
187
+ const apiError = createApiError(interceptedResponse.status, responseData);
188
+ throw apiError;
189
+ }
190
+ catch (error) {
191
+ // Apply response error interceptors
192
+ return exports.interceptors.applyResponseErrorInterceptors(error, {
193
+ ...requestConfig,
194
+ url: interceptedUrl,
195
+ });
196
+ }
68
197
  }
69
198
  function createApiError(status, responseData) {
70
199
  const error = new Error(typeof responseData === "object"
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.10.3",
6
+ "version": "1.10.4",
7
7
  "description": "A package containing DTOs, validation classes and common modules and interfaces for Alba Cars",
8
8
  "main": "dist/index.js",
9
9
  "types": "dist/index.d.ts",