@authowl/react 0.18.1 → 0.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -625,7 +625,17 @@ var KNOWN_METHODS = [
625
625
  function emailAutocomplete(isPasskeyHost) {
626
626
  return isPasskeyHost ? "email webauthn" : "email";
627
627
  }
628
- function resolveSignInMethods(config) {
628
+ function passkeyReachableFrom(authBaseUrl, pageHost) {
629
+ if (pageHost === void 0 || !authBaseUrl) return true;
630
+ let rpId;
631
+ try {
632
+ rpId = new URL(authBaseUrl).hostname;
633
+ } catch {
634
+ return true;
635
+ }
636
+ return pageHost === rpId || pageHost.endsWith(`.${rpId}`);
637
+ }
638
+ function resolveSignInMethods(config, pageHost) {
629
639
  const methods = config?.enabledMethods ?? ["password"];
630
640
  const social = config?.socialProviders ?? [];
631
641
  const has = (m) => methods.includes(m);
@@ -635,7 +645,7 @@ function resolveSignInMethods(config) {
635
645
  const magicLink = capabilities.magicLinkSignIn;
636
646
  const emailOtp = capabilities.emailOtpSignIn && !capabilities.totp && !capabilities.mfaRequired;
637
647
  const phoneOtp = capabilities.phoneSignIn;
638
- const passkey = capabilities.passkeySignIn;
648
+ const passkey = capabilities.passkeySignIn && passkeyReachableFrom(config?.authBaseUrl, pageHost);
639
649
  const sso = has("sso");
640
650
  const renderable = password || username || magicLink || emailOtp || phoneOtp || passkey || sso || social.length > 0;
641
651
  const emptyReason = renderable ? null : methods.length > 0 ? "unsupported" : "none";
@@ -688,8 +698,15 @@ function hasUsableSession(store) {
688
698
  const data = store.getSnapshot().data;
689
699
  return Boolean(data?.user && data.session.pendingMfaEnrollment !== true);
690
700
  }
701
+ function isHeldAtEnrollment(store) {
702
+ const data = store.getSnapshot().data;
703
+ return Boolean(data?.user && data.session.pendingMfaEnrollment === true);
704
+ }
691
705
  function waitForUsableSession(store) {
692
- if (hasUsableSession(store)) return Promise.resolve();
706
+ const outcome = () => isHeldAtEnrollment(store) ? "held" : "settled";
707
+ if (hasUsableSession(store) || isHeldAtEnrollment(store)) {
708
+ return Promise.resolve(outcome());
709
+ }
693
710
  return new Promise((resolve) => {
694
711
  let settled = false;
695
712
  let unsubscribe = () => {
@@ -699,23 +716,22 @@ function waitForUsableSession(store) {
699
716
  settled = true;
700
717
  window.clearTimeout(timeout);
701
718
  unsubscribe();
702
- resolve();
719
+ resolve(outcome());
703
720
  };
704
721
  const timeout = window.setTimeout(finish, SESSION_SETTLE_TIMEOUT_MS);
705
722
  unsubscribe = store.subscribe(() => {
706
- if (hasUsableSession(store)) finish();
723
+ if (hasUsableSession(store) || isHeldAtEnrollment(store)) finish();
707
724
  });
708
- if (hasUsableSession(store)) finish();
725
+ if (hasUsableSession(store) || isHeldAtEnrollment(store)) finish();
709
726
  });
710
727
  }
711
728
  async function finishSignIn(opts) {
729
+ if (await waitForUsableSession(opts.sessionStore) === "held") return;
712
730
  opts.onSignedIn?.();
713
731
  if (safeRedirect(opts.redirectTo)) {
714
732
  await new Promise(() => {
715
733
  });
716
- return;
717
734
  }
718
- await waitForUsableSession(opts.sessionStore);
719
735
  }
720
736
 
721
737
  // src/components/use-submit-action.ts
@@ -3623,7 +3639,10 @@ function SignIn({
3623
3639
  const [challenge, setChallenge] = React16.useState(false);
3624
3640
  const mfaEnrolment = useConfirmedMfaPending();
3625
3641
  const emailRef = React16.useRef(null);
3626
- const plan = resolveSignInMethods(config);
3642
+ const plan = resolveSignInMethods(
3643
+ config,
3644
+ typeof window === "undefined" ? void 0 : window.location.hostname
3645
+ );
3627
3646
  usePasskeyAutofill({
3628
3647
  enabled: credentialMode === "email" && plan.autofillHost !== null,
3629
3648
  redirectTo,
package/dist/index.d.cts CHANGED
@@ -311,12 +311,9 @@ type SignInPlan = {
311
311
  * passkeys inline. One place owns the token string.
312
312
  */
313
313
  declare function emailAutocomplete(isPasskeyHost: boolean): string;
314
- /**
315
- * Resolve the sign-in surfaces from a project's public config. On a config error
316
- * (`config` null) fall back to password - the safe default that always renders -
317
- * rather than showing nothing.
318
- */
319
- declare function resolveSignInMethods(config: PublicConfig | null): SignInPlan;
314
+ declare function resolveSignInMethods(config: PublicConfig | null,
315
+ /** The hostname the form is rendering on; omit when it is not knowable. */
316
+ pageHost?: string): SignInPlan;
320
317
 
321
318
  type SignInProps = {
322
319
  redirectTo?: string;
package/dist/index.d.ts CHANGED
@@ -311,12 +311,9 @@ type SignInPlan = {
311
311
  * passkeys inline. One place owns the token string.
312
312
  */
313
313
  declare function emailAutocomplete(isPasskeyHost: boolean): string;
314
- /**
315
- * Resolve the sign-in surfaces from a project's public config. On a config error
316
- * (`config` null) fall back to password - the safe default that always renders -
317
- * rather than showing nothing.
318
- */
319
- declare function resolveSignInMethods(config: PublicConfig | null): SignInPlan;
314
+ declare function resolveSignInMethods(config: PublicConfig | null,
315
+ /** The hostname the form is rendering on; omit when it is not knowable. */
316
+ pageHost?: string): SignInPlan;
320
317
 
321
318
  type SignInProps = {
322
319
  redirectTo?: string;
package/dist/index.js CHANGED
@@ -544,7 +544,17 @@ var KNOWN_METHODS = [
544
544
  function emailAutocomplete(isPasskeyHost) {
545
545
  return isPasskeyHost ? "email webauthn" : "email";
546
546
  }
547
- function resolveSignInMethods(config) {
547
+ function passkeyReachableFrom(authBaseUrl, pageHost) {
548
+ if (pageHost === void 0 || !authBaseUrl) return true;
549
+ let rpId;
550
+ try {
551
+ rpId = new URL(authBaseUrl).hostname;
552
+ } catch {
553
+ return true;
554
+ }
555
+ return pageHost === rpId || pageHost.endsWith(`.${rpId}`);
556
+ }
557
+ function resolveSignInMethods(config, pageHost) {
548
558
  const methods = config?.enabledMethods ?? ["password"];
549
559
  const social = config?.socialProviders ?? [];
550
560
  const has = (m) => methods.includes(m);
@@ -554,7 +564,7 @@ function resolveSignInMethods(config) {
554
564
  const magicLink = capabilities.magicLinkSignIn;
555
565
  const emailOtp = capabilities.emailOtpSignIn && !capabilities.totp && !capabilities.mfaRequired;
556
566
  const phoneOtp = capabilities.phoneSignIn;
557
- const passkey = capabilities.passkeySignIn;
567
+ const passkey = capabilities.passkeySignIn && passkeyReachableFrom(config?.authBaseUrl, pageHost);
558
568
  const sso = has("sso");
559
569
  const renderable = password || username || magicLink || emailOtp || phoneOtp || passkey || sso || social.length > 0;
560
570
  const emptyReason = renderable ? null : methods.length > 0 ? "unsupported" : "none";
@@ -607,8 +617,15 @@ function hasUsableSession(store) {
607
617
  const data = store.getSnapshot().data;
608
618
  return Boolean(data?.user && data.session.pendingMfaEnrollment !== true);
609
619
  }
620
+ function isHeldAtEnrollment(store) {
621
+ const data = store.getSnapshot().data;
622
+ return Boolean(data?.user && data.session.pendingMfaEnrollment === true);
623
+ }
610
624
  function waitForUsableSession(store) {
611
- if (hasUsableSession(store)) return Promise.resolve();
625
+ const outcome = () => isHeldAtEnrollment(store) ? "held" : "settled";
626
+ if (hasUsableSession(store) || isHeldAtEnrollment(store)) {
627
+ return Promise.resolve(outcome());
628
+ }
612
629
  return new Promise((resolve) => {
613
630
  let settled = false;
614
631
  let unsubscribe = () => {
@@ -618,23 +635,22 @@ function waitForUsableSession(store) {
618
635
  settled = true;
619
636
  window.clearTimeout(timeout);
620
637
  unsubscribe();
621
- resolve();
638
+ resolve(outcome());
622
639
  };
623
640
  const timeout = window.setTimeout(finish, SESSION_SETTLE_TIMEOUT_MS);
624
641
  unsubscribe = store.subscribe(() => {
625
- if (hasUsableSession(store)) finish();
642
+ if (hasUsableSession(store) || isHeldAtEnrollment(store)) finish();
626
643
  });
627
- if (hasUsableSession(store)) finish();
644
+ if (hasUsableSession(store) || isHeldAtEnrollment(store)) finish();
628
645
  });
629
646
  }
630
647
  async function finishSignIn(opts) {
648
+ if (await waitForUsableSession(opts.sessionStore) === "held") return;
631
649
  opts.onSignedIn?.();
632
650
  if (safeRedirect(opts.redirectTo)) {
633
651
  await new Promise(() => {
634
652
  });
635
- return;
636
653
  }
637
- await waitForUsableSession(opts.sessionStore);
638
654
  }
639
655
 
640
656
  // src/components/use-submit-action.ts
@@ -3545,7 +3561,10 @@ function SignIn({
3545
3561
  const [challenge, setChallenge] = React16.useState(false);
3546
3562
  const mfaEnrolment = useConfirmedMfaPending();
3547
3563
  const emailRef = React16.useRef(null);
3548
- const plan = resolveSignInMethods(config);
3564
+ const plan = resolveSignInMethods(
3565
+ config,
3566
+ typeof window === "undefined" ? void 0 : window.location.hostname
3567
+ );
3549
3568
  usePasskeyAutofill({
3550
3569
  enabled: credentialMode === "email" && plan.autofillHost !== null,
3551
3570
  redirectTo,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@authowl/react",
3
- "version": "0.18.1",
3
+ "version": "0.18.2",
4
4
  "description": "React provider, hooks, and drop-in components for AuthOwl, the multi-tenant auth SaaS.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {