@nauth-toolkit/client-angular 0.1.55 → 0.1.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/esm2022/lib/auth.guard.mjs +83 -0
  2. package/esm2022/lib/auth.interceptor.mjs +158 -0
  3. package/esm2022/lib/social-redirect-callback.guard.mjs +81 -0
  4. package/esm2022/nauth-toolkit-client-angular.mjs +5 -0
  5. package/esm2022/ngmodule/auth.interceptor.class.mjs +109 -0
  6. package/esm2022/ngmodule/auth.service.mjs +777 -0
  7. package/esm2022/ngmodule/http-adapter.mjs +81 -0
  8. package/esm2022/ngmodule/nauth.module.mjs +65 -0
  9. package/esm2022/ngmodule/tokens.mjs +6 -0
  10. package/esm2022/public-api.mjs +19 -0
  11. package/esm2022/src/standalone/nauth-toolkit-client-angular-src-standalone.mjs +5 -0
  12. package/esm2022/src/standalone/public-api.mjs +12 -0
  13. package/esm2022/standalone/auth.guard.mjs +83 -0
  14. package/esm2022/standalone/auth.interceptor.mjs +158 -0
  15. package/esm2022/standalone/auth.service.mjs +777 -0
  16. package/esm2022/standalone/http-adapter.mjs +81 -0
  17. package/esm2022/standalone/nauth-toolkit-client-angular-standalone.mjs +5 -0
  18. package/esm2022/standalone/public-api.mjs +16 -0
  19. package/esm2022/standalone/social-redirect-callback.guard.mjs +81 -0
  20. package/esm2022/standalone/tokens.mjs +6 -0
  21. package/fesm2022/nauth-toolkit-client-angular-src-standalone.mjs +17 -0
  22. package/fesm2022/nauth-toolkit-client-angular-src-standalone.mjs.map +1 -0
  23. package/fesm2022/nauth-toolkit-client-angular-standalone.mjs +1183 -0
  24. package/fesm2022/nauth-toolkit-client-angular-standalone.mjs.map +1 -0
  25. package/fesm2022/nauth-toolkit-client-angular.mjs +1344 -0
  26. package/fesm2022/nauth-toolkit-client-angular.mjs.map +1 -0
  27. package/index.d.ts +5 -0
  28. package/{src/lib/auth.guard.ts → lib/auth.guard.d.ts} +15 -37
  29. package/lib/auth.interceptor.d.ts +15 -0
  30. package/lib/social-redirect-callback.guard.d.ts +25 -0
  31. package/ngmodule/auth.interceptor.class.d.ts +34 -0
  32. package/ngmodule/auth.service.d.ts +580 -0
  33. package/ngmodule/http-adapter.d.ts +37 -0
  34. package/ngmodule/nauth.module.d.ts +31 -0
  35. package/{src/ngmodule/tokens.ts → ngmodule/tokens.d.ts} +1 -2
  36. package/package.json +30 -20
  37. package/{src/public-api.ts → public-api.d.ts} +0 -6
  38. package/src/standalone/index.d.ts +5 -0
  39. package/src/standalone/{public-api.ts → public-api.d.ts} +0 -2
  40. package/standalone/{auth.guard.ts → auth.guard.d.ts} +15 -37
  41. package/standalone/auth.interceptor.d.ts +15 -0
  42. package/standalone/auth.service.d.ts +580 -0
  43. package/standalone/http-adapter.d.ts +37 -0
  44. package/standalone/index.d.ts +5 -0
  45. package/standalone/{public-api.ts → public-api.d.ts} +1 -6
  46. package/standalone/social-redirect-callback.guard.d.ts +25 -0
  47. package/standalone/{tokens.ts → tokens.d.ts} +1 -2
  48. package/ng-package.json +0 -12
  49. package/src/lib/auth.interceptor.ts +0 -194
  50. package/src/lib/social-redirect-callback.guard.ts +0 -87
  51. package/src/ngmodule/auth.interceptor.class.ts +0 -124
  52. package/src/ngmodule/auth.service.ts +0 -865
  53. package/src/ngmodule/http-adapter.ts +0 -79
  54. package/src/ngmodule/nauth.module.ts +0 -59
  55. package/src/package.json +0 -11
  56. package/src/standalone/ng-package.json +0 -7
  57. package/src/standalone/package.json +0 -8
  58. package/standalone/auth.interceptor.ts +0 -194
  59. package/standalone/auth.service.ts +0 -865
  60. package/standalone/http-adapter.ts +0 -79
  61. package/standalone/ng-package.json +0 -7
  62. package/standalone/package.json +0 -8
  63. package/standalone/social-redirect-callback.guard.ts +0 -87
  64. package/tsconfig.json +0 -10
  65. package/tsconfig.lib.json +0 -28
  66. package/tsconfig.lib.prod.json +0 -10
@@ -0,0 +1,1183 @@
1
+ import { NAuthErrorCode, NAuthClientError, NAuthClient } from '@nauth-toolkit/client';
2
+ export * from '@nauth-toolkit/client';
3
+ import * as i0 from '@angular/core';
4
+ import { InjectionToken, Injectable, Inject, inject, PLATFORM_ID } from '@angular/core';
5
+ import { firstValueFrom, BehaviorSubject, Subject, catchError, throwError, from, switchMap, filter as filter$1, take } from 'rxjs';
6
+ import { filter } from 'rxjs/operators';
7
+ import * as i1 from '@angular/common/http';
8
+ import { HttpErrorResponse, HttpClient } from '@angular/common/http';
9
+ import { isPlatformBrowser } from '@angular/common';
10
+ import { Router } from '@angular/router';
11
+
12
+ /**
13
+ * Injection token for providing NAuthClientConfig in Angular apps.
14
+ */
15
+ const NAUTH_CLIENT_CONFIG = new InjectionToken('NAUTH_CLIENT_CONFIG');
16
+
17
+ /**
18
+ * HTTP adapter for Angular using HttpClient.
19
+ *
20
+ * This adapter:
21
+ * - Uses Angular's HttpClient for all requests
22
+ * - Works with Angular's HTTP interceptors (including authInterceptor)
23
+ * - Auto-provided via Angular DI (providedIn: 'root')
24
+ * - Converts HttpClient responses to HttpResponse format
25
+ * - Converts HttpErrorResponse to NAuthClientError
26
+ *
27
+ * Users don't need to configure this manually - it's automatically
28
+ * injected when using AuthService in Angular apps.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * // Automatic usage (no manual setup needed)
33
+ * // AuthService automatically injects AngularHttpAdapter
34
+ * constructor(private auth: AuthService) {}
35
+ * ```
36
+ */
37
+ class AngularHttpAdapter {
38
+ http;
39
+ constructor(http) {
40
+ this.http = http;
41
+ }
42
+ /**
43
+ * Execute HTTP request using Angular's HttpClient.
44
+ *
45
+ * @param config - Request configuration
46
+ * @returns Response with parsed data
47
+ * @throws NAuthClientError if request fails
48
+ */
49
+ async request(config) {
50
+ try {
51
+ // Use Angular's HttpClient - goes through ALL interceptors
52
+ const data = await firstValueFrom(this.http.request(config.method, config.url, {
53
+ body: config.body,
54
+ headers: config.headers,
55
+ withCredentials: config.credentials === 'include',
56
+ observe: 'body', // Only return body data
57
+ }));
58
+ return {
59
+ data,
60
+ status: 200, // HttpClient only returns data on success
61
+ headers: {}, // Can extract from observe: 'response' if needed
62
+ };
63
+ }
64
+ catch (error) {
65
+ if (error instanceof HttpErrorResponse) {
66
+ // Convert Angular's HttpErrorResponse to NAuthClientError
67
+ const errorData = error.error || {};
68
+ const code = typeof errorData['code'] === 'string' ? errorData.code : NAuthErrorCode.INTERNAL_ERROR;
69
+ const message = typeof errorData['message'] === 'string'
70
+ ? errorData.message
71
+ : error.message || `Request failed with status ${error.status}`;
72
+ const timestamp = typeof errorData['timestamp'] === 'string' ? errorData.timestamp : undefined;
73
+ const details = errorData['details'];
74
+ throw new NAuthClientError(code, message, {
75
+ statusCode: error.status,
76
+ timestamp,
77
+ details,
78
+ isNetworkError: error.status === 0, // Network error (no response from server)
79
+ });
80
+ }
81
+ // Re-throw non-HTTP errors
82
+ throw error;
83
+ }
84
+ }
85
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AngularHttpAdapter, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
86
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AngularHttpAdapter });
87
+ }
88
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AngularHttpAdapter, decorators: [{
89
+ type: Injectable
90
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
91
+
92
+ /**
93
+ * Angular wrapper around NAuthClient that provides promise-based auth methods and reactive state.
94
+ *
95
+ * This service provides:
96
+ * - Reactive state (currentUser$, isAuthenticated$, challenge$)
97
+ * - All core auth methods as Promises (login, signup, logout, refresh)
98
+ * - Profile management (getProfile, updateProfile, changePassword)
99
+ * - Challenge flow methods (respondToChallenge, resendCode)
100
+ * - MFA management (getMfaStatus, setupMfaDevice, etc.)
101
+ * - Social authentication and account linking
102
+ * - Device trust management
103
+ * - Audit history
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * constructor(private auth: AuthService) {}
108
+ *
109
+ * // Reactive state
110
+ * this.auth.currentUser$.subscribe(user => ...);
111
+ * this.auth.isAuthenticated$.subscribe(isAuth => ...);
112
+ *
113
+ * // Auth operations with async/await
114
+ * const response = await this.auth.login(email, password);
115
+ *
116
+ * // Profile management
117
+ * await this.auth.changePassword(oldPassword, newPassword);
118
+ * const user = await this.auth.updateProfile({ firstName: 'John' });
119
+ *
120
+ * // MFA operations
121
+ * const status = await this.auth.getMfaStatus();
122
+ * ```
123
+ */
124
+ class AuthService {
125
+ client;
126
+ config;
127
+ currentUserSubject = new BehaviorSubject(null);
128
+ isAuthenticatedSubject = new BehaviorSubject(false);
129
+ challengeSubject = new BehaviorSubject(null);
130
+ authEventsSubject = new Subject();
131
+ initialized = false;
132
+ /**
133
+ * @param config - Injected client configuration (required)
134
+ * @param httpAdapter - Angular HTTP adapter for making requests (required)
135
+ */
136
+ constructor(config, httpAdapter) {
137
+ this.config = config;
138
+ // Use provided httpAdapter (from config or injected)
139
+ const adapter = config.httpAdapter ?? httpAdapter;
140
+ if (!adapter) {
141
+ throw new Error('HttpAdapter not found. Either provide httpAdapter in NAUTH_CLIENT_CONFIG or ensure HttpClient is available.');
142
+ }
143
+ this.client = new NAuthClient({
144
+ ...config,
145
+ httpAdapter: adapter,
146
+ onAuthStateChange: (user) => {
147
+ this.currentUserSubject.next(user);
148
+ this.isAuthenticatedSubject.next(Boolean(user));
149
+ config.onAuthStateChange?.(user);
150
+ },
151
+ });
152
+ // Forward all client events to Observable stream
153
+ this.client.on('*', (event) => {
154
+ this.authEventsSubject.next(event);
155
+ });
156
+ // Auto-initialize on construction (hydrate from storage)
157
+ this.initialize();
158
+ }
159
+ // ============================================================================
160
+ // Reactive State Observables
161
+ // ============================================================================
162
+ /**
163
+ * Current user observable.
164
+ */
165
+ get currentUser$() {
166
+ return this.currentUserSubject.asObservable();
167
+ }
168
+ /**
169
+ * Authenticated state observable.
170
+ */
171
+ get isAuthenticated$() {
172
+ return this.isAuthenticatedSubject.asObservable();
173
+ }
174
+ /**
175
+ * Current challenge observable (for reactive challenge navigation).
176
+ */
177
+ get challenge$() {
178
+ return this.challengeSubject.asObservable();
179
+ }
180
+ /**
181
+ * Authentication events stream.
182
+ * Emits all auth lifecycle events for custom logic, analytics, or UI updates.
183
+ */
184
+ get authEvents$() {
185
+ return this.authEventsSubject.asObservable();
186
+ }
187
+ /**
188
+ * Successful authentication events stream.
189
+ * Emits when user successfully authenticates (login, signup, social auth).
190
+ */
191
+ get authSuccess$() {
192
+ return this.authEventsSubject.pipe(filter((e) => e.type === 'auth:success'));
193
+ }
194
+ /**
195
+ * Authentication error events stream.
196
+ * Emits when authentication fails (login error, OAuth error, etc.).
197
+ */
198
+ get authError$() {
199
+ return this.authEventsSubject.pipe(filter((e) => e.type === 'auth:error' || e.type === 'oauth:error'));
200
+ }
201
+ // ============================================================================
202
+ // Sync State Accessors (for guards, templates)
203
+ // ============================================================================
204
+ /**
205
+ * Check if authenticated (sync, uses cached state).
206
+ */
207
+ isAuthenticated() {
208
+ return this.client.isAuthenticatedSync();
209
+ }
210
+ /**
211
+ * Get current user (sync, uses cached state).
212
+ */
213
+ getCurrentUser() {
214
+ return this.client.getCurrentUser();
215
+ }
216
+ /**
217
+ * Get current challenge (sync).
218
+ */
219
+ getCurrentChallenge() {
220
+ return this.challengeSubject.value;
221
+ }
222
+ // ============================================================================
223
+ // Core Auth Methods
224
+ // ============================================================================
225
+ /**
226
+ * Login with identifier and password.
227
+ *
228
+ * @param identifier - User email or username
229
+ * @param password - User password
230
+ * @returns Promise with auth response or challenge
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * const response = await this.auth.login('user@example.com', 'password');
235
+ * if (response.challengeName) {
236
+ * // Handle challenge
237
+ * } else {
238
+ * // Login successful
239
+ * }
240
+ * ```
241
+ */
242
+ async login(identifier, password) {
243
+ const res = await this.client.login(identifier, password);
244
+ return this.updateChallengeState(res);
245
+ }
246
+ /**
247
+ * Signup with credentials.
248
+ *
249
+ * @param payload - Signup request payload
250
+ * @returns Promise with auth response or challenge
251
+ *
252
+ * @example
253
+ * ```typescript
254
+ * const response = await this.auth.signup({
255
+ * email: 'new@example.com',
256
+ * password: 'SecurePass123!',
257
+ * firstName: 'John',
258
+ * });
259
+ * ```
260
+ */
261
+ async signup(payload) {
262
+ const res = await this.client.signup(payload);
263
+ return this.updateChallengeState(res);
264
+ }
265
+ /**
266
+ * Logout current session.
267
+ *
268
+ * @param forgetDevice - If true, removes device trust
269
+ *
270
+ * @example
271
+ * ```typescript
272
+ * await this.auth.logout();
273
+ * ```
274
+ */
275
+ async logout(forgetDevice) {
276
+ await this.client.logout(forgetDevice);
277
+ this.challengeSubject.next(null);
278
+ // Explicitly update auth state after logout
279
+ this.currentUserSubject.next(null);
280
+ this.isAuthenticatedSubject.next(false);
281
+ // Clear CSRF token cookie if in cookies mode
282
+ // Note: Backend should clear httpOnly cookies, but we clear non-httpOnly ones
283
+ if (this.config.tokenDelivery === 'cookies' && typeof document !== 'undefined') {
284
+ const csrfCookieName = this.config.csrf?.cookieName ?? 'nauth_csrf_token';
285
+ // Extract domain from baseUrl if possible
286
+ try {
287
+ const url = new URL(this.config.baseUrl);
288
+ document.cookie = `${csrfCookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${url.hostname}`;
289
+ // Also try without domain (for localhost)
290
+ document.cookie = `${csrfCookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;
291
+ }
292
+ catch {
293
+ // Fallback if baseUrl parsing fails
294
+ document.cookie = `${csrfCookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;
295
+ }
296
+ }
297
+ }
298
+ /**
299
+ * Logout all sessions.
300
+ *
301
+ * Revokes all active sessions for the current user across all devices.
302
+ * Optionally revokes all trusted devices if forgetDevices is true.
303
+ *
304
+ * @param forgetDevices - If true, also revokes all trusted devices (default: false)
305
+ * @returns Promise with number of sessions revoked
306
+ *
307
+ * @example
308
+ * ```typescript
309
+ * const result = await this.auth.logoutAll();
310
+ * console.log(`Revoked ${result.revokedCount} sessions`);
311
+ * ```
312
+ */
313
+ async logoutAll(forgetDevices) {
314
+ const res = await this.client.logoutAll(forgetDevices);
315
+ this.challengeSubject.next(null);
316
+ // Explicitly update auth state after logout
317
+ this.currentUserSubject.next(null);
318
+ this.isAuthenticatedSubject.next(false);
319
+ return res;
320
+ }
321
+ /**
322
+ * Refresh tokens.
323
+ *
324
+ * @returns Promise with new tokens
325
+ *
326
+ * @example
327
+ * ```typescript
328
+ * const tokens = await this.auth.refresh();
329
+ * ```
330
+ */
331
+ async refresh() {
332
+ return this.client.refreshTokens();
333
+ }
334
+ // ============================================================================
335
+ // Account Recovery (Forgot Password)
336
+ // ============================================================================
337
+ /**
338
+ * Request a password reset code (forgot password).
339
+ *
340
+ * @param identifier - User email, username, or phone
341
+ * @returns Promise with password reset response
342
+ *
343
+ * @example
344
+ * ```typescript
345
+ * await this.auth.forgotPassword('user@example.com');
346
+ * ```
347
+ */
348
+ async forgotPassword(identifier) {
349
+ return this.client.forgotPassword(identifier);
350
+ }
351
+ /**
352
+ * Confirm a password reset code and set a new password.
353
+ *
354
+ * @param identifier - User email, username, or phone
355
+ * @param code - One-time reset code
356
+ * @param newPassword - New password
357
+ * @returns Promise with confirmation response
358
+ *
359
+ * @example
360
+ * ```typescript
361
+ * await this.auth.confirmForgotPassword('user@example.com', '123456', 'NewPass123!');
362
+ * ```
363
+ */
364
+ async confirmForgotPassword(identifier, code, newPassword) {
365
+ return this.client.confirmForgotPassword(identifier, code, newPassword);
366
+ }
367
+ /**
368
+ * Change user password (requires current password).
369
+ *
370
+ * @param oldPassword - Current password
371
+ * @param newPassword - New password (must meet requirements)
372
+ * @returns Promise that resolves when password is changed
373
+ *
374
+ * @example
375
+ * ```typescript
376
+ * await this.auth.changePassword('oldPassword123', 'newSecurePassword456!');
377
+ * ```
378
+ */
379
+ async changePassword(oldPassword, newPassword) {
380
+ return this.client.changePassword(oldPassword, newPassword);
381
+ }
382
+ /**
383
+ * Request password change (must change on next login).
384
+ *
385
+ * @returns Promise that resolves when request is sent
386
+ *
387
+ * @example
388
+ * ```typescript
389
+ * await this.auth.requestPasswordChange();
390
+ * ```
391
+ */
392
+ async requestPasswordChange() {
393
+ return this.client.requestPasswordChange();
394
+ }
395
+ // ============================================================================
396
+ // Profile Management
397
+ // ============================================================================
398
+ /**
399
+ * Get current user profile.
400
+ *
401
+ * @returns Promise of current user profile
402
+ *
403
+ * @example
404
+ * ```typescript
405
+ * const user = await this.auth.getProfile();
406
+ * console.log('User profile:', user);
407
+ * ```
408
+ */
409
+ async getProfile() {
410
+ const user = await this.client.getProfile();
411
+ // Update local state when profile is fetched
412
+ this.currentUserSubject.next(user);
413
+ return user;
414
+ }
415
+ /**
416
+ * Update user profile.
417
+ *
418
+ * @param updates - Profile fields to update
419
+ * @returns Promise of updated user profile
420
+ *
421
+ * @example
422
+ * ```typescript
423
+ * const user = await this.auth.updateProfile({ firstName: 'John', lastName: 'Doe' });
424
+ * console.log('Profile updated:', user);
425
+ * ```
426
+ */
427
+ async updateProfile(updates) {
428
+ const user = await this.client.updateProfile(updates);
429
+ // Update local state when profile is updated
430
+ this.currentUserSubject.next(user);
431
+ return user;
432
+ }
433
+ // ============================================================================
434
+ // Challenge Flow Methods (Essential for any auth flow)
435
+ // ============================================================================
436
+ /**
437
+ * Respond to a challenge (VERIFY_EMAIL, VERIFY_PHONE, MFA_REQUIRED, etc.).
438
+ *
439
+ * @param response - Challenge response data
440
+ * @returns Promise with auth response or next challenge
441
+ *
442
+ * @example
443
+ * ```typescript
444
+ * const result = await this.auth.respondToChallenge({
445
+ * session: challengeSession,
446
+ * type: 'VERIFY_EMAIL',
447
+ * code: '123456',
448
+ * });
449
+ * ```
450
+ */
451
+ async respondToChallenge(response) {
452
+ const res = await this.client.respondToChallenge(response);
453
+ return this.updateChallengeState(res);
454
+ }
455
+ /**
456
+ * Resend challenge code.
457
+ *
458
+ * @param session - Challenge session token
459
+ * @returns Promise with destination information
460
+ *
461
+ * @example
462
+ * ```typescript
463
+ * const result = await this.auth.resendCode(session);
464
+ * console.log('Code sent to:', result.destination);
465
+ * ```
466
+ */
467
+ async resendCode(session) {
468
+ return this.client.resendCode(session);
469
+ }
470
+ /**
471
+ * Get MFA setup data (for MFA_SETUP_REQUIRED challenge).
472
+ *
473
+ * Returns method-specific setup information:
474
+ * - TOTP: { secret, qrCode, manualEntryKey }
475
+ * - SMS: { maskedPhone }
476
+ * - Email: { maskedEmail }
477
+ * - Passkey: WebAuthn registration options
478
+ *
479
+ * @param session - Challenge session token
480
+ * @param method - MFA method to set up
481
+ * @returns Promise of setup data response
482
+ *
483
+ * @example
484
+ * ```typescript
485
+ * const setupData = await this.auth.getSetupData(session, 'totp');
486
+ * console.log('QR Code:', setupData.setupData.qrCode);
487
+ * ```
488
+ */
489
+ async getSetupData(session, method) {
490
+ return this.client.getSetupData(session, method);
491
+ }
492
+ /**
493
+ * Get MFA challenge data (for MFA_REQUIRED challenge - e.g., passkey options).
494
+ *
495
+ * @param session - Challenge session token
496
+ * @param method - Challenge method
497
+ * @returns Promise of challenge data response
498
+ *
499
+ * @example
500
+ * ```typescript
501
+ * const challengeData = await this.auth.getChallengeData(session, 'passkey');
502
+ * ```
503
+ */
504
+ async getChallengeData(session, method) {
505
+ return this.client.getChallengeData(session, method);
506
+ }
507
+ /**
508
+ * Clear stored challenge (when navigating away from challenge flow).
509
+ *
510
+ * @returns Promise that resolves when challenge is cleared
511
+ *
512
+ * @example
513
+ * ```typescript
514
+ * await this.auth.clearChallenge();
515
+ * ```
516
+ */
517
+ async clearChallenge() {
518
+ await this.client.clearStoredChallenge();
519
+ this.challengeSubject.next(null);
520
+ }
521
+ // ============================================================================
522
+ // Social Authentication
523
+ // ============================================================================
524
+ /**
525
+ * Initiate social OAuth login flow.
526
+ * Redirects the browser to backend `/auth/social/:provider/redirect`.
527
+ *
528
+ * @param provider - Social provider ('google', 'apple', 'facebook')
529
+ * @param options - Optional redirect options
530
+ * @returns Promise that resolves when redirect starts
531
+ *
532
+ * @example
533
+ * ```typescript
534
+ * await this.auth.loginWithSocial('google', { returnTo: '/auth/callback' });
535
+ * ```
536
+ */
537
+ async loginWithSocial(provider, options) {
538
+ return this.client.loginWithSocial(provider, options);
539
+ }
540
+ /**
541
+ * Exchange an exchangeToken (from redirect callback URL) into an AuthResponse.
542
+ *
543
+ * Used for `tokenDelivery: 'json'` or hybrid flows where the backend redirects back
544
+ * with `exchangeToken` instead of setting cookies.
545
+ *
546
+ * @param exchangeToken - One-time exchange token from the callback URL
547
+ * @returns Promise of AuthResponse
548
+ *
549
+ * @example
550
+ * ```typescript
551
+ * const response = await this.auth.exchangeSocialRedirect(exchangeToken);
552
+ * ```
553
+ */
554
+ async exchangeSocialRedirect(exchangeToken) {
555
+ const res = await this.client.exchangeSocialRedirect(exchangeToken);
556
+ return this.updateChallengeState(res);
557
+ }
558
+ /**
559
+ * Verify native social token (mobile).
560
+ *
561
+ * @param request - Social verification request with provider and token
562
+ * @returns Promise of AuthResponse
563
+ *
564
+ * @example
565
+ * ```typescript
566
+ * const result = await this.auth.verifyNativeSocial({
567
+ * provider: 'google',
568
+ * idToken: nativeIdToken,
569
+ * });
570
+ * ```
571
+ */
572
+ async verifyNativeSocial(request) {
573
+ const res = await this.client.verifyNativeSocial(request);
574
+ return this.updateChallengeState(res);
575
+ }
576
+ /**
577
+ * Get linked social accounts.
578
+ *
579
+ * @returns Promise of linked accounts response
580
+ *
581
+ * @example
582
+ * ```typescript
583
+ * const accounts = await this.auth.getLinkedAccounts();
584
+ * console.log('Linked providers:', accounts.providers);
585
+ * ```
586
+ */
587
+ async getLinkedAccounts() {
588
+ return this.client.getLinkedAccounts();
589
+ }
590
+ /**
591
+ * Link social account.
592
+ *
593
+ * @param provider - Social provider to link
594
+ * @param code - OAuth authorization code
595
+ * @param state - OAuth state parameter
596
+ * @returns Promise with success message
597
+ *
598
+ * @example
599
+ * ```typescript
600
+ * await this.auth.linkSocialAccount('google', code, state);
601
+ * ```
602
+ */
603
+ async linkSocialAccount(provider, code, state) {
604
+ return this.client.linkSocialAccount(provider, code, state);
605
+ }
606
+ /**
607
+ * Unlink social account.
608
+ *
609
+ * @param provider - Social provider to unlink
610
+ * @returns Promise with success message
611
+ *
612
+ * @example
613
+ * ```typescript
614
+ * await this.auth.unlinkSocialAccount('google');
615
+ * ```
616
+ */
617
+ async unlinkSocialAccount(provider) {
618
+ return this.client.unlinkSocialAccount(provider);
619
+ }
620
+ // ============================================================================
621
+ // MFA Management
622
+ // ============================================================================
623
+ /**
624
+ * Get MFA status for the current user.
625
+ *
626
+ * @returns Promise of MFA status
627
+ *
628
+ * @example
629
+ * ```typescript
630
+ * const status = await this.auth.getMfaStatus();
631
+ * console.log('MFA enabled:', status.enabled);
632
+ * ```
633
+ */
634
+ async getMfaStatus() {
635
+ return this.client.getMfaStatus();
636
+ }
637
+ /**
638
+ * Get MFA devices for the current user.
639
+ *
640
+ * @returns Promise of MFA devices array
641
+ *
642
+ * @example
643
+ * ```typescript
644
+ * const devices = await this.auth.getMfaDevices();
645
+ * ```
646
+ */
647
+ async getMfaDevices() {
648
+ return this.client.getMfaDevices();
649
+ }
650
+ /**
651
+ * Setup MFA device (authenticated user).
652
+ *
653
+ * @param method - MFA method to set up
654
+ * @returns Promise of setup data
655
+ *
656
+ * @example
657
+ * ```typescript
658
+ * const setupData = await this.auth.setupMfaDevice('totp');
659
+ * ```
660
+ */
661
+ async setupMfaDevice(method) {
662
+ return this.client.setupMfaDevice(method);
663
+ }
664
+ /**
665
+ * Verify MFA setup (authenticated user).
666
+ *
667
+ * @param method - MFA method
668
+ * @param setupData - Setup data from setupMfaDevice
669
+ * @param deviceName - Optional device name
670
+ * @returns Promise with device ID
671
+ *
672
+ * @example
673
+ * ```typescript
674
+ * const result = await this.auth.verifyMfaSetup('totp', { code: '123456' }, 'My Phone');
675
+ * ```
676
+ */
677
+ async verifyMfaSetup(method, setupData, deviceName) {
678
+ return this.client.verifyMfaSetup(method, setupData, deviceName);
679
+ }
680
+ /**
681
+ * Remove MFA device.
682
+ *
683
+ * @param method - MFA method to remove
684
+ * @returns Promise with success message
685
+ *
686
+ * @example
687
+ * ```typescript
688
+ * await this.auth.removeMfaDevice('sms');
689
+ * ```
690
+ */
691
+ async removeMfaDevice(method) {
692
+ return this.client.removeMfaDevice(method);
693
+ }
694
+ /**
695
+ * Set preferred MFA method.
696
+ *
697
+ * @param method - Device method to set as preferred ('totp', 'sms', 'email', or 'passkey')
698
+ * @returns Promise with success message
699
+ *
700
+ * @example
701
+ * ```typescript
702
+ * await this.auth.setPreferredMfaMethod('totp');
703
+ * ```
704
+ */
705
+ async setPreferredMfaMethod(method) {
706
+ return this.client.setPreferredMfaMethod(method);
707
+ }
708
+ /**
709
+ * Generate backup codes.
710
+ *
711
+ * @returns Promise of backup codes array
712
+ *
713
+ * @example
714
+ * ```typescript
715
+ * const codes = await this.auth.generateBackupCodes();
716
+ * console.log('Backup codes:', codes);
717
+ * ```
718
+ */
719
+ async generateBackupCodes() {
720
+ return this.client.generateBackupCodes();
721
+ }
722
+ /**
723
+ * Set MFA exemption (admin/test scenarios).
724
+ *
725
+ * @param exempt - Whether to exempt user from MFA
726
+ * @param reason - Optional reason for exemption
727
+ * @returns Promise that resolves when exemption is set
728
+ *
729
+ * @example
730
+ * ```typescript
731
+ * await this.auth.setMfaExemption(true, 'Test account');
732
+ * ```
733
+ */
734
+ async setMfaExemption(exempt, reason) {
735
+ return this.client.setMfaExemption(exempt, reason);
736
+ }
737
+ // ============================================================================
738
+ // Device Trust
739
+ // ============================================================================
740
+ /**
741
+ * Trust current device.
742
+ *
743
+ * @returns Promise with device token
744
+ *
745
+ * @example
746
+ * ```typescript
747
+ * const result = await this.auth.trustDevice();
748
+ * console.log('Device trusted:', result.deviceToken);
749
+ * ```
750
+ */
751
+ async trustDevice() {
752
+ return this.client.trustDevice();
753
+ }
754
+ /**
755
+ * Check if the current device is trusted.
756
+ *
757
+ * @returns Promise with trusted status
758
+ *
759
+ * @example
760
+ * ```typescript
761
+ * const result = await this.auth.isTrustedDevice();
762
+ * if (result.trusted) {
763
+ * console.log('This device is trusted');
764
+ * }
765
+ * ```
766
+ */
767
+ async isTrustedDevice() {
768
+ return this.client.isTrustedDevice();
769
+ }
770
+ // ============================================================================
771
+ // Audit History
772
+ // ============================================================================
773
+ /**
774
+ * Get paginated audit history for the current user.
775
+ *
776
+ * @param params - Query parameters for filtering and pagination
777
+ * @returns Promise of audit history response
778
+ *
779
+ * @example
780
+ * ```typescript
781
+ * const history = await this.auth.getAuditHistory({
782
+ * page: 1,
783
+ * limit: 20,
784
+ * eventType: 'LOGIN_SUCCESS'
785
+ * });
786
+ * console.log('Audit history:', history);
787
+ * ```
788
+ */
789
+ async getAuditHistory(params) {
790
+ return this.client.getAuditHistory(params);
791
+ }
792
+ // ============================================================================
793
+ // Escape Hatch
794
+ // ============================================================================
795
+ /**
796
+ * Expose underlying NAuthClient for advanced scenarios.
797
+ *
798
+ * @deprecated All core functionality is now exposed directly on AuthService as Promises.
799
+ * Use the direct methods on AuthService instead (e.g., `auth.changePassword()` instead of `auth.getClient().changePassword()`).
800
+ * This method is kept for backward compatibility only and may be removed in a future version.
801
+ *
802
+ * @returns The underlying NAuthClient instance
803
+ *
804
+ * @example
805
+ * ```typescript
806
+ * // Deprecated - use direct methods instead
807
+ * const status = await this.auth.getClient().getMfaStatus();
808
+ *
809
+ * // Preferred - use direct methods
810
+ * const status = await this.auth.getMfaStatus();
811
+ * ```
812
+ */
813
+ getClient() {
814
+ return this.client;
815
+ }
816
+ // ============================================================================
817
+ // Internal Methods
818
+ // ============================================================================
819
+ /**
820
+ * Initialize by hydrating state from storage.
821
+ * Called automatically on construction.
822
+ */
823
+ async initialize() {
824
+ if (this.initialized)
825
+ return;
826
+ this.initialized = true;
827
+ await this.client.initialize();
828
+ // Hydrate challenge state
829
+ const storedChallenge = await this.client.getStoredChallenge();
830
+ if (storedChallenge) {
831
+ this.challengeSubject.next(storedChallenge);
832
+ }
833
+ // Update subjects from client state
834
+ const user = this.client.getCurrentUser();
835
+ if (user) {
836
+ this.currentUserSubject.next(user);
837
+ this.isAuthenticatedSubject.next(true);
838
+ }
839
+ }
840
+ /**
841
+ * Update challenge state after auth response.
842
+ */
843
+ updateChallengeState(response) {
844
+ if (response.challengeName) {
845
+ this.challengeSubject.next(response);
846
+ }
847
+ else {
848
+ this.challengeSubject.next(null);
849
+ }
850
+ return response;
851
+ }
852
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AuthService, deps: [{ token: NAUTH_CLIENT_CONFIG }, { token: AngularHttpAdapter }], target: i0.ɵɵFactoryTarget.Injectable });
853
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AuthService });
854
+ }
855
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AuthService, decorators: [{
856
+ type: Injectable
857
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
858
+ type: Inject,
859
+ args: [NAUTH_CLIENT_CONFIG]
860
+ }] }, { type: AngularHttpAdapter }] });
861
+
862
+ /**
863
+ * Refresh state management.
864
+ * BehaviorSubject pattern is the industry-standard for token refresh.
865
+ */
866
+ let isRefreshing = false;
867
+ const refreshTokenSubject = new BehaviorSubject(null);
868
+ /**
869
+ * Track retried requests to prevent infinite loops.
870
+ */
871
+ const retriedRequests = new WeakSet();
872
+ /**
873
+ * Get CSRF token from cookie.
874
+ */
875
+ function getCsrfToken(cookieName) {
876
+ if (typeof document === 'undefined')
877
+ return null;
878
+ const match = document.cookie.match(new RegExp(`(^| )${cookieName}=([^;]+)`));
879
+ return match ? decodeURIComponent(match[2]) : null;
880
+ }
881
+ /**
882
+ * Angular HTTP interceptor for nauth-toolkit.
883
+ *
884
+ * Handles:
885
+ * - Cookies mode: withCredentials + CSRF tokens + refresh via POST
886
+ * - JSON mode: refresh via SDK, retry with new token
887
+ */
888
+ const authInterceptor = (req, next) => {
889
+ const config = inject(NAUTH_CLIENT_CONFIG);
890
+ const http = inject(HttpClient);
891
+ const authService = inject(AuthService);
892
+ const platformId = inject(PLATFORM_ID);
893
+ const router = inject(Router);
894
+ const isBrowser = isPlatformBrowser(platformId);
895
+ if (!isBrowser) {
896
+ return next(req);
897
+ }
898
+ const tokenDelivery = config.tokenDelivery;
899
+ const baseUrl = config.baseUrl;
900
+ const endpoints = config.endpoints ?? {};
901
+ const refreshPath = endpoints.refresh ?? '/refresh';
902
+ const loginPath = endpoints.login ?? '/login';
903
+ const signupPath = endpoints.signup ?? '/signup';
904
+ const socialExchangePath = endpoints.socialExchange ?? '/social/exchange';
905
+ const refreshUrl = `${baseUrl}${refreshPath}`;
906
+ const isAuthApiRequest = req.url.includes(baseUrl);
907
+ const isRefreshEndpoint = req.url.includes(refreshPath);
908
+ const isPublicEndpoint = req.url.includes(loginPath) || req.url.includes(signupPath) || req.url.includes(socialExchangePath);
909
+ // Build request with credentials (cookies mode only)
910
+ let authReq = req;
911
+ if (tokenDelivery === 'cookies') {
912
+ authReq = authReq.clone({ withCredentials: true });
913
+ if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {
914
+ const csrfCookieName = config.csrf?.cookieName ?? 'nauth_csrf_token';
915
+ const csrfHeaderName = config.csrf?.headerName ?? 'x-csrf-token';
916
+ const csrfToken = getCsrfToken(csrfCookieName);
917
+ if (csrfToken) {
918
+ authReq = authReq.clone({ setHeaders: { [csrfHeaderName]: csrfToken } });
919
+ }
920
+ }
921
+ }
922
+ return next(authReq).pipe(catchError((error) => {
923
+ const shouldHandle = error instanceof HttpErrorResponse &&
924
+ error.status === 401 &&
925
+ isAuthApiRequest &&
926
+ !isRefreshEndpoint &&
927
+ !isPublicEndpoint &&
928
+ !retriedRequests.has(req);
929
+ if (!shouldHandle) {
930
+ return throwError(() => error);
931
+ }
932
+ if (config.debug) {
933
+ console.warn('[nauth-interceptor] 401 detected:', req.url);
934
+ }
935
+ if (!isRefreshing) {
936
+ isRefreshing = true;
937
+ refreshTokenSubject.next(null);
938
+ if (config.debug) {
939
+ console.warn('[nauth-interceptor] Starting refresh...');
940
+ }
941
+ // Refresh based on mode
942
+ const refresh$ = tokenDelivery === 'cookies'
943
+ ? http.post(refreshUrl, {}, { withCredentials: true })
944
+ : from(authService.refresh());
945
+ return refresh$.pipe(switchMap((response) => {
946
+ if (config.debug) {
947
+ console.warn('[nauth-interceptor] Refresh successful');
948
+ }
949
+ isRefreshing = false;
950
+ // Get new token (JSON mode) or signal success (cookies mode)
951
+ const newToken = 'accessToken' in response ? response.accessToken : 'success';
952
+ refreshTokenSubject.next(newToken ?? 'success');
953
+ // Build retry request
954
+ const retryReq = buildRetryRequest(authReq, tokenDelivery, newToken);
955
+ retriedRequests.add(retryReq);
956
+ if (config.debug) {
957
+ console.warn('[nauth-interceptor] Retrying:', req.url);
958
+ }
959
+ return next(retryReq);
960
+ }), catchError((err) => {
961
+ if (config.debug) {
962
+ console.error('[nauth-interceptor] Refresh failed:', err);
963
+ }
964
+ isRefreshing = false;
965
+ refreshTokenSubject.next(null);
966
+ // Handle session expiration - redirect to configured URL
967
+ if (config.redirects?.sessionExpired) {
968
+ router.navigateByUrl(config.redirects.sessionExpired).catch((navError) => {
969
+ if (config.debug) {
970
+ console.error('[nauth-interceptor] Navigation failed:', navError);
971
+ }
972
+ });
973
+ }
974
+ return throwError(() => err);
975
+ }));
976
+ }
977
+ else {
978
+ // Wait for ongoing refresh
979
+ if (config.debug) {
980
+ console.warn('[nauth-interceptor] Waiting for refresh...');
981
+ }
982
+ return refreshTokenSubject.pipe(filter$1((token) => token !== null), take(1), switchMap((token) => {
983
+ if (config.debug) {
984
+ console.warn('[nauth-interceptor] Refresh done, retrying:', req.url);
985
+ }
986
+ const retryReq = buildRetryRequest(authReq, tokenDelivery, token);
987
+ retriedRequests.add(retryReq);
988
+ return next(retryReq);
989
+ }));
990
+ }
991
+ }));
992
+ };
993
+ /**
994
+ * Build retry request with appropriate auth.
995
+ */
996
+ function buildRetryRequest(originalReq, tokenDelivery, newToken) {
997
+ if (tokenDelivery === 'json' && newToken && newToken !== 'success') {
998
+ return originalReq.clone({
999
+ setHeaders: { Authorization: `Bearer ${newToken}` },
1000
+ });
1001
+ }
1002
+ return originalReq.clone();
1003
+ }
1004
+ /**
1005
+ * Class-based interceptor for NgModule compatibility.
1006
+ */
1007
+ class AuthInterceptor {
1008
+ intercept(req, next) {
1009
+ return authInterceptor(req, next);
1010
+ }
1011
+ }
1012
+
1013
+ /**
1014
+ * Functional route guard for authentication (Angular 17+).
1015
+ *
1016
+ * Protects routes by checking if user is authenticated.
1017
+ * Redirects to login page if not authenticated.
1018
+ *
1019
+ * @param redirectTo - Path to redirect to if not authenticated (default: '/login')
1020
+ * @returns CanActivateFn guard function
1021
+ *
1022
+ * @example
1023
+ * ```typescript
1024
+ * // In route configuration
1025
+ * const routes: Routes = [
1026
+ * {
1027
+ * path: 'home',
1028
+ * component: HomeComponent,
1029
+ * canActivate: [authGuard()]
1030
+ * },
1031
+ * {
1032
+ * path: 'admin',
1033
+ * component: AdminComponent,
1034
+ * canActivate: [authGuard('/admin/login')]
1035
+ * }
1036
+ * ];
1037
+ * ```
1038
+ */
1039
+ function authGuard(redirectTo = '/login') {
1040
+ return () => {
1041
+ const auth = inject(AuthService);
1042
+ const router = inject(Router);
1043
+ if (auth.isAuthenticated()) {
1044
+ return true;
1045
+ }
1046
+ return router.createUrlTree([redirectTo]);
1047
+ };
1048
+ }
1049
+ /**
1050
+ * Class-based authentication guard for NgModule compatibility.
1051
+ *
1052
+ * @example
1053
+ * ```typescript
1054
+ * // In route configuration (NgModule)
1055
+ * const routes: Routes = [
1056
+ * {
1057
+ * path: 'home',
1058
+ * component: HomeComponent,
1059
+ * canActivate: [AuthGuard]
1060
+ * }
1061
+ * ];
1062
+ *
1063
+ * // In module providers
1064
+ * @NgModule({
1065
+ * providers: [AuthGuard]
1066
+ * })
1067
+ * ```
1068
+ */
1069
+ class AuthGuard {
1070
+ auth;
1071
+ router;
1072
+ /**
1073
+ * @param auth - Authentication service
1074
+ * @param router - Angular router
1075
+ */
1076
+ constructor(auth, router) {
1077
+ this.auth = auth;
1078
+ this.router = router;
1079
+ }
1080
+ /**
1081
+ * Check if route can be activated.
1082
+ *
1083
+ * @returns True if authenticated, otherwise redirects to login
1084
+ */
1085
+ canActivate() {
1086
+ if (this.auth.isAuthenticated()) {
1087
+ return true;
1088
+ }
1089
+ return this.router.createUrlTree(['/login']);
1090
+ }
1091
+ }
1092
+
1093
+ /**
1094
+ * Social redirect callback route guard.
1095
+ *
1096
+ * This guard supports the redirect-first social flow where the backend redirects
1097
+ * back to the frontend with:
1098
+ * - `appState` (always optional)
1099
+ * - `exchangeToken` (present for json/hybrid flows, and for cookie flows that return a challenge)
1100
+ * - `error` / `error_description` (provider errors)
1101
+ *
1102
+ * Behavior:
1103
+ * - If `exchangeToken` exists: exchanges it via backend and redirects to success or challenge routes.
1104
+ * - If no `exchangeToken`: treat as cookie-success path and redirect to success route.
1105
+ * - If `error` exists: redirects to oauthError route.
1106
+ *
1107
+ * @example
1108
+ * ```typescript
1109
+ * import { socialRedirectCallbackGuard } from '@nauth-toolkit/client/angular';
1110
+ *
1111
+ * export const routes: Routes = [
1112
+ * { path: 'auth/callback', canActivate: [socialRedirectCallbackGuard], component: CallbackComponent },
1113
+ * ];
1114
+ * ```
1115
+ */
1116
+ const socialRedirectCallbackGuard = async () => {
1117
+ const auth = inject(AuthService);
1118
+ const config = inject(NAUTH_CLIENT_CONFIG);
1119
+ const platformId = inject(PLATFORM_ID);
1120
+ const isBrowser = isPlatformBrowser(platformId);
1121
+ if (!isBrowser) {
1122
+ return false;
1123
+ }
1124
+ const params = new URLSearchParams(window.location.search);
1125
+ const error = params.get('error');
1126
+ const exchangeToken = params.get('exchangeToken');
1127
+ // Provider error: redirect to oauthError
1128
+ if (error) {
1129
+ const errorUrl = config.redirects?.oauthError || '/login';
1130
+ window.location.replace(errorUrl);
1131
+ return false;
1132
+ }
1133
+ // No exchangeToken: cookie success path; redirect to success.
1134
+ //
1135
+ // Note: we do not "activate" the callback route to avoid consumers needing to render a page.
1136
+ if (!exchangeToken) {
1137
+ // ============================================================================
1138
+ // Cookies mode: hydrate user state before redirecting
1139
+ // ============================================================================
1140
+ // WHY: In cookie delivery, the OAuth callback completes via browser redirects, so the frontend
1141
+ // does not receive a JSON AuthResponse to populate the SDK's cached `currentUser`.
1142
+ //
1143
+ // Without this, sync guards (`authGuard`) can immediately redirect to /login because
1144
+ // `currentUser` is still null even though cookies were set successfully.
1145
+ try {
1146
+ await auth.getProfile();
1147
+ }
1148
+ catch {
1149
+ const errorUrl = config.redirects?.oauthError || '/login';
1150
+ window.location.replace(errorUrl);
1151
+ return false;
1152
+ }
1153
+ const successUrl = config.redirects?.success || '/';
1154
+ window.location.replace(successUrl);
1155
+ return false;
1156
+ }
1157
+ // Exchange token and route accordingly
1158
+ const response = await auth.exchangeSocialRedirect(exchangeToken);
1159
+ if (response.challengeName) {
1160
+ const challengeBase = config.redirects?.challengeBase || '/auth/challenge';
1161
+ const challengeRoute = response.challengeName.toLowerCase().replace(/_/g, '-');
1162
+ window.location.replace(`${challengeBase}/${challengeRoute}`);
1163
+ return false;
1164
+ }
1165
+ const successUrl = config.redirects?.success || '/';
1166
+ window.location.replace(successUrl);
1167
+ return false;
1168
+ };
1169
+
1170
+ /**
1171
+ * Public API Surface of @nauth-toolkit/client-angular/standalone
1172
+ *
1173
+ * This entry point is for standalone component-based Angular apps (Angular 14+).
1174
+ * For NgModule apps, use: @nauth-toolkit/client-angular
1175
+ */
1176
+ // Re-export core client types and utilities
1177
+
1178
+ /**
1179
+ * Generated bundle index. Do not edit.
1180
+ */
1181
+
1182
+ export { AngularHttpAdapter, AuthGuard, AuthInterceptor, AuthService, NAUTH_CLIENT_CONFIG, authGuard, authInterceptor, socialRedirectCallbackGuard };
1183
+ //# sourceMappingURL=nauth-toolkit-client-angular-standalone.mjs.map