@nauth-toolkit/client 0.1.58 → 0.1.59
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.cjs +172 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +276 -56
- package/dist/index.d.ts +276 -56
- package/dist/index.mjs +171 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -25,6 +25,7 @@ __export(index_exports, {
|
|
|
25
25
|
AuthAuditEventType: () => AuthAuditEventType,
|
|
26
26
|
AuthChallenge: () => AuthChallenge,
|
|
27
27
|
BrowserStorage: () => BrowserStorage,
|
|
28
|
+
ChallengeRouter: () => ChallengeRouter,
|
|
28
29
|
EventEmitter: () => EventEmitter,
|
|
29
30
|
FetchAdapter: () => FetchAdapter,
|
|
30
31
|
InMemoryStorage: () => InMemoryStorage,
|
|
@@ -562,6 +563,155 @@ var FetchAdapter = class {
|
|
|
562
563
|
}
|
|
563
564
|
};
|
|
564
565
|
|
|
566
|
+
// src/core/challenge-router.ts
|
|
567
|
+
var ChallengeRouter = class {
|
|
568
|
+
constructor(config) {
|
|
569
|
+
this.config = config;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Handle auth response - either call callback or auto-navigate.
|
|
573
|
+
*
|
|
574
|
+
* @param response - Auth response from backend
|
|
575
|
+
* @param context - Context about the auth operation
|
|
576
|
+
*/
|
|
577
|
+
async handleAuthResponse(response, context) {
|
|
578
|
+
if (this.config.onAuthResponse) {
|
|
579
|
+
await this.config.onAuthResponse(response, context);
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
if (response.challengeName) {
|
|
583
|
+
await this.navigateToChallenge(response);
|
|
584
|
+
} else {
|
|
585
|
+
await this.navigateToSuccess();
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Navigate to appropriate challenge route.
|
|
590
|
+
*
|
|
591
|
+
* @param response - Auth response containing challenge info
|
|
592
|
+
*/
|
|
593
|
+
async navigateToChallenge(response) {
|
|
594
|
+
const url = this.buildChallengeUrl(response);
|
|
595
|
+
await this.navigate(url);
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Navigate to success URL.
|
|
599
|
+
*/
|
|
600
|
+
async navigateToSuccess() {
|
|
601
|
+
const url = this.config.redirects?.success || "/";
|
|
602
|
+
await this.navigate(url);
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Navigate to error URL.
|
|
606
|
+
*
|
|
607
|
+
* @param type - Type of error (oauth or session)
|
|
608
|
+
*/
|
|
609
|
+
async navigateToError(type) {
|
|
610
|
+
const url = type === "oauth" ? this.config.redirects?.oauthError || "/login" : this.config.redirects?.sessionExpired || "/login";
|
|
611
|
+
await this.navigate(url);
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Build challenge URL based on configuration.
|
|
615
|
+
*
|
|
616
|
+
* Priority:
|
|
617
|
+
* 1. Custom route mapping (challengeRoutes)
|
|
618
|
+
* 2. Single route with query param (useSingleChallengeRoute)
|
|
619
|
+
* 3. MFA-specific routes (mfaRoutes) - for MFA_REQUIRED challenge only
|
|
620
|
+
* 4. Default separate routes (challengeBase + kebab-case)
|
|
621
|
+
*
|
|
622
|
+
* @param response - Auth response containing challenge info
|
|
623
|
+
* @returns URL to navigate to
|
|
624
|
+
*/
|
|
625
|
+
buildChallengeUrl(response) {
|
|
626
|
+
const challengeName = response.challengeName;
|
|
627
|
+
if (this.config.redirects?.challengeRoutes?.[challengeName]) {
|
|
628
|
+
return this.config.redirects.challengeRoutes[challengeName];
|
|
629
|
+
}
|
|
630
|
+
const base = this.config.redirects?.challengeBase || "/auth/challenge";
|
|
631
|
+
if (this.config.redirects?.useSingleChallengeRoute) {
|
|
632
|
+
return `${base}?challenge=${challengeName}`;
|
|
633
|
+
}
|
|
634
|
+
if (challengeName === "MFA_REQUIRED" /* MFA_REQUIRED */) {
|
|
635
|
+
const mfaUrl = this.buildMFAUrl(response);
|
|
636
|
+
if (mfaUrl) {
|
|
637
|
+
return mfaUrl;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
const route = this.buildDefaultRouteSegment(challengeName, response);
|
|
641
|
+
return `${base}/${route}`;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Build MFA-specific URL if custom mfaRoutes are configured.
|
|
645
|
+
*
|
|
646
|
+
* @param response - Auth response with MFA challenge parameters
|
|
647
|
+
* @returns Custom MFA URL if configured, null otherwise
|
|
648
|
+
*/
|
|
649
|
+
buildMFAUrl(response) {
|
|
650
|
+
const params = response.challengeParameters;
|
|
651
|
+
const method = params?.["preferredMethod"] || params?.["method"];
|
|
652
|
+
const mfaRoutes = this.config.redirects?.mfaRoutes;
|
|
653
|
+
if (!mfaRoutes) {
|
|
654
|
+
return null;
|
|
655
|
+
}
|
|
656
|
+
if (method === "passkey" && mfaRoutes.passkey) {
|
|
657
|
+
return mfaRoutes.passkey;
|
|
658
|
+
}
|
|
659
|
+
if (!method && params?.["availableMethods"] && Array.isArray(params["availableMethods"]) && params["availableMethods"].length > 1) {
|
|
660
|
+
if (mfaRoutes.selector) {
|
|
661
|
+
return mfaRoutes.selector;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if (mfaRoutes.default) {
|
|
665
|
+
return mfaRoutes.default;
|
|
666
|
+
}
|
|
667
|
+
return null;
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Build default route segment for a challenge.
|
|
671
|
+
*
|
|
672
|
+
* @param challengeName - Challenge type
|
|
673
|
+
* @param response - Auth response for extracting challenge parameters (needed for MFA)
|
|
674
|
+
* @returns Route segment (e.g., 'mfa-required/passkey', 'verify-email')
|
|
675
|
+
*/
|
|
676
|
+
buildDefaultRouteSegment(challengeName, response) {
|
|
677
|
+
if (challengeName === "MFA_REQUIRED" /* MFA_REQUIRED */ && response) {
|
|
678
|
+
const params = response.challengeParameters;
|
|
679
|
+
const method = params?.["preferredMethod"] || params?.["method"];
|
|
680
|
+
if (method === "passkey") {
|
|
681
|
+
return "mfa-required/passkey";
|
|
682
|
+
}
|
|
683
|
+
if (!method && params?.["availableMethods"] && Array.isArray(params["availableMethods"]) && params["availableMethods"].length > 1) {
|
|
684
|
+
return "mfa-selector";
|
|
685
|
+
}
|
|
686
|
+
return "mfa-required";
|
|
687
|
+
}
|
|
688
|
+
return challengeName.toLowerCase().replace(/_/g, "-");
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Execute navigation using configured handler or default.
|
|
692
|
+
*
|
|
693
|
+
* @param url - URL to navigate to
|
|
694
|
+
*/
|
|
695
|
+
async navigate(url) {
|
|
696
|
+
if (this.config.navigationHandler) {
|
|
697
|
+
await this.config.navigationHandler(url);
|
|
698
|
+
} else {
|
|
699
|
+
if (typeof window !== "undefined") {
|
|
700
|
+
window.location.replace(url);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Expose URL builder for guards/components that need it.
|
|
706
|
+
*
|
|
707
|
+
* @param response - Auth response containing challenge info
|
|
708
|
+
* @returns URL for the challenge
|
|
709
|
+
*/
|
|
710
|
+
getChallengeUrl(response) {
|
|
711
|
+
return this.buildChallengeUrl(response);
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
|
|
565
715
|
// src/core/client.ts
|
|
566
716
|
var USER_KEY2 = "nauth_user";
|
|
567
717
|
var CHALLENGE_KEY2 = "nauth_challenge_session";
|
|
@@ -582,6 +732,7 @@ var NAuthClient = class {
|
|
|
582
732
|
__publicField(this, "config");
|
|
583
733
|
__publicField(this, "tokenManager");
|
|
584
734
|
__publicField(this, "eventEmitter");
|
|
735
|
+
__publicField(this, "challengeRouter");
|
|
585
736
|
__publicField(this, "currentUser", null);
|
|
586
737
|
/**
|
|
587
738
|
* Handle cross-tab storage updates.
|
|
@@ -600,6 +751,7 @@ var NAuthClient = class {
|
|
|
600
751
|
this.config = resolveConfig({ ...userConfig, storage }, defaultAdapter);
|
|
601
752
|
this.tokenManager = new TokenManager(storage);
|
|
602
753
|
this.eventEmitter = new EventEmitter();
|
|
754
|
+
this.challengeRouter = new ChallengeRouter(this.config);
|
|
603
755
|
if (hasWindow()) {
|
|
604
756
|
window.addEventListener("storage", this.handleStorageEvent);
|
|
605
757
|
}
|
|
@@ -629,6 +781,7 @@ var NAuthClient = class {
|
|
|
629
781
|
const successEvent = { type: "auth:success", data: response, timestamp: Date.now() };
|
|
630
782
|
this.eventEmitter.emit(successEvent);
|
|
631
783
|
}
|
|
784
|
+
await this.challengeRouter.handleAuthResponse(response, { source: "login" });
|
|
632
785
|
return response;
|
|
633
786
|
} catch (error) {
|
|
634
787
|
const authError = error instanceof NAuthClientError ? error : new NAuthClientError("AUTH_INVALID_CREDENTIALS" /* AUTH_INVALID_CREDENTIALS */, error.message || "Login failed");
|
|
@@ -650,6 +803,7 @@ var NAuthClient = class {
|
|
|
650
803
|
} else {
|
|
651
804
|
this.eventEmitter.emit({ type: "auth:success", data: response, timestamp: Date.now() });
|
|
652
805
|
}
|
|
806
|
+
await this.challengeRouter.handleAuthResponse(response, { source: "signup" });
|
|
653
807
|
return response;
|
|
654
808
|
} catch (error) {
|
|
655
809
|
const authError = error instanceof NAuthClientError ? error : new NAuthClientError("AUTH_INVALID_CREDENTIALS" /* AUTH_INVALID_CREDENTIALS */, error.message || "Signup failed");
|
|
@@ -779,6 +933,7 @@ var NAuthClient = class {
|
|
|
779
933
|
const successEvent = { type: "auth:success", data: result, timestamp: Date.now() };
|
|
780
934
|
this.eventEmitter.emit(successEvent);
|
|
781
935
|
}
|
|
936
|
+
await this.challengeRouter.handleAuthResponse(result, { source: "challenge" });
|
|
782
937
|
return result;
|
|
783
938
|
} catch (error) {
|
|
784
939
|
const authError = error instanceof NAuthClientError ? error : new NAuthClientError(
|
|
@@ -1026,6 +1181,7 @@ var NAuthClient = class {
|
|
|
1026
1181
|
}
|
|
1027
1182
|
const result = await this.post(this.config.endpoints.socialExchange, { exchangeToken: token });
|
|
1028
1183
|
await this.handleAuthResponse(result);
|
|
1184
|
+
await this.challengeRouter.handleAuthResponse(result, { source: "social" });
|
|
1029
1185
|
return result;
|
|
1030
1186
|
}
|
|
1031
1187
|
/**
|
|
@@ -1379,6 +1535,21 @@ var NAuthClient = class {
|
|
|
1379
1535
|
});
|
|
1380
1536
|
return response.data;
|
|
1381
1537
|
}
|
|
1538
|
+
/**
|
|
1539
|
+
* Get challenge router for manual navigation control.
|
|
1540
|
+
* Useful for guards that need to handle errors or build custom URLs.
|
|
1541
|
+
*
|
|
1542
|
+
* @returns ChallengeRouter instance
|
|
1543
|
+
*
|
|
1544
|
+
* @example
|
|
1545
|
+
* ```typescript
|
|
1546
|
+
* const router = client.getChallengeRouter();
|
|
1547
|
+
* await router.navigateToError('oauth');
|
|
1548
|
+
* ```
|
|
1549
|
+
*/
|
|
1550
|
+
getChallengeRouter() {
|
|
1551
|
+
return this.challengeRouter;
|
|
1552
|
+
}
|
|
1382
1553
|
};
|
|
1383
1554
|
|
|
1384
1555
|
// src/core/challenge-helpers.ts
|
|
@@ -1427,6 +1598,7 @@ function isOTPChallenge(challenge) {
|
|
|
1427
1598
|
AuthAuditEventType,
|
|
1428
1599
|
AuthChallenge,
|
|
1429
1600
|
BrowserStorage,
|
|
1601
|
+
ChallengeRouter,
|
|
1430
1602
|
EventEmitter,
|
|
1431
1603
|
FetchAdapter,
|
|
1432
1604
|
InMemoryStorage,
|