@acontplus/ng-infrastructure 2.0.8 → 2.0.11
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.
|
@@ -1,225 +1,169 @@
|
|
|
1
1
|
import { HttpContextToken, HttpResponse, HttpContext, HttpClient } from '@angular/common/http';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
3
|
import { inject, Injectable, signal, computed, InjectionToken } from '@angular/core';
|
|
4
|
-
import { retry,
|
|
5
|
-
import { throwError, catchError as catchError$1, switchMap, lastValueFrom } from 'rxjs';
|
|
4
|
+
import { retry, timer, switchMap, throwError, of, catchError, lastValueFrom } from 'rxjs';
|
|
6
5
|
import { NotificationService } from '@acontplus/ng-notifications';
|
|
7
6
|
import { AUTH_TOKEN, ENVIRONMENT, CORE_CONFIG, DEFAULT_CONFIG as DEFAULT_CONFIG$1 } from '@acontplus/ng-config';
|
|
8
7
|
import { Router } from '@angular/router';
|
|
8
|
+
import { finalize, catchError as catchError$1 } from 'rxjs/operators';
|
|
9
9
|
import { OverlayService } from '@acontplus/ng-components';
|
|
10
10
|
|
|
11
|
-
//
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// HTTP Context Tokens
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
/**
|
|
15
|
+
* Skip all toast notifications for a specific request.
|
|
16
|
+
* Usage: new HttpContext().set(SKIP_NOTIFICATION, true)
|
|
17
|
+
*/
|
|
12
18
|
const SKIP_NOTIFICATION = new HttpContextToken(() => false);
|
|
13
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Force-show or force-hide notifications, overriding URL/method exclusion logic.
|
|
21
|
+
* Usage: new HttpContext().set(SHOW_NOTIFICATIONS, true)
|
|
22
|
+
*/
|
|
14
23
|
const SHOW_NOTIFICATIONS = new HttpContextToken(() => undefined);
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Interceptor
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
15
27
|
const apiInterceptor = (req, next) => {
|
|
16
28
|
const toastr = inject(NotificationService);
|
|
17
29
|
const tokenProvider = inject(AUTH_TOKEN, { optional: true });
|
|
18
|
-
//
|
|
19
|
-
let modifiedReq = req;
|
|
30
|
+
// Attach Bearer token when available
|
|
20
31
|
const token = tokenProvider?.getToken();
|
|
21
|
-
|
|
22
|
-
modifiedReq = req.clone({
|
|
23
|
-
setHeaders: { Authorization: `Bearer ${token}` },
|
|
24
|
-
});
|
|
25
|
-
}
|
|
32
|
+
const modifiedReq = token ? req.clone({ setHeaders: { Authorization: `Bearer ${token}` } }) : req;
|
|
26
33
|
return next(modifiedReq).pipe(
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
// Retry only on network errors or 5xx — never on 4xx client errors.
|
|
35
|
+
// Uses exponential back-off: 1 s, 2 s.
|
|
36
|
+
retry({
|
|
37
|
+
count: 2,
|
|
38
|
+
delay: (error, attempt) => {
|
|
39
|
+
const isRetryable = error.status === 0 || (error.status >= 500 && error.status < 600);
|
|
40
|
+
if (!isRetryable)
|
|
41
|
+
throw error; // 4xx — do not retry, bubble up immediately
|
|
42
|
+
return timer(1000 * attempt); // attempt 1 → 1 s, attempt 2 → 2 s
|
|
43
|
+
},
|
|
44
|
+
}),
|
|
45
|
+
// Handle successful responses via switchMap so we can return an Observable
|
|
46
|
+
// (needed to properly throw ApiResponse errors into the RxJS stream).
|
|
47
|
+
switchMap((event) => {
|
|
31
48
|
if (event instanceof HttpResponse) {
|
|
32
|
-
|
|
49
|
+
const standardized = standardizeApiResponse(event.body);
|
|
50
|
+
handleToastNotifications(standardized, toastr, req);
|
|
51
|
+
if (standardized.status === 'error') {
|
|
52
|
+
handleApiResponseError(standardized, toastr, req);
|
|
53
|
+
return throwError(() => standardized);
|
|
54
|
+
}
|
|
55
|
+
return of(transformResponseForConsumers(standardized, event));
|
|
33
56
|
}
|
|
34
|
-
return event;
|
|
57
|
+
return of(event);
|
|
35
58
|
}),
|
|
36
|
-
//
|
|
37
|
-
catchError((error) =>
|
|
59
|
+
// Handle HTTP-level errors — show notification for critical errors, always re-throw.
|
|
60
|
+
catchError((error) => handleHttpError(error, toastr)));
|
|
38
61
|
};
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
*/
|
|
43
|
-
function handleSuccessResponse(event, notificationService, req) {
|
|
44
|
-
const body = event.body;
|
|
45
|
-
// Standardize the response to always have ApiResponse structure
|
|
46
|
-
const standardizedResponse = standardizeApiResponse(body);
|
|
47
|
-
// Handle toast notifications based on standardized response
|
|
48
|
-
handleToastNotifications(standardizedResponse, notificationService, req);
|
|
49
|
-
// Return the appropriate data based on response type
|
|
50
|
-
return transformResponseForConsumers(standardizedResponse, event);
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Handles HTTP errors (from the interceptor chain, not backend ApiResponse).
|
|
54
|
-
*/
|
|
55
|
-
function handleErrorResponse(error, notificationService) {
|
|
56
|
-
const status = error.status;
|
|
57
|
-
// Only show notifications for critical HTTP-level errors.
|
|
58
|
-
// We avoid showing toasts for 4xx errors, which are handled by the component.
|
|
59
|
-
if (status !== null && shouldShowCriticalErrorNotification(status)) {
|
|
60
|
-
const message = getCriticalErrorMessage(error);
|
|
61
|
-
const title = getErrorTitle(status);
|
|
62
|
-
notificationService.error({
|
|
63
|
-
message: message,
|
|
64
|
-
title: title,
|
|
65
|
-
config: { duration: 5000 },
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
// Always re-throw the error so components/services can handle it.
|
|
69
|
-
return throwError(() => error);
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Standardizes any response to follow the ApiResponse structure
|
|
73
|
-
*/
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Standardisation
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
74
65
|
function standardizeApiResponse(body) {
|
|
75
|
-
|
|
76
|
-
if (isValidApiResponse(body)) {
|
|
66
|
+
if (isValidApiResponse(body))
|
|
77
67
|
return body;
|
|
68
|
+
// Raw object without ApiResponse wrapper
|
|
69
|
+
if (body !== null && body !== undefined && typeof body === 'object' && !('status' in body)) {
|
|
70
|
+
return wrapSuccess(body);
|
|
78
71
|
}
|
|
79
|
-
//
|
|
80
|
-
if (body && typeof body === 'object' && !('status' in body)) {
|
|
81
|
-
return {
|
|
82
|
-
status: 'success',
|
|
83
|
-
code: '200',
|
|
84
|
-
message: 'Operation completed successfully',
|
|
85
|
-
data: body,
|
|
86
|
-
timestamp: new Date().toISOString(),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
// If it's a primitive value, wrap it
|
|
72
|
+
// Primitive value
|
|
90
73
|
if (body !== null && body !== undefined && typeof body !== 'object') {
|
|
91
|
-
return
|
|
92
|
-
status: 'success',
|
|
93
|
-
code: '200',
|
|
94
|
-
message: 'Operation completed successfully',
|
|
95
|
-
data: body,
|
|
96
|
-
timestamp: new Date().toISOString(),
|
|
97
|
-
};
|
|
74
|
+
return wrapSuccess(body);
|
|
98
75
|
}
|
|
99
|
-
//
|
|
76
|
+
// null / undefined
|
|
77
|
+
return wrapSuccess(undefined);
|
|
78
|
+
}
|
|
79
|
+
function wrapSuccess(data) {
|
|
100
80
|
return {
|
|
101
81
|
status: 'success',
|
|
102
82
|
code: '200',
|
|
103
83
|
message: 'Operation completed successfully',
|
|
84
|
+
data,
|
|
104
85
|
timestamp: new Date().toISOString(),
|
|
105
86
|
};
|
|
106
87
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
88
|
+
function isValidApiResponse(response) {
|
|
89
|
+
if (response === null || typeof response !== 'object')
|
|
90
|
+
return false;
|
|
91
|
+
const r = response;
|
|
92
|
+
return ('status' in r &&
|
|
93
|
+
'code' in r &&
|
|
94
|
+
typeof r['status'] === 'string' &&
|
|
95
|
+
['success', 'error', 'warning'].includes(r['status']));
|
|
96
|
+
}
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// Notifications
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
110
100
|
function handleToastNotifications(response, notificationService, req) {
|
|
111
|
-
|
|
101
|
+
// SKIP_NOTIFICATION always wins — even over SHOW_NOTIFICATIONS
|
|
102
|
+
if (req.context.get(SKIP_NOTIFICATION))
|
|
103
|
+
return;
|
|
112
104
|
const forceShow = req.context.get(SHOW_NOTIFICATIONS);
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (skipNotification)
|
|
105
|
+
const autoShow = shouldShowSuccessToast(req);
|
|
106
|
+
const showNotifications = forceShow !== undefined ? forceShow : autoShow;
|
|
107
|
+
if (!showNotifications)
|
|
117
108
|
return;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
//
|
|
128
|
-
if (response.status === 'warning' && response.warnings && response.
|
|
129
|
-
response.warnings.forEach((
|
|
130
|
-
notificationService.show({
|
|
131
|
-
type: 'warning',
|
|
132
|
-
message: warning.message,
|
|
133
|
-
});
|
|
134
|
-
});
|
|
109
|
+
if (!response.message)
|
|
110
|
+
return;
|
|
111
|
+
if (!['success', 'warning', 'error'].includes(response.status))
|
|
112
|
+
return;
|
|
113
|
+
// Primary notification — show main message once
|
|
114
|
+
notificationService.show({
|
|
115
|
+
type: response.status,
|
|
116
|
+
message: response.message,
|
|
117
|
+
});
|
|
118
|
+
// Secondary: show individual warnings only when no primary message covered them
|
|
119
|
+
if (response.status === 'warning' && response.warnings?.length && !response.message) {
|
|
120
|
+
response.warnings.forEach((w) => notificationService.show({ type: 'warning', message: w.message }));
|
|
135
121
|
}
|
|
136
|
-
//
|
|
137
|
-
if (response.status === 'error' && response.errors && response.
|
|
138
|
-
response.errors.forEach((
|
|
139
|
-
notificationService.show({
|
|
140
|
-
type: 'error',
|
|
141
|
-
message: error.message,
|
|
142
|
-
});
|
|
143
|
-
});
|
|
122
|
+
// Secondary: show individual errors only when no primary message covered them
|
|
123
|
+
if (response.status === 'error' && response.errors?.length && !response.message) {
|
|
124
|
+
response.errors.forEach((e) => notificationService.show({ type: 'error', message: e.message }));
|
|
144
125
|
}
|
|
145
126
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
127
|
+
function handleApiResponseError(response, notificationService, req) {
|
|
128
|
+
if (req.context.get(SKIP_NOTIFICATION))
|
|
129
|
+
return;
|
|
130
|
+
const message = response.message || response.errors?.[0]?.message || 'An unexpected error occurred';
|
|
131
|
+
notificationService.error({ message, config: { duration: 5000 } });
|
|
132
|
+
}
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
// Response transformation
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
149
136
|
function transformResponseForConsumers(response, originalEvent) {
|
|
150
137
|
switch (response.status) {
|
|
151
138
|
case 'success':
|
|
152
|
-
// For success responses, return the data if it exists, otherwise the full response
|
|
153
|
-
if (response.data !== undefined && response.data !== null) {
|
|
154
|
-
return originalEvent.clone({ body: response.data });
|
|
155
|
-
}
|
|
156
|
-
// For message-only success responses, return the full response
|
|
157
|
-
return originalEvent.clone({ body: response });
|
|
158
139
|
case 'warning':
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return originalEvent.clone({ body: response });
|
|
140
|
+
// Unwrap data for consumers; fall back to full envelope when no data
|
|
141
|
+
return response.data !== undefined && response.data !== null
|
|
142
|
+
? originalEvent.clone({ body: response.data })
|
|
143
|
+
: originalEvent.clone({ body: response });
|
|
164
144
|
case 'error':
|
|
165
|
-
//
|
|
166
|
-
|
|
145
|
+
// Already handled in switchMap — this is a safety fallback
|
|
146
|
+
return originalEvent.clone({ body: response });
|
|
167
147
|
default:
|
|
168
148
|
return originalEvent.clone({ body: response });
|
|
169
149
|
}
|
|
170
150
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
function
|
|
175
|
-
if (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
['success', 'error', 'warning'].includes(r['status']));
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Determines whether to show success toast notifications based on the request type.
|
|
185
|
-
*/
|
|
186
|
-
function shouldShowSuccessToast(req) {
|
|
187
|
-
const url = req.url?.toLowerCase() || '';
|
|
188
|
-
const method = req.method?.toLowerCase() || '';
|
|
189
|
-
// Never show for these cases
|
|
190
|
-
const excludedPatterns = [
|
|
191
|
-
'get',
|
|
192
|
-
'/list',
|
|
193
|
-
'/search',
|
|
194
|
-
'/query',
|
|
195
|
-
'/page',
|
|
196
|
-
'/paginated',
|
|
197
|
-
'/health',
|
|
198
|
-
'/status',
|
|
199
|
-
'/ping',
|
|
200
|
-
];
|
|
201
|
-
if (excludedPatterns.some((pattern) => method === pattern || url.includes(pattern))) {
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
204
|
-
// Always show for these methods
|
|
205
|
-
if (['post', 'put', 'patch', 'delete'].includes(method)) {
|
|
206
|
-
return true;
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Error handling
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
function handleHttpError(error, notificationService) {
|
|
155
|
+
if (shouldShowCriticalErrorNotification(error.status)) {
|
|
156
|
+
notificationService.error({
|
|
157
|
+
message: getCriticalErrorMessage(error),
|
|
158
|
+
title: getErrorTitle(error.status),
|
|
159
|
+
config: { duration: 5000 },
|
|
160
|
+
});
|
|
207
161
|
}
|
|
208
|
-
|
|
209
|
-
return method !== 'get';
|
|
162
|
+
return throwError(() => error);
|
|
210
163
|
}
|
|
211
|
-
/**
|
|
212
|
-
* Determines if we should show a notification for this HTTP error.
|
|
213
|
-
*/
|
|
214
164
|
function shouldShowCriticalErrorNotification(status) {
|
|
215
|
-
// Show notifications for:
|
|
216
|
-
// - Network errors (status 0)
|
|
217
|
-
// - Server errors (5xx)
|
|
218
165
|
return status === 0 || (status >= 500 && status < 600);
|
|
219
166
|
}
|
|
220
|
-
/**
|
|
221
|
-
* Gets the appropriate title for error notifications.
|
|
222
|
-
*/
|
|
223
167
|
function getErrorTitle(status) {
|
|
224
168
|
if (status === 0)
|
|
225
169
|
return 'Connection Error';
|
|
@@ -227,17 +171,37 @@ function getErrorTitle(status) {
|
|
|
227
171
|
return 'Server Error';
|
|
228
172
|
return 'Error';
|
|
229
173
|
}
|
|
230
|
-
/**
|
|
231
|
-
* Gets the appropriate message for critical errors.
|
|
232
|
-
*/
|
|
233
174
|
function getCriticalErrorMessage(error) {
|
|
234
175
|
if (error.status === 0) {
|
|
235
176
|
return 'Unable to connect to the server. Please check your network connection.';
|
|
236
177
|
}
|
|
237
178
|
if (error.status >= 500) {
|
|
238
|
-
return (error.error?.message
|
|
239
|
-
}
|
|
240
|
-
return error.error?.message
|
|
179
|
+
return (error.error?.message ?? error.message ?? 'A server error occurred. Please try again later.');
|
|
180
|
+
}
|
|
181
|
+
return error.error?.message ?? error.message ?? 'An unexpected error occurred';
|
|
182
|
+
}
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
// Utility: decide whether to auto-show toast
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
const MUTABLE_METHODS = new Set(['post', 'put', 'patch', 'delete']);
|
|
187
|
+
const EXCLUDED_URL_PATTERNS = [
|
|
188
|
+
'/list',
|
|
189
|
+
'/search',
|
|
190
|
+
'/query',
|
|
191
|
+
'/page',
|
|
192
|
+
'/paginated',
|
|
193
|
+
'/health',
|
|
194
|
+
'/status',
|
|
195
|
+
'/ping',
|
|
196
|
+
];
|
|
197
|
+
function shouldShowSuccessToast(req) {
|
|
198
|
+
const method = req.method.toLowerCase();
|
|
199
|
+
const url = req.url.toLowerCase();
|
|
200
|
+
if (!MUTABLE_METHODS.has(method))
|
|
201
|
+
return false;
|
|
202
|
+
if (EXCLUDED_URL_PATTERNS.some((p) => url.includes(p)))
|
|
203
|
+
return false;
|
|
204
|
+
return true;
|
|
241
205
|
}
|
|
242
206
|
|
|
243
207
|
class LoggingService {
|
|
@@ -309,10 +273,10 @@ class LoggingService {
|
|
|
309
273
|
// e.g., Sentry, LogRocket, etc.
|
|
310
274
|
// This is a placeholder for production logging implementation
|
|
311
275
|
}
|
|
312
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
313
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.
|
|
276
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LoggingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
277
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LoggingService, providedIn: 'root' });
|
|
314
278
|
}
|
|
315
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
279
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: LoggingService, decorators: [{
|
|
316
280
|
type: Injectable,
|
|
317
281
|
args: [{
|
|
318
282
|
providedIn: 'root',
|
|
@@ -358,10 +322,10 @@ class TenantInfo {
|
|
|
358
322
|
localStorage.removeItem('tenantId');
|
|
359
323
|
sessionStorage.removeItem('tenantId');
|
|
360
324
|
}
|
|
361
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
362
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.
|
|
325
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TenantInfo, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
326
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TenantInfo, providedIn: 'root' });
|
|
363
327
|
}
|
|
364
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
328
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TenantInfo, decorators: [{
|
|
365
329
|
type: Injectable,
|
|
366
330
|
args: [{
|
|
367
331
|
providedIn: 'root',
|
|
@@ -393,21 +357,25 @@ class CorrelationInfo {
|
|
|
393
357
|
getId() {
|
|
394
358
|
return this.getOrCreateCorrelationId();
|
|
395
359
|
}
|
|
396
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
397
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.
|
|
360
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CorrelationInfo, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
361
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CorrelationInfo, providedIn: 'root' });
|
|
398
362
|
}
|
|
399
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
363
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CorrelationInfo, decorators: [{
|
|
400
364
|
type: Injectable,
|
|
401
365
|
args: [{
|
|
402
366
|
providedIn: 'root',
|
|
403
367
|
}]
|
|
404
368
|
}] });
|
|
405
369
|
|
|
406
|
-
//
|
|
370
|
+
// ---------------------------------------------------------------------------
|
|
371
|
+
// HTTP Context Tokens & helpers
|
|
372
|
+
// ---------------------------------------------------------------------------
|
|
373
|
+
/** Mark a request as using an absolute URL (skip base-URL injection). */
|
|
407
374
|
const CUSTOM_URL = new HttpContextToken(() => false);
|
|
375
|
+
/** Skip all context headers (correlation, tenant, etc.) for this request. */
|
|
408
376
|
const SKIP_CONTEXT_HEADERS = new HttpContextToken(() => false);
|
|
377
|
+
/** Merge additional headers into the request at call-site. */
|
|
409
378
|
const CUSTOM_HEADERS = new HttpContextToken(() => ({}));
|
|
410
|
-
// Helper functions for HTTP context
|
|
411
379
|
function customUrl() {
|
|
412
380
|
return new HttpContext().set(CUSTOM_URL, true);
|
|
413
381
|
}
|
|
@@ -417,10 +385,9 @@ function skipContextHeaders() {
|
|
|
417
385
|
function withCustomHeaders(headers) {
|
|
418
386
|
return new HttpContext().set(CUSTOM_HEADERS, headers);
|
|
419
387
|
}
|
|
420
|
-
// Default configuration
|
|
421
388
|
const DEFAULT_CONFIG = {
|
|
422
389
|
enableCorrelationTracking: true,
|
|
423
|
-
enableRequestLogging: false,
|
|
390
|
+
enableRequestLogging: false,
|
|
424
391
|
enableErrorLogging: true,
|
|
425
392
|
customHeaders: {},
|
|
426
393
|
clientVersion: '1.0.0',
|
|
@@ -429,100 +396,94 @@ const DEFAULT_CONFIG = {
|
|
|
429
396
|
requestIdHeader: 'Request-Id',
|
|
430
397
|
timestampHeader: 'Timestamp',
|
|
431
398
|
excludeUrls: [],
|
|
399
|
+
skipAuthUrls: ['/login', '/register', '/refresh'],
|
|
432
400
|
includeAuthToken: true,
|
|
433
401
|
baseUrlInjection: true,
|
|
434
402
|
refreshTokenCallback: undefined,
|
|
435
403
|
logoutCallback: undefined,
|
|
436
404
|
};
|
|
437
|
-
// Injection token for configuration - FIXED
|
|
438
405
|
const HTTP_CONTEXT_CONFIG = new InjectionToken('HTTP_CONTEXT_CONFIG', {
|
|
439
|
-
factory: () => DEFAULT_CONFIG,
|
|
406
|
+
factory: () => DEFAULT_CONFIG,
|
|
440
407
|
});
|
|
408
|
+
// ---------------------------------------------------------------------------
|
|
409
|
+
// Interceptor
|
|
410
|
+
// ---------------------------------------------------------------------------
|
|
441
411
|
const httpContextInterceptor = (req, next) => {
|
|
442
412
|
const tokenProvider = inject(AUTH_TOKEN, { optional: true });
|
|
443
|
-
console.log(tokenProvider);
|
|
444
413
|
const router = inject(Router);
|
|
445
414
|
const tenantService = inject(TenantInfo);
|
|
446
415
|
const correlationService = inject(CorrelationInfo);
|
|
447
416
|
const loggingService = inject(LoggingService);
|
|
448
417
|
const environment = inject(ENVIRONMENT);
|
|
449
|
-
// Get configuration (with fallback to default) - FIXED
|
|
450
418
|
const config = {
|
|
451
419
|
...DEFAULT_CONFIG,
|
|
452
|
-
// The default enableRequestLogging needs to be set based on environment here,
|
|
453
|
-
// as it's dynamic, and DEFAULT_CONFIG is static.
|
|
454
420
|
enableRequestLogging: !environment.isProduction,
|
|
455
421
|
...inject(HTTP_CONTEXT_CONFIG, { optional: true }),
|
|
456
422
|
};
|
|
457
|
-
//
|
|
423
|
+
// ── Context token flags ──────────────────────────────────────────────────
|
|
458
424
|
const isCustomUrl = req.context.get(CUSTOM_URL);
|
|
459
425
|
const skipHeaders = req.context.get(SKIP_CONTEXT_HEADERS);
|
|
460
426
|
const contextHeaders = req.context.get(CUSTOM_HEADERS);
|
|
461
|
-
|
|
462
|
-
if (skipHeaders) {
|
|
427
|
+
if (skipHeaders)
|
|
463
428
|
return next(req);
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
429
|
+
// ── URL exclusion (with ReDoS protection) ────────────────────────────────
|
|
430
|
+
const shouldExclude = config.excludeUrls.some((pattern) => {
|
|
431
|
+
try {
|
|
432
|
+
return req.url.includes(pattern) || new RegExp(pattern).test(req.url);
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
return false; // malformed regex — skip safely
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
if (shouldExclude)
|
|
468
439
|
return next(req);
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
// Handle URL transformation
|
|
440
|
+
// ── Auth skip check ──────────────────────────────────────────────────────
|
|
441
|
+
const skipAuth = config.skipAuthUrls.some((u) => req.url.includes(u));
|
|
442
|
+
// ── URL resolution ───────────────────────────────────────────────────────
|
|
473
443
|
const baseUrl = environment.apiBaseUrl;
|
|
474
444
|
const finalUrl = isCustomUrl || !config.baseUrlInjection ? req.url : `${baseUrl}${req.url}`;
|
|
475
|
-
//
|
|
445
|
+
// ── Header construction ──────────────────────────────────────────────────
|
|
476
446
|
const correlationId = config.enableCorrelationTracking
|
|
477
447
|
? correlationService.getOrCreateCorrelationId()
|
|
478
448
|
: crypto.randomUUID();
|
|
479
449
|
const tenantId = tenantService.getTenantId();
|
|
480
450
|
const requestId = crypto.randomUUID();
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
451
|
+
const headers = {
|
|
452
|
+
[config.requestIdHeader]: requestId,
|
|
453
|
+
[config.timestampHeader]: new Date().toISOString(),
|
|
454
|
+
};
|
|
485
455
|
if (config.enableCorrelationTracking) {
|
|
486
456
|
headers[config.correlationIdHeader] = correlationId;
|
|
487
457
|
}
|
|
488
458
|
if (tenantId) {
|
|
489
459
|
headers[config.tenantIdHeader] = tenantId;
|
|
490
460
|
}
|
|
491
|
-
headers[config.timestampHeader] = new Date().toISOString();
|
|
492
|
-
// Client information
|
|
493
461
|
if (config.clientVersion) {
|
|
494
462
|
headers['Client-Version'] = config.clientVersion;
|
|
495
463
|
}
|
|
496
|
-
// Environment client ID
|
|
497
464
|
if (environment.clientId) {
|
|
498
465
|
headers['Client-Id'] = environment.clientId;
|
|
499
466
|
}
|
|
500
|
-
// Add authorization header if configured and available
|
|
501
467
|
if (config.includeAuthToken && !skipAuth) {
|
|
502
468
|
const authToken = tokenProvider?.getToken();
|
|
503
|
-
if (authToken)
|
|
469
|
+
if (authToken)
|
|
504
470
|
headers['Authorization'] = `Bearer ${authToken}`;
|
|
505
|
-
}
|
|
506
471
|
}
|
|
507
|
-
//
|
|
472
|
+
// Static and dynamic custom headers from config
|
|
508
473
|
Object.entries(config.customHeaders).forEach(([key, value]) => {
|
|
509
474
|
headers[key] = typeof value === 'function' ? value() : value;
|
|
510
475
|
});
|
|
511
|
-
//
|
|
476
|
+
// Per-request headers from HttpContext
|
|
512
477
|
Object.entries(contextHeaders).forEach(([key, value]) => {
|
|
513
478
|
headers[key] = value;
|
|
514
479
|
});
|
|
515
|
-
//
|
|
516
|
-
if (['POST', 'PUT', 'PATCH'].includes(req.method.
|
|
517
|
-
!req.headers.has('Content-Type')) {
|
|
480
|
+
// Content-Type for mutation requests (do not override if already set)
|
|
481
|
+
if (['POST', 'PUT', 'PATCH'].includes(req.method) && !req.headers.has('Content-Type')) {
|
|
518
482
|
headers['Content-Type'] = 'application/json';
|
|
519
483
|
}
|
|
520
|
-
// Clone request
|
|
521
|
-
const enhancedReq = req.clone({
|
|
522
|
-
|
|
523
|
-
setHeaders: headers,
|
|
524
|
-
});
|
|
525
|
-
// Log outgoing request if enabled
|
|
484
|
+
// ── Clone request ────────────────────────────────────────────────────────
|
|
485
|
+
const enhancedReq = req.clone({ url: finalUrl, setHeaders: headers });
|
|
486
|
+
// ── Request logging ──────────────────────────────────────────────────────
|
|
526
487
|
if (config.enableRequestLogging) {
|
|
527
488
|
loggingService.logHttpRequest({
|
|
528
489
|
method: req.method,
|
|
@@ -536,113 +497,107 @@ const httpContextInterceptor = (req, next) => {
|
|
|
536
497
|
isCustomUrl,
|
|
537
498
|
});
|
|
538
499
|
}
|
|
539
|
-
//
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
correlationId,
|
|
568
|
-
tenantId,
|
|
569
|
-
status: error.status,
|
|
570
|
-
statusText: error.statusText,
|
|
571
|
-
message: error.message,
|
|
572
|
-
timestamp: new Date().toISOString(),
|
|
573
|
-
errorDetails: error.error,
|
|
574
|
-
environment: environment.clientId,
|
|
575
|
-
isCustomUrl,
|
|
576
|
-
headers: [], // Headers are not included in HttpErrorResponse by default, adjust if needed
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
// Handle other error scenarios
|
|
580
|
-
switch (error.status) {
|
|
581
|
-
case 403:
|
|
582
|
-
tenantService.handleForbidden();
|
|
583
|
-
break;
|
|
584
|
-
case 0:
|
|
585
|
-
loggingService.logNetworkError(correlationId);
|
|
586
|
-
break;
|
|
587
|
-
case 429:
|
|
588
|
-
loggingService.logRateLimitError(correlationId, finalUrl);
|
|
589
|
-
break;
|
|
590
|
-
}
|
|
500
|
+
// ── Execute request with unified error handling ──────────────────────────
|
|
501
|
+
const hasAuth = !!headers['Authorization'];
|
|
502
|
+
// Shared error context for both handlers below
|
|
503
|
+
const errorCtx = {
|
|
504
|
+
req,
|
|
505
|
+
finalUrl,
|
|
506
|
+
requestId,
|
|
507
|
+
correlationId,
|
|
508
|
+
tenantId,
|
|
509
|
+
isCustomUrl,
|
|
510
|
+
hasAuth,
|
|
511
|
+
config,
|
|
512
|
+
router,
|
|
513
|
+
loggingService,
|
|
514
|
+
tenantService,
|
|
515
|
+
tokenProvider,
|
|
516
|
+
environment,
|
|
517
|
+
};
|
|
518
|
+
// Base pipeline — always present
|
|
519
|
+
const base$ = next(enhancedReq).pipe(catchError((error) => handleContextError(error, errorCtx)));
|
|
520
|
+
// When auth + refresh callback are available, prepend a 401-refresh layer
|
|
521
|
+
if (!hasAuth || !config.refreshTokenCallback) {
|
|
522
|
+
return base$;
|
|
523
|
+
}
|
|
524
|
+
return next(enhancedReq).pipe(
|
|
525
|
+
// Intercept 401 first — attempt token refresh before general error handling
|
|
526
|
+
catchError((error) => {
|
|
527
|
+
if (error.status !== 401)
|
|
591
528
|
return throwError(() => error);
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
else {
|
|
595
|
-
// No auth header, use standard error handling
|
|
596
|
-
return next(enhancedReq).pipe(catchError$1((error) => {
|
|
597
|
-
// Enhanced error logging with context
|
|
598
|
-
if (config.enableErrorLogging) {
|
|
599
|
-
loggingService.logHttpError({
|
|
600
|
-
method: req.method,
|
|
601
|
-
url: finalUrl,
|
|
602
|
-
originalUrl: req.url,
|
|
603
|
-
requestId,
|
|
604
|
-
correlationId,
|
|
605
|
-
tenantId,
|
|
606
|
-
status: error.status,
|
|
607
|
-
statusText: error.statusText,
|
|
608
|
-
message: error.message,
|
|
609
|
-
timestamp: new Date().toISOString(),
|
|
610
|
-
errorDetails: error.error,
|
|
611
|
-
environment: environment.clientId,
|
|
612
|
-
isCustomUrl,
|
|
613
|
-
headers: [], // Headers are not included in HttpErrorResponse by default, adjust if needed
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
// Handle specific error scenarios
|
|
617
|
-
switch (error.status) {
|
|
618
|
-
case 401: {
|
|
619
|
-
loggingService.error('Unauthorized access - token expired or invalid');
|
|
620
|
-
// Note: Token clearing should be handled by the auth service, not infrastructure
|
|
621
|
-
router.navigate([`/${environment.loginRoute}`]);
|
|
622
|
-
break;
|
|
623
|
-
}
|
|
624
|
-
case 403:
|
|
625
|
-
tenantService.handleForbidden();
|
|
626
|
-
break;
|
|
627
|
-
case 0:
|
|
628
|
-
loggingService.logNetworkError(correlationId);
|
|
629
|
-
break;
|
|
630
|
-
case 429:
|
|
631
|
-
loggingService.logRateLimitError(correlationId, finalUrl);
|
|
632
|
-
break;
|
|
633
|
-
}
|
|
529
|
+
const refreshToken = tokenProvider?.getRefreshToken?.();
|
|
530
|
+
if (!refreshToken?.trim())
|
|
634
531
|
return throwError(() => error);
|
|
532
|
+
return config.refreshTokenCallback().pipe(switchMap(({ token }) => next(req.clone({
|
|
533
|
+
url: finalUrl,
|
|
534
|
+
setHeaders: { ...headers, Authorization: `Bearer ${token}` },
|
|
535
|
+
}))), catchError((refreshError) => {
|
|
536
|
+
config.logoutCallback?.();
|
|
537
|
+
return throwError(() => refreshError);
|
|
635
538
|
}));
|
|
636
|
-
}
|
|
539
|
+
}),
|
|
540
|
+
// General error handling (logs, redirects, tenant, rate-limit, etc.)
|
|
541
|
+
catchError((error) => handleContextError(error, errorCtx)));
|
|
637
542
|
};
|
|
638
|
-
|
|
543
|
+
function handleContextError(error, ctx) {
|
|
544
|
+
const { req, finalUrl, requestId, correlationId, tenantId, isCustomUrl, config, router, loggingService, tenantService, environment, } = ctx;
|
|
545
|
+
if (config.enableErrorLogging) {
|
|
546
|
+
loggingService.logHttpError({
|
|
547
|
+
method: req.method,
|
|
548
|
+
url: finalUrl,
|
|
549
|
+
originalUrl: req.url,
|
|
550
|
+
requestId,
|
|
551
|
+
correlationId,
|
|
552
|
+
tenantId,
|
|
553
|
+
status: error.status,
|
|
554
|
+
statusText: error.statusText,
|
|
555
|
+
message: error.message,
|
|
556
|
+
timestamp: new Date().toISOString(),
|
|
557
|
+
errorDetails: error.error,
|
|
558
|
+
environment: environment.clientId,
|
|
559
|
+
isCustomUrl,
|
|
560
|
+
headers: [],
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
switch (error.status) {
|
|
564
|
+
case 401:
|
|
565
|
+
loggingService.error('Unauthorized — redirecting to login');
|
|
566
|
+
// Let auth service clear tokens before navigation
|
|
567
|
+
config.logoutCallback?.();
|
|
568
|
+
router.navigate([`/${environment.loginRoute}`]);
|
|
569
|
+
break;
|
|
570
|
+
case 403:
|
|
571
|
+
tenantService.handleForbidden();
|
|
572
|
+
break;
|
|
573
|
+
case 0:
|
|
574
|
+
loggingService.logNetworkError(correlationId);
|
|
575
|
+
break;
|
|
576
|
+
case 429:
|
|
577
|
+
loggingService.logRateLimitError(correlationId, finalUrl);
|
|
578
|
+
break;
|
|
579
|
+
}
|
|
580
|
+
return throwError(() => error);
|
|
581
|
+
}
|
|
582
|
+
// ---------------------------------------------------------------------------
|
|
583
|
+
// Public helpers for library consumers
|
|
584
|
+
// ---------------------------------------------------------------------------
|
|
639
585
|
function createHttpContextConfig(overrides = {}) {
|
|
640
|
-
return {
|
|
641
|
-
...DEFAULT_CONFIG,
|
|
642
|
-
...overrides,
|
|
643
|
-
};
|
|
586
|
+
return { ...DEFAULT_CONFIG, ...overrides };
|
|
644
587
|
}
|
|
645
|
-
|
|
588
|
+
/**
|
|
589
|
+
* Register the interceptor configuration in your app providers.
|
|
590
|
+
*
|
|
591
|
+
* @example
|
|
592
|
+
* // app.config.ts
|
|
593
|
+
* provideHttpClient(
|
|
594
|
+
* withInterceptors([
|
|
595
|
+
* httpContextInterceptor, // 1st — adds headers, handles 401 refresh
|
|
596
|
+
* apiInterceptor, // 2nd — normalises response, shows toasts
|
|
597
|
+
* ])
|
|
598
|
+
* ),
|
|
599
|
+
* ...provideHttpContext({ clientVersion: '2.0.0' }),
|
|
600
|
+
*/
|
|
646
601
|
function provideHttpContext(config = {}) {
|
|
647
602
|
return [
|
|
648
603
|
{
|
|
@@ -652,65 +607,50 @@ function provideHttpContext(config = {}) {
|
|
|
652
607
|
];
|
|
653
608
|
}
|
|
654
609
|
|
|
655
|
-
/**
|
|
656
|
-
* Token to determine if a request should show spinner
|
|
657
|
-
* Default is true (show spinner for all requests)
|
|
658
|
-
*/
|
|
659
610
|
const SHOW_SPINNER = new HttpContextToken(() => true);
|
|
660
|
-
const requests = [];
|
|
661
|
-
/**
|
|
662
|
-
* Helper function to disable spinner for specific requests
|
|
663
|
-
* @returns HttpContext with spinner disabled
|
|
664
|
-
*/
|
|
665
611
|
function withoutSpinner() {
|
|
666
612
|
return new HttpContext().set(SHOW_SPINNER, false);
|
|
667
613
|
}
|
|
668
|
-
/**
|
|
669
|
-
* Service to track active HTTP requests
|
|
670
|
-
*/
|
|
671
614
|
class ActiveRequestsTracker {
|
|
615
|
+
requests = [];
|
|
672
616
|
get count() {
|
|
673
|
-
return requests.length;
|
|
617
|
+
return this.requests.length;
|
|
674
618
|
}
|
|
619
|
+
/** Retorna true si se pasa de 0 → 1 (primera request activa). */
|
|
675
620
|
add(request) {
|
|
676
|
-
requests.push(request);
|
|
621
|
+
this.requests.push(request);
|
|
622
|
+
return this.requests.length === 1;
|
|
677
623
|
}
|
|
624
|
+
/** Retorna true si se pasa de 1 → 0 (última request completada). */
|
|
678
625
|
remove(request) {
|
|
679
|
-
const index = requests.indexOf(request);
|
|
626
|
+
const index = this.requests.indexOf(request);
|
|
680
627
|
if (index >= 0) {
|
|
681
|
-
requests.splice(index, 1);
|
|
628
|
+
this.requests.splice(index, 1);
|
|
682
629
|
}
|
|
630
|
+
return this.requests.length === 0;
|
|
683
631
|
}
|
|
684
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
685
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.
|
|
632
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ActiveRequestsTracker, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
633
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ActiveRequestsTracker, providedIn: 'root' });
|
|
686
634
|
}
|
|
687
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
635
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ActiveRequestsTracker, decorators: [{
|
|
688
636
|
type: Injectable,
|
|
689
|
-
args: [{
|
|
690
|
-
providedIn: 'root',
|
|
691
|
-
}]
|
|
637
|
+
args: [{ providedIn: 'root' }]
|
|
692
638
|
}] });
|
|
693
|
-
/**
|
|
694
|
-
* Interceptor that shows/hides a loading spinner based on active HTTP requests
|
|
695
|
-
*/
|
|
696
639
|
const spinnerInterceptor = (req, next) => {
|
|
697
|
-
// Track active requests requiring spinner
|
|
698
640
|
const activeRequests = inject(ActiveRequestsTracker);
|
|
699
641
|
const overlayService = inject(OverlayService);
|
|
700
|
-
// Skip spinner if disabled for this request
|
|
701
642
|
if (!req.context.get(SHOW_SPINNER)) {
|
|
702
643
|
return next(req);
|
|
703
644
|
}
|
|
704
|
-
//
|
|
705
|
-
activeRequests.add(req);
|
|
706
|
-
|
|
707
|
-
if (activeRequests.count === 1) {
|
|
645
|
+
// showSpinner solo cuando pasamos de 0 → 1 requests
|
|
646
|
+
const isFirst = activeRequests.add(req);
|
|
647
|
+
if (isFirst) {
|
|
708
648
|
overlayService.showSpinner();
|
|
709
649
|
}
|
|
710
650
|
return next(req).pipe(finalize(() => {
|
|
711
|
-
//
|
|
712
|
-
activeRequests.remove(req);
|
|
713
|
-
if (
|
|
651
|
+
// hideSpinner solo cuando pasamos de 1 → 0 requests
|
|
652
|
+
const isEmpty = activeRequests.remove(req);
|
|
653
|
+
if (isEmpty) {
|
|
714
654
|
overlayService.hideSpinner();
|
|
715
655
|
}
|
|
716
656
|
}));
|
|
@@ -739,10 +679,10 @@ class BaseHttpRepository {
|
|
|
739
679
|
delete(path = '') {
|
|
740
680
|
return this.http.delete(this.buildUrl(path));
|
|
741
681
|
}
|
|
742
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
743
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.
|
|
682
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BaseHttpRepository, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
683
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BaseHttpRepository });
|
|
744
684
|
}
|
|
745
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
685
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: BaseHttpRepository, decorators: [{
|
|
746
686
|
type: Injectable
|
|
747
687
|
}] });
|
|
748
688
|
|
|
@@ -786,10 +726,10 @@ class GenericRepository extends BaseHttpRepository {
|
|
|
786
726
|
}
|
|
787
727
|
return params;
|
|
788
728
|
}
|
|
789
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
790
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.
|
|
729
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: GenericRepository, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
730
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: GenericRepository });
|
|
791
731
|
}
|
|
792
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
732
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: GenericRepository, decorators: [{
|
|
793
733
|
type: Injectable
|
|
794
734
|
}], ctorParameters: () => [] });
|
|
795
735
|
class SearchableGenericRepository extends GenericRepository {
|
|
@@ -798,10 +738,10 @@ class SearchableGenericRepository extends GenericRepository {
|
|
|
798
738
|
const params = this.buildParams(pagination, searchFilters);
|
|
799
739
|
return this.get('search', params);
|
|
800
740
|
}
|
|
801
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
802
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.
|
|
741
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SearchableGenericRepository, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
742
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SearchableGenericRepository });
|
|
803
743
|
}
|
|
804
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
744
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SearchableGenericRepository, decorators: [{
|
|
805
745
|
type: Injectable
|
|
806
746
|
}] });
|
|
807
747
|
|
|
@@ -844,10 +784,10 @@ class RepositoryFactory {
|
|
|
844
784
|
remove: (id) => this.http.delete(buildUrl(idToString(id))),
|
|
845
785
|
};
|
|
846
786
|
}
|
|
847
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
848
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.
|
|
787
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RepositoryFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
788
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RepositoryFactory, providedIn: 'root' });
|
|
849
789
|
}
|
|
850
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
790
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RepositoryFactory, decorators: [{
|
|
851
791
|
type: Injectable,
|
|
852
792
|
args: [{ providedIn: 'root' }]
|
|
853
793
|
}] });
|
|
@@ -979,10 +919,10 @@ class CoreConfigService {
|
|
|
979
919
|
resetConfig() {
|
|
980
920
|
this.config = this.initializeConfig();
|
|
981
921
|
}
|
|
982
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
983
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.
|
|
922
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CoreConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
923
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CoreConfigService, providedIn: 'root' });
|
|
984
924
|
}
|
|
985
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
925
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CoreConfigService, decorators: [{
|
|
986
926
|
type: Injectable,
|
|
987
927
|
args: [{
|
|
988
928
|
providedIn: 'root',
|
|
@@ -1025,7 +965,7 @@ class Command extends BaseUseCase {
|
|
|
1025
965
|
timestamp: new Date().toISOString(),
|
|
1026
966
|
}));
|
|
1027
967
|
}
|
|
1028
|
-
return this.executeInternal(request).pipe(catchError((error) => {
|
|
968
|
+
return this.executeInternal(request).pipe(catchError$1((error) => {
|
|
1029
969
|
// Log the error for debugging
|
|
1030
970
|
const logger = inject(LoggingService);
|
|
1031
971
|
logger.error('An error occurred during command execution:', error);
|
|
@@ -1037,7 +977,7 @@ class Command extends BaseUseCase {
|
|
|
1037
977
|
|
|
1038
978
|
class Query extends BaseUseCase {
|
|
1039
979
|
execute(request) {
|
|
1040
|
-
return this.executeInternal(request).pipe(catchError((error) => {
|
|
980
|
+
return this.executeInternal(request).pipe(catchError$1((error) => {
|
|
1041
981
|
const logger = inject(LoggingService);
|
|
1042
982
|
logger.error('An error occurred during query execution:', error);
|
|
1043
983
|
return throwError(() => error);
|
|
@@ -1049,5 +989,5 @@ class Query extends BaseUseCase {
|
|
|
1049
989
|
* Generated bundle index. Do not edit.
|
|
1050
990
|
*/
|
|
1051
991
|
|
|
1052
|
-
export { ActiveRequestsTracker, AngularHttpAdapter, BaseHttpRepository, BaseUseCase, Command, CoreConfigService, CorrelationInfo, GenericRepository, HTTP_CONTEXT_CONFIG, LoggingService, Query, REPOSITORY_CONFIG, RepositoryFactory, SHOW_NOTIFICATIONS, SKIP_NOTIFICATION, SearchableGenericRepository, apiInterceptor, createCoreConfig, createHttpContextConfig, customUrl, httpContextInterceptor, provideCoreConfig, provideHttpContext, skipContextHeaders, spinnerInterceptor, withCustomHeaders, withoutSpinner };
|
|
992
|
+
export { ActiveRequestsTracker, AngularHttpAdapter, BaseHttpRepository, BaseUseCase, Command, CoreConfigService, CorrelationInfo, GenericRepository, HTTP_CONTEXT_CONFIG, LoggingService, Query, REPOSITORY_CONFIG, RepositoryFactory, SHOW_NOTIFICATIONS, SHOW_SPINNER, SKIP_NOTIFICATION, SearchableGenericRepository, apiInterceptor, createCoreConfig, createHttpContextConfig, customUrl, httpContextInterceptor, provideCoreConfig, provideHttpContext, skipContextHeaders, spinnerInterceptor, withCustomHeaders, withoutSpinner };
|
|
1053
993
|
//# sourceMappingURL=acontplus-ng-infrastructure.mjs.map
|