mesauth-angular 1.0.1 → 1.1.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/README.md +123 -317
- package/dist/README.md +123 -317
- package/dist/fesm2022/mesauth-angular.mjs +80 -45
- package/dist/fesm2022/mesauth-angular.mjs.map +1 -1
- package/dist/index.d.ts +31 -12
- package/package.json +1 -1
|
@@ -1,14 +1,46 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, NgModule, EventEmitter, signal, HostListener, HostBinding, Output, Component, ViewChild } from '@angular/core';
|
|
2
|
+
import { InjectionToken, makeEnvironmentProviders, provideAppInitializer, inject, Injectable, NgModule, EventEmitter, signal, HostListener, HostBinding, Output, Component, ViewChild } from '@angular/core';
|
|
3
|
+
import { HttpClient } from '@angular/common/http';
|
|
3
4
|
import { HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
|
|
4
5
|
import { BehaviorSubject, Subject, throwError } from 'rxjs';
|
|
5
6
|
import { filter, debounceTime, tap, catchError, takeUntil } from 'rxjs/operators';
|
|
6
7
|
import * as i2 from '@angular/router';
|
|
7
|
-
import { NavigationEnd } from '@angular/router';
|
|
8
|
-
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
8
|
+
import { Router, NavigationEnd } from '@angular/router';
|
|
9
9
|
import * as i3 from '@angular/common';
|
|
10
10
|
import { NgIf, CommonModule, NgFor } from '@angular/common';
|
|
11
11
|
|
|
12
|
+
/** Injection token for MesAuth configuration */
|
|
13
|
+
const MES_AUTH_CONFIG = new InjectionToken('MES_AUTH_CONFIG');
|
|
14
|
+
/**
|
|
15
|
+
* Provides MesAuth with configuration.
|
|
16
|
+
* This is the recommended way to set up mesauth-angular in standalone apps.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // app.config.ts
|
|
21
|
+
* export const appConfig: ApplicationConfig = {
|
|
22
|
+
* providers: [
|
|
23
|
+
* provideHttpClient(withInterceptors([mesAuthInterceptor])),
|
|
24
|
+
* provideMesAuth({
|
|
25
|
+
* apiBaseUrl: 'https://auth.example.com',
|
|
26
|
+
* userBaseUrl: 'https://app.example.com'
|
|
27
|
+
* })
|
|
28
|
+
* ]
|
|
29
|
+
* };
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
function provideMesAuth(config) {
|
|
33
|
+
return makeEnvironmentProviders([
|
|
34
|
+
{ provide: MES_AUTH_CONFIG, useValue: config },
|
|
35
|
+
MesAuthService,
|
|
36
|
+
provideAppInitializer(() => {
|
|
37
|
+
const mesAuthService = inject(MesAuthService);
|
|
38
|
+
const httpClient = inject(HttpClient);
|
|
39
|
+
const router = inject(Router);
|
|
40
|
+
mesAuthService.init(config, httpClient, router);
|
|
41
|
+
})
|
|
42
|
+
]);
|
|
43
|
+
}
|
|
12
44
|
var NotificationType;
|
|
13
45
|
(function (NotificationType) {
|
|
14
46
|
NotificationType["Info"] = "Info";
|
|
@@ -58,7 +90,6 @@ class MesAuthService {
|
|
|
58
90
|
});
|
|
59
91
|
}
|
|
60
92
|
this.fetchCurrentUser();
|
|
61
|
-
this.fetchInitialNotifications();
|
|
62
93
|
}
|
|
63
94
|
getConfig() {
|
|
64
95
|
return this.config;
|
|
@@ -72,6 +103,8 @@ class MesAuthService {
|
|
|
72
103
|
this._currentUser.next(u);
|
|
73
104
|
if (u && this.config) {
|
|
74
105
|
this.startConnection(this.config);
|
|
106
|
+
// Only fetch notifications after confirming user is logged in
|
|
107
|
+
this.fetchInitialNotifications();
|
|
75
108
|
}
|
|
76
109
|
},
|
|
77
110
|
error: (err) => {
|
|
@@ -83,7 +116,8 @@ class MesAuthService {
|
|
|
83
116
|
});
|
|
84
117
|
}
|
|
85
118
|
fetchInitialNotifications() {
|
|
86
|
-
if
|
|
119
|
+
// Skip if no user is logged in or apiBase not set
|
|
120
|
+
if (!this.apiBase || !this._currentUser.value)
|
|
87
121
|
return;
|
|
88
122
|
this.http.get(`${this.apiBase}/notif/me`, { withCredentials: this.config?.withCredentials ?? true }).subscribe({
|
|
89
123
|
next: (notifications) => {
|
|
@@ -260,57 +294,58 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
260
294
|
type: Injectable
|
|
261
295
|
}], ctorParameters: () => [] });
|
|
262
296
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
297
|
+
// Track if we're currently redirecting to prevent loopback
|
|
298
|
+
let isRedirecting = false;
|
|
299
|
+
/**
|
|
300
|
+
* Functional HTTP interceptor for handling 401/403 auth errors.
|
|
301
|
+
* Redirects to login page on 401, and to 403 page on 403.
|
|
302
|
+
* Includes loopback prevention to avoid infinite redirects.
|
|
303
|
+
*/
|
|
304
|
+
const mesAuthInterceptor = (req, next) => {
|
|
305
|
+
const authService = inject(MesAuthService);
|
|
306
|
+
const router = inject(Router);
|
|
307
|
+
return next(req).pipe(catchError((error) => {
|
|
308
|
+
const status = error.status;
|
|
309
|
+
// Check if we should handle this error and prevent loopback
|
|
310
|
+
if ((status === 401 || status === 403) && !isRedirecting) {
|
|
311
|
+
const config = authService.getConfig();
|
|
312
|
+
const baseUrl = config?.userBaseUrl || '';
|
|
313
|
+
// Use router URL for internal navigation (cleaner URLs)
|
|
314
|
+
// Falls back to window.location for full URL if needed
|
|
315
|
+
const currentUrl = router.url + (window.location.hash || '');
|
|
316
|
+
const returnUrl = encodeURIComponent(currentUrl);
|
|
317
|
+
// Avoid loops if already on auth/unauth pages
|
|
318
|
+
const isLoginPage = currentUrl.includes('/login');
|
|
319
|
+
const is403Page = currentUrl.includes('/403');
|
|
320
|
+
const isAuthPage = currentUrl.includes('/auth');
|
|
321
|
+
if (status === 401 && !isLoginPage && !isAuthPage) {
|
|
322
|
+
isRedirecting = true;
|
|
323
|
+
// Reset flag after a delay to allow future redirects after user returns
|
|
324
|
+
setTimeout(() => { isRedirecting = false; }, 5000);
|
|
325
|
+
window.location.href = `${baseUrl}/login?returnUrl=${returnUrl}`;
|
|
289
326
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
327
|
+
else if (status === 403 && !is403Page) {
|
|
328
|
+
isRedirecting = true;
|
|
329
|
+
setTimeout(() => { isRedirecting = false; }, 5000);
|
|
330
|
+
window.location.href = `${baseUrl}/403?returnUrl=${returnUrl}`;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return throwError(() => error);
|
|
334
|
+
}));
|
|
335
|
+
};
|
|
299
336
|
|
|
300
337
|
class MesAuthModule {
|
|
301
338
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MesAuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
302
339
|
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.16", ngImport: i0, type: MesAuthModule });
|
|
303
340
|
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MesAuthModule, providers: [
|
|
304
|
-
MesAuthService
|
|
305
|
-
{ provide: HTTP_INTERCEPTORS, useClass: MesAuthInterceptor, multi: true }
|
|
341
|
+
MesAuthService
|
|
306
342
|
] });
|
|
307
343
|
}
|
|
308
344
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MesAuthModule, decorators: [{
|
|
309
345
|
type: NgModule,
|
|
310
346
|
args: [{
|
|
311
347
|
providers: [
|
|
312
|
-
MesAuthService
|
|
313
|
-
{ provide: HTTP_INTERCEPTORS, useClass: MesAuthInterceptor, multi: true }
|
|
348
|
+
MesAuthService
|
|
314
349
|
]
|
|
315
350
|
}]
|
|
316
351
|
}] });
|
|
@@ -1185,5 +1220,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1185
1220
|
* Generated bundle index. Do not edit.
|
|
1186
1221
|
*/
|
|
1187
1222
|
|
|
1188
|
-
export {
|
|
1223
|
+
export { MES_AUTH_CONFIG, MaUserComponent, MesAuthModule, MesAuthService, NotificationBadgeComponent, NotificationPanelComponent, NotificationType, ThemeService, ToastContainerComponent, ToastService, UserProfileComponent, mesAuthInterceptor, provideMesAuth };
|
|
1189
1224
|
//# sourceMappingURL=mesauth-angular.mjs.map
|