@insforge/sdk 1.1.2-pkce.0 → 1.1.2-pkce.1

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.js CHANGED
@@ -343,21 +343,12 @@ var TokenManager = class {
343
343
  }
344
344
  };
345
345
 
346
- // src/modules/auth.ts
347
- function isHostedAuthEnvironment() {
348
- if (typeof window === "undefined") {
349
- return false;
350
- }
351
- const { hostname, port, protocol } = window.location;
352
- if (hostname === "localhost" && port === "7130") {
353
- return true;
354
- }
355
- if (protocol === "https:" && hostname.endsWith(".insforge.app")) {
356
- return true;
357
- }
358
- return false;
359
- }
346
+ // src/modules/auth/helpers.ts
360
347
  var PKCE_VERIFIER_KEY = "insforge_pkce_verifier";
348
+ function base64UrlEncode(buffer) {
349
+ const base64 = btoa(String.fromCharCode(...buffer));
350
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
351
+ }
361
352
  function generateCodeVerifier() {
362
353
  const array = new Uint8Array(32);
363
354
  crypto.getRandomValues(array);
@@ -369,10 +360,6 @@ async function generateCodeChallenge(verifier) {
369
360
  const hash = await crypto.subtle.digest("SHA-256", data);
370
361
  return base64UrlEncode(new Uint8Array(hash));
371
362
  }
372
- function base64UrlEncode(buffer) {
373
- const base64 = btoa(String.fromCharCode(...buffer));
374
- return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
375
- }
376
363
  function storePkceVerifier(verifier) {
377
364
  if (typeof sessionStorage !== "undefined") {
378
365
  sessionStorage.setItem(PKCE_VERIFIER_KEY, verifier);
@@ -388,6 +375,42 @@ function retrievePkceVerifier() {
388
375
  }
389
376
  return verifier;
390
377
  }
378
+ function isHostedAuthEnvironment() {
379
+ if (typeof window === "undefined") {
380
+ return false;
381
+ }
382
+ const { hostname, port, protocol } = window.location;
383
+ if (hostname === "localhost" && port === "7130") {
384
+ return true;
385
+ }
386
+ if (protocol === "https:" && hostname.endsWith(".insforge.app")) {
387
+ return true;
388
+ }
389
+ return false;
390
+ }
391
+ function wrapError(error, fallbackMessage) {
392
+ if (error instanceof InsForgeError) {
393
+ return { data: null, error };
394
+ }
395
+ return {
396
+ data: null,
397
+ error: new InsForgeError(
398
+ error instanceof Error ? error.message : fallbackMessage,
399
+ 500,
400
+ "UNEXPECTED_ERROR"
401
+ )
402
+ };
403
+ }
404
+ function cleanUrlParams(...params) {
405
+ if (typeof window === "undefined") {
406
+ return;
407
+ }
408
+ const url = new URL(window.location.href);
409
+ params.forEach((p) => url.searchParams.delete(p));
410
+ window.history.replaceState({}, document.title, url.toString());
411
+ }
412
+
413
+ // src/modules/auth/auth.ts
391
414
  var Auth = class {
392
415
  constructor(http, tokenManager) {
393
416
  this.http = http;
@@ -395,12 +418,31 @@ var Auth = class {
395
418
  this.authCallbackHandled = this.detectAuthCallback();
396
419
  }
397
420
  /**
398
- * Automatically detect and handle OAuth callback parameters in the URL
399
- * This runs after initialization to seamlessly complete the OAuth flow
400
- *
401
- * Supports two flows:
402
- * - PKCE flow (new): Backend returns `insforge_code` param, exchanged for tokens
403
- * - Legacy flow: Backend returns tokens directly in URL (backward compatible)
421
+ * Save session from API response
422
+ * Handles token storage, CSRF token, and HTTP client auth header
423
+ */
424
+ saveSessionFromResponse(response) {
425
+ if (isHostedAuthEnvironment() || !response.accessToken || !response.user) {
426
+ return false;
427
+ }
428
+ const session = {
429
+ accessToken: response.accessToken,
430
+ user: response.user
431
+ };
432
+ if (response.csrfToken) {
433
+ this.tokenManager.setMemoryMode();
434
+ setCsrfToken(response.csrfToken);
435
+ }
436
+ this.tokenManager.saveSession(session);
437
+ this.http.setAuthToken(response.accessToken);
438
+ return true;
439
+ }
440
+ // ============================================================================
441
+ // OAuth Callback Detection (runs on initialization)
442
+ // ============================================================================
443
+ /**
444
+ * Detect and handle OAuth callback parameters in URL
445
+ * Supports PKCE flow (insforge_code) and legacy flow (access_token in URL)
404
446
  */
405
447
  async detectAuthCallback() {
406
448
  if (typeof window === "undefined") return;
@@ -408,17 +450,13 @@ var Auth = class {
408
450
  const params = new URLSearchParams(window.location.search);
409
451
  const error = params.get("error");
410
452
  if (error) {
411
- const url = new URL(window.location.href);
412
- url.searchParams.delete("error");
413
- window.history.replaceState({}, document.title, url.toString());
453
+ cleanUrlParams("error");
414
454
  console.debug("OAuth callback error:", error);
415
455
  return;
416
456
  }
417
457
  const code = params.get("insforge_code");
418
458
  if (code) {
419
- const url = new URL(window.location.href);
420
- url.searchParams.delete("insforge_code");
421
- window.history.replaceState({}, document.title, url.toString());
459
+ cleanUrlParams("insforge_code");
422
460
  const { error: exchangeError } = await this.exchangeOAuthCode(code);
423
461
  if (exchangeError) {
424
462
  console.debug("OAuth code exchange failed:", exchangeError.message);
@@ -428,9 +466,9 @@ var Auth = class {
428
466
  const accessToken = params.get("access_token");
429
467
  const userId = params.get("user_id");
430
468
  const email = params.get("email");
431
- const name = params.get("name");
432
- const csrfToken = params.get("csrf_token");
433
469
  if (accessToken && userId && email) {
470
+ const csrfToken = params.get("csrf_token");
471
+ const name = params.get("name");
434
472
  if (csrfToken) {
435
473
  this.tokenManager.setMemoryMode();
436
474
  setCsrfToken(csrfToken);
@@ -449,93 +487,62 @@ var Auth = class {
449
487
  };
450
488
  this.tokenManager.saveSession(session);
451
489
  this.http.setAuthToken(accessToken);
452
- const url = new URL(window.location.href);
453
- url.searchParams.delete("access_token");
454
- url.searchParams.delete("user_id");
455
- url.searchParams.delete("email");
456
- url.searchParams.delete("name");
457
- url.searchParams.delete("csrf_token");
458
- window.history.replaceState({}, document.title, url.toString());
490
+ cleanUrlParams("access_token", "user_id", "email", "name", "csrf_token");
459
491
  }
460
492
  } catch (error) {
461
493
  console.debug("OAuth callback detection skipped:", error);
462
494
  }
463
495
  }
464
- /**
465
- * Sign up a new user
466
- */
496
+ // ============================================================================
497
+ // Sign Up / Sign In / Sign Out
498
+ // ============================================================================
467
499
  async signUp(request) {
468
500
  try {
469
- const response = await this.http.post("/api/auth/users", request, { credentials: "include" });
470
- if (response.accessToken && response.user && !isHostedAuthEnvironment()) {
471
- const session = {
472
- accessToken: response.accessToken,
473
- user: response.user
474
- };
475
- if (response.csrfToken) {
476
- this.tokenManager.setMemoryMode();
477
- setCsrfToken(response.csrfToken);
478
- }
479
- this.tokenManager.saveSession(session);
480
- this.http.setAuthToken(response.accessToken);
501
+ const response = await this.http.post(
502
+ "/api/auth/users",
503
+ request,
504
+ { credentials: "include" }
505
+ );
506
+ if (response.accessToken && response.user) {
507
+ this.saveSessionFromResponse(response);
481
508
  }
482
- return {
483
- data: response,
484
- error: null
485
- };
509
+ return { data: response, error: null };
486
510
  } catch (error) {
487
- if (error instanceof InsForgeError) {
488
- return { data: null, error };
489
- }
490
- return {
491
- data: null,
492
- error: new InsForgeError(
493
- error instanceof Error ? error.message : "An unexpected error occurred during sign up",
494
- 500,
495
- "UNEXPECTED_ERROR"
496
- )
497
- };
511
+ return wrapError(error, "An unexpected error occurred during sign up");
498
512
  }
499
513
  }
500
- /**
501
- * Sign in with email and password
502
- */
503
514
  async signInWithPassword(request) {
504
515
  try {
505
- const response = await this.http.post("/api/auth/sessions", request, { credentials: "include" });
506
- if (!isHostedAuthEnvironment()) {
507
- const session = {
508
- accessToken: response.accessToken,
509
- user: response.user
510
- };
511
- if (response.csrfToken) {
512
- this.tokenManager.setMemoryMode();
513
- setCsrfToken(response.csrfToken);
514
- }
515
- this.tokenManager.saveSession(session);
516
- this.http.setAuthToken(response.accessToken);
517
- }
518
- return {
519
- data: response,
520
- error: null
521
- };
516
+ const response = await this.http.post(
517
+ "/api/auth/sessions",
518
+ request,
519
+ { credentials: "include" }
520
+ );
521
+ this.saveSessionFromResponse(response);
522
+ return { data: response, error: null };
522
523
  } catch (error) {
523
- if (error instanceof InsForgeError) {
524
- return { data: null, error };
524
+ return wrapError(error, "An unexpected error occurred during sign in");
525
+ }
526
+ }
527
+ async signOut() {
528
+ try {
529
+ try {
530
+ await this.http.post("/api/auth/logout", void 0, { credentials: "include" });
531
+ } catch {
525
532
  }
526
- return {
527
- data: null,
528
- error: new InsForgeError(
529
- "An unexpected error occurred during sign in",
530
- 500,
531
- "UNEXPECTED_ERROR"
532
- )
533
- };
533
+ this.tokenManager.clearSession();
534
+ this.http.setAuthToken(null);
535
+ clearCsrfToken();
536
+ return { error: null };
537
+ } catch {
538
+ return { error: new InsForgeError("Failed to sign out", 500, "SIGNOUT_ERROR") };
534
539
  }
535
540
  }
541
+ // ============================================================================
542
+ // OAuth Authentication
543
+ // ============================================================================
536
544
  /**
537
- * Sign in with OAuth provider
538
- * Uses PKCE (Proof Key for Code Exchange) for enhanced security
545
+ * Sign in with OAuth provider using PKCE flow
539
546
  */
540
547
  async signInWithOAuth(options) {
541
548
  try {
@@ -543,25 +550,18 @@ var Auth = class {
543
550
  const codeVerifier = generateCodeVerifier();
544
551
  const codeChallenge = await generateCodeChallenge(codeVerifier);
545
552
  storePkceVerifier(codeVerifier);
546
- const params = {
547
- code_challenge: codeChallenge
548
- };
549
- if (redirectTo) {
550
- params.redirect_uri = redirectTo;
551
- }
552
- const endpoint = `/api/auth/oauth/${provider}`;
553
- const response = await this.http.get(endpoint, { params });
553
+ const params = { code_challenge: codeChallenge };
554
+ if (redirectTo) params.redirect_uri = redirectTo;
555
+ const response = await this.http.get(
556
+ `/api/auth/oauth/${provider}`,
557
+ { params }
558
+ );
554
559
  if (typeof window !== "undefined" && !skipBrowserRedirect) {
555
560
  window.location.href = response.authUrl;
556
561
  return { data: {}, error: null };
557
562
  }
558
563
  return {
559
- data: {
560
- url: response.authUrl,
561
- provider,
562
- codeVerifier
563
- // Return verifier for manual flow (skipBrowserRedirect)
564
- },
564
+ data: { url: response.authUrl, provider, codeVerifier },
565
565
  error: null
566
566
  };
567
567
  } catch (error) {
@@ -580,30 +580,7 @@ var Auth = class {
580
580
  }
581
581
  /**
582
582
  * Exchange OAuth authorization code for tokens (PKCE flow)
583
- *
584
- * After OAuth callback redirects with an `insforge_code` parameter, call this method
585
- * to exchange it for access tokens. The code verifier is automatically
586
- * retrieved from sessionStorage if available.
587
- *
588
- * Note: This is called automatically by the SDK on initialization. You typically
589
- * don't need to call this directly unless using `skipBrowserRedirect: true`.
590
- *
591
- * @param code - The authorization code from OAuth callback URL
592
- * @param codeVerifier - Optional code verifier (auto-retrieved from sessionStorage if not provided)
593
- * @returns Session data with access token and user info
594
- *
595
- * @example
596
- * ```ts
597
- * // Automatic verifier retrieval (recommended for browser)
598
- * const params = new URLSearchParams(window.location.search);
599
- * const code = params.get('insforge_code');
600
- * if (code) {
601
- * const { data, error } = await insforge.auth.exchangeOAuthCode(code);
602
- * }
603
- *
604
- * // Manual verifier (for custom flows)
605
- * const { data, error } = await insforge.auth.exchangeOAuthCode(code, codeVerifier);
606
- * ```
583
+ * Called automatically on initialization when insforge_code is in URL
607
584
  */
608
585
  async exchangeOAuthCode(code, codeVerifier) {
609
586
  try {
@@ -618,23 +595,9 @@ var Auth = class {
618
595
  )
619
596
  };
620
597
  }
621
- const request = {
622
- code,
623
- code_verifier: verifier
624
- };
598
+ const request = { code, code_verifier: verifier };
625
599
  const response = await this.http.post("/api/auth/oauth/exchange", request, { credentials: "include" });
626
- if (!isHostedAuthEnvironment()) {
627
- const session = {
628
- accessToken: response.accessToken,
629
- user: response.user
630
- };
631
- if (response.csrfToken) {
632
- this.tokenManager.setMemoryMode();
633
- setCsrfToken(response.csrfToken);
634
- }
635
- this.tokenManager.saveSession(session);
636
- this.http.setAuthToken(response.accessToken);
637
- }
600
+ this.saveSessionFromResponse(response);
638
601
  return {
639
602
  data: {
640
603
  accessToken: response.accessToken,
@@ -644,108 +607,14 @@ var Auth = class {
644
607
  error: null
645
608
  };
646
609
  } catch (error) {
647
- if (error instanceof InsForgeError) {
648
- return { data: null, error };
649
- }
650
- return {
651
- data: null,
652
- error: new InsForgeError(
653
- "An unexpected error occurred during OAuth code exchange",
654
- 500,
655
- "UNEXPECTED_ERROR"
656
- )
657
- };
610
+ return wrapError(error, "An unexpected error occurred during OAuth code exchange");
658
611
  }
659
612
  }
613
+ // ============================================================================
614
+ // Session Management
615
+ // ============================================================================
660
616
  /**
661
- * Sign out the current user
662
- */
663
- async signOut() {
664
- try {
665
- try {
666
- await this.http.post("/api/auth/logout", void 0, { credentials: "include" });
667
- } catch {
668
- }
669
- this.tokenManager.clearSession();
670
- this.http.setAuthToken(null);
671
- clearCsrfToken();
672
- return { error: null };
673
- } catch (error) {
674
- return {
675
- error: new InsForgeError(
676
- "Failed to sign out",
677
- 500,
678
- "SIGNOUT_ERROR"
679
- )
680
- };
681
- }
682
- }
683
- /**
684
- * Get all public authentication configuration (OAuth + Email)
685
- * Returns both OAuth providers and email authentication settings in one request
686
- * This is a public endpoint that doesn't require authentication
687
- *
688
- * @returns Complete public authentication configuration including OAuth providers and email auth settings
689
- *
690
- * @example
691
- * ```ts
692
- * const { data, error } = await insforge.auth.getPublicAuthConfig();
693
- * if (data) {
694
- * console.log(`OAuth providers: ${data.oauth.data.length}`);
695
- * console.log(`Password min length: ${data.email.passwordMinLength}`);
696
- * }
697
- * ```
698
- */
699
- async getPublicAuthConfig() {
700
- try {
701
- const response = await this.http.get("/api/auth/public-config");
702
- return {
703
- data: response,
704
- error: null
705
- };
706
- } catch (error) {
707
- if (error instanceof InsForgeError) {
708
- return { data: null, error };
709
- }
710
- return {
711
- data: null,
712
- error: new InsForgeError(
713
- "An unexpected error occurred while fetching public authentication configuration",
714
- 500,
715
- "UNEXPECTED_ERROR"
716
- )
717
- };
718
- }
719
- }
720
- /**
721
- * Get any user's profile by ID
722
- * Returns profile information from the users table
723
- */
724
- async getProfile(userId) {
725
- try {
726
- const response = await this.http.get(`/api/auth/profiles/${userId}`);
727
- return {
728
- data: response,
729
- error: null
730
- };
731
- } catch (error) {
732
- if (error instanceof InsForgeError) {
733
- return { data: null, error };
734
- }
735
- return {
736
- data: null,
737
- error: new InsForgeError(
738
- "An unexpected error occurred while fetching user profile",
739
- 500,
740
- "UNEXPECTED_ERROR"
741
- )
742
- };
743
- }
744
- }
745
- /**
746
- * Get the current session (only session data, no API call)
747
- * Returns the stored JWT token and basic user info from local storage
748
- * Automatically waits for any pending OAuth callback to complete first
617
+ * Get current session, automatically waits for pending OAuth callback
749
618
  */
750
619
  async getCurrentSession() {
751
620
  await this.authCallbackHandled;
@@ -761,38 +630,24 @@ var Auth = class {
761
630
  if (typeof window !== "undefined") {
762
631
  try {
763
632
  const csrfToken = getCsrfToken();
764
- const response = await this.http.post(
765
- "/api/auth/refresh",
766
- void 0,
767
- {
768
- headers: csrfToken ? { "X-CSRF-Token": csrfToken } : {},
769
- credentials: "include"
770
- }
771
- );
633
+ const response = await this.http.post("/api/auth/refresh", void 0, {
634
+ headers: csrfToken ? { "X-CSRF-Token": csrfToken } : {},
635
+ credentials: "include"
636
+ });
772
637
  if (response.accessToken) {
773
638
  this.tokenManager.setMemoryMode();
774
639
  this.tokenManager.setAccessToken(response.accessToken);
775
640
  this.http.setAuthToken(response.accessToken);
776
- if (response.user) {
777
- this.tokenManager.setUser(response.user);
778
- }
779
- if (response.csrfToken) {
780
- setCsrfToken(response.csrfToken);
781
- }
782
- return {
783
- data: { session: this.tokenManager.getSession() },
784
- error: null
785
- };
641
+ if (response.user) this.tokenManager.setUser(response.user);
642
+ if (response.csrfToken) setCsrfToken(response.csrfToken);
643
+ return { data: { session: this.tokenManager.getSession() }, error: null };
786
644
  }
787
645
  } catch (error) {
788
646
  if (error instanceof InsForgeError) {
789
647
  if (error.statusCode === 404) {
790
648
  this.tokenManager.setStorageMode();
791
649
  const session2 = this.tokenManager.getSession();
792
- if (session2) {
793
- return { data: { session: session2 }, error: null };
794
- }
795
- return { data: { session: null }, error: null };
650
+ return { data: { session: session2 }, error: null };
796
651
  }
797
652
  return { data: { session: null }, error };
798
653
  }
@@ -813,11 +668,17 @@ var Auth = class {
813
668
  };
814
669
  }
815
670
  }
816
- /**
817
- * Set/Update the current user's profile
818
- * Updates profile information in the users table (supports any dynamic fields)
819
- * Requires authentication
820
- */
671
+ // ============================================================================
672
+ // Profile Management
673
+ // ============================================================================
674
+ async getProfile(userId) {
675
+ try {
676
+ const response = await this.http.get(`/api/auth/profiles/${userId}`);
677
+ return { data: response, error: null };
678
+ } catch (error) {
679
+ return wrapError(error, "An unexpected error occurred while fetching user profile");
680
+ }
681
+ }
821
682
  async setProfile(profile) {
822
683
  try {
823
684
  const response = await this.http.patch(
@@ -826,217 +687,89 @@ var Auth = class {
826
687
  );
827
688
  const currentUser = this.tokenManager.getUser();
828
689
  if (currentUser && response.profile !== void 0) {
829
- this.tokenManager.setUser({
830
- ...currentUser,
831
- profile: response.profile
832
- });
690
+ this.tokenManager.setUser({ ...currentUser, profile: response.profile });
833
691
  }
834
- return {
835
- data: response,
836
- error: null
837
- };
692
+ return { data: response, error: null };
838
693
  } catch (error) {
839
- if (error instanceof InsForgeError) {
840
- return { data: null, error };
841
- }
842
- return {
843
- data: null,
844
- error: new InsForgeError(
845
- "An unexpected error occurred while updating user profile",
846
- 500,
847
- "UNEXPECTED_ERROR"
848
- )
849
- };
694
+ return wrapError(error, "An unexpected error occurred while updating user profile");
850
695
  }
851
696
  }
852
- /**
853
- * Resend email verification (code or link based on config)
854
- *
855
- * Resend email verification when the previous OTP has expired or was not received.
856
- * Uses the method configured in auth settings (verifyEmailMethod).
857
- * When method is 'code', sends a 6-digit numeric code. When method is 'link', sends a magic link.
858
- * Prevents user enumeration by returning success even if email doesn't exist.
859
- */
697
+ // ============================================================================
698
+ // Email Verification
699
+ // ============================================================================
860
700
  async resendVerificationEmail(request) {
861
701
  try {
862
702
  const response = await this.http.post(
863
703
  "/api/auth/email/send-verification",
864
704
  request
865
705
  );
866
- return {
867
- data: response,
868
- error: null
869
- };
706
+ return { data: response, error: null };
870
707
  } catch (error) {
871
- if (error instanceof InsForgeError) {
872
- return { data: null, error };
873
- }
874
- return {
875
- data: null,
876
- error: new InsForgeError(
877
- "An unexpected error occurred while sending verification code",
878
- 500,
879
- "UNEXPECTED_ERROR"
880
- )
881
- };
708
+ return wrapError(error, "An unexpected error occurred while sending verification code");
882
709
  }
883
710
  }
884
- /**
885
- * @deprecated Use `resendVerificationEmail` instead. This method will be removed in a future version.
886
- */
711
+ /** @deprecated Use `resendVerificationEmail` instead */
887
712
  async sendVerificationEmail(request) {
888
713
  return this.resendVerificationEmail(request);
889
714
  }
890
- /**
891
- * Send password reset (code or link based on config)
892
- *
893
- * Send password reset email using the method configured in auth settings (resetPasswordMethod).
894
- * When method is 'code', sends a 6-digit numeric code for two-step flow.
895
- * When method is 'link', sends a magic link.
896
- * Prevents user enumeration by returning success even if email doesn't exist.
897
- */
715
+ async verifyEmail(request) {
716
+ try {
717
+ const response = await this.http.post(
718
+ "/api/auth/email/verify",
719
+ request,
720
+ { credentials: "include" }
721
+ );
722
+ this.saveSessionFromResponse(response);
723
+ return { data: response, error: null };
724
+ } catch (error) {
725
+ return wrapError(error, "An unexpected error occurred while verifying email");
726
+ }
727
+ }
728
+ // ============================================================================
729
+ // Password Reset
730
+ // ============================================================================
898
731
  async sendResetPasswordEmail(request) {
899
732
  try {
900
733
  const response = await this.http.post(
901
734
  "/api/auth/email/send-reset-password",
902
735
  request
903
736
  );
904
- return {
905
- data: response,
906
- error: null
907
- };
737
+ return { data: response, error: null };
908
738
  } catch (error) {
909
- if (error instanceof InsForgeError) {
910
- return { data: null, error };
911
- }
912
- return {
913
- data: null,
914
- error: new InsForgeError(
915
- "An unexpected error occurred while sending password reset code",
916
- 500,
917
- "UNEXPECTED_ERROR"
918
- )
919
- };
739
+ return wrapError(error, "An unexpected error occurred while sending password reset code");
920
740
  }
921
741
  }
922
- /**
923
- * Exchange reset password code for reset token
924
- *
925
- * Step 1 of two-step password reset flow (only used when resetPasswordMethod is 'code'):
926
- * 1. Verify the 6-digit code sent to user's email
927
- * 2. Return a reset token that can be used to actually reset the password
928
- *
929
- * This endpoint is not used when resetPasswordMethod is 'link' (magic link flow is direct).
930
- */
931
742
  async exchangeResetPasswordToken(request) {
932
743
  try {
933
744
  const response = await this.http.post(
934
745
  "/api/auth/email/exchange-reset-password-token",
935
746
  request
936
747
  );
937
- return {
938
- data: response,
939
- error: null
940
- };
748
+ return { data: response, error: null };
941
749
  } catch (error) {
942
- if (error instanceof InsForgeError) {
943
- return { data: null, error };
944
- }
945
- return {
946
- data: null,
947
- error: new InsForgeError(
948
- "An unexpected error occurred while verifying reset code",
949
- 500,
950
- "UNEXPECTED_ERROR"
951
- )
952
- };
750
+ return wrapError(error, "An unexpected error occurred while verifying reset code");
953
751
  }
954
752
  }
955
- /**
956
- * Reset password with token
957
- *
958
- * Reset user password with a token. The token can be:
959
- * - Magic link token (64-character hex token from send-reset-password when method is 'link')
960
- * - Reset token (from exchange-reset-password-token after code verification when method is 'code')
961
- *
962
- * Both token types use RESET_PASSWORD purpose and are verified the same way.
963
- *
964
- * Flow summary:
965
- * - Code method: send-reset-password → exchange-reset-password-token → reset-password (with resetToken)
966
- * - Link method: send-reset-password → reset-password (with link token directly)
967
- */
968
753
  async resetPassword(request) {
969
754
  try {
970
755
  const response = await this.http.post(
971
756
  "/api/auth/email/reset-password",
972
757
  request
973
758
  );
974
- return {
975
- data: response,
976
- error: null
977
- };
759
+ return { data: response, error: null };
978
760
  } catch (error) {
979
- if (error instanceof InsForgeError) {
980
- return { data: null, error };
981
- }
982
- return {
983
- data: null,
984
- error: new InsForgeError(
985
- "An unexpected error occurred while resetting password",
986
- 500,
987
- "UNEXPECTED_ERROR"
988
- )
989
- };
761
+ return wrapError(error, "An unexpected error occurred while resetting password");
990
762
  }
991
763
  }
992
- /**
993
- * Verify email with code or link
994
- *
995
- * Verify email address using the method configured in auth settings (verifyEmailMethod):
996
- * - Code verification: Provide both `email` and `otp` (6-digit numeric code)
997
- * - Link verification: Provide only `otp` (64-character hex token from magic link)
998
- *
999
- * Successfully verified users will receive a session token.
1000
- *
1001
- * The email verification link sent to users always points to the backend API endpoint.
1002
- * If `verifyEmailRedirectTo` is configured, the backend will redirect to that URL after successful verification.
1003
- * Otherwise, a default success page is displayed.
1004
- */
1005
- async verifyEmail(request) {
764
+ // ============================================================================
765
+ // Configuration
766
+ // ============================================================================
767
+ async getPublicAuthConfig() {
1006
768
  try {
1007
- const response = await this.http.post(
1008
- "/api/auth/email/verify",
1009
- request,
1010
- { credentials: "include" }
1011
- );
1012
- if (!isHostedAuthEnvironment()) {
1013
- const session = {
1014
- accessToken: response.accessToken,
1015
- user: response.user
1016
- };
1017
- if (response.csrfToken) {
1018
- this.tokenManager.setMemoryMode();
1019
- setCsrfToken(response.csrfToken);
1020
- }
1021
- this.tokenManager.saveSession(session);
1022
- this.http.setAuthToken(response.accessToken);
1023
- }
1024
- return {
1025
- data: response,
1026
- error: null
1027
- };
769
+ const response = await this.http.get("/api/auth/public-config");
770
+ return { data: response, error: null };
1028
771
  } catch (error) {
1029
- if (error instanceof InsForgeError) {
1030
- return { data: null, error };
1031
- }
1032
- return {
1033
- data: null,
1034
- error: new InsForgeError(
1035
- "An unexpected error occurred while verifying email",
1036
- 500,
1037
- "UNEXPECTED_ERROR"
1038
- )
1039
- };
772
+ return wrapError(error, "An unexpected error occurred while fetching auth configuration");
1040
773
  }
1041
774
  }
1042
775
  };