@opensourcekd/ng-common-libs 2.0.10 → 2.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -413,6 +413,7 @@ declare function buildUserData(userInfo: UserInfo): UserData;
413
413
  declare class AuthService {
414
414
  private auth0Client;
415
415
  private initializationPromise;
416
+ /** Remains false if callback processing fails, allowing the callback to be retried. */
416
417
  private callbackHandled;
417
418
  private callbackPromise;
418
419
  private userSubject;
@@ -447,6 +448,13 @@ declare class AuthService {
447
448
  * @throws {Error} When required config fields (domain, clientId) are missing
448
449
  */
449
450
  private initializeAuth0;
451
+ /**
452
+ * Ensure the Auth0 client instance is created, without triggering callback detection.
453
+ * Used internally by {@link handleCallback} to avoid a circular async dependency:
454
+ * `ensureInitialized` → `checkAndHandleCallback` → `handleCallback` → `ensureInitialized`.
455
+ * @throws {Error} When the Auth0 client fails to initialize
456
+ */
457
+ private ensureAuth0Client;
450
458
  /**
451
459
  * Ensure the Auth0 client is initialized before use
452
460
  * Lazy-initializes on the first call and auto-handles OAuth callbacks when detected
@@ -459,6 +467,10 @@ declare class AuthService {
459
467
  * The Auth0 SDK's `handleRedirectCallback` validates the `state` parameter
460
468
  * to prevent CSRF attacks. This method only detects presence of callback
461
469
  * params before delegating securely to the SDK.
470
+ *
471
+ * Uses an async IIFE to store the in-flight promise for concurrency deduplication
472
+ * (concurrent callers await the same promise) while still using async/await
473
+ * internally instead of `.then()/.catch()` chains.
462
474
  */
463
475
  private checkAndHandleCallback;
464
476
  /**
@@ -474,11 +486,20 @@ declare class AuthService {
474
486
  /**
475
487
  * Handle the OAuth2 redirect callback after successful authorization
476
488
  * Stores the user info and access token, then cleans up the callback URL
489
+ *
490
+ * Uses {@link ensureAuth0Client} (not {@link ensureInitialized}) to avoid a circular
491
+ * async dependency: `ensureInitialized` → `checkAndHandleCallback` → `handleCallback`
492
+ * → `ensureInitialized`. Only the Auth0 client instance is needed here.
477
493
  * @returns {@link CallbackResult} with `success` flag and optional `appState`
478
494
  */
479
495
  handleCallback(): Promise<CallbackResult>;
480
496
  /**
481
497
  * Log the user out, clear all stored auth data, and redirect to the logout URI
498
+ *
499
+ * Uses {@link ensureAuth0Client} (not {@link ensureInitialized}) to avoid triggering
500
+ * callback detection during logout. Calling `ensureInitialized` here would invoke
501
+ * `checkAndHandleCallback`, which re-authenticates the user if callback URL params
502
+ * are present, causing them to be sent back to Auth0 instead of the logout URI.
482
503
  */
483
504
  logout(): Promise<void>;
484
505
  /**
package/dist/index.mjs CHANGED
@@ -446,6 +446,7 @@ function e(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o
446
446
  class AuthService {
447
447
  auth0Client = null;
448
448
  initializationPromise = null;
449
+ /** Remains false if callback processing fails, allowing the callback to be retried. */
449
450
  callbackHandled = false;
450
451
  callbackPromise = null;
451
452
  userSubject;
@@ -480,6 +481,14 @@ class AuthService {
480
481
  const existingUserInfo = this.getUserInfoFromStorage();
481
482
  this.userSubject = new BehaviorSubject(existingUserInfo);
482
483
  this.user$ = this.userSubject.asObservable();
484
+ // Eagerly begin Auth0 client initialization so logs are visible immediately.
485
+ // The .catch() only suppresses an unhandled-rejection warning; the rejected
486
+ // promise is stored in initializationPromise and re-throws when awaited by
487
+ // ensureInitialized() or ensureAuth0Client(), surfacing the error to callers.
488
+ this.initializationPromise = this.initializeAuth0();
489
+ this.initializationPromise.catch(error => {
490
+ console.error('[AuthService] Failed to initialize Auth0 client:', error);
491
+ });
483
492
  }
484
493
  /**
485
494
  * Get the identifier of this AuthService instance
@@ -519,6 +528,25 @@ class AuthService {
519
528
  console.log('[AuthService] Auth0 client initialized successfully');
520
529
  this.emitAuthEvent('init', null);
521
530
  }
531
+ /**
532
+ * Ensure the Auth0 client instance is created, without triggering callback detection.
533
+ * Used internally by {@link handleCallback} to avoid a circular async dependency:
534
+ * `ensureInitialized` → `checkAndHandleCallback` → `handleCallback` → `ensureInitialized`.
535
+ * @throws {Error} When the Auth0 client fails to initialize
536
+ */
537
+ async ensureAuth0Client() {
538
+ if (this.auth0Client)
539
+ return;
540
+ if (this.initializationPromise) {
541
+ await this.initializationPromise;
542
+ return;
543
+ }
544
+ this.initializationPromise = this.initializeAuth0();
545
+ await this.initializationPromise;
546
+ if (!this.auth0Client) {
547
+ throw new Error('[AuthService] Auth0 client failed to initialize');
548
+ }
549
+ }
522
550
  /**
523
551
  * Ensure the Auth0 client is initialized before use
524
552
  * Lazy-initializes on the first call and auto-handles OAuth callbacks when detected
@@ -547,6 +575,10 @@ class AuthService {
547
575
  * The Auth0 SDK's `handleRedirectCallback` validates the `state` parameter
548
576
  * to prevent CSRF attacks. This method only detects presence of callback
549
577
  * params before delegating securely to the SDK.
578
+ *
579
+ * Uses an async IIFE to store the in-flight promise for concurrency deduplication
580
+ * (concurrent callers await the same promise) while still using async/await
581
+ * internally instead of `.then()/.catch()` chains.
550
582
  */
551
583
  async checkAndHandleCallback() {
552
584
  if (this.callbackHandled || typeof window === 'undefined')
@@ -556,15 +588,22 @@ class AuthService {
556
588
  return;
557
589
  }
558
590
  const urlParams = new URLSearchParams(window.location.search);
559
- if (urlParams.has('code') && urlParams.has('state')) {
560
- console.log('[AuthService] Auth0 callback detected in URL, processing...');
561
- this.emitAuthEvent('callback_detected', null);
562
- this.callbackPromise = this.handleCallback()
563
- .then(() => { this.callbackHandled = true; })
564
- .catch(error => { throw error; })
565
- .finally(() => { this.callbackPromise = null; });
591
+ if (!urlParams.has('code') || !urlParams.has('state'))
592
+ return;
593
+ console.log('[AuthService] Auth0 callback detected in URL, processing...');
594
+ this.emitAuthEvent('callback_detected', null);
595
+ // Store the promise before the first await so concurrent callers see it
596
+ // and deduplicate by awaiting the same in-flight promise.
597
+ this.callbackPromise = (async () => {
598
+ await this.handleCallback();
599
+ this.callbackHandled = true;
600
+ })();
601
+ try {
566
602
  await this.callbackPromise;
567
603
  }
604
+ finally {
605
+ this.callbackPromise = null;
606
+ }
568
607
  }
569
608
  /**
570
609
  * Redirect the user to Auth0 Universal Login
@@ -601,11 +640,15 @@ class AuthService {
601
640
  /**
602
641
  * Handle the OAuth2 redirect callback after successful authorization
603
642
  * Stores the user info and access token, then cleans up the callback URL
643
+ *
644
+ * Uses {@link ensureAuth0Client} (not {@link ensureInitialized}) to avoid a circular
645
+ * async dependency: `ensureInitialized` → `checkAndHandleCallback` → `handleCallback`
646
+ * → `ensureInitialized`. Only the Auth0 client instance is needed here.
604
647
  * @returns {@link CallbackResult} with `success` flag and optional `appState`
605
648
  */
606
649
  async handleCallback() {
607
650
  try {
608
- await this.ensureInitialized();
651
+ await this.ensureAuth0Client();
609
652
  console.log('[AuthService] Processing Auth0 redirect callback...');
610
653
  const result = await this.auth0Client.handleRedirectCallback();
611
654
  const user = await this.auth0Client.getUser();
@@ -629,6 +672,11 @@ class AuthService {
629
672
  }
630
673
  /**
631
674
  * Log the user out, clear all stored auth data, and redirect to the logout URI
675
+ *
676
+ * Uses {@link ensureAuth0Client} (not {@link ensureInitialized}) to avoid triggering
677
+ * callback detection during logout. Calling `ensureInitialized` here would invoke
678
+ * `checkAndHandleCallback`, which re-authenticates the user if callback URL params
679
+ * are present, causing them to be sent back to Auth0 instead of the logout URI.
632
680
  */
633
681
  async logout() {
634
682
  console.log('[AuthService] User logging out...');
@@ -638,7 +686,7 @@ class AuthService {
638
686
  this.userSubject.next(null);
639
687
  this.emitAuthEvent('logout', null);
640
688
  try {
641
- await this.ensureInitialized();
689
+ await this.ensureAuth0Client();
642
690
  await this.auth0Client.logout({
643
691
  logoutParams: { returnTo: this.config.logoutUri }
644
692
  });