@xbg.solutions/bpsk-utils-api-client 1.2.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.
Files changed (49) hide show
  1. package/lib/index.d.ts +10 -0
  2. package/lib/index.d.ts.map +1 -0
  3. package/lib/index.js +14 -0
  4. package/lib/index.js.map +1 -0
  5. package/lib/services/api/api.service.d.ts +67 -0
  6. package/lib/services/api/api.service.d.ts.map +1 -0
  7. package/lib/services/api/api.service.js +344 -0
  8. package/lib/services/api/api.service.js.map +1 -0
  9. package/lib/services/api/index.d.ts +13 -0
  10. package/lib/services/api/index.d.ts.map +1 -0
  11. package/lib/services/api/index.js +15 -0
  12. package/lib/services/api/index.js.map +1 -0
  13. package/lib/services/api/request-handler.d.ts +17 -0
  14. package/lib/services/api/request-handler.d.ts.map +1 -0
  15. package/lib/services/api/request-handler.js +289 -0
  16. package/lib/services/api/request-handler.js.map +1 -0
  17. package/lib/services/api/response-handler.d.ts +16 -0
  18. package/lib/services/api/response-handler.d.ts.map +1 -0
  19. package/lib/services/api/response-handler.js +254 -0
  20. package/lib/services/api/response-handler.js.map +1 -0
  21. package/lib/services/caching/api-cache.service.d.ts +97 -0
  22. package/lib/services/caching/api-cache.service.d.ts.map +1 -0
  23. package/lib/services/caching/api-cache.service.js +294 -0
  24. package/lib/services/caching/api-cache.service.js.map +1 -0
  25. package/lib/services/caching/cache.service.d.ts +86 -0
  26. package/lib/services/caching/cache.service.d.ts.map +1 -0
  27. package/lib/services/caching/cache.service.js +519 -0
  28. package/lib/services/caching/cache.service.js.map +1 -0
  29. package/lib/services/caching/index.d.ts +5 -0
  30. package/lib/services/caching/index.d.ts.map +1 -0
  31. package/lib/services/caching/index.js +3 -0
  32. package/lib/services/caching/index.js.map +1 -0
  33. package/lib/stores/api.service.d.ts +6 -0
  34. package/lib/stores/api.service.d.ts.map +1 -0
  35. package/lib/stores/api.service.js +6 -0
  36. package/lib/stores/api.service.js.map +1 -0
  37. package/lib/stores/request-handler.d.ts +6 -0
  38. package/lib/stores/request-handler.d.ts.map +1 -0
  39. package/lib/stores/request-handler.js +6 -0
  40. package/lib/stores/request-handler.js.map +1 -0
  41. package/lib/stores/response-handler.d.ts +6 -0
  42. package/lib/stores/response-handler.d.ts.map +1 -0
  43. package/lib/stores/response-handler.js +6 -0
  44. package/lib/stores/response-handler.js.map +1 -0
  45. package/lib/utils/cache-helpers.d.ts +112 -0
  46. package/lib/utils/cache-helpers.d.ts.map +1 -0
  47. package/lib/utils/cache-helpers.js +302 -0
  48. package/lib/utils/cache-helpers.js.map +1 -0
  49. package/package.json +27 -0
@@ -0,0 +1,289 @@
1
+ /**
2
+ * src/lib/services/api/request-handler.ts
3
+ * API Request Handler
4
+ *
5
+ * Handles API request preparation with support for:
6
+ * - Authentication token inclusion
7
+ * - CSRF protection
8
+ * - Request timeout management
9
+ * - Header normalization
10
+ * - Data serialization
11
+ */
12
+ import { loggerService } from '@xbg.solutions/bpsk-core';
13
+ import { tokenService } from '@xbg.solutions/bpsk-utils-firebase-auth';
14
+ import { csrfProtection } from '@xbg.solutions/bpsk-utils-csrf';
15
+ import { inputSanitizer } from '@xbg.solutions/bpsk-utils-sanitizer';
16
+ import { ApiError, NetworkError, normalizeError } from '@xbg.solutions/bpsk-core';
17
+ import { API_CONSTANTS } from '@xbg.solutions/bpsk-core';
18
+ // Create a context-aware logger
19
+ const requestLogger = loggerService.withContext('RequestHandler');
20
+ /**
21
+ * Creates a timeout promise that rejects after the specified time
22
+ *
23
+ * @param ms Timeout in milliseconds
24
+ * @param controller AbortController to abort the request
25
+ * @param url Request URL for error context
26
+ * @returns A promise that rejects after the timeout
27
+ */
28
+ function createRequestTimeout(ms, controller, url) {
29
+ return new Promise((_, reject) => {
30
+ setTimeout(() => {
31
+ controller.abort();
32
+ const timeoutError = new NetworkError('Request timeout', {
33
+ isTimeout: true,
34
+ context: { endpoint: url },
35
+ userMessage: 'The request took too long to complete. Please try again.'
36
+ });
37
+ reject(timeoutError);
38
+ }, ms);
39
+ });
40
+ }
41
+ /**
42
+ * Request Handler implementation
43
+ */
44
+ export const requestHandler = {
45
+ /**
46
+ * Prepares a request with proper headers, authentication, and CSRF protection
47
+ */
48
+ async prepareRequest(method, url, data, options = {}) {
49
+ try {
50
+ const logContext = {
51
+ method,
52
+ url,
53
+ hasData: !!data
54
+ };
55
+ // Log the preparation start
56
+ requestLogger.info(`Preparing ${method} request to ${url}`, logContext);
57
+ // Create request headers combining defaults with provided options
58
+ const headers = new Headers(API_CONSTANTS.REQUEST_CONFIG.headers);
59
+ // Add any custom headers from options
60
+ if (options.headers) {
61
+ Object.entries(options.headers).forEach(([key, value]) => {
62
+ headers.set(key, value);
63
+ });
64
+ }
65
+ // Create base request options
66
+ const requestOptions = {
67
+ method,
68
+ credentials: options.credentials || API_CONSTANTS.REQUEST_CONFIG.credentials,
69
+ headers
70
+ };
71
+ // Copy valid RequestInit properties from options
72
+ if (options.mode)
73
+ requestOptions.mode = options.mode;
74
+ if (options.enableCache)
75
+ requestOptions.cache = 'default';
76
+ if (options.redirect)
77
+ requestOptions.redirect = options.redirect;
78
+ if (options.referrer)
79
+ requestOptions.referrer = options.referrer;
80
+ if (options.referrerPolicy)
81
+ requestOptions.referrerPolicy = options.referrerPolicy;
82
+ if (options.integrity)
83
+ requestOptions.integrity = options.integrity;
84
+ if (options.keepalive)
85
+ requestOptions.keepalive = options.keepalive;
86
+ // Add auth token if user is authenticated
87
+ if (tokenService.isAuthenticated()) {
88
+ const token = tokenService.getToken();
89
+ if (token) {
90
+ headers.set('Authorization', `Bearer ${token}`);
91
+ requestLogger.info('Added authentication token to request', {
92
+ ...logContext,
93
+ tokenPresent: true
94
+ });
95
+ }
96
+ }
97
+ // Prepare request body for non-GET requests
98
+ if (data && method !== 'GET') {
99
+ // Don't sanitize file uploads or FormData
100
+ if (data instanceof FormData) {
101
+ requestOptions.body = data;
102
+ // Remove content-type so browser can set it with correct boundary
103
+ headers.delete('Content-Type');
104
+ requestLogger.info('Prepared FormData request body', logContext);
105
+ }
106
+ else if (data instanceof Blob || data instanceof ArrayBuffer) {
107
+ requestOptions.body = data;
108
+ requestLogger.info('Prepared binary request body', logContext);
109
+ }
110
+ else if (options.body) {
111
+ // Use body from options if provided
112
+ requestOptions.body = options.body;
113
+ requestLogger.info('Using provided body from options', logContext);
114
+ }
115
+ else {
116
+ // For JSON data, sanitize input and stringify
117
+ const sanitizedData = inputSanitizer(data);
118
+ requestOptions.body = JSON.stringify(sanitizedData);
119
+ requestLogger.info('Prepared JSON request body', {
120
+ ...logContext,
121
+ dataType: 'json'
122
+ });
123
+ }
124
+ }
125
+ else if (options.body) {
126
+ // Use body from options if provided
127
+ requestOptions.body = options.body;
128
+ requestLogger.info('Using provided body from options', logContext);
129
+ }
130
+ // Add CSRF protection for state-changing methods
131
+ if (API_CONSTANTS.CSRF_PROTECTED_METHODS.includes(method)) {
132
+ requestLogger.info(`Adding CSRF protection to ${method} request`, logContext);
133
+ return await csrfProtection.protectRequest(url, requestOptions);
134
+ }
135
+ requestLogger.info(`Successfully prepared ${method} request to ${url}`, logContext);
136
+ return requestOptions;
137
+ }
138
+ catch (error) {
139
+ const normalizedError = normalizeError(error, 'Failed to prepare request', {
140
+ category: 'api',
141
+ context: { method, url }
142
+ });
143
+ requestLogger.error(`Failed to prepare ${method} request to ${url}`, normalizedError, { method, url });
144
+ throw normalizedError;
145
+ }
146
+ },
147
+ /**
148
+ * Executes a request with timeout handling
149
+ */
150
+ async executeRequest(url, options, timeoutMs = API_CONSTANTS.REQUEST_CONFIG.timeout) {
151
+ const logContext = {
152
+ url,
153
+ timeout: timeoutMs,
154
+ method: options.method
155
+ };
156
+ requestLogger.info(`Executing request to ${url}`, logContext);
157
+ // Create AbortController for timeout handling
158
+ const controller = new AbortController();
159
+ // If options already has a signal, we need to handle both
160
+ const originalSignal = options.signal;
161
+ // Clone options to avoid mutating the original
162
+ const requestOptions = { ...options };
163
+ // Add our signal to the options
164
+ requestOptions.signal = controller.signal;
165
+ // If there was an original signal, we need to abort when it aborts
166
+ if (originalSignal) {
167
+ if (originalSignal.aborted) {
168
+ // Already aborted
169
+ controller.abort();
170
+ requestLogger.info('Request already aborted by original signal', logContext);
171
+ }
172
+ else {
173
+ // Support both addEventListener and onabort patterns for different environments
174
+ if (typeof originalSignal.addEventListener === 'function') {
175
+ originalSignal.addEventListener('abort', () => {
176
+ requestLogger.info('Request aborted by original signal', logContext);
177
+ controller.abort();
178
+ });
179
+ }
180
+ else if ('onabort' in originalSignal) {
181
+ // For environments that don't support addEventListener (like some test runners)
182
+ const originalOnAbort = originalSignal.onabort;
183
+ originalSignal.onabort = (event) => {
184
+ if (originalOnAbort)
185
+ originalOnAbort.call(originalSignal, event);
186
+ requestLogger.info('Request aborted by original signal', logContext);
187
+ controller.abort();
188
+ };
189
+ }
190
+ }
191
+ }
192
+ try {
193
+ // Create a promise that races between the fetch and the timeout
194
+ requestLogger.info(`Starting request to ${url} with ${timeoutMs}ms timeout`, logContext);
195
+ const response = await Promise.race([
196
+ fetch(url, requestOptions),
197
+ createRequestTimeout(timeoutMs, controller, url)
198
+ ]);
199
+ // Use format expected by tests
200
+ requestLogger.info(`Request to ${url} completed`, {
201
+ status: response.status,
202
+ statusText: response.statusText || 'OK',
203
+ method: options.method,
204
+ url
205
+ });
206
+ return response;
207
+ }
208
+ catch (error) {
209
+ // Handle network errors and timeouts
210
+ if (error instanceof Error && error.name === 'AbortError' && !originalSignal?.aborted) {
211
+ const timeoutError = new NetworkError('Request timeout', {
212
+ isTimeout: true,
213
+ context: { endpoint: url },
214
+ userMessage: 'The request took too long to complete. Please try again.'
215
+ });
216
+ // Use the exact message format expected by the test
217
+ requestLogger.error(`Request to ${url} timed out`, timeoutError, logContext);
218
+ throw timeoutError;
219
+ }
220
+ if (!navigator.onLine) {
221
+ const offlineError = new NetworkError('Network offline', {
222
+ isOffline: true,
223
+ context: { endpoint: url },
224
+ userMessage: 'You appear to be offline. Please check your internet connection.'
225
+ });
226
+ requestLogger.error(`Cannot execute request to ${url} while offline`, offlineError, logContext);
227
+ throw offlineError;
228
+ }
229
+ // Rethrow original error or wrap in ApiError
230
+ if (error instanceof ApiError || error instanceof NetworkError) {
231
+ // For timeout errors, use a specific format expected by the test
232
+ if (error instanceof NetworkError && error.isTimeout) {
233
+ requestLogger.error(`Request to ${url} timed out`, error, logContext);
234
+ }
235
+ else {
236
+ requestLogger.error(`Request to ${url} failed with network error`, error, logContext);
237
+ }
238
+ throw error;
239
+ }
240
+ const networkError = new ApiError('Network request failed', {
241
+ context: {
242
+ endpoint: url,
243
+ originalError: error instanceof Error ? error.message : String(error)
244
+ },
245
+ userMessage: 'Failed to connect to the server. Please try again.',
246
+ cause: error instanceof Error ? error : undefined
247
+ });
248
+ requestLogger.error(`Request to ${url} failed with network error`, networkError, logContext);
249
+ throw networkError;
250
+ }
251
+ },
252
+ /**
253
+ * Combines URL and query parameters
254
+ */
255
+ buildUrl(url, params) {
256
+ if (!params || Object.keys(params).length === 0) {
257
+ return url;
258
+ }
259
+ const filteredParams = Object.entries(params)
260
+ .filter(([_, value]) => value !== undefined && value !== null);
261
+ if (filteredParams.length === 0) {
262
+ return url; // Return original URL if no valid params
263
+ }
264
+ const queryString = filteredParams.map(([key, value]) => {
265
+ // Handle arrays and objects
266
+ if (Array.isArray(value)) {
267
+ return value
268
+ .map(item => `${encodeURIComponent(key)}=${encodeURIComponent(String(item))}`)
269
+ .join('&');
270
+ }
271
+ else if (typeof value === 'object') {
272
+ return `${encodeURIComponent(key)}=${encodeURIComponent(JSON.stringify(value))}`;
273
+ }
274
+ return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`;
275
+ }).join('&');
276
+ // Add query string to URL only if we have parameters
277
+ if (!queryString || queryString.length === 0) {
278
+ return url;
279
+ }
280
+ const separator = url.includes('?') ? '&' : '?';
281
+ const fullUrl = `${url}${separator}${queryString}`;
282
+ requestLogger.info(`Built URL with parameters: ${fullUrl}`, {
283
+ originalUrl: url,
284
+ paramCount: filteredParams.length
285
+ });
286
+ return fullUrl;
287
+ }
288
+ };
289
+ //# sourceMappingURL=request-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-handler.js","sourceRoot":"","sources":["../../../src/services/api/request-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * src/lib/services/api/response-handler.ts
3
+ * API Response Handler
4
+ *
5
+ * Handles API response processing with support for:
6
+ * - Status code interpretation
7
+ * - Content type handling
8
+ * - Error response processing
9
+ * - Token refresh on authentication failures
10
+ */
11
+ import type { IResponseHandler } from '@xbg.solutions/bpsk-core';
12
+ /**
13
+ * Response Handler implementation
14
+ */
15
+ export declare const responseHandler: IResponseHandler;
16
+ //# sourceMappingURL=response-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-handler.d.ts","sourceRoot":"","sources":["../../../src/services/api/response-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAWH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AA8IjE;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,gBAsJ7B,CAAC"}
@@ -0,0 +1,254 @@
1
+ /**
2
+ * src/lib/services/api/response-handler.ts
3
+ * API Response Handler
4
+ *
5
+ * Handles API response processing with support for:
6
+ * - Status code interpretation
7
+ * - Content type handling
8
+ * - Error response processing
9
+ * - Token refresh on authentication failures
10
+ */
11
+ import { loggerService } from '@xbg.solutions/bpsk-core';
12
+ import { tokenService } from '@xbg.solutions/bpsk-utils-firebase-auth';
13
+ import { ApiError, AuthError, ValidationError, normalizeError } from '@xbg.solutions/bpsk-core';
14
+ import { API_CONSTANTS } from '@xbg.solutions/bpsk-core';
15
+ // Create a context-aware logger
16
+ const responseLogger = loggerService.withContext('ResponseHandler');
17
+ /**
18
+ * Parses response body based on content type
19
+ *
20
+ * @param response Fetch Response object
21
+ * @param logContext Optional logging context
22
+ * @returns Parsed response body
23
+ */
24
+ async function parseResponseBody(response, logContext) {
25
+ const contentType = response.headers.get('Content-Type') || '';
26
+ // Handle empty responses
27
+ if (response.status === 204 || response.headers.get('Content-Length') === '0') {
28
+ responseLogger.info('Received empty response', logContext);
29
+ return null;
30
+ }
31
+ try {
32
+ // Parse based on content type
33
+ if (contentType.includes('application/json')) {
34
+ responseLogger.info('Parsing JSON response', logContext);
35
+ return await response.json();
36
+ }
37
+ else if (contentType.includes('text/')) {
38
+ responseLogger.info('Parsing text response', logContext);
39
+ return await response.text();
40
+ }
41
+ else if (contentType.includes('application/octet-stream')) {
42
+ responseLogger.info('Parsing binary response', logContext);
43
+ return await response.blob();
44
+ }
45
+ else {
46
+ // Default to JSON parsing with fallback to text
47
+ responseLogger.info(`Attempting to parse unknown content type: ${contentType}`, logContext);
48
+ try {
49
+ return await response.json();
50
+ }
51
+ catch {
52
+ return await response.text();
53
+ }
54
+ }
55
+ }
56
+ catch (error) {
57
+ responseLogger.error(`Failed to parse response body (${contentType})`, error instanceof Error ? error : new Error(String(error)), logContext);
58
+ throw new ApiError('Failed to parse response body', {
59
+ context: {
60
+ contentType,
61
+ responseSize: response.headers.get('Content-Length')
62
+ },
63
+ userMessage: 'Failed to read response from server.'
64
+ });
65
+ }
66
+ }
67
+ /**
68
+ * Creates appropriate API error based on status code
69
+ *
70
+ * @param status HTTP status code
71
+ * @param errorData Error data from response
72
+ * @param method HTTP method
73
+ * @param url Request URL
74
+ * @returns Appropriate error object
75
+ */
76
+ function createApiErrorFromStatus(status, errorData, method, url) {
77
+ // Default error message and user message
78
+ const errorMessage = errorData?.message || errorData?.error || 'API request failed';
79
+ const userMessage = errorData?.userMessage || errorData?.message || 'An error occurred during the request.';
80
+ // Create context object for error
81
+ const context = {
82
+ endpoint: url,
83
+ method,
84
+ status,
85
+ errorData: errorData ? {
86
+ message: errorData.message,
87
+ code: errorData.code
88
+ } : undefined
89
+ };
90
+ // Create appropriate error based on status code
91
+ switch (true) {
92
+ case status === API_CONSTANTS.STATUS.BAD_REQUEST:
93
+ return new ValidationError(errorMessage, {
94
+ statusCode: status,
95
+ userMessage,
96
+ context,
97
+ fieldErrors: errorData?.errors || errorData?.fieldErrors || {}
98
+ });
99
+ case status === API_CONSTANTS.STATUS.UNAUTHORIZED:
100
+ return new AuthError(errorMessage, {
101
+ action: 'login', // Assume token expiration for 401
102
+ statusCode: status,
103
+ userMessage: 'Your session has expired. Please log in again.',
104
+ context
105
+ });
106
+ case status === API_CONSTANTS.STATUS.FORBIDDEN:
107
+ return new AuthError(errorMessage, {
108
+ action: 'authorize',
109
+ statusCode: status,
110
+ userMessage: "You don't have permission to perform this action.",
111
+ context
112
+ });
113
+ case status === API_CONSTANTS.STATUS.NOT_FOUND:
114
+ return new ApiError(errorMessage, {
115
+ statusCode: status,
116
+ userMessage: 'The requested resource was not found.',
117
+ context
118
+ });
119
+ case status >= 500:
120
+ // Server errors are usually retryable
121
+ return new ApiError(errorMessage, {
122
+ statusCode: status,
123
+ userMessage: 'The server encountered an error. Please try again later.',
124
+ context: {
125
+ ...context,
126
+ isRetryable: true
127
+ }
128
+ });
129
+ default:
130
+ return new ApiError(errorMessage, {
131
+ statusCode: status,
132
+ userMessage,
133
+ context
134
+ });
135
+ }
136
+ }
137
+ /**
138
+ * Response Handler implementation
139
+ */
140
+ export const responseHandler = {
141
+ /**
142
+ * Processes an API response based on status code and content type
143
+ */
144
+ async processResponse(response, method, url) {
145
+ const logContext = {
146
+ url,
147
+ method,
148
+ status: response.status,
149
+ contentType: response.headers.get('Content-Type')
150
+ };
151
+ try {
152
+ responseLogger.info(`Processing ${method} response from ${url} (${response.status})`, logContext);
153
+ // Handle successful responses
154
+ if (response.ok) {
155
+ const responseData = await parseResponseBody(response, logContext);
156
+ responseLogger.info(`Successfully processed ${method} response from ${url}`, logContext);
157
+ return responseData;
158
+ }
159
+ // Log error response
160
+ responseLogger.warn(`Received error response from ${url}: ${response.status} ${response.statusText}`, logContext);
161
+ // Handle error responses
162
+ try {
163
+ // Try to parse error response data
164
+ let errorData = null;
165
+ const contentType = response.headers.get('Content-Type') || '';
166
+ if (contentType.includes('application/json')) {
167
+ errorData = await response.json();
168
+ responseLogger.info('Parsed JSON error response', {
169
+ ...logContext,
170
+ errorData: errorData?.message || errorData?.error
171
+ });
172
+ }
173
+ else if (contentType.includes('text/')) {
174
+ errorData = { message: await response.text() };
175
+ responseLogger.info('Parsed text error response', logContext);
176
+ }
177
+ // Create appropriate error object based on status code
178
+ const error = createApiErrorFromStatus(response.status, errorData, method, url);
179
+ // Special handling for 401 Unauthorized - attempt token refresh
180
+ if (response.status === API_CONSTANTS.STATUS.UNAUTHORIZED && tokenService.isAuthenticated()) {
181
+ responseLogger.warn(`Authentication error for ${method} ${url}, attempting token refresh`, logContext);
182
+ // Try to refresh the token
183
+ const refreshResult = await tokenService.refreshToken();
184
+ if (refreshResult.success) {
185
+ // Token refreshed successfully, suggest retry
186
+ responseLogger.info('Token refreshed successfully after auth error', logContext);
187
+ // Create a special error with a token refreshed flag
188
+ const refreshedError = new AuthError('Token refreshed successfully', {
189
+ action: 'login',
190
+ statusCode: API_CONSTANTS.STATUS.UNAUTHORIZED,
191
+ context: {
192
+ endpoint: url,
193
+ method,
194
+ tokenRefreshed: true // Special flag for API service to recognize
195
+ },
196
+ userMessage: 'Your session has been refreshed. Please try again.'
197
+ });
198
+ throw refreshedError;
199
+ }
200
+ else {
201
+ // Token refresh failed, throw original error
202
+ responseLogger.warn('Token refresh failed after auth error', {
203
+ ...logContext,
204
+ refreshError: refreshResult.error?.message
205
+ });
206
+ throw error;
207
+ }
208
+ }
209
+ // For other status codes, throw the error
210
+ throw error;
211
+ }
212
+ catch (error) {
213
+ // If error is already one of our error types, rethrow it
214
+ if (error instanceof ApiError || error instanceof AuthError || error instanceof ValidationError) {
215
+ throw error;
216
+ }
217
+ // Otherwise create a generic API error
218
+ const apiError = new ApiError(`Error response from ${url}`, {
219
+ statusCode: response.status,
220
+ context: {
221
+ url,
222
+ method,
223
+ status: response.status,
224
+ statusText: response.statusText
225
+ },
226
+ userMessage: 'The server returned an error response.'
227
+ });
228
+ throw apiError;
229
+ }
230
+ }
231
+ catch (error) {
232
+ // Handle errors that occurred during response processing
233
+ // Pass through our specific error types
234
+ if (error instanceof ApiError || error instanceof AuthError || error instanceof ValidationError) {
235
+ // Special case for token refreshed error
236
+ if (error instanceof AuthError && error.context && error.context.tokenRefreshed) {
237
+ responseLogger.info('Propagating token refreshed error for retry', logContext);
238
+ throw error;
239
+ }
240
+ responseLogger.error(`Error processing ${method} response from ${url}`, error, logContext);
241
+ throw error;
242
+ }
243
+ // Normalize other errors
244
+ const normalizedError = normalizeError(error, `Error processing ${method} response from ${url}`, {
245
+ category: 'api',
246
+ context: logContext,
247
+ statusCode: response.status
248
+ });
249
+ responseLogger.error(`Failed to process ${method} response from ${url}`, normalizedError, logContext);
250
+ throw normalizedError;
251
+ }
252
+ }
253
+ };
254
+ //# sourceMappingURL=response-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-handler.js","sourceRoot":"","sources":["../../../src/services/api/response-handler.ts"],"names":[],"mappings":"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"}