@medha-analytics/medhasso-auth 1.0.1 → 1.0.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 CHANGED
@@ -1,297 +1,297 @@
1
- # MedHasso Authentication Library
2
-
3
- Angular authentication library for seamless integration with MedHasso SSO services. This library provides JWT token management, route guards, HTTP interceptors, and user management utilities.
4
-
5
- ## Features
6
-
7
- - 🔐 **JWT Token Management** - Automatic token refresh and storage
8
- - 🛡️ **Route Guards** - Protect routes with authentication and role-based access
9
- - 🔄 **HTTP Interceptor** - Automatic token attachment to HTTP requests
10
- - 👤 **User Management** - Extract and manage user information from JWT tokens
11
- - ⚙️ **Configurable** - Extensive configuration options for different environments
12
- - 📱 **Angular 14+ Support** - Compatible with Angular 14 through latest versions
13
-
14
- ## Installation
15
-
16
- ```bash
17
- npm install @medha-analytics/medhasso-auth
18
- ```
19
-
20
- ## Quick Start
21
-
22
- ### 1. Import and Configure
23
-
24
- In your `app.config.ts` (Angular 17+ standalone) or `app.module.ts`:
25
-
26
- #### Standalone Bootstrap (Angular 17+)
27
- ```typescript
28
- import { bootstrapApplication } from '@angular/platform-browser';
29
- import { provideRouter } from '@angular/router';
30
- import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
31
- import { MedHassoAuthModule } from '@medha-analytics/medhasso-auth';
32
- import { AppComponent } from './app/app.component';
33
- import { routes } from './app/app.routes';
34
- import { environment } from './environments/environment';
35
-
36
- bootstrapApplication(AppComponent, {
37
- providers: [
38
- provideRouter(routes),
39
- provideHttpClient(withInterceptorsFromDi()),
40
- ...MedHassoAuthModule.forStandalone({
41
- ssoUrl: environment.ssoUrl,
42
- refreshUrl: environment.refreshUrl,
43
- applicationName: 'Your App Name'
44
- })
45
- ]
46
- });
47
- ```
48
-
49
- #### Module-based (Angular 14-16)
50
- ```typescript
51
- import { NgModule } from '@angular/core';
52
- import { BrowserModule } from '@angular/platform-browser';
53
- import { HttpClientModule } from '@angular/common/http';
54
- import { MedHassoAuthModule } from '@medha-analytics/medhasso-auth';
55
- import { AppComponent } from './app.component';
56
- import { environment } from '../environments/environment';
57
-
58
- @NgModule({
59
- declarations: [AppComponent],
60
- imports: [
61
- BrowserModule,
62
- HttpClientModule,
63
- MedHassoAuthModule.forRoot({
64
- ssoUrl: environment.ssoUrl,
65
- refreshUrl: environment.refreshUrl,
66
- applicationName: 'Your App Name'
67
- })
68
- ],
69
- bootstrap: [AppComponent]
70
- })
71
- export class AppModule { }
72
- ```
73
-
74
- ### 2. Protect Routes
75
-
76
- ```typescript
77
- import { Routes } from '@angular/router';
78
- import { MedHassoAuthGuard, MedHassoRoleGuard, MedHassoAdminGuard } from '@medha-analytics/medhasso-auth';
79
-
80
- export const routes: Routes = [
81
- {
82
- path: 'dashboard',
83
- component: DashboardComponent,
84
- canActivate: [MedHassoAuthGuard]
85
- },
86
- {
87
- path: 'admin',
88
- component: AdminComponent,
89
- canActivate: [MedHassoAdminGuard]
90
- },
91
- {
92
- path: 'manager',
93
- component: ManagerComponent,
94
- canActivate: [MedHassoRoleGuard],
95
- data: { roles: ['manager', 'admin'] }
96
- }
97
- ];
98
- ```
99
-
100
- ### 3. Use in Components
101
-
102
- ```typescript
103
- import { Component } from '@angular/core';
104
- import { MedHassoAuthService } from '@medha-analytics/medhasso-auth';
105
-
106
- @Component({
107
- selector: 'app-user-profile',
108
- template: `
109
- <div *ngIf="authService.isAuthenticated()">
110
- <h2>Welcome, {{ authService.getUserDisplayName() }}!</h2>
111
- <p>Email: {{ authService.getUserEmail() }}</p>
112
- <div *ngIf="authService.isAdmin()">
113
- <button>Admin Panel</button>
114
- </div>
115
- <button (click)="logout()">Logout</button>
116
- </div>
117
- `
118
- })
119
- export class UserProfileComponent {
120
- constructor(public authService: MedHassoAuthService) {}
121
-
122
- logout() {
123
- this.authService.logout();
124
- }
125
- }
126
- ```
127
-
128
- ## Configuration Options
129
-
130
- ### Environment Setup
131
- First, configure your environment files:
132
-
133
- ```typescript
134
- // src/environments/environment.ts
135
- export const environment = {
136
- production: false,
137
- ssoUrl: 'https://your-dev-sso.domain.com:3000',
138
- refreshUrl: 'https://your-dev-refresh.domain.com:4000',
139
- // ... other config
140
- };
141
-
142
- // src/environments/environment.production.ts
143
- export const environment = {
144
- production: true,
145
- ssoUrl: 'https://your-prod-sso.domain.com:3000',
146
- refreshUrl: 'https://your-prod-refresh.domain.com:4000',
147
- // ... other config
148
- };
149
- ```
150
-
151
- ### Basic Configuration
152
- ```typescript
153
- {
154
- ssoUrl: environment.ssoUrl,
155
- refreshUrl: environment.refreshUrl,
156
- applicationName: 'Your Application Name'
157
- }
158
- ```
159
-
160
- ### Advanced Configuration
161
- ```typescript
162
- {
163
- ssoUrl: environment.ssoUrl,
164
- refreshUrl: environment.refreshUrl,
165
- applicationName: 'Your Application Name',
166
-
167
- // Token configuration
168
- tokenConfig: {
169
- storageType: 'localStorage', // or 'sessionStorage'
170
- idTokenKey: 'idToken',
171
- refreshTokenKey: 'refreshToken',
172
- refreshBeforeExpiryMinutes: 5,
173
- autoRefresh: true
174
- },
175
-
176
- // HTTP Interceptor configuration
177
- interceptorConfig: {
178
- enabled: true,
179
- authHeaderPrefix: 'Bearer',
180
- excludeUrls: ['*/public/*', '*/assets/*'],
181
- includeUrls: ['*/api/*'] // Optional: if specified, only these URLs get tokens
182
- },
183
-
184
- // Security configuration
185
- securityConfig: {
186
- httpsOnly: true,
187
- secureCookies: true,
188
- additionalCspSources: ['https://your-cdn.com']
189
- }
190
- }
191
- ```
192
-
193
- ## Guards
194
-
195
- ### MedHassoAuthGuard
196
- Basic authentication guard that ensures user is logged in.
197
-
198
- ### MedHassoRoleGuard
199
- Role-based access guard. Use with route data:
200
- ```typescript
201
- {
202
- path: 'admin',
203
- component: AdminComponent,
204
- canActivate: [MedHassoRoleGuard],
205
- data: {
206
- role: 'admin', // Single role
207
- roles: ['admin', 'manager'] // Multiple roles (OR condition)
208
- }
209
- }
210
- ```
211
-
212
- ### MedHassoAdminGuard
213
- Admin-only access guard.
214
-
215
- ## Services
216
-
217
- ### MedHassoAuthService
218
- Main authentication service with methods:
219
- - `isAuthenticated(): boolean`
220
- - `getCurrentUser(): MedHassoUser | null`
221
- - `hasRole(role: string): boolean`
222
- - `isAdmin(): boolean`
223
- - `login(returnUrl?: string): void`
224
- - `logout(): void`
225
- - `getUserEmail(): string | null`
226
- - `getUserDisplayName(): string | null`
227
-
228
- ### TokenManagementService
229
- Low-level token management (usually not needed directly):
230
- - `getTokenInfo(): TokenInfo | null`
231
- - `refreshToken(): Observable<any>`
232
- - `setTokens(idToken: string, refreshToken?: string): void`
233
-
234
- ## Environment-Specific Setup
235
-
236
- ### Development
237
- ```typescript
238
- // src/environments/environment.ts
239
- export const environment = {
240
- production: false,
241
- ssoUrl: 'https://dev-sso.your-domain.com:3000',
242
- refreshUrl: 'https://dev-refresh.your-domain.com:4000'
243
- };
244
-
245
- // Usage in module/config
246
- MedHassoAuthModule.forRoot({
247
- ssoUrl: environment.ssoUrl,
248
- refreshUrl: environment.refreshUrl,
249
- applicationName: 'Your App (Dev)'
250
- })
251
- ```
252
-
253
- ### Production
254
- ```typescript
255
- // src/environments/environment.production.ts
256
- export const environment = {
257
- production: true,
258
- ssoUrl: 'https://sso.your-domain.com:3000',
259
- refreshUrl: 'https://refresh.your-domain.com:4000'
260
- };
261
-
262
- // Usage in module/config
263
- MedHassoAuthModule.forRoot({
264
- ssoUrl: environment.ssoUrl,
265
- refreshUrl: environment.refreshUrl,
266
- applicationName: 'Your App'
267
- })
268
- ```
269
-
270
- ## CSP Configuration
271
-
272
- For server-side Content Security Policy, include these domains:
273
-
274
- ```javascript
275
- // In your server configuration (e.g., Express.js)
276
- const cspSources = [
277
- process.env.SSO_URL || 'https://your-sso.domain.com:3000',
278
- process.env.REFRESH_URL || 'https://your-refresh.domain.com:4000'
279
- ];
280
- ```
281
-
282
- ## Migration Guide
283
-
284
- ### From Custom Implementation
285
- 1. Remove your existing auth guard, interceptor, and token service
286
- 2. Install this library
287
- 3. Update your imports and module configuration
288
- 4. Update route guards to use library guards
289
- 5. Update components to use `MedHassoAuthService`
290
-
291
- ## Contributing
292
-
293
- Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
294
-
295
- ## License
296
-
1
+ # MedHasso Authentication Library
2
+
3
+ Angular authentication library for seamless integration with MedHasso SSO services. This library provides JWT token management, route guards, HTTP interceptors, and user management utilities.
4
+
5
+ ## Features
6
+
7
+ - 🔐 **JWT Token Management** - Automatic token refresh and storage
8
+ - 🛡️ **Route Guards** - Protect routes with authentication and role-based access
9
+ - 🔄 **HTTP Interceptor** - Automatic token attachment to HTTP requests
10
+ - 👤 **User Management** - Extract and manage user information from JWT tokens
11
+ - ⚙️ **Configurable** - Extensive configuration options for different environments
12
+ - 📱 **Angular 14+ Support** - Compatible with Angular 14 through latest versions
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @medha-analytics/medhasso-auth
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ### 1. Import and Configure
23
+
24
+ In your `app.config.ts` (Angular 17+ standalone) or `app.module.ts`:
25
+
26
+ #### Standalone Bootstrap (Angular 17+)
27
+ ```typescript
28
+ import { bootstrapApplication } from '@angular/platform-browser';
29
+ import { provideRouter } from '@angular/router';
30
+ import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
31
+ import { MedHassoAuthModule } from '@medha-analytics/medhasso-auth';
32
+ import { AppComponent } from './app/app.component';
33
+ import { routes } from './app/app.routes';
34
+ import { environment } from './environments/environment';
35
+
36
+ bootstrapApplication(AppComponent, {
37
+ providers: [
38
+ provideRouter(routes),
39
+ provideHttpClient(withInterceptorsFromDi()),
40
+ ...MedHassoAuthModule.forStandalone({
41
+ ssoUrl: environment.ssoUrl,
42
+ refreshUrl: environment.refreshUrl,
43
+ applicationName: 'Your App Name'
44
+ })
45
+ ]
46
+ });
47
+ ```
48
+
49
+ #### Module-based (Angular 14-16)
50
+ ```typescript
51
+ import { NgModule } from '@angular/core';
52
+ import { BrowserModule } from '@angular/platform-browser';
53
+ import { HttpClientModule } from '@angular/common/http';
54
+ import { MedHassoAuthModule } from '@medha-analytics/medhasso-auth';
55
+ import { AppComponent } from './app.component';
56
+ import { environment } from '../environments/environment';
57
+
58
+ @NgModule({
59
+ declarations: [AppComponent],
60
+ imports: [
61
+ BrowserModule,
62
+ HttpClientModule,
63
+ MedHassoAuthModule.forRoot({
64
+ ssoUrl: environment.ssoUrl,
65
+ refreshUrl: environment.refreshUrl,
66
+ applicationName: 'Your App Name'
67
+ })
68
+ ],
69
+ bootstrap: [AppComponent]
70
+ })
71
+ export class AppModule { }
72
+ ```
73
+
74
+ ### 2. Protect Routes
75
+
76
+ ```typescript
77
+ import { Routes } from '@angular/router';
78
+ import { MedHassoAuthGuard, MedHassoRoleGuard, MedHassoAdminGuard } from '@medha-analytics/medhasso-auth';
79
+
80
+ export const routes: Routes = [
81
+ {
82
+ path: 'dashboard',
83
+ component: DashboardComponent,
84
+ canActivate: [MedHassoAuthGuard]
85
+ },
86
+ {
87
+ path: 'admin',
88
+ component: AdminComponent,
89
+ canActivate: [MedHassoAdminGuard]
90
+ },
91
+ {
92
+ path: 'manager',
93
+ component: ManagerComponent,
94
+ canActivate: [MedHassoRoleGuard],
95
+ data: { roles: ['manager', 'admin'] }
96
+ }
97
+ ];
98
+ ```
99
+
100
+ ### 3. Use in Components
101
+
102
+ ```typescript
103
+ import { Component } from '@angular/core';
104
+ import { MedHassoAuthService } from '@medha-analytics/medhasso-auth';
105
+
106
+ @Component({
107
+ selector: 'app-user-profile',
108
+ template: `
109
+ <div *ngIf="authService.isAuthenticated()">
110
+ <h2>Welcome, {{ authService.getUserDisplayName() }}!</h2>
111
+ <p>Email: {{ authService.getUserEmail() }}</p>
112
+ <div *ngIf="authService.isAdmin()">
113
+ <button>Admin Panel</button>
114
+ </div>
115
+ <button (click)="logout()">Logout</button>
116
+ </div>
117
+ `
118
+ })
119
+ export class UserProfileComponent {
120
+ constructor(public authService: MedHassoAuthService) {}
121
+
122
+ logout() {
123
+ this.authService.logout();
124
+ }
125
+ }
126
+ ```
127
+
128
+ ## Configuration Options
129
+
130
+ ### Environment Setup
131
+ First, configure your environment files:
132
+
133
+ ```typescript
134
+ // src/environments/environment.ts
135
+ export const environment = {
136
+ production: false,
137
+ ssoUrl: 'https://your-dev-sso.domain.com:3000',
138
+ refreshUrl: 'https://your-dev-refresh.domain.com:4000',
139
+ // ... other config
140
+ };
141
+
142
+ // src/environments/environment.production.ts
143
+ export const environment = {
144
+ production: true,
145
+ ssoUrl: 'https://your-prod-sso.domain.com:3000',
146
+ refreshUrl: 'https://your-prod-refresh.domain.com:4000',
147
+ // ... other config
148
+ };
149
+ ```
150
+
151
+ ### Basic Configuration
152
+ ```typescript
153
+ {
154
+ ssoUrl: environment.ssoUrl,
155
+ refreshUrl: environment.refreshUrl,
156
+ applicationName: 'Your Application Name'
157
+ }
158
+ ```
159
+
160
+ ### Advanced Configuration
161
+ ```typescript
162
+ {
163
+ ssoUrl: environment.ssoUrl,
164
+ refreshUrl: environment.refreshUrl,
165
+ applicationName: 'Your Application Name',
166
+
167
+ // Token configuration
168
+ tokenConfig: {
169
+ storageType: 'localStorage', // or 'sessionStorage'
170
+ idTokenKey: 'idToken',
171
+ refreshTokenKey: 'refreshToken',
172
+ refreshBeforeExpiryMinutes: 5,
173
+ autoRefresh: true
174
+ },
175
+
176
+ // HTTP Interceptor configuration
177
+ interceptorConfig: {
178
+ enabled: true,
179
+ authHeaderPrefix: 'Bearer',
180
+ excludeUrls: ['*/public/*', '*/assets/*'],
181
+ includeUrls: ['*/api/*'] // Optional: if specified, only these URLs get tokens
182
+ },
183
+
184
+ // Security configuration
185
+ securityConfig: {
186
+ httpsOnly: true,
187
+ secureCookies: true,
188
+ additionalCspSources: ['https://your-cdn.com']
189
+ }
190
+ }
191
+ ```
192
+
193
+ ## Guards
194
+
195
+ ### MedHassoAuthGuard
196
+ Basic authentication guard that ensures user is logged in.
197
+
198
+ ### MedHassoRoleGuard
199
+ Role-based access guard. Use with route data:
200
+ ```typescript
201
+ {
202
+ path: 'admin',
203
+ component: AdminComponent,
204
+ canActivate: [MedHassoRoleGuard],
205
+ data: {
206
+ role: 'admin', // Single role
207
+ roles: ['admin', 'manager'] // Multiple roles (OR condition)
208
+ }
209
+ }
210
+ ```
211
+
212
+ ### MedHassoAdminGuard
213
+ Admin-only access guard.
214
+
215
+ ## Services
216
+
217
+ ### MedHassoAuthService
218
+ Main authentication service with methods:
219
+ - `isAuthenticated(): boolean`
220
+ - `getCurrentUser(): MedHassoUser | null`
221
+ - `hasRole(role: string): boolean`
222
+ - `isAdmin(): boolean`
223
+ - `login(returnUrl?: string): void`
224
+ - `logout(): void`
225
+ - `getUserEmail(): string | null`
226
+ - `getUserDisplayName(): string | null`
227
+
228
+ ### TokenManagementService
229
+ Low-level token management (usually not needed directly):
230
+ - `getTokenInfo(): TokenInfo | null`
231
+ - `refreshToken(): Observable<any>`
232
+ - `setTokens(idToken: string, refreshToken?: string): void`
233
+
234
+ ## Environment-Specific Setup
235
+
236
+ ### Development
237
+ ```typescript
238
+ // src/environments/environment.ts
239
+ export const environment = {
240
+ production: false,
241
+ ssoUrl: 'https://dev-sso.your-domain.com:3000',
242
+ refreshUrl: 'https://dev-refresh.your-domain.com:4000'
243
+ };
244
+
245
+ // Usage in module/config
246
+ MedHassoAuthModule.forRoot({
247
+ ssoUrl: environment.ssoUrl,
248
+ refreshUrl: environment.refreshUrl,
249
+ applicationName: 'Your App (Dev)'
250
+ })
251
+ ```
252
+
253
+ ### Production
254
+ ```typescript
255
+ // src/environments/environment.production.ts
256
+ export const environment = {
257
+ production: true,
258
+ ssoUrl: 'https://sso.your-domain.com:3000',
259
+ refreshUrl: 'https://refresh.your-domain.com:4000'
260
+ };
261
+
262
+ // Usage in module/config
263
+ MedHassoAuthModule.forRoot({
264
+ ssoUrl: environment.ssoUrl,
265
+ refreshUrl: environment.refreshUrl,
266
+ applicationName: 'Your App'
267
+ })
268
+ ```
269
+
270
+ ## CSP Configuration
271
+
272
+ For server-side Content Security Policy, include these domains:
273
+
274
+ ```javascript
275
+ // In your server configuration (e.g., Express.js)
276
+ const cspSources = [
277
+ process.env.SSO_URL || 'https://your-sso.domain.com:3000',
278
+ process.env.REFRESH_URL || 'https://your-refresh.domain.com:4000'
279
+ ];
280
+ ```
281
+
282
+ ## Migration Guide
283
+
284
+ ### From Custom Implementation
285
+ 1. Remove your existing auth guard, interceptor, and token service
286
+ 2. Install this library
287
+ 3. Update your imports and module configuration
288
+ 4. Update route guards to use library guards
289
+ 5. Update components to use `MedHassoAuthService`
290
+
291
+ ## Contributing
292
+
293
+ Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
294
+
295
+ ## License
296
+
297
297
  MIT License - see [LICENSE](LICENSE) file for details.
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, Inject, Injectable, NgModule } from '@angular/core';
3
3
  import * as i1 from '@angular/common/http';
4
- import { HTTP_INTERCEPTORS } from '@angular/common/http';
4
+ import { HttpClient, HTTP_INTERCEPTORS } from '@angular/common/http';
5
5
  import { BehaviorSubject, timer, throwError, of } from 'rxjs';
6
6
  import { tap, catchError, finalize, shareReplay, map, switchMap } from 'rxjs/operators';
7
7
  import * as i2 from '@angular/router';
@@ -27,7 +27,7 @@ class TokenManagementService {
27
27
  get autoRefresh() {
28
28
  return this.tokenConfig.autoRefresh !== false;
29
29
  }
30
- constructor(config, http) {
30
+ constructor(config, http, httpBackend) {
31
31
  this.config = config;
32
32
  this.http = http;
33
33
  this.refreshInProgress$ = null;
@@ -43,6 +43,7 @@ class TokenManagementService {
43
43
  };
44
44
  this.token$ = this.tokenSubject.asObservable();
45
45
  this.user$ = this.userSubject.asObservable();
46
+ this.refreshHttp = new HttpClient(httpBackend);
46
47
  this.initializeFromStorage();
47
48
  this.setupWakeDetection();
48
49
  }
@@ -140,19 +141,26 @@ class TokenManagementService {
140
141
  storage.removeItem(this.refreshTokenKey);
141
142
  }
142
143
  /**
143
- * Create token info object from JWT token
144
+ * Create token info object from JWT token.
145
+ *
146
+ * `isExpired` and `needsRefresh` are getters, not snapshotted booleans:
147
+ * the TokenInfo object may outlive wall-clock events that change its
148
+ * expiry status (e.g. OS/browser suspended overnight, laptop sleep).
149
+ * A snapshotted boolean captured at creation time would then lie — the
150
+ * wake handler would call ensureValidToken(), see `isExpired: false`
151
+ * from the pre-sleep snapshot, and skip the refresh. Reading these as
152
+ * getters means every access reflects the current clock.
144
153
  */
145
154
  createTokenInfo(token) {
146
155
  const payload = this.decodeJwt(token);
147
156
  const expiresAt = payload.exp * 1000; // Convert to milliseconds
148
- const now = Date.now();
149
157
  const refreshWindow = this.refreshBeforeExpiryMinutes * 60 * 1000;
150
158
  return {
151
159
  token,
152
160
  payload,
153
161
  expiresAt,
154
- isExpired: now >= expiresAt,
155
- needsRefresh: now >= (expiresAt - refreshWindow)
162
+ get isExpired() { return Date.now() >= expiresAt; },
163
+ get needsRefresh() { return Date.now() >= (expiresAt - refreshWindow); }
156
164
  };
157
165
  }
158
166
  /**
@@ -272,14 +280,24 @@ class TokenManagementService {
272
280
  if (!refreshToken) {
273
281
  return throwError(() => new Error('No refresh token available'));
274
282
  }
275
- const request$ = this.http.post(`${this.config.refreshUrl}/api/refresh-token`, { refreshToken })
283
+ const request$ = this.refreshHttp.post(`${this.config.refreshUrl}/api/refresh-token`, { refreshToken })
276
284
  .pipe(tap((response) => {
277
285
  if (response.id_token) {
278
286
  this.setTokens(response.id_token, response.refresh_token);
279
287
  }
280
288
  }), catchError(error => {
281
289
  console.error('Token refresh failed:', error);
282
- this.logout();
290
+ // Only clear the session on a definitive auth failure from the refresh
291
+ // endpoint (dead/revoked/invalid refresh token). Transient failures —
292
+ // network blips, 5xx, timeouts — must NOT force a logout: the current
293
+ // id_token may still be valid for the rest of its lifetime, and the
294
+ // background-refresh path (ensureValidToken → needsRefresh) runs on
295
+ // every request within the 5-min window, so a single network hiccup
296
+ // would otherwise log the user out mid-session.
297
+ const status = error?.status;
298
+ if (status === 400 || status === 401) {
299
+ this.logout();
300
+ }
283
301
  return throwError(() => error);
284
302
  }), finalize(() => {
285
303
  this.refreshInProgress$ = null;
@@ -370,7 +388,7 @@ class TokenManagementService {
370
388
  this.clearTokenRefreshInterval();
371
389
  this.teardownWakeDetection();
372
390
  }
373
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TokenManagementService, deps: [{ token: MEDHASSO_CONFIG }, { token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
391
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TokenManagementService, deps: [{ token: MEDHASSO_CONFIG }, { token: i1.HttpClient }, { token: i1.HttpBackend }], target: i0.ɵɵFactoryTarget.Injectable }); }
374
392
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TokenManagementService, providedIn: 'root' }); }
375
393
  }
376
394
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TokenManagementService, decorators: [{
@@ -381,7 +399,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
381
399
  }], ctorParameters: () => [{ type: undefined, decorators: [{
382
400
  type: Inject,
383
401
  args: [MEDHASSO_CONFIG]
384
- }] }, { type: i1.HttpClient }] });
402
+ }] }, { type: i1.HttpClient }, { type: i1.HttpBackend }] });
385
403
 
386
404
  class MedHassoAuthInterceptor {
387
405
  constructor(config, tokenService) {
@@ -470,25 +488,32 @@ class MedHassoAuthInterceptor {
470
488
  });
471
489
  }
472
490
  /**
473
- * Handle 401 Unauthorized errors by attempting token refresh
491
+ * Handle 401 Unauthorized errors by attempting token refresh.
492
+ *
493
+ * Always tries the refresh path first, even when the in-memory token looks
494
+ * expired to our clock. The server already said "unauthorized" — whether our
495
+ * local isExpired check agrees doesn't change what we need to do next.
496
+ * Short-circuiting to SSO on `tokenInfo.isExpired` would bounce the user on
497
+ * mid-flight expirations and small client/server clock skews, cases where the
498
+ * refresh token is still perfectly valid and would have recovered. If the
499
+ * refresh really can't succeed (no refresh token in storage, dead refresh
500
+ * token → 400/401), refreshToken() throws and the catchError below redirects.
474
501
  */
475
502
  handle401Error(request, next) {
476
- const tokenInfo = this.tokenService.getTokenInfo();
477
- // If no token or token is expired, redirect to SSO
478
- if (!tokenInfo || tokenInfo.isExpired) {
503
+ // catchError sits BEFORE switchMap on purpose: it must only catch failures
504
+ // from refreshToken(), not from the retried next.handle(retryRequest). If
505
+ // the refresh succeeds but the retry fails (403, 500, etc.), that error
506
+ // has nothing to do with authentication — redirecting to SSO would be
507
+ // wrong. Keep the SSO redirect scoped to the "refresh really can't help"
508
+ // case; let any retry error propagate normally to the component.
509
+ return this.tokenService.refreshToken().pipe(catchError((refreshError) => {
510
+ console.error('MedHasso Auth: Token refresh failed', refreshError);
479
511
  this.redirectToSSO();
480
- return throwError(() => new Error('Authentication required'));
481
- }
482
- // If token exists but request failed, try to refresh
483
- return this.tokenService.refreshToken().pipe(switchMap(() => {
512
+ return throwError(() => refreshError);
513
+ }), switchMap(() => {
484
514
  // Retry the original request with new token
485
515
  const retryRequest = this.addAuthorizationHeader(request);
486
516
  return next.handle(retryRequest);
487
- }), catchError((refreshError) => {
488
- // If refresh fails, redirect to SSO
489
- console.error('MedHasso Auth: Token refresh failed', refreshError);
490
- this.redirectToSSO();
491
- return throwError(() => refreshError);
492
517
  }));
493
518
  }
494
519
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"medha-analytics-medhasso-auth.mjs","sources":["../../../projects/medhasso-auth/src/lib/tokens/medhasso-config.token.ts","../../../projects/medhasso-auth/src/lib/services/token-management.service.ts","../../../projects/medhasso-auth/src/lib/interceptors/medhasso-auth.interceptor.ts","../../../projects/medhasso-auth/src/lib/services/medhasso-auth.service.ts","../../../projects/medhasso-auth/src/lib/medhasso-auth.module.ts","../../../projects/medhasso-auth/src/lib/guards/medhasso-auth.guard.ts","../../../projects/medhasso-auth/src/public-api.ts","../../../projects/medhasso-auth/src/medha-analytics-medhasso-auth.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\nimport { MedHassoConfig } from '../interfaces/medhasso-config.interface';\r\n\r\nexport const MEDHASSO_CONFIG = new InjectionToken<MedHassoConfig>('MEDHASSO_CONFIG');","import { Injectable, Inject } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { BehaviorSubject, Observable, of, throwError, timer } from 'rxjs';\r\nimport { catchError, finalize, map, shareReplay, tap } from 'rxjs/operators';\r\nimport { MedHassoConfig, TokenConfig, TokenInfo, MedHassoUser } from '../interfaces/medhasso-config.interface';\r\nimport { MEDHASSO_CONFIG } from '../tokens/medhasso-config.token';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class TokenManagementService {\r\n private refreshTokenInterval: any;\r\n private refreshInProgress$: Observable<any> | null = null;\r\n private tokenSubject = new BehaviorSubject<TokenInfo | null>(null);\r\n private userSubject = new BehaviorSubject<MedHassoUser | null>(null);\r\n private readonly onVisibilityChange = () => {\r\n if (document.visibilityState === 'visible') {\r\n this.ensureValidToken().subscribe();\r\n }\r\n };\r\n private readonly onWindowFocus = () => {\r\n this.ensureValidToken().subscribe();\r\n };\r\n\r\n public token$ = this.tokenSubject.asObservable();\r\n public user$ = this.userSubject.asObservable();\r\n\r\n private get tokenConfig(): TokenConfig {\r\n return this.config.tokenConfig || {};\r\n }\r\n\r\n private get storageType(): 'localStorage' | 'sessionStorage' {\r\n return this.tokenConfig.storageType || 'localStorage';\r\n }\r\n\r\n private get idTokenKey(): string {\r\n return this.tokenConfig.idTokenKey || 'idToken';\r\n }\r\n\r\n private get refreshTokenKey(): string {\r\n return this.tokenConfig.refreshTokenKey || 'refreshToken';\r\n }\r\n\r\n private get refreshBeforeExpiryMinutes(): number {\r\n return this.tokenConfig.refreshBeforeExpiryMinutes || 5;\r\n }\r\n\r\n private get autoRefresh(): boolean {\r\n return this.tokenConfig.autoRefresh !== false;\r\n }\r\n\r\n constructor(\r\n @Inject(MEDHASSO_CONFIG) private config: MedHassoConfig,\r\n private http: HttpClient\r\n ) {\r\n this.initializeFromStorage();\r\n this.setupWakeDetection();\r\n }\r\n\r\n /**\r\n * Re-validate the token whenever the tab regains focus/visibility.\r\n * The refresh timer is a JS timer and does not fire while the OS/browser\r\n * was suspended (e.g. laptop sleep overnight), so it can't be relied on\r\n * alone to catch a token that went stale while the app was inactive.\r\n */\r\n private setupWakeDetection(): void {\r\n if (typeof document === 'undefined' || typeof window === 'undefined') {\r\n return;\r\n }\r\n\r\n document.addEventListener('visibilitychange', this.onVisibilityChange);\r\n window.addEventListener('focus', this.onWindowFocus);\r\n }\r\n\r\n /**\r\n * Remove wake-detection listeners registered in setupWakeDetection().\r\n */\r\n private teardownWakeDetection(): void {\r\n if (typeof document === 'undefined' || typeof window === 'undefined') {\r\n return;\r\n }\r\n\r\n document.removeEventListener('visibilitychange', this.onVisibilityChange);\r\n window.removeEventListener('focus', this.onWindowFocus);\r\n }\r\n\r\n /**\r\n * Initialize token information from storage\r\n */\r\n private initializeFromStorage(): void {\r\n const token = this.getStoredToken();\r\n if (token) {\r\n const tokenInfo = this.createTokenInfo(token);\r\n this.tokenSubject.next(tokenInfo);\r\n this.userSubject.next(this.extractUserFromToken(token));\r\n \r\n if (this.autoRefresh && !tokenInfo.isExpired) {\r\n this.setTokenRefreshInterval(tokenInfo);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Re-sync in-memory token state from storage if it has drifted (e.g.\r\n * something wrote tokens directly to storage without going through\r\n * setTokens()). No-op when storage already matches memory.\r\n */\r\n private syncFromStorage(): void {\r\n const storedToken = this.getStoredToken();\r\n const currentToken = this.getTokenInfo()?.token ?? null;\r\n\r\n if (storedToken === currentToken) {\r\n return;\r\n }\r\n\r\n if (!storedToken) {\r\n this.tokenSubject.next(null);\r\n this.userSubject.next(null);\r\n this.clearTokenRefreshInterval();\r\n return;\r\n }\r\n\r\n const tokenInfo = this.createTokenInfo(storedToken);\r\n this.tokenSubject.next(tokenInfo);\r\n this.userSubject.next(this.extractUserFromToken(storedToken));\r\n\r\n if (this.autoRefresh && !tokenInfo.isExpired) {\r\n this.setTokenRefreshInterval(tokenInfo);\r\n }\r\n }\r\n\r\n /**\r\n * Get stored token from configured storage\r\n */\r\n private getStoredToken(): string | null {\r\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\r\n return storage.getItem(this.idTokenKey);\r\n }\r\n\r\n /**\r\n * Get stored refresh token from configured storage\r\n */\r\n private getStoredRefreshToken(): string | null {\r\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\r\n return storage.getItem(this.refreshTokenKey);\r\n }\r\n\r\n /**\r\n * Store tokens in configured storage\r\n */\r\n private storeTokens(idToken: string, refreshToken?: string): void {\r\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\r\n storage.setItem(this.idTokenKey, idToken);\r\n if (refreshToken) {\r\n storage.setItem(this.refreshTokenKey, refreshToken);\r\n }\r\n }\r\n\r\n /**\r\n * Clear stored tokens\r\n */\r\n private clearStoredTokens(): void {\r\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\r\n storage.removeItem(this.idTokenKey);\r\n storage.removeItem(this.refreshTokenKey);\r\n }\r\n\r\n /**\r\n * Create token info object from JWT token\r\n */\r\n private createTokenInfo(token: string): TokenInfo {\r\n const payload = this.decodeJwt(token);\r\n const expiresAt = payload.exp * 1000; // Convert to milliseconds\r\n const now = Date.now();\r\n const refreshWindow = this.refreshBeforeExpiryMinutes * 60 * 1000;\r\n\r\n return {\r\n token,\r\n payload,\r\n expiresAt,\r\n isExpired: now >= expiresAt,\r\n needsRefresh: now >= (expiresAt - refreshWindow)\r\n };\r\n }\r\n\r\n /**\r\n * Decode JWT token payload\r\n */\r\n private decodeJwt(token: string): any {\r\n try {\r\n const parts = token.split('.');\r\n if (parts.length !== 3) {\r\n throw new Error('Invalid JWT token format');\r\n }\r\n const payload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/')));\r\n return payload;\r\n } catch (error) {\r\n console.error('Error decoding JWT token:', error);\r\n throw new Error('Invalid JWT token');\r\n }\r\n }\r\n\r\n /**\r\n * Extract user information from JWT token\r\n */\r\n private extractUserFromToken(token: string): MedHassoUser {\r\n const payload = this.decodeJwt(token);\r\n return {\r\n upn: payload.upn || payload.email,\r\n name: payload.name,\r\n roles: payload.roles || [],\r\n ...payload\r\n };\r\n }\r\n\r\n /**\r\n * Set up automatic token refresh interval\r\n */\r\n private setTokenRefreshInterval(tokenInfo: TokenInfo): void {\r\n this.clearTokenRefreshInterval();\r\n\r\n if (!this.autoRefresh || tokenInfo.isExpired) {\r\n return;\r\n }\r\n\r\n const remainingTime = tokenInfo.expiresAt - Date.now();\r\n const refreshTime = remainingTime - (this.refreshBeforeExpiryMinutes * 60 * 1000);\r\n\r\n if (refreshTime > 0) {\r\n this.refreshTokenInterval = timer(refreshTime).subscribe(() => {\r\n this.refreshToken().subscribe();\r\n });\r\n } else {\r\n // Token needs immediate refresh\r\n this.refreshToken().subscribe();\r\n }\r\n }\r\n\r\n /**\r\n * Clear token refresh interval\r\n */\r\n private clearTokenRefreshInterval(): void {\r\n if (this.refreshTokenInterval) {\r\n this.refreshTokenInterval.unsubscribe();\r\n this.refreshTokenInterval = null;\r\n }\r\n }\r\n\r\n /**\r\n * Get current token information\r\n */\r\n getTokenInfo(): TokenInfo | null {\r\n return this.tokenSubject.value;\r\n }\r\n\r\n /**\r\n * Get current user information\r\n */\r\n getCurrentUser(): MedHassoUser | null {\r\n return this.userSubject.value;\r\n }\r\n\r\n /**\r\n * Check if user is authenticated\r\n */\r\n isAuthenticated(): boolean {\r\n const tokenInfo = this.getTokenInfo();\r\n return tokenInfo !== null && !tokenInfo.isExpired;\r\n }\r\n\r\n /**\r\n * Check if user has specific role\r\n */\r\n hasRole(role: string): boolean {\r\n const user = this.getCurrentUser();\r\n return user?.roles?.includes(role) || false;\r\n }\r\n\r\n /**\r\n * Check if user is admin\r\n */\r\n isAdmin(): boolean {\r\n return this.hasRole('admin') || this.hasRole('administrator');\r\n }\r\n\r\n /**\r\n * Set tokens (typically called after successful authentication)\r\n */\r\n setTokens(idToken: string, refreshToken?: string): void {\r\n this.storeTokens(idToken, refreshToken);\r\n const tokenInfo = this.createTokenInfo(idToken);\r\n const user = this.extractUserFromToken(idToken);\r\n\r\n this.tokenSubject.next(tokenInfo);\r\n this.userSubject.next(user);\r\n\r\n if (this.autoRefresh) {\r\n this.setTokenRefreshInterval(tokenInfo);\r\n }\r\n }\r\n\r\n /**\r\n * Refresh the current token.\r\n * Concurrent callers (auto-refresh timer, wake detection, interceptor,\r\n * route guard) share the same in-flight request instead of each firing\r\n * their own POST to the refresh endpoint.\r\n */\r\n refreshToken(): Observable<any> {\r\n if (this.refreshInProgress$) {\r\n return this.refreshInProgress$;\r\n }\r\n\r\n const refreshToken = this.getStoredRefreshToken();\r\n\r\n if (!refreshToken) {\r\n return throwError(() => new Error('No refresh token available'));\r\n }\r\n\r\n const request$ = this.http.post(`${this.config.refreshUrl}/api/refresh-token`, { refreshToken })\r\n .pipe(\r\n tap((response: any) => {\r\n if (response.id_token) {\r\n this.setTokens(response.id_token, response.refresh_token);\r\n }\r\n }),\r\n catchError(error => {\r\n console.error('Token refresh failed:', error);\r\n this.logout();\r\n return throwError(() => error);\r\n }),\r\n finalize(() => {\r\n this.refreshInProgress$ = null;\r\n }),\r\n shareReplay({ bufferSize: 1, refCount: false })\r\n );\r\n\r\n this.refreshInProgress$ = request$;\r\n return request$;\r\n }\r\n\r\n /**\r\n * Ensure the current token is valid, refreshing it first if it is\r\n * expired. Resolves `false` if there is no token at all, or the token\r\n * is expired and refreshing it failed (in both cases the caller should\r\n * redirect to SSO).\r\n *\r\n * A token that merely `needsRefresh` (inside the refresh window, but\r\n * not yet expired) is still good enough to use: the refresh for it is\r\n * kicked off in the background so the *current* request/route isn't\r\n * blocked or logged out by a transient refresh failure (network blip,\r\n * refresh endpoint hiccup) while the existing token would have worked\r\n * fine. Only an actually-expired token blocks the caller.\r\n *\r\n * Re-syncs from storage first: the in-memory token snapshot is only\r\n * updated via setTokens()/logout(), so if something wrote directly to\r\n * storage (e.g. the SSO callback flow) without going through this\r\n * service, the in-memory copy would otherwise be stale until the next\r\n * full page load re-runs initializeFromStorage().\r\n *\r\n * Anonymous/bootstrap endpoints that must be reachable before any token\r\n * exists (e.g. the SSO callback's own token-exchange request) should be\r\n * added to `interceptorConfig.excludeUrls` so they bypass this check\r\n * entirely, rather than relying on this method to let them through.\r\n */\r\n ensureValidToken(): Observable<boolean> {\r\n this.syncFromStorage();\r\n const tokenInfo = this.getTokenInfo();\r\n\r\n if (!tokenInfo) {\r\n return of(false);\r\n }\r\n\r\n if (tokenInfo.isExpired) {\r\n return this.refreshToken().pipe(\r\n map(() => true),\r\n catchError(() => of(false))\r\n );\r\n }\r\n\r\n if (tokenInfo.needsRefresh) {\r\n this.refreshToken().subscribe({ error: () => {} });\r\n }\r\n\r\n return of(true);\r\n }\r\n\r\n /**\r\n * Logout user and clear all tokens\r\n */\r\n logout(): void {\r\n this.clearTokenRefreshInterval();\r\n this.clearStoredTokens();\r\n this.tokenSubject.next(null);\r\n this.userSubject.next(null);\r\n }\r\n\r\n /**\r\n * Redirect to MedHasso SSO for authentication\r\n */\r\n redirectToSSO(returnUrl?: string): void {\r\n const currentUrl = returnUrl || window.location.href;\r\n const ssoUrl = `${this.config.ssoUrl}?url=${encodeURIComponent(currentUrl)}&applicationName=${encodeURIComponent(this.config.applicationName)}`;\r\n window.location.href = ssoUrl;\r\n }\r\n\r\n /**\r\n * Handle authentication callback (typically from SSO redirect)\r\n */\r\n handleAuthCallback(params: { idToken?: string; refreshToken?: string }): boolean {\r\n if (params.idToken) {\r\n this.setTokens(params.idToken, params.refreshToken);\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Get authorization header value\r\n */\r\n getAuthorizationHeader(): string | null {\r\n const tokenInfo = this.getTokenInfo();\r\n if (tokenInfo && !tokenInfo.isExpired) {\r\n const prefix = this.config.interceptorConfig?.authHeaderPrefix || 'Bearer';\r\n return `${prefix} ${tokenInfo.token}`;\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Cleanup on service destruction\r\n */\r\n ngOnDestroy(): void {\r\n this.clearTokenRefreshInterval();\r\n this.teardownWakeDetection();\r\n }\r\n}\r\n","import { Injectable, Inject } from '@angular/core';\r\nimport { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';\r\nimport { Observable, throwError } from 'rxjs';\r\nimport { catchError, switchMap } from 'rxjs/operators';\r\nimport { MedHassoConfig } from '../interfaces/medhasso-config.interface';\r\nimport { MEDHASSO_CONFIG } from '../tokens/medhasso-config.token';\r\nimport { TokenManagementService } from '../services/token-management.service';\r\n\r\n@Injectable()\r\nexport class MedHassoAuthInterceptor implements HttpInterceptor {\r\n\r\n constructor(\r\n @Inject(MEDHASSO_CONFIG) private config: MedHassoConfig,\r\n private tokenService: TokenManagementService\r\n ) {}\r\n\r\n intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\r\n // Check if interceptor is enabled\r\n if (this.config.interceptorConfig?.enabled === false) {\r\n return next.handle(request);\r\n }\r\n\r\n // Check if request should be excluded\r\n if (this.shouldExcludeRequest(request)) {\r\n return next.handle(request);\r\n }\r\n\r\n // Check if request should be included (if includeUrls is specified)\r\n if (!this.shouldIncludeRequest(request)) {\r\n return next.handle(request);\r\n }\r\n\r\n // Proactively ensure the token is valid (refreshing first if it's\r\n // expired or within the refresh window) before attaching the header.\r\n // This avoids sending a guaranteed-401 request after the app has been\r\n // idle/suspended long enough for the in-memory refresh timer to miss it.\r\n return this.tokenService.ensureValidToken().pipe(\r\n switchMap(valid => {\r\n if (!valid) {\r\n this.redirectToSSO();\r\n return throwError(() => new Error('Authentication required'));\r\n }\r\n\r\n const modifiedRequest = this.addAuthorizationHeader(request);\r\n\r\n return next.handle(modifiedRequest).pipe(\r\n catchError((error: HttpErrorResponse) => {\r\n // Handle 401 Unauthorized errors\r\n if (error.status === 401) {\r\n return this.handle401Error(request, next);\r\n }\r\n\r\n // Handle 403 Forbidden errors\r\n if (error.status === 403) {\r\n console.warn('MedHasso Auth: Access forbidden (403)', error);\r\n }\r\n\r\n return throwError(() => error);\r\n })\r\n );\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Check if request URL should be excluded from authentication\r\n */\r\n private shouldExcludeRequest(request: HttpRequest<any>): boolean {\r\n const excludeUrls = this.config.interceptorConfig?.excludeUrls || [];\r\n return excludeUrls.some(url => this.matchesUrl(request.url, url));\r\n }\r\n\r\n /**\r\n * Check if request URL should be included for authentication\r\n * If includeUrls is not specified, all requests are included (unless excluded)\r\n */\r\n private shouldIncludeRequest(request: HttpRequest<any>): boolean {\r\n const includeUrls = this.config.interceptorConfig?.includeUrls;\r\n \r\n // If no includeUrls specified, include all requests\r\n if (!includeUrls || includeUrls.length === 0) {\r\n return true;\r\n }\r\n\r\n // If includeUrls specified, only include matching requests\r\n return includeUrls.some(url => this.matchesUrl(request.url, url));\r\n }\r\n\r\n /**\r\n * Check if request URL matches the pattern\r\n */\r\n private matchesUrl(requestUrl: string, pattern: string): boolean {\r\n // Support wildcards and exact matches\r\n if (pattern.includes('*')) {\r\n const regex = new RegExp(pattern.replace(/\\*/g, '.*'));\r\n return regex.test(requestUrl);\r\n }\r\n \r\n return requestUrl.includes(pattern);\r\n }\r\n\r\n /**\r\n * Add authorization header to request\r\n */\r\n private addAuthorizationHeader(request: HttpRequest<any>): HttpRequest<any> {\r\n const authHeader = this.tokenService.getAuthorizationHeader();\r\n \r\n if (!authHeader) {\r\n return request;\r\n }\r\n\r\n return request.clone({\r\n setHeaders: {\r\n Authorization: authHeader\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Handle 401 Unauthorized errors by attempting token refresh\r\n */\r\n private handle401Error(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\r\n const tokenInfo = this.tokenService.getTokenInfo();\r\n \r\n // If no token or token is expired, redirect to SSO\r\n if (!tokenInfo || tokenInfo.isExpired) {\r\n this.redirectToSSO();\r\n return throwError(() => new Error('Authentication required'));\r\n }\r\n\r\n // If token exists but request failed, try to refresh\r\n return this.tokenService.refreshToken().pipe(\r\n switchMap(() => {\r\n // Retry the original request with new token\r\n const retryRequest = this.addAuthorizationHeader(request);\r\n return next.handle(retryRequest);\r\n }),\r\n catchError((refreshError) => {\r\n // If refresh fails, redirect to SSO\r\n console.error('MedHasso Auth: Token refresh failed', refreshError);\r\n this.redirectToSSO();\r\n return throwError(() => refreshError);\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Redirect to SSO for authentication\r\n */\r\n private redirectToSSO(): void {\r\n // Add a small delay to prevent multiple redirects\r\n setTimeout(() => {\r\n this.tokenService.redirectToSSO();\r\n }, 100);\r\n }\r\n}","import { Injectable, Inject } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { Observable, of } from 'rxjs';\r\nimport { map, catchError } from 'rxjs/operators';\r\nimport { MedHassoConfig, MedHassoUser } from '../interfaces/medhasso-config.interface';\r\nimport { MEDHASSO_CONFIG } from '../tokens/medhasso-config.token';\r\nimport { TokenManagementService } from './token-management.service';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class MedHassoAuthService {\r\n\r\n constructor(\r\n @Inject(MEDHASSO_CONFIG) private config: MedHassoConfig,\r\n private tokenService: TokenManagementService,\r\n private http: HttpClient\r\n ) {}\r\n\r\n /**\r\n * Get current authentication status\r\n */\r\n isAuthenticated(): boolean {\r\n return this.tokenService.isAuthenticated();\r\n }\r\n\r\n /**\r\n * Get current user information\r\n */\r\n getCurrentUser(): MedHassoUser | null {\r\n return this.tokenService.getCurrentUser();\r\n }\r\n\r\n /**\r\n * Get current user as observable\r\n */\r\n getCurrentUser$(): Observable<MedHassoUser | null> {\r\n return this.tokenService.user$;\r\n }\r\n\r\n /**\r\n * Check if user has specific role\r\n */\r\n hasRole(role: string): boolean {\r\n return this.tokenService.hasRole(role);\r\n }\r\n\r\n /**\r\n * Check if user has any of the specified roles\r\n */\r\n hasAnyRole(roles: string[]): boolean {\r\n return roles.some(role => this.tokenService.hasRole(role));\r\n }\r\n\r\n /**\r\n * Check if user has all of the specified roles\r\n */\r\n hasAllRoles(roles: string[]): boolean {\r\n return roles.every(role => this.tokenService.hasRole(role));\r\n }\r\n\r\n /**\r\n * Check if user is admin\r\n */\r\n isAdmin(): boolean {\r\n return this.tokenService.isAdmin();\r\n }\r\n\r\n /**\r\n * Login user (redirect to SSO)\r\n */\r\n login(returnUrl?: string): void {\r\n this.tokenService.redirectToSSO(returnUrl);\r\n }\r\n\r\n /**\r\n * Logout user\r\n */\r\n logout(): void {\r\n this.tokenService.logout();\r\n }\r\n\r\n /**\r\n * Refresh authentication token\r\n */\r\n refreshToken(): Observable<any> {\r\n return this.tokenService.refreshToken();\r\n }\r\n\r\n /**\r\n * Check access permissions for a simple key (if applicable)\r\n */\r\n checkAccess(simpleKey: string, backendUrl?: string): Observable<any> {\r\n const url = backendUrl || this.getBackendUrl();\r\n if (!url) {\r\n return of(null);\r\n }\r\n\r\n return this.http.get(`${url}/auth/guard?simple_key=${simpleKey}`)\r\n .pipe(\r\n catchError(error => {\r\n console.error('Access check failed:', error);\r\n return of(null);\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Check if user is admin via backend API (if applicable)\r\n */\r\n checkIsAdmin(backendUrl?: string): Observable<boolean> {\r\n const user = this.getCurrentUser();\r\n const url = backendUrl || this.getBackendUrl();\r\n \r\n if (!user?.upn || !url) {\r\n return of(false);\r\n }\r\n\r\n return this.http.get(`${url}/isAdmin?email=${user.upn}`)\r\n .pipe(\r\n map((response: any) => !!response),\r\n catchError(() => of(false))\r\n );\r\n }\r\n\r\n /**\r\n * Get backend URL from config (helper method)\r\n */\r\n private getBackendUrl(): string | null {\r\n // This would need to be configured or passed in\r\n // For now, return null as it's application-specific\r\n return null;\r\n }\r\n\r\n /**\r\n * Get token information\r\n */\r\n getTokenInfo() {\r\n return this.tokenService.getTokenInfo();\r\n }\r\n\r\n /**\r\n * Get token as observable\r\n */\r\n getToken$() {\r\n return this.tokenService.token$;\r\n }\r\n\r\n /**\r\n * Handle authentication callback\r\n */\r\n handleAuthCallback(params: { idToken?: string; refreshToken?: string }): boolean {\r\n return this.tokenService.handleAuthCallback(params);\r\n }\r\n\r\n /**\r\n * Get user email\r\n */\r\n getUserEmail(): string | null {\r\n return this.getCurrentUser()?.upn || null;\r\n }\r\n\r\n /**\r\n * Get user display name\r\n */\r\n getUserDisplayName(): string | null {\r\n return this.getCurrentUser()?.name || null;\r\n }\r\n\r\n /**\r\n * Get all user roles\r\n */\r\n getUserRoles(): string[] {\r\n return this.getCurrentUser()?.roles || [];\r\n }\r\n\r\n /**\r\n * Get authorization header value\r\n */\r\n getAuthorizationHeader(): string | null {\r\n return this.tokenService.getAuthorizationHeader();\r\n }\r\n}","import { NgModule, ModuleWithProviders, Provider } from '@angular/core';\r\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\r\nimport { MedHassoConfig } from './interfaces/medhasso-config.interface';\r\nimport { MEDHASSO_CONFIG } from './tokens/medhasso-config.token';\r\nimport { MedHassoAuthInterceptor } from './interceptors/medhasso-auth.interceptor';\r\nimport { TokenManagementService } from './services/token-management.service';\r\nimport { MedHassoAuthService } from './services/medhasso-auth.service';\r\n\r\n@NgModule({\r\n declarations: [],\r\n imports: [],\r\n exports: []\r\n})\r\nexport class MedHassoAuthModule {\r\n \r\n /**\r\n * Configure the MedHasso authentication module with required settings\r\n */\r\n static forRoot(config: MedHassoConfig): ModuleWithProviders<MedHassoAuthModule> {\r\n return {\r\n ngModule: MedHassoAuthModule,\r\n providers: [\r\n {\r\n provide: MEDHASSO_CONFIG,\r\n useValue: this.mergeWithDefaults(config)\r\n },\r\n TokenManagementService,\r\n MedHassoAuthService,\r\n {\r\n provide: HTTP_INTERCEPTORS,\r\n useClass: MedHassoAuthInterceptor,\r\n multi: true\r\n }\r\n ]\r\n };\r\n }\r\n\r\n /**\r\n * Configure the MedHasso authentication module for feature modules\r\n */\r\n static forChild(): ModuleWithProviders<MedHassoAuthModule> {\r\n return {\r\n ngModule: MedHassoAuthModule,\r\n providers: []\r\n };\r\n }\r\n\r\n /**\r\n * Provide MedHasso authentication with standalone components\r\n */\r\n static forStandalone(config: MedHassoConfig): Provider[] {\r\n return [\r\n {\r\n provide: MEDHASSO_CONFIG,\r\n useValue: this.mergeWithDefaults(config)\r\n },\r\n TokenManagementService,\r\n MedHassoAuthService,\r\n {\r\n provide: HTTP_INTERCEPTORS,\r\n useClass: MedHassoAuthInterceptor,\r\n multi: true\r\n }\r\n ];\r\n }\r\n\r\n /**\r\n * Merge user configuration with sensible defaults\r\n */\r\n private static mergeWithDefaults(config: MedHassoConfig): MedHassoConfig {\r\n const defaultConfig: Partial<MedHassoConfig> = {\r\n tokenConfig: {\r\n storageType: 'localStorage',\r\n idTokenKey: 'idToken',\r\n refreshTokenKey: 'refreshToken',\r\n refreshBeforeExpiryMinutes: 5,\r\n autoRefresh: true,\r\n ...config.tokenConfig\r\n },\r\n interceptorConfig: {\r\n enabled: true,\r\n authHeaderPrefix: 'Bearer',\r\n excludeUrls: [],\r\n includeUrls: [],\r\n ...config.interceptorConfig\r\n },\r\n securityConfig: {\r\n httpsOnly: true,\r\n secureCookies: true,\r\n additionalCspSources: [],\r\n ...config.securityConfig\r\n }\r\n };\r\n\r\n return {\r\n ...config,\r\n ...defaultConfig,\r\n tokenConfig: {\r\n ...defaultConfig.tokenConfig,\r\n ...config.tokenConfig\r\n },\r\n interceptorConfig: {\r\n ...defaultConfig.interceptorConfig,\r\n ...config.interceptorConfig\r\n },\r\n securityConfig: {\r\n ...defaultConfig.securityConfig,\r\n ...config.securityConfig\r\n }\r\n };\r\n }\r\n}","import { Injectable } from '@angular/core';\r\nimport { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, UrlTree } from '@angular/router';\r\nimport { Observable, of } from 'rxjs';\r\nimport { map, catchError } from 'rxjs/operators';\r\nimport { TokenManagementService } from '../services/token-management.service';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class MedHassoAuthGuard implements CanActivate, CanActivateChild {\r\n\r\n constructor(\r\n private tokenService: TokenManagementService,\r\n private router: Router\r\n ) {}\r\n\r\n canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\r\n return this.checkAuthentication(route);\r\n }\r\n\r\n canActivateChild(childRoute: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\r\n return this.checkAuthentication(childRoute);\r\n }\r\n\r\n private checkAuthentication(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> {\r\n // Check for authentication callback parameters\r\n if (this.handleAuthCallback(route)) {\r\n return of(true);\r\n }\r\n\r\n // Re-syncs from storage and refreshes a stale/expired token before\r\n // deciding, so this guard shares the same de-duplicated refresh and\r\n // storage-drift handling as the HTTP interceptor.\r\n return this.tokenService.ensureValidToken().pipe(\r\n map(valid => {\r\n if (!valid) {\r\n this.tokenService.redirectToSSO();\r\n return false;\r\n }\r\n return true;\r\n }),\r\n catchError(() => {\r\n this.tokenService.redirectToSSO();\r\n return of(false);\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Handle authentication callback from MedHasso SSO\r\n */\r\n private handleAuthCallback(route: ActivatedRouteSnapshot): boolean {\r\n const queryParams = route.queryParams;\r\n \r\n // Check for AIRO redirect flow\r\n if (queryParams['redirectapp'] === 'airo' && queryParams['idToken']) {\r\n return this.tokenService.handleAuthCallback({\r\n idToken: queryParams['idToken'],\r\n refreshToken: queryParams['refreshToken']\r\n });\r\n }\r\n\r\n // Check for standard authentication callback\r\n if (queryParams['idToken'] || queryParams['token']) {\r\n return this.tokenService.handleAuthCallback({\r\n idToken: queryParams['idToken'] || queryParams['token'],\r\n refreshToken: queryParams['refreshToken']\r\n });\r\n }\r\n\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Role-based authentication guard\r\n */\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class MedHassoRoleGuard implements CanActivate, CanActivateChild {\r\n\r\n constructor(\r\n private tokenService: TokenManagementService,\r\n private router: Router\r\n ) {}\r\n\r\n canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\r\n return this.checkRole(route);\r\n }\r\n\r\n canActivateChild(childRoute: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\r\n return this.checkRole(childRoute);\r\n }\r\n\r\n private checkRole(route: ActivatedRouteSnapshot): boolean | UrlTree {\r\n const requiredRoles = route.data['roles'] as string[];\r\n const requiredRole = route.data['role'] as string;\r\n\r\n if (!this.tokenService.isAuthenticated()) {\r\n this.tokenService.redirectToSSO();\r\n return false;\r\n }\r\n\r\n // Check multiple roles (OR condition)\r\n if (requiredRoles && requiredRoles.length > 0) {\r\n const hasAnyRole = requiredRoles.some(role => this.tokenService.hasRole(role));\r\n if (!hasAnyRole) {\r\n return this.router.createUrlTree(['/unauthorized']);\r\n }\r\n }\r\n\r\n // Check single role\r\n if (requiredRole && !this.tokenService.hasRole(requiredRole)) {\r\n return this.router.createUrlTree(['/unauthorized']);\r\n }\r\n\r\n return true;\r\n }\r\n}\r\n\r\n/**\r\n * Admin-only authentication guard\r\n */\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class MedHassoAdminGuard implements CanActivate, CanActivateChild {\r\n\r\n constructor(\r\n private tokenService: TokenManagementService,\r\n private router: Router\r\n ) {}\r\n\r\n canActivate(): boolean | UrlTree {\r\n return this.checkAdmin();\r\n }\r\n\r\n canActivateChild(): boolean | UrlTree {\r\n return this.checkAdmin();\r\n }\r\n\r\n private checkAdmin(): boolean | UrlTree {\r\n if (!this.tokenService.isAuthenticated()) {\r\n this.tokenService.redirectToSSO();\r\n return false;\r\n }\r\n\r\n if (!this.tokenService.isAdmin()) {\r\n return this.router.createUrlTree(['/unauthorized']);\r\n }\r\n\r\n return true;\r\n }\r\n}","/*\r\n * Public API Surface of medhasso-auth\r\n */\r\n\r\n// Module\r\nexport * from './lib/medhasso-auth.module';\r\n\r\n// Services\r\nexport * from './lib/services/token-management.service';\r\nexport * from './lib/services/medhasso-auth.service';\r\n\r\n// Guards\r\nexport * from './lib/guards/medhasso-auth.guard';\r\n\r\n// Interceptors\r\nexport * from './lib/interceptors/medhasso-auth.interceptor';\r\n\r\n// Interfaces\r\nexport * from './lib/interfaces/medhasso-config.interface';\r\n\r\n// Tokens\r\nexport * from './lib/tokens/medhasso-config.token';","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.TokenManagementService","i2"],"mappings":";;;;;;;;MAGa,eAAe,GAAG,IAAI,cAAc,CAAiB,iBAAiB;;MCOtE,sBAAsB,CAAA;AAiBjC,IAAA,IAAY,WAAW,GAAA;AACrB,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE;;AAGtC,IAAA,IAAY,WAAW,GAAA;AACrB,QAAA,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,IAAI,cAAc;;AAGvD,IAAA,IAAY,UAAU,GAAA;AACpB,QAAA,OAAO,IAAI,CAAC,WAAW,CAAC,UAAU,IAAI,SAAS;;AAGjD,IAAA,IAAY,eAAe,GAAA;AACzB,QAAA,OAAO,IAAI,CAAC,WAAW,CAAC,eAAe,IAAI,cAAc;;AAG3D,IAAA,IAAY,0BAA0B,GAAA;AACpC,QAAA,OAAO,IAAI,CAAC,WAAW,CAAC,0BAA0B,IAAI,CAAC;;AAGzD,IAAA,IAAY,WAAW,GAAA;AACrB,QAAA,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,KAAK,KAAK;;IAG/C,WACmC,CAAA,MAAsB,EAC/C,IAAgB,EAAA;QADS,IAAM,CAAA,MAAA,GAAN,MAAM;QAC/B,IAAI,CAAA,IAAA,GAAJ,IAAI;QAzCN,IAAkB,CAAA,kBAAA,GAA2B,IAAI;AACjD,QAAA,IAAA,CAAA,YAAY,GAAG,IAAI,eAAe,CAAmB,IAAI,CAAC;AAC1D,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,eAAe,CAAsB,IAAI,CAAC;QACnD,IAAkB,CAAA,kBAAA,GAAG,MAAK;AACzC,YAAA,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS,EAAE;AAC1C,gBAAA,IAAI,CAAC,gBAAgB,EAAE,CAAC,SAAS,EAAE;;AAEvC,SAAC;QACgB,IAAa,CAAA,aAAA,GAAG,MAAK;AACpC,YAAA,IAAI,CAAC,gBAAgB,EAAE,CAAC,SAAS,EAAE;AACrC,SAAC;AAEM,QAAA,IAAA,CAAA,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE;AACzC,QAAA,IAAA,CAAA,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE;QA8B5C,IAAI,CAAC,qBAAqB,EAAE;QAC5B,IAAI,CAAC,kBAAkB,EAAE;;AAG3B;;;;;AAKG;IACK,kBAAkB,GAAA;QACxB,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;YACpE;;QAGF,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,CAAC;QACtE,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC;;AAGtD;;AAEG;IACK,qBAAqB,GAAA;QAC3B,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;YACpE;;QAGF,QAAQ,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,CAAC;QACzE,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC;;AAGzD;;AAEG;IACK,qBAAqB,GAAA;AAC3B,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE;QACnC,IAAI,KAAK,EAAE;YACT,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;AAC7C,YAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;AACjC,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;YAEvD,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE;AAC5C,gBAAA,IAAI,CAAC,uBAAuB,CAAC,SAAS,CAAC;;;;AAK7C;;;;AAIG;IACK,eAAe,GAAA;AACrB,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,EAAE;QACzC,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE,EAAE,KAAK,IAAI,IAAI;AAEvD,QAAA,IAAI,WAAW,KAAK,YAAY,EAAE;YAChC;;QAGF,IAAI,CAAC,WAAW,EAAE;AAChB,YAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;AAC5B,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;YAC3B,IAAI,CAAC,yBAAyB,EAAE;YAChC;;QAGF,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC;AACnD,QAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;AACjC,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC;QAE7D,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE;AAC5C,YAAA,IAAI,CAAC,uBAAuB,CAAC,SAAS,CAAC;;;AAI3C;;AAEG;IACK,cAAc,GAAA;AACpB,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,KAAK,cAAc,GAAG,YAAY,GAAG,cAAc;QACnF,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;;AAGzC;;AAEG;IACK,qBAAqB,GAAA;AAC3B,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,KAAK,cAAc,GAAG,YAAY,GAAG,cAAc;QACnF,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC;;AAG9C;;AAEG;IACK,WAAW,CAAC,OAAe,EAAE,YAAqB,EAAA;AACxD,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,KAAK,cAAc,GAAG,YAAY,GAAG,cAAc;QACnF,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC;QACzC,IAAI,YAAY,EAAE;YAChB,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC;;;AAIvD;;AAEG;IACK,iBAAiB,GAAA;AACvB,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,KAAK,cAAc,GAAG,YAAY,GAAG,cAAc;AACnF,QAAA,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;AACnC,QAAA,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC;;AAG1C;;AAEG;AACK,IAAA,eAAe,CAAC,KAAa,EAAA;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;QACrC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;AACrC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;QACtB,MAAM,aAAa,GAAG,IAAI,CAAC,0BAA0B,GAAG,EAAE,GAAG,IAAI;QAEjE,OAAO;YACL,KAAK;YACL,OAAO;YACP,SAAS;YACT,SAAS,EAAE,GAAG,IAAI,SAAS;AAC3B,YAAA,YAAY,EAAE,GAAG,KAAK,SAAS,GAAG,aAAa;SAChD;;AAGH;;AAEG;AACK,IAAA,SAAS,CAAC,KAAa,EAAA;AAC7B,QAAA,IAAI;YACF,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;AAC9B,YAAA,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;AACtB,gBAAA,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC;;AAE7C,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;AAChF,YAAA,OAAO,OAAO;;QACd,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC;AACjD,YAAA,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC;;;AAIxC;;AAEG;AACK,IAAA,oBAAoB,CAAC,KAAa,EAAA;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;QACrC,OAAO;AACL,YAAA,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,KAAK;YACjC,IAAI,EAAE,OAAO,CAAC,IAAI;AAClB,YAAA,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,EAAE;AAC1B,YAAA,GAAG;SACJ;;AAGH;;AAEG;AACK,IAAA,uBAAuB,CAAC,SAAoB,EAAA;QAClD,IAAI,CAAC,yBAAyB,EAAE;QAEhC,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,SAAS,CAAC,SAAS,EAAE;YAC5C;;QAGF,MAAM,aAAa,GAAG,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE;AACtD,QAAA,MAAM,WAAW,GAAG,aAAa,IAAI,IAAI,CAAC,0BAA0B,GAAG,EAAE,GAAG,IAAI,CAAC;AAEjF,QAAA,IAAI,WAAW,GAAG,CAAC,EAAE;YACnB,IAAI,CAAC,oBAAoB,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,MAAK;AAC5D,gBAAA,IAAI,CAAC,YAAY,EAAE,CAAC,SAAS,EAAE;AACjC,aAAC,CAAC;;aACG;;AAEL,YAAA,IAAI,CAAC,YAAY,EAAE,CAAC,SAAS,EAAE;;;AAInC;;AAEG;IACK,yBAAyB,GAAA;AAC/B,QAAA,IAAI,IAAI,CAAC,oBAAoB,EAAE;AAC7B,YAAA,IAAI,CAAC,oBAAoB,CAAC,WAAW,EAAE;AACvC,YAAA,IAAI,CAAC,oBAAoB,GAAG,IAAI;;;AAIpC;;AAEG;IACH,YAAY,GAAA;AACV,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK;;AAGhC;;AAEG;IACH,cAAc,GAAA;AACZ,QAAA,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK;;AAG/B;;AAEG;IACH,eAAe,GAAA;AACb,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE;QACrC,OAAO,SAAS,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS;;AAGnD;;AAEG;AACH,IAAA,OAAO,CAAC,IAAY,EAAA;AAClB,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE;QAClC,OAAO,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK;;AAG7C;;AAEG;IACH,OAAO,GAAA;AACL,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC;;AAG/D;;AAEG;IACH,SAAS,CAAC,OAAe,EAAE,YAAqB,EAAA;AAC9C,QAAA,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC;QACvC,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC;AAE/C,QAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;AACjC,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;AAE3B,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE;AACpB,YAAA,IAAI,CAAC,uBAAuB,CAAC,SAAS,CAAC;;;AAI3C;;;;;AAKG;IACH,YAAY,GAAA;AACV,QAAA,IAAI,IAAI,CAAC,kBAAkB,EAAE;YAC3B,OAAO,IAAI,CAAC,kBAAkB;;AAGhC,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,qBAAqB,EAAE;QAEjD,IAAI,CAAC,YAAY,EAAE;YACjB,OAAO,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;;AAGlE,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,EAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAA,kBAAA,CAAoB,EAAE,EAAE,YAAY,EAAE;AAC5F,aAAA,IAAI,CACH,GAAG,CAAC,CAAC,QAAa,KAAI;AACpB,YAAA,IAAI,QAAQ,CAAC,QAAQ,EAAE;gBACrB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC;;AAE7D,SAAC,CAAC,EACF,UAAU,CAAC,KAAK,IAAG;AACjB,YAAA,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC;YAC7C,IAAI,CAAC,MAAM,EAAE;AACb,YAAA,OAAO,UAAU,CAAC,MAAM,KAAK,CAAC;AAChC,SAAC,CAAC,EACF,QAAQ,CAAC,MAAK;AACZ,YAAA,IAAI,CAAC,kBAAkB,GAAG,IAAI;AAChC,SAAC,CAAC,EACF,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAChD;AAEH,QAAA,IAAI,CAAC,kBAAkB,GAAG,QAAQ;AAClC,QAAA,OAAO,QAAQ;;AAGjB;;;;;;;;;;;;;;;;;;;;;;;AAuBG;IACH,gBAAgB,GAAA;QACd,IAAI,CAAC,eAAe,EAAE;AACtB,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE;QAErC,IAAI,CAAC,SAAS,EAAE;AACd,YAAA,OAAO,EAAE,CAAC,KAAK,CAAC;;AAGlB,QAAA,IAAI,SAAS,CAAC,SAAS,EAAE;YACvB,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,CAC7B,GAAG,CAAC,MAAM,IAAI,CAAC,EACf,UAAU,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,CAC5B;;AAGH,QAAA,IAAI,SAAS,CAAC,YAAY,EAAE;AAC1B,YAAA,IAAI,CAAC,YAAY,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAK,GAAG,EAAE,CAAC;;AAGpD,QAAA,OAAO,EAAE,CAAC,IAAI,CAAC;;AAGjB;;AAEG;IACH,MAAM,GAAA;QACJ,IAAI,CAAC,yBAAyB,EAAE;QAChC,IAAI,CAAC,iBAAiB,EAAE;AACxB,QAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;AAC5B,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;;AAG7B;;AAEG;AACH,IAAA,aAAa,CAAC,SAAkB,EAAA;QAC9B,MAAM,UAAU,GAAG,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI;QACpD,MAAM,MAAM,GAAG,CAAG,EAAA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAA,KAAA,EAAQ,kBAAkB,CAAC,UAAU,CAAC,CAAA,iBAAA,EAAoB,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAA,CAAE;AAC/I,QAAA,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,MAAM;;AAG/B;;AAEG;AACH,IAAA,kBAAkB,CAAC,MAAmD,EAAA;AACpE,QAAA,IAAI,MAAM,CAAC,OAAO,EAAE;YAClB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC;AACnD,YAAA,OAAO,IAAI;;AAEb,QAAA,OAAO,KAAK;;AAGd;;AAEG;IACH,sBAAsB,GAAA;AACpB,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE;AACrC,QAAA,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE;YACrC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,gBAAgB,IAAI,QAAQ;AAC1E,YAAA,OAAO,GAAG,MAAM,CAAA,CAAA,EAAI,SAAS,CAAC,KAAK,EAAE;;AAEvC,QAAA,OAAO,IAAI;;AAGb;;AAEG;IACH,WAAW,GAAA;QACT,IAAI,CAAC,yBAAyB,EAAE;QAChC,IAAI,CAAC,qBAAqB,EAAE;;AAvanB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,kBA0CvB,eAAe,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,UAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AA1Cd,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,cAFrB,MAAM,EAAA,CAAA,CAAA;;4FAEP,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBAHlC,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE;AACb,iBAAA;;0BA2CI,MAAM;2BAAC,eAAe;;;MC3Cd,uBAAuB,CAAA;IAElC,WACmC,CAAA,MAAsB,EAC/C,YAAoC,EAAA;QADX,IAAM,CAAA,MAAA,GAAN,MAAM;QAC/B,IAAY,CAAA,YAAA,GAAZ,YAAY;;IAGtB,SAAS,CAAC,OAAyB,EAAE,IAAiB,EAAA;;QAEpD,IAAI,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,OAAO,KAAK,KAAK,EAAE;AACpD,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;;;AAI7B,QAAA,IAAI,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE;AACtC,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;;;QAI7B,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE;AACvC,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;AAO7B,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAC9C,SAAS,CAAC,KAAK,IAAG;YAChB,IAAI,CAAC,KAAK,EAAE;gBACV,IAAI,CAAC,aAAa,EAAE;gBACpB,OAAO,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;;YAG/D,MAAM,eAAe,GAAG,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC;AAE5D,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CACtC,UAAU,CAAC,CAAC,KAAwB,KAAI;;AAEtC,gBAAA,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE;oBACxB,OAAO,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC;;;AAI3C,gBAAA,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE;AACxB,oBAAA,OAAO,CAAC,IAAI,CAAC,uCAAuC,EAAE,KAAK,CAAC;;AAG9D,gBAAA,OAAO,UAAU,CAAC,MAAM,KAAK,CAAC;aAC/B,CAAC,CACH;SACF,CAAC,CACH;;AAGH;;AAEG;AACK,IAAA,oBAAoB,CAAC,OAAyB,EAAA;QACpD,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,WAAW,IAAI,EAAE;AACpE,QAAA,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;;AAGnE;;;AAGG;AACK,IAAA,oBAAoB,CAAC,OAAyB,EAAA;QACpD,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,WAAW;;QAG9D,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;AAC5C,YAAA,OAAO,IAAI;;;AAIb,QAAA,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;;AAGnE;;AAEG;IACK,UAAU,CAAC,UAAkB,EAAE,OAAe,EAAA;;AAEpD,QAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AACzB,YAAA,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACtD,YAAA,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;;AAG/B,QAAA,OAAO,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC;;AAGrC;;AAEG;AACK,IAAA,sBAAsB,CAAC,OAAyB,EAAA;QACtD,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,sBAAsB,EAAE;QAE7D,IAAI,CAAC,UAAU,EAAE;AACf,YAAA,OAAO,OAAO;;QAGhB,OAAO,OAAO,CAAC,KAAK,CAAC;AACnB,YAAA,UAAU,EAAE;AACV,gBAAA,aAAa,EAAE;AAChB;AACF,SAAA,CAAC;;AAGJ;;AAEG;IACK,cAAc,CAAC,OAAyB,EAAE,IAAiB,EAAA;QACjE,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE;;AAGlD,QAAA,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,SAAS,EAAE;YACrC,IAAI,CAAC,aAAa,EAAE;YACpB,OAAO,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;;;AAI/D,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,IAAI,CAC1C,SAAS,CAAC,MAAK;;YAEb,MAAM,YAAY,GAAG,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC;AACzD,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;AAClC,SAAC,CAAC,EACF,UAAU,CAAC,CAAC,YAAY,KAAI;;AAE1B,YAAA,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,YAAY,CAAC;YAClE,IAAI,CAAC,aAAa,EAAE;AACpB,YAAA,OAAO,UAAU,CAAC,MAAM,YAAY,CAAC;SACtC,CAAC,CACH;;AAGH;;AAEG;IACK,aAAa,GAAA;;QAEnB,UAAU,CAAC,MAAK;AACd,YAAA,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE;SAClC,EAAE,GAAG,CAAC;;AAhJE,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,uBAAuB,kBAGxB,eAAe,EAAA,EAAA,EAAA,KAAA,EAAAA,sBAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;mHAHd,uBAAuB,EAAA,CAAA,CAAA;;4FAAvB,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBADnC;;0BAII,MAAM;2BAAC,eAAe;;;MCDd,mBAAmB,CAAA;AAE9B,IAAA,WAAA,CACmC,MAAsB,EAC/C,YAAoC,EACpC,IAAgB,EAAA;QAFS,IAAM,CAAA,MAAA,GAAN,MAAM;QAC/B,IAAY,CAAA,YAAA,GAAZ,YAAY;QACZ,IAAI,CAAA,IAAA,GAAJ,IAAI;;AAGd;;AAEG;IACH,eAAe,GAAA;AACb,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE;;AAG5C;;AAEG;IACH,cAAc,GAAA;AACZ,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE;;AAG3C;;AAEG;IACH,eAAe,GAAA;AACb,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK;;AAGhC;;AAEG;AACH,IAAA,OAAO,CAAC,IAAY,EAAA;QAClB,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC;;AAGxC;;AAEG;AACH,IAAA,UAAU,CAAC,KAAe,EAAA;AACxB,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;;AAG5D;;AAEG;AACH,IAAA,WAAW,CAAC,KAAe,EAAA;AACzB,QAAA,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;;AAG7D;;AAEG;IACH,OAAO,GAAA;AACL,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE;;AAGpC;;AAEG;AACH,IAAA,KAAK,CAAC,SAAkB,EAAA;AACtB,QAAA,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,SAAS,CAAC;;AAG5C;;AAEG;IACH,MAAM,GAAA;AACJ,QAAA,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE;;AAG5B;;AAEG;IACH,YAAY,GAAA;AACV,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE;;AAGzC;;AAEG;IACH,WAAW,CAAC,SAAiB,EAAE,UAAmB,EAAA;QAChD,MAAM,GAAG,GAAG,UAAU,IAAI,IAAI,CAAC,aAAa,EAAE;QAC9C,IAAI,CAAC,GAAG,EAAE;AACR,YAAA,OAAO,EAAE,CAAC,IAAI,CAAC;;QAGjB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA,EAAG,GAAG,CAAA,uBAAA,EAA0B,SAAS,CAAA,CAAE;AAC7D,aAAA,IAAI,CACH,UAAU,CAAC,KAAK,IAAG;AACjB,YAAA,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC;AAC5C,YAAA,OAAO,EAAE,CAAC,IAAI,CAAC;SAChB,CAAC,CACH;;AAGL;;AAEG;AACH,IAAA,YAAY,CAAC,UAAmB,EAAA;AAC9B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE;QAClC,MAAM,GAAG,GAAG,UAAU,IAAI,IAAI,CAAC,aAAa,EAAE;QAE9C,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE;AACtB,YAAA,OAAO,EAAE,CAAC,KAAK,CAAC;;AAGlB,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAG,EAAA,GAAG,CAAkB,eAAA,EAAA,IAAI,CAAC,GAAG,EAAE;aACpD,IAAI,CACH,GAAG,CAAC,CAAC,QAAa,KAAK,CAAC,CAAC,QAAQ,CAAC,EAClC,UAAU,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,CAC5B;;AAGL;;AAEG;IACK,aAAa,GAAA;;;AAGnB,QAAA,OAAO,IAAI;;AAGb;;AAEG;IACH,YAAY,GAAA;AACV,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE;;AAGzC;;AAEG;IACH,SAAS,GAAA;AACP,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM;;AAGjC;;AAEG;AACH,IAAA,kBAAkB,CAAC,MAAmD,EAAA;QACpE,OAAO,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC,MAAM,CAAC;;AAGrD;;AAEG;IACH,YAAY,GAAA;QACV,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,GAAG,IAAI,IAAI;;AAG3C;;AAEG;IACH,kBAAkB,GAAA;QAChB,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,IAAI,IAAI;;AAG5C;;AAEG;IACH,YAAY,GAAA;QACV,OAAO,IAAI,CAAC,cAAc,EAAE,EAAE,KAAK,IAAI,EAAE;;AAG3C;;AAEG;IACH,sBAAsB,GAAA;AACpB,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,sBAAsB,EAAE;;AAzKxC,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,mBAAmB,kBAGpB,eAAe,EAAA,EAAA,EAAA,KAAA,EAAAA,sBAAA,EAAA,EAAA,EAAA,KAAA,EAAAC,EAAA,CAAA,UAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAHd,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,mBAAmB,cAFlB,MAAM,EAAA,CAAA,CAAA;;4FAEP,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAH/B,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE;AACb,iBAAA;;0BAII,MAAM;2BAAC,eAAe;;;MCDd,kBAAkB,CAAA;AAE7B;;AAEG;IACH,OAAO,OAAO,CAAC,MAAsB,EAAA;QACnC,OAAO;AACL,YAAA,QAAQ,EAAE,kBAAkB;AAC5B,YAAA,SAAS,EAAE;AACT,gBAAA;AACE,oBAAA,OAAO,EAAE,eAAe;AACxB,oBAAA,QAAQ,EAAE,IAAI,CAAC,iBAAiB,CAAC,MAAM;AACxC,iBAAA;gBACD,sBAAsB;gBACtB,mBAAmB;AACnB,gBAAA;AACE,oBAAA,OAAO,EAAE,iBAAiB;AAC1B,oBAAA,QAAQ,EAAE,uBAAuB;AACjC,oBAAA,KAAK,EAAE;AACR;AACF;SACF;;AAGH;;AAEG;AACH,IAAA,OAAO,QAAQ,GAAA;QACb,OAAO;AACL,YAAA,QAAQ,EAAE,kBAAkB;AAC5B,YAAA,SAAS,EAAE;SACZ;;AAGH;;AAEG;IACH,OAAO,aAAa,CAAC,MAAsB,EAAA;QACzC,OAAO;AACL,YAAA;AACE,gBAAA,OAAO,EAAE,eAAe;AACxB,gBAAA,QAAQ,EAAE,IAAI,CAAC,iBAAiB,CAAC,MAAM;AACxC,aAAA;YACD,sBAAsB;YACtB,mBAAmB;AACnB,YAAA;AACE,gBAAA,OAAO,EAAE,iBAAiB;AAC1B,gBAAA,QAAQ,EAAE,uBAAuB;AACjC,gBAAA,KAAK,EAAE;AACR;SACF;;AAGH;;AAEG;IACK,OAAO,iBAAiB,CAAC,MAAsB,EAAA;AACrD,QAAA,MAAM,aAAa,GAA4B;AAC7C,YAAA,WAAW,EAAE;AACX,gBAAA,WAAW,EAAE,cAAc;AAC3B,gBAAA,UAAU,EAAE,SAAS;AACrB,gBAAA,eAAe,EAAE,cAAc;AAC/B,gBAAA,0BAA0B,EAAE,CAAC;AAC7B,gBAAA,WAAW,EAAE,IAAI;gBACjB,GAAG,MAAM,CAAC;AACX,aAAA;AACD,YAAA,iBAAiB,EAAE;AACjB,gBAAA,OAAO,EAAE,IAAI;AACb,gBAAA,gBAAgB,EAAE,QAAQ;AAC1B,gBAAA,WAAW,EAAE,EAAE;AACf,gBAAA,WAAW,EAAE,EAAE;gBACf,GAAG,MAAM,CAAC;AACX,aAAA;AACD,YAAA,cAAc,EAAE;AACd,gBAAA,SAAS,EAAE,IAAI;AACf,gBAAA,aAAa,EAAE,IAAI;AACnB,gBAAA,oBAAoB,EAAE,EAAE;gBACxB,GAAG,MAAM,CAAC;AACX;SACF;QAED,OAAO;AACL,YAAA,GAAG,MAAM;AACT,YAAA,GAAG,aAAa;AAChB,YAAA,WAAW,EAAE;gBACX,GAAG,aAAa,CAAC,WAAW;gBAC5B,GAAG,MAAM,CAAC;AACX,aAAA;AACD,YAAA,iBAAiB,EAAE;gBACjB,GAAG,aAAa,CAAC,iBAAiB;gBAClC,GAAG,MAAM,CAAC;AACX,aAAA;AACD,YAAA,cAAc,EAAE;gBACd,GAAG,aAAa,CAAC,cAAc;gBAC/B,GAAG,MAAM,CAAC;AACX;SACF;;+GAhGQ,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA,CAAA;gHAAlB,kBAAkB,EAAA,CAAA,CAAA;gHAAlB,kBAAkB,EAAA,CAAA,CAAA;;4FAAlB,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAL9B,QAAQ;AAAC,YAAA,IAAA,EAAA,CAAA;AACR,oBAAA,YAAY,EAAE,EAAE;AAChB,oBAAA,OAAO,EAAE,EAAE;AACX,oBAAA,OAAO,EAAE;AACV,iBAAA;;;MCHY,iBAAiB,CAAA;IAE5B,WACU,CAAA,YAAoC,EACpC,MAAc,EAAA;QADd,IAAY,CAAA,YAAA,GAAZ,YAAY;QACZ,IAAM,CAAA,MAAA,GAAN,MAAM;;AAGhB,IAAA,WAAW,CAAC,KAA6B,EAAA;AACvC,QAAA,OAAO,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC;;AAGxC,IAAA,gBAAgB,CAAC,UAAkC,EAAA;AACjD,QAAA,OAAO,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC;;AAGrC,IAAA,mBAAmB,CAAC,KAA6B,EAAA;;AAEvD,QAAA,IAAI,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE;AAClC,YAAA,OAAO,EAAE,CAAC,IAAI,CAAC;;;;;AAMjB,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAC9C,GAAG,CAAC,KAAK,IAAG;YACV,IAAI,CAAC,KAAK,EAAE;AACV,gBAAA,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE;AACjC,gBAAA,OAAO,KAAK;;AAEd,YAAA,OAAO,IAAI;AACb,SAAC,CAAC,EACF,UAAU,CAAC,MAAK;AACd,YAAA,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE;AACjC,YAAA,OAAO,EAAE,CAAC,KAAK,CAAC;SACjB,CAAC,CACH;;AAGH;;AAEG;AACK,IAAA,kBAAkB,CAAC,KAA6B,EAAA;AACtD,QAAA,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW;;AAGrC,QAAA,IAAI,WAAW,CAAC,aAAa,CAAC,KAAK,MAAM,IAAI,WAAW,CAAC,SAAS,CAAC,EAAE;AACnE,YAAA,OAAO,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC;AAC1C,gBAAA,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC;AAC/B,gBAAA,YAAY,EAAE,WAAW,CAAC,cAAc;AACzC,aAAA,CAAC;;;QAIJ,IAAI,WAAW,CAAC,SAAS,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE;AAClD,YAAA,OAAO,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC;gBAC1C,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC;AACvD,gBAAA,YAAY,EAAE,WAAW,CAAC,cAAc;AACzC,aAAA,CAAC;;AAGJ,QAAA,OAAO,KAAK;;+GA7DH,iBAAiB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAAD,sBAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,MAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAjB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,iBAAiB,cAFhB,MAAM,EAAA,CAAA,CAAA;;4FAEP,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAH7B,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE;AACb,iBAAA;;AAkED;;AAEG;MAIU,iBAAiB,CAAA;IAE5B,WACU,CAAA,YAAoC,EACpC,MAAc,EAAA;QADd,IAAY,CAAA,YAAA,GAAZ,YAAY;QACZ,IAAM,CAAA,MAAA,GAAN,MAAM;;AAGhB,IAAA,WAAW,CAAC,KAA6B,EAAA;AACvC,QAAA,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;;AAG9B,IAAA,gBAAgB,CAAC,UAAkC,EAAA;AACjD,QAAA,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;;AAG3B,IAAA,SAAS,CAAC,KAA6B,EAAA;QAC7C,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAa;QACrD,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAW;QAEjD,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,EAAE;AACxC,YAAA,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE;AACjC,YAAA,OAAO,KAAK;;;QAId,IAAI,aAAa,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE;AAC7C,YAAA,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC9E,IAAI,CAAC,UAAU,EAAE;gBACf,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,eAAe,CAAC,CAAC;;;;AAKvD,QAAA,IAAI,YAAY,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE;YAC5D,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,eAAe,CAAC,CAAC;;AAGrD,QAAA,OAAO,IAAI;;+GArCF,iBAAiB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAAA,sBAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,MAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAjB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,iBAAiB,cAFhB,MAAM,EAAA,CAAA,CAAA;;4FAEP,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAH7B,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE;AACb,iBAAA;;AA0CD;;AAEG;MAIU,kBAAkB,CAAA;IAE7B,WACU,CAAA,YAAoC,EACpC,MAAc,EAAA;QADd,IAAY,CAAA,YAAA,GAAZ,YAAY;QACZ,IAAM,CAAA,MAAA,GAAN,MAAM;;IAGhB,WAAW,GAAA;AACT,QAAA,OAAO,IAAI,CAAC,UAAU,EAAE;;IAG1B,gBAAgB,GAAA;AACd,QAAA,OAAO,IAAI,CAAC,UAAU,EAAE;;IAGlB,UAAU,GAAA;QAChB,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,EAAE;AACxC,YAAA,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE;AACjC,YAAA,OAAO,KAAK;;QAGd,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE;YAChC,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,eAAe,CAAC,CAAC;;AAGrD,QAAA,OAAO,IAAI;;+GAzBF,kBAAkB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAAA,sBAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,MAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAlB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,kBAAkB,cAFjB,MAAM,EAAA,CAAA,CAAA;;4FAEP,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAH9B,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE;AACb,iBAAA;;;AC9HD;;AAEG;AAEH;;ACJA;;AAEG;;;;"}
1
+ {"version":3,"file":"medha-analytics-medhasso-auth.mjs","sources":["../../../projects/medhasso-auth/src/lib/tokens/medhasso-config.token.ts","../../../projects/medhasso-auth/src/lib/services/token-management.service.ts","../../../projects/medhasso-auth/src/lib/interceptors/medhasso-auth.interceptor.ts","../../../projects/medhasso-auth/src/lib/services/medhasso-auth.service.ts","../../../projects/medhasso-auth/src/lib/medhasso-auth.module.ts","../../../projects/medhasso-auth/src/lib/guards/medhasso-auth.guard.ts","../../../projects/medhasso-auth/src/public-api.ts","../../../projects/medhasso-auth/src/medha-analytics-medhasso-auth.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport { MedHassoConfig } from '../interfaces/medhasso-config.interface';\n\nexport const MEDHASSO_CONFIG = new InjectionToken<MedHassoConfig>('MEDHASSO_CONFIG');","import { Injectable, Inject } from '@angular/core';\nimport { HttpBackend, HttpClient } from '@angular/common/http';\nimport { BehaviorSubject, Observable, of, throwError, timer } from 'rxjs';\nimport { catchError, finalize, map, shareReplay, tap } from 'rxjs/operators';\nimport { MedHassoConfig, TokenConfig, TokenInfo, MedHassoUser } from '../interfaces/medhasso-config.interface';\nimport { MEDHASSO_CONFIG } from '../tokens/medhasso-config.token';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class TokenManagementService {\n private refreshTokenInterval: any;\n private refreshInProgress$: Observable<any> | null = null;\n private tokenSubject = new BehaviorSubject<TokenInfo | null>(null);\n private userSubject = new BehaviorSubject<MedHassoUser | null>(null);\n /**\n * Dedicated HttpClient wired directly to HttpBackend so the refresh POST\n * bypasses the HTTP_INTERCEPTORS chain. Routing refresh through the normal\n * http (which runs MedHassoAuthInterceptor) causes self-interception:\n * interceptor → ensureValidToken → refreshToken → returns the in-flight\n * refreshInProgress$ which is itself → deadlock, with finalize never firing\n * so refreshInProgress$ stays pinned and every subsequent request hangs too.\n */\n private readonly refreshHttp: HttpClient;\n private readonly onVisibilityChange = () => {\n if (document.visibilityState === 'visible') {\n this.ensureValidToken().subscribe();\n }\n };\n private readonly onWindowFocus = () => {\n this.ensureValidToken().subscribe();\n };\n\n public token$ = this.tokenSubject.asObservable();\n public user$ = this.userSubject.asObservable();\n\n private get tokenConfig(): TokenConfig {\n return this.config.tokenConfig || {};\n }\n\n private get storageType(): 'localStorage' | 'sessionStorage' {\n return this.tokenConfig.storageType || 'localStorage';\n }\n\n private get idTokenKey(): string {\n return this.tokenConfig.idTokenKey || 'idToken';\n }\n\n private get refreshTokenKey(): string {\n return this.tokenConfig.refreshTokenKey || 'refreshToken';\n }\n\n private get refreshBeforeExpiryMinutes(): number {\n return this.tokenConfig.refreshBeforeExpiryMinutes || 5;\n }\n\n private get autoRefresh(): boolean {\n return this.tokenConfig.autoRefresh !== false;\n }\n\n constructor(\n @Inject(MEDHASSO_CONFIG) private config: MedHassoConfig,\n private http: HttpClient,\n httpBackend: HttpBackend\n ) {\n this.refreshHttp = new HttpClient(httpBackend);\n this.initializeFromStorage();\n this.setupWakeDetection();\n }\n\n /**\n * Re-validate the token whenever the tab regains focus/visibility.\n * The refresh timer is a JS timer and does not fire while the OS/browser\n * was suspended (e.g. laptop sleep overnight), so it can't be relied on\n * alone to catch a token that went stale while the app was inactive.\n */\n private setupWakeDetection(): void {\n if (typeof document === 'undefined' || typeof window === 'undefined') {\n return;\n }\n\n document.addEventListener('visibilitychange', this.onVisibilityChange);\n window.addEventListener('focus', this.onWindowFocus);\n }\n\n /**\n * Remove wake-detection listeners registered in setupWakeDetection().\n */\n private teardownWakeDetection(): void {\n if (typeof document === 'undefined' || typeof window === 'undefined') {\n return;\n }\n\n document.removeEventListener('visibilitychange', this.onVisibilityChange);\n window.removeEventListener('focus', this.onWindowFocus);\n }\n\n /**\n * Initialize token information from storage\n */\n private initializeFromStorage(): void {\n const token = this.getStoredToken();\n if (token) {\n const tokenInfo = this.createTokenInfo(token);\n this.tokenSubject.next(tokenInfo);\n this.userSubject.next(this.extractUserFromToken(token));\n \n if (this.autoRefresh && !tokenInfo.isExpired) {\n this.setTokenRefreshInterval(tokenInfo);\n }\n }\n }\n\n /**\n * Re-sync in-memory token state from storage if it has drifted (e.g.\n * something wrote tokens directly to storage without going through\n * setTokens()). No-op when storage already matches memory.\n */\n private syncFromStorage(): void {\n const storedToken = this.getStoredToken();\n const currentToken = this.getTokenInfo()?.token ?? null;\n\n if (storedToken === currentToken) {\n return;\n }\n\n if (!storedToken) {\n this.tokenSubject.next(null);\n this.userSubject.next(null);\n this.clearTokenRefreshInterval();\n return;\n }\n\n const tokenInfo = this.createTokenInfo(storedToken);\n this.tokenSubject.next(tokenInfo);\n this.userSubject.next(this.extractUserFromToken(storedToken));\n\n if (this.autoRefresh && !tokenInfo.isExpired) {\n this.setTokenRefreshInterval(tokenInfo);\n }\n }\n\n /**\n * Get stored token from configured storage\n */\n private getStoredToken(): string | null {\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\n return storage.getItem(this.idTokenKey);\n }\n\n /**\n * Get stored refresh token from configured storage\n */\n private getStoredRefreshToken(): string | null {\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\n return storage.getItem(this.refreshTokenKey);\n }\n\n /**\n * Store tokens in configured storage\n */\n private storeTokens(idToken: string, refreshToken?: string): void {\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\n storage.setItem(this.idTokenKey, idToken);\n if (refreshToken) {\n storage.setItem(this.refreshTokenKey, refreshToken);\n }\n }\n\n /**\n * Clear stored tokens\n */\n private clearStoredTokens(): void {\n const storage = this.storageType === 'localStorage' ? localStorage : sessionStorage;\n storage.removeItem(this.idTokenKey);\n storage.removeItem(this.refreshTokenKey);\n }\n\n /**\n * Create token info object from JWT token.\n *\n * `isExpired` and `needsRefresh` are getters, not snapshotted booleans:\n * the TokenInfo object may outlive wall-clock events that change its\n * expiry status (e.g. OS/browser suspended overnight, laptop sleep).\n * A snapshotted boolean captured at creation time would then lie — the\n * wake handler would call ensureValidToken(), see `isExpired: false`\n * from the pre-sleep snapshot, and skip the refresh. Reading these as\n * getters means every access reflects the current clock.\n */\n private createTokenInfo(token: string): TokenInfo {\n const payload = this.decodeJwt(token);\n const expiresAt = payload.exp * 1000; // Convert to milliseconds\n const refreshWindow = this.refreshBeforeExpiryMinutes * 60 * 1000;\n\n return {\n token,\n payload,\n expiresAt,\n get isExpired() { return Date.now() >= expiresAt; },\n get needsRefresh() { return Date.now() >= (expiresAt - refreshWindow); }\n };\n }\n\n /**\n * Decode JWT token payload\n */\n private decodeJwt(token: string): any {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n throw new Error('Invalid JWT token format');\n }\n const payload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/')));\n return payload;\n } catch (error) {\n console.error('Error decoding JWT token:', error);\n throw new Error('Invalid JWT token');\n }\n }\n\n /**\n * Extract user information from JWT token\n */\n private extractUserFromToken(token: string): MedHassoUser {\n const payload = this.decodeJwt(token);\n return {\n upn: payload.upn || payload.email,\n name: payload.name,\n roles: payload.roles || [],\n ...payload\n };\n }\n\n /**\n * Set up automatic token refresh interval\n */\n private setTokenRefreshInterval(tokenInfo: TokenInfo): void {\n this.clearTokenRefreshInterval();\n\n if (!this.autoRefresh || tokenInfo.isExpired) {\n return;\n }\n\n const remainingTime = tokenInfo.expiresAt - Date.now();\n const refreshTime = remainingTime - (this.refreshBeforeExpiryMinutes * 60 * 1000);\n\n if (refreshTime > 0) {\n this.refreshTokenInterval = timer(refreshTime).subscribe(() => {\n this.refreshToken().subscribe();\n });\n } else {\n // Token needs immediate refresh\n this.refreshToken().subscribe();\n }\n }\n\n /**\n * Clear token refresh interval\n */\n private clearTokenRefreshInterval(): void {\n if (this.refreshTokenInterval) {\n this.refreshTokenInterval.unsubscribe();\n this.refreshTokenInterval = null;\n }\n }\n\n /**\n * Get current token information\n */\n getTokenInfo(): TokenInfo | null {\n return this.tokenSubject.value;\n }\n\n /**\n * Get current user information\n */\n getCurrentUser(): MedHassoUser | null {\n return this.userSubject.value;\n }\n\n /**\n * Check if user is authenticated\n */\n isAuthenticated(): boolean {\n const tokenInfo = this.getTokenInfo();\n return tokenInfo !== null && !tokenInfo.isExpired;\n }\n\n /**\n * Check if user has specific role\n */\n hasRole(role: string): boolean {\n const user = this.getCurrentUser();\n return user?.roles?.includes(role) || false;\n }\n\n /**\n * Check if user is admin\n */\n isAdmin(): boolean {\n return this.hasRole('admin') || this.hasRole('administrator');\n }\n\n /**\n * Set tokens (typically called after successful authentication)\n */\n setTokens(idToken: string, refreshToken?: string): void {\n this.storeTokens(idToken, refreshToken);\n const tokenInfo = this.createTokenInfo(idToken);\n const user = this.extractUserFromToken(idToken);\n\n this.tokenSubject.next(tokenInfo);\n this.userSubject.next(user);\n\n if (this.autoRefresh) {\n this.setTokenRefreshInterval(tokenInfo);\n }\n }\n\n /**\n * Refresh the current token.\n * Concurrent callers (auto-refresh timer, wake detection, interceptor,\n * route guard) share the same in-flight request instead of each firing\n * their own POST to the refresh endpoint.\n */\n refreshToken(): Observable<any> {\n if (this.refreshInProgress$) {\n return this.refreshInProgress$;\n }\n\n const refreshToken = this.getStoredRefreshToken();\n\n if (!refreshToken) {\n return throwError(() => new Error('No refresh token available'));\n }\n\n const request$ = this.refreshHttp.post(`${this.config.refreshUrl}/api/refresh-token`, { refreshToken })\n .pipe(\n tap((response: any) => {\n if (response.id_token) {\n this.setTokens(response.id_token, response.refresh_token);\n }\n }),\n catchError(error => {\n console.error('Token refresh failed:', error);\n // Only clear the session on a definitive auth failure from the refresh\n // endpoint (dead/revoked/invalid refresh token). Transient failures —\n // network blips, 5xx, timeouts — must NOT force a logout: the current\n // id_token may still be valid for the rest of its lifetime, and the\n // background-refresh path (ensureValidToken → needsRefresh) runs on\n // every request within the 5-min window, so a single network hiccup\n // would otherwise log the user out mid-session.\n const status = error?.status;\n if (status === 400 || status === 401) {\n this.logout();\n }\n return throwError(() => error);\n }),\n finalize(() => {\n this.refreshInProgress$ = null;\n }),\n shareReplay({ bufferSize: 1, refCount: false })\n );\n\n this.refreshInProgress$ = request$;\n return request$;\n }\n\n /**\n * Ensure the current token is valid, refreshing it first if it is\n * expired. Resolves `false` if there is no token at all, or the token\n * is expired and refreshing it failed (in both cases the caller should\n * redirect to SSO).\n *\n * A token that merely `needsRefresh` (inside the refresh window, but\n * not yet expired) is still good enough to use: the refresh for it is\n * kicked off in the background so the *current* request/route isn't\n * blocked or logged out by a transient refresh failure (network blip,\n * refresh endpoint hiccup) while the existing token would have worked\n * fine. Only an actually-expired token blocks the caller.\n *\n * Re-syncs from storage first: the in-memory token snapshot is only\n * updated via setTokens()/logout(), so if something wrote directly to\n * storage (e.g. the SSO callback flow) without going through this\n * service, the in-memory copy would otherwise be stale until the next\n * full page load re-runs initializeFromStorage().\n *\n * Anonymous/bootstrap endpoints that must be reachable before any token\n * exists (e.g. the SSO callback's own token-exchange request) should be\n * added to `interceptorConfig.excludeUrls` so they bypass this check\n * entirely, rather than relying on this method to let them through.\n */\n ensureValidToken(): Observable<boolean> {\n this.syncFromStorage();\n const tokenInfo = this.getTokenInfo();\n\n if (!tokenInfo) {\n return of(false);\n }\n\n if (tokenInfo.isExpired) {\n return this.refreshToken().pipe(\n map(() => true),\n catchError(() => of(false))\n );\n }\n\n if (tokenInfo.needsRefresh) {\n this.refreshToken().subscribe({ error: () => {} });\n }\n\n return of(true);\n }\n\n /**\n * Logout user and clear all tokens\n */\n logout(): void {\n this.clearTokenRefreshInterval();\n this.clearStoredTokens();\n this.tokenSubject.next(null);\n this.userSubject.next(null);\n }\n\n /**\n * Redirect to MedHasso SSO for authentication\n */\n redirectToSSO(returnUrl?: string): void {\n const currentUrl = returnUrl || window.location.href;\n const ssoUrl = `${this.config.ssoUrl}?url=${encodeURIComponent(currentUrl)}&applicationName=${encodeURIComponent(this.config.applicationName)}`;\n window.location.href = ssoUrl;\n }\n\n /**\n * Handle authentication callback (typically from SSO redirect)\n */\n handleAuthCallback(params: { idToken?: string; refreshToken?: string }): boolean {\n if (params.idToken) {\n this.setTokens(params.idToken, params.refreshToken);\n return true;\n }\n return false;\n }\n\n /**\n * Get authorization header value\n */\n getAuthorizationHeader(): string | null {\n const tokenInfo = this.getTokenInfo();\n if (tokenInfo && !tokenInfo.isExpired) {\n const prefix = this.config.interceptorConfig?.authHeaderPrefix || 'Bearer';\n return `${prefix} ${tokenInfo.token}`;\n }\n return null;\n }\n\n /**\n * Cleanup on service destruction\n */\n ngOnDestroy(): void {\n this.clearTokenRefreshInterval();\n this.teardownWakeDetection();\n }\n}\n","import { Injectable, Inject } from '@angular/core';\nimport { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';\nimport { Observable, throwError } from 'rxjs';\nimport { catchError, switchMap } from 'rxjs/operators';\nimport { MedHassoConfig } from '../interfaces/medhasso-config.interface';\nimport { MEDHASSO_CONFIG } from '../tokens/medhasso-config.token';\nimport { TokenManagementService } from '../services/token-management.service';\n\n@Injectable()\nexport class MedHassoAuthInterceptor implements HttpInterceptor {\n\n constructor(\n @Inject(MEDHASSO_CONFIG) private config: MedHassoConfig,\n private tokenService: TokenManagementService\n ) {}\n\n intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\n // Check if interceptor is enabled\n if (this.config.interceptorConfig?.enabled === false) {\n return next.handle(request);\n }\n\n // Check if request should be excluded\n if (this.shouldExcludeRequest(request)) {\n return next.handle(request);\n }\n\n // Check if request should be included (if includeUrls is specified)\n if (!this.shouldIncludeRequest(request)) {\n return next.handle(request);\n }\n\n // Proactively ensure the token is valid (refreshing first if it's\n // expired or within the refresh window) before attaching the header.\n // This avoids sending a guaranteed-401 request after the app has been\n // idle/suspended long enough for the in-memory refresh timer to miss it.\n return this.tokenService.ensureValidToken().pipe(\n switchMap(valid => {\n if (!valid) {\n this.redirectToSSO();\n return throwError(() => new Error('Authentication required'));\n }\n\n const modifiedRequest = this.addAuthorizationHeader(request);\n\n return next.handle(modifiedRequest).pipe(\n catchError((error: HttpErrorResponse) => {\n // Handle 401 Unauthorized errors\n if (error.status === 401) {\n return this.handle401Error(request, next);\n }\n\n // Handle 403 Forbidden errors\n if (error.status === 403) {\n console.warn('MedHasso Auth: Access forbidden (403)', error);\n }\n\n return throwError(() => error);\n })\n );\n })\n );\n }\n\n /**\n * Check if request URL should be excluded from authentication\n */\n private shouldExcludeRequest(request: HttpRequest<any>): boolean {\n const excludeUrls = this.config.interceptorConfig?.excludeUrls || [];\n return excludeUrls.some(url => this.matchesUrl(request.url, url));\n }\n\n /**\n * Check if request URL should be included for authentication\n * If includeUrls is not specified, all requests are included (unless excluded)\n */\n private shouldIncludeRequest(request: HttpRequest<any>): boolean {\n const includeUrls = this.config.interceptorConfig?.includeUrls;\n \n // If no includeUrls specified, include all requests\n if (!includeUrls || includeUrls.length === 0) {\n return true;\n }\n\n // If includeUrls specified, only include matching requests\n return includeUrls.some(url => this.matchesUrl(request.url, url));\n }\n\n /**\n * Check if request URL matches the pattern\n */\n private matchesUrl(requestUrl: string, pattern: string): boolean {\n // Support wildcards and exact matches\n if (pattern.includes('*')) {\n const regex = new RegExp(pattern.replace(/\\*/g, '.*'));\n return regex.test(requestUrl);\n }\n \n return requestUrl.includes(pattern);\n }\n\n /**\n * Add authorization header to request\n */\n private addAuthorizationHeader(request: HttpRequest<any>): HttpRequest<any> {\n const authHeader = this.tokenService.getAuthorizationHeader();\n \n if (!authHeader) {\n return request;\n }\n\n return request.clone({\n setHeaders: {\n Authorization: authHeader\n }\n });\n }\n\n /**\n * Handle 401 Unauthorized errors by attempting token refresh.\n *\n * Always tries the refresh path first, even when the in-memory token looks\n * expired to our clock. The server already said \"unauthorized\" — whether our\n * local isExpired check agrees doesn't change what we need to do next.\n * Short-circuiting to SSO on `tokenInfo.isExpired` would bounce the user on\n * mid-flight expirations and small client/server clock skews, cases where the\n * refresh token is still perfectly valid and would have recovered. If the\n * refresh really can't succeed (no refresh token in storage, dead refresh\n * token → 400/401), refreshToken() throws and the catchError below redirects.\n */\n private handle401Error(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\n // catchError sits BEFORE switchMap on purpose: it must only catch failures\n // from refreshToken(), not from the retried next.handle(retryRequest). If\n // the refresh succeeds but the retry fails (403, 500, etc.), that error\n // has nothing to do with authentication — redirecting to SSO would be\n // wrong. Keep the SSO redirect scoped to the \"refresh really can't help\"\n // case; let any retry error propagate normally to the component.\n return this.tokenService.refreshToken().pipe(\n catchError((refreshError) => {\n console.error('MedHasso Auth: Token refresh failed', refreshError);\n this.redirectToSSO();\n return throwError(() => refreshError);\n }),\n switchMap(() => {\n // Retry the original request with new token\n const retryRequest = this.addAuthorizationHeader(request);\n return next.handle(retryRequest);\n })\n );\n }\n\n /**\n * Redirect to SSO for authentication\n */\n private redirectToSSO(): void {\n // Add a small delay to prevent multiple redirects\n setTimeout(() => {\n this.tokenService.redirectToSSO();\n }, 100);\n }\n}","import { Injectable, Inject } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { Observable, of } from 'rxjs';\nimport { map, catchError } from 'rxjs/operators';\nimport { MedHassoConfig, MedHassoUser } from '../interfaces/medhasso-config.interface';\nimport { MEDHASSO_CONFIG } from '../tokens/medhasso-config.token';\nimport { TokenManagementService } from './token-management.service';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class MedHassoAuthService {\n\n constructor(\n @Inject(MEDHASSO_CONFIG) private config: MedHassoConfig,\n private tokenService: TokenManagementService,\n private http: HttpClient\n ) {}\n\n /**\n * Get current authentication status\n */\n isAuthenticated(): boolean {\n return this.tokenService.isAuthenticated();\n }\n\n /**\n * Get current user information\n */\n getCurrentUser(): MedHassoUser | null {\n return this.tokenService.getCurrentUser();\n }\n\n /**\n * Get current user as observable\n */\n getCurrentUser$(): Observable<MedHassoUser | null> {\n return this.tokenService.user$;\n }\n\n /**\n * Check if user has specific role\n */\n hasRole(role: string): boolean {\n return this.tokenService.hasRole(role);\n }\n\n /**\n * Check if user has any of the specified roles\n */\n hasAnyRole(roles: string[]): boolean {\n return roles.some(role => this.tokenService.hasRole(role));\n }\n\n /**\n * Check if user has all of the specified roles\n */\n hasAllRoles(roles: string[]): boolean {\n return roles.every(role => this.tokenService.hasRole(role));\n }\n\n /**\n * Check if user is admin\n */\n isAdmin(): boolean {\n return this.tokenService.isAdmin();\n }\n\n /**\n * Login user (redirect to SSO)\n */\n login(returnUrl?: string): void {\n this.tokenService.redirectToSSO(returnUrl);\n }\n\n /**\n * Logout user\n */\n logout(): void {\n this.tokenService.logout();\n }\n\n /**\n * Refresh authentication token\n */\n refreshToken(): Observable<any> {\n return this.tokenService.refreshToken();\n }\n\n /**\n * Check access permissions for a simple key (if applicable)\n */\n checkAccess(simpleKey: string, backendUrl?: string): Observable<any> {\n const url = backendUrl || this.getBackendUrl();\n if (!url) {\n return of(null);\n }\n\n return this.http.get(`${url}/auth/guard?simple_key=${simpleKey}`)\n .pipe(\n catchError(error => {\n console.error('Access check failed:', error);\n return of(null);\n })\n );\n }\n\n /**\n * Check if user is admin via backend API (if applicable)\n */\n checkIsAdmin(backendUrl?: string): Observable<boolean> {\n const user = this.getCurrentUser();\n const url = backendUrl || this.getBackendUrl();\n \n if (!user?.upn || !url) {\n return of(false);\n }\n\n return this.http.get(`${url}/isAdmin?email=${user.upn}`)\n .pipe(\n map((response: any) => !!response),\n catchError(() => of(false))\n );\n }\n\n /**\n * Get backend URL from config (helper method)\n */\n private getBackendUrl(): string | null {\n // This would need to be configured or passed in\n // For now, return null as it's application-specific\n return null;\n }\n\n /**\n * Get token information\n */\n getTokenInfo() {\n return this.tokenService.getTokenInfo();\n }\n\n /**\n * Get token as observable\n */\n getToken$() {\n return this.tokenService.token$;\n }\n\n /**\n * Handle authentication callback\n */\n handleAuthCallback(params: { idToken?: string; refreshToken?: string }): boolean {\n return this.tokenService.handleAuthCallback(params);\n }\n\n /**\n * Get user email\n */\n getUserEmail(): string | null {\n return this.getCurrentUser()?.upn || null;\n }\n\n /**\n * Get user display name\n */\n getUserDisplayName(): string | null {\n return this.getCurrentUser()?.name || null;\n }\n\n /**\n * Get all user roles\n */\n getUserRoles(): string[] {\n return this.getCurrentUser()?.roles || [];\n }\n\n /**\n * Get authorization header value\n */\n getAuthorizationHeader(): string | null {\n return this.tokenService.getAuthorizationHeader();\n }\n}","import { NgModule, ModuleWithProviders, Provider } from '@angular/core';\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\nimport { MedHassoConfig } from './interfaces/medhasso-config.interface';\nimport { MEDHASSO_CONFIG } from './tokens/medhasso-config.token';\nimport { MedHassoAuthInterceptor } from './interceptors/medhasso-auth.interceptor';\nimport { TokenManagementService } from './services/token-management.service';\nimport { MedHassoAuthService } from './services/medhasso-auth.service';\n\n@NgModule({\n declarations: [],\n imports: [],\n exports: []\n})\nexport class MedHassoAuthModule {\n \n /**\n * Configure the MedHasso authentication module with required settings\n */\n static forRoot(config: MedHassoConfig): ModuleWithProviders<MedHassoAuthModule> {\n return {\n ngModule: MedHassoAuthModule,\n providers: [\n {\n provide: MEDHASSO_CONFIG,\n useValue: this.mergeWithDefaults(config)\n },\n TokenManagementService,\n MedHassoAuthService,\n {\n provide: HTTP_INTERCEPTORS,\n useClass: MedHassoAuthInterceptor,\n multi: true\n }\n ]\n };\n }\n\n /**\n * Configure the MedHasso authentication module for feature modules\n */\n static forChild(): ModuleWithProviders<MedHassoAuthModule> {\n return {\n ngModule: MedHassoAuthModule,\n providers: []\n };\n }\n\n /**\n * Provide MedHasso authentication with standalone components\n */\n static forStandalone(config: MedHassoConfig): Provider[] {\n return [\n {\n provide: MEDHASSO_CONFIG,\n useValue: this.mergeWithDefaults(config)\n },\n TokenManagementService,\n MedHassoAuthService,\n {\n provide: HTTP_INTERCEPTORS,\n useClass: MedHassoAuthInterceptor,\n multi: true\n }\n ];\n }\n\n /**\n * Merge user configuration with sensible defaults\n */\n private static mergeWithDefaults(config: MedHassoConfig): MedHassoConfig {\n const defaultConfig: Partial<MedHassoConfig> = {\n tokenConfig: {\n storageType: 'localStorage',\n idTokenKey: 'idToken',\n refreshTokenKey: 'refreshToken',\n refreshBeforeExpiryMinutes: 5,\n autoRefresh: true,\n ...config.tokenConfig\n },\n interceptorConfig: {\n enabled: true,\n authHeaderPrefix: 'Bearer',\n excludeUrls: [],\n includeUrls: [],\n ...config.interceptorConfig\n },\n securityConfig: {\n httpsOnly: true,\n secureCookies: true,\n additionalCspSources: [],\n ...config.securityConfig\n }\n };\n\n return {\n ...config,\n ...defaultConfig,\n tokenConfig: {\n ...defaultConfig.tokenConfig,\n ...config.tokenConfig\n },\n interceptorConfig: {\n ...defaultConfig.interceptorConfig,\n ...config.interceptorConfig\n },\n securityConfig: {\n ...defaultConfig.securityConfig,\n ...config.securityConfig\n }\n };\n }\n}","import { Injectable } from '@angular/core';\nimport { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, UrlTree } from '@angular/router';\nimport { Observable, of } from 'rxjs';\nimport { map, catchError } from 'rxjs/operators';\nimport { TokenManagementService } from '../services/token-management.service';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class MedHassoAuthGuard implements CanActivate, CanActivateChild {\n\n constructor(\n private tokenService: TokenManagementService,\n private router: Router\n ) {}\n\n canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\n return this.checkAuthentication(route);\n }\n\n canActivateChild(childRoute: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\n return this.checkAuthentication(childRoute);\n }\n\n private checkAuthentication(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> {\n // Check for authentication callback parameters\n if (this.handleAuthCallback(route)) {\n return of(true);\n }\n\n // Re-syncs from storage and refreshes a stale/expired token before\n // deciding, so this guard shares the same de-duplicated refresh and\n // storage-drift handling as the HTTP interceptor.\n return this.tokenService.ensureValidToken().pipe(\n map(valid => {\n if (!valid) {\n this.tokenService.redirectToSSO();\n return false;\n }\n return true;\n }),\n catchError(() => {\n this.tokenService.redirectToSSO();\n return of(false);\n })\n );\n }\n\n /**\n * Handle authentication callback from MedHasso SSO\n */\n private handleAuthCallback(route: ActivatedRouteSnapshot): boolean {\n const queryParams = route.queryParams;\n \n // Check for AIRO redirect flow\n if (queryParams['redirectapp'] === 'airo' && queryParams['idToken']) {\n return this.tokenService.handleAuthCallback({\n idToken: queryParams['idToken'],\n refreshToken: queryParams['refreshToken']\n });\n }\n\n // Check for standard authentication callback\n if (queryParams['idToken'] || queryParams['token']) {\n return this.tokenService.handleAuthCallback({\n idToken: queryParams['idToken'] || queryParams['token'],\n refreshToken: queryParams['refreshToken']\n });\n }\n\n return false;\n }\n}\n\n/**\n * Role-based authentication guard\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class MedHassoRoleGuard implements CanActivate, CanActivateChild {\n\n constructor(\n private tokenService: TokenManagementService,\n private router: Router\n ) {}\n\n canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\n return this.checkRole(route);\n }\n\n canActivateChild(childRoute: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\n return this.checkRole(childRoute);\n }\n\n private checkRole(route: ActivatedRouteSnapshot): boolean | UrlTree {\n const requiredRoles = route.data['roles'] as string[];\n const requiredRole = route.data['role'] as string;\n\n if (!this.tokenService.isAuthenticated()) {\n this.tokenService.redirectToSSO();\n return false;\n }\n\n // Check multiple roles (OR condition)\n if (requiredRoles && requiredRoles.length > 0) {\n const hasAnyRole = requiredRoles.some(role => this.tokenService.hasRole(role));\n if (!hasAnyRole) {\n return this.router.createUrlTree(['/unauthorized']);\n }\n }\n\n // Check single role\n if (requiredRole && !this.tokenService.hasRole(requiredRole)) {\n return this.router.createUrlTree(['/unauthorized']);\n }\n\n return true;\n }\n}\n\n/**\n * Admin-only authentication guard\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class MedHassoAdminGuard implements CanActivate, CanActivateChild {\n\n constructor(\n private tokenService: TokenManagementService,\n private router: Router\n ) {}\n\n canActivate(): boolean | UrlTree {\n return this.checkAdmin();\n }\n\n canActivateChild(): boolean | UrlTree {\n return this.checkAdmin();\n }\n\n private checkAdmin(): boolean | UrlTree {\n if (!this.tokenService.isAuthenticated()) {\n this.tokenService.redirectToSSO();\n return false;\n }\n\n if (!this.tokenService.isAdmin()) {\n return this.router.createUrlTree(['/unauthorized']);\n }\n\n return true;\n }\n}","/*\n * Public API Surface of medhasso-auth\n */\n\n// Module\nexport * from './lib/medhasso-auth.module';\n\n// Services\nexport * from './lib/services/token-management.service';\nexport * from './lib/services/medhasso-auth.service';\n\n// Guards\nexport * from './lib/guards/medhasso-auth.guard';\n\n// Interceptors\nexport * from './lib/interceptors/medhasso-auth.interceptor';\n\n// Interfaces\nexport * from './lib/interfaces/medhasso-config.interface';\n\n// Tokens\nexport * from './lib/tokens/medhasso-config.token';","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.TokenManagementService","i2"],"mappings":"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"}
@@ -26,7 +26,16 @@ export declare class MedHassoAuthInterceptor implements HttpInterceptor {
26
26
  */
27
27
  private addAuthorizationHeader;
28
28
  /**
29
- * Handle 401 Unauthorized errors by attempting token refresh
29
+ * Handle 401 Unauthorized errors by attempting token refresh.
30
+ *
31
+ * Always tries the refresh path first, even when the in-memory token looks
32
+ * expired to our clock. The server already said "unauthorized" — whether our
33
+ * local isExpired check agrees doesn't change what we need to do next.
34
+ * Short-circuiting to SSO on `tokenInfo.isExpired` would bounce the user on
35
+ * mid-flight expirations and small client/server clock skews, cases where the
36
+ * refresh token is still perfectly valid and would have recovered. If the
37
+ * refresh really can't succeed (no refresh token in storage, dead refresh
38
+ * token → 400/401), refreshToken() throws and the catchError below redirects.
30
39
  */
31
40
  private handle401Error;
32
41
  /**
@@ -110,11 +110,17 @@ export interface TokenInfo {
110
110
  */
111
111
  expiresAt: number;
112
112
  /**
113
- * Whether token is expired
113
+ * Whether token is expired. Backed by a dynamic getter: every read
114
+ * re-evaluates against the current clock, so the value stays accurate even
115
+ * after a long idle/suspend when nothing has written to storage. Spreading
116
+ * (`{...tokenInfo}`) or `JSON.stringify`-ing a TokenInfo captures a boolean
117
+ * snapshot and loses this behavior — pass the object itself around, don't
118
+ * clone it.
114
119
  */
115
- isExpired: boolean;
120
+ readonly isExpired: boolean;
116
121
  /**
117
- * Whether token will expire soon (within refresh window)
122
+ * Whether token will expire soon (within refresh window). Dynamic getter —
123
+ * same spread/JSON caveat as `isExpired`.
118
124
  */
119
- needsRefresh: boolean;
125
+ readonly needsRefresh: boolean;
120
126
  }
@@ -1,4 +1,4 @@
1
- import { HttpClient } from '@angular/common/http';
1
+ import { HttpBackend, HttpClient } from '@angular/common/http';
2
2
  import { Observable } from 'rxjs';
3
3
  import { MedHassoConfig, TokenInfo, MedHassoUser } from '../interfaces/medhasso-config.interface';
4
4
  import * as i0 from "@angular/core";
@@ -9,6 +9,15 @@ export declare class TokenManagementService {
9
9
  private refreshInProgress$;
10
10
  private tokenSubject;
11
11
  private userSubject;
12
+ /**
13
+ * Dedicated HttpClient wired directly to HttpBackend so the refresh POST
14
+ * bypasses the HTTP_INTERCEPTORS chain. Routing refresh through the normal
15
+ * http (which runs MedHassoAuthInterceptor) causes self-interception:
16
+ * interceptor → ensureValidToken → refreshToken → returns the in-flight
17
+ * refreshInProgress$ which is itself → deadlock, with finalize never firing
18
+ * so refreshInProgress$ stays pinned and every subsequent request hangs too.
19
+ */
20
+ private readonly refreshHttp;
12
21
  private readonly onVisibilityChange;
13
22
  private readonly onWindowFocus;
14
23
  token$: Observable<TokenInfo | null>;
@@ -19,7 +28,7 @@ export declare class TokenManagementService {
19
28
  private get refreshTokenKey();
20
29
  private get refreshBeforeExpiryMinutes();
21
30
  private get autoRefresh();
22
- constructor(config: MedHassoConfig, http: HttpClient);
31
+ constructor(config: MedHassoConfig, http: HttpClient, httpBackend: HttpBackend);
23
32
  /**
24
33
  * Re-validate the token whenever the tab regains focus/visibility.
25
34
  * The refresh timer is a JS timer and does not fire while the OS/browser
@@ -58,7 +67,15 @@ export declare class TokenManagementService {
58
67
  */
59
68
  private clearStoredTokens;
60
69
  /**
61
- * Create token info object from JWT token
70
+ * Create token info object from JWT token.
71
+ *
72
+ * `isExpired` and `needsRefresh` are getters, not snapshotted booleans:
73
+ * the TokenInfo object may outlive wall-clock events that change its
74
+ * expiry status (e.g. OS/browser suspended overnight, laptop sleep).
75
+ * A snapshotted boolean captured at creation time would then lie — the
76
+ * wake handler would call ensureValidToken(), see `isExpired: false`
77
+ * from the pre-sleep snapshot, and skip the refresh. Reading these as
78
+ * getters means every access reflects the current clock.
62
79
  */
63
80
  private createTokenInfo;
64
81
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medha-analytics/medhasso-auth",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Angular authentication library for MedHasso SSO integration",
5
5
  "keywords": [
6
6
  "angular",