@dloizides/auth-web 1.19.0 → 1.21.0

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.mts CHANGED
@@ -525,10 +525,19 @@ declare const enum RegisterErrorCode {
525
525
  PasswordMismatch = "passwordMismatch",
526
526
  /** The server reported `USERNAME_TAKEN`. */
527
527
  UsernameTaken = "usernameTaken",
528
- /** The server reported `EMAIL_TAKEN`. */
528
+ /** The server reported `EMAIL_TAKEN` or `USER_EXISTS` (409). */
529
529
  EmailTaken = "emailTaken",
530
530
  /** The server reported `REALM_REQUIRED` or `REALM_INVALID`. */
531
531
  RealmInvalid = "realmInvalid",
532
+ /** The server reported `TENANT_NAME_TAKEN` (409): the organisation / shop name is in use. */
533
+ TenantNameTaken = "tenantNameTaken",
534
+ /** The server rate-limited the request (HTTP 429). */
535
+ RateLimited = "rateLimited",
536
+ /**
537
+ * The account WAS created but the automatic sign-in failed (`AUTO_LOGIN_FAILED`).
538
+ * Tell the user to sign in; do not ask them to register again.
539
+ */
540
+ AutoLoginFailed = "autoLoginFailed",
532
541
  /** The server rejected the request with an unrecognised message. */
533
542
  ValidationFailed = "validationFailed",
534
543
  /** Generic failure: network error, empty message, or a filled honeypot (never revealed). */
@@ -676,6 +685,12 @@ interface LoginFormProps {
676
685
  * unconditional — omit it and every nonce bump applies.
677
686
  */
678
687
  prefillIntent?: PrefillIntent;
688
+ /**
689
+ * When `true`, the username field is an email field: `type="email"` +
690
+ * `autocomplete="username"` on web, the email keyboard + `username` content
691
+ * type on native. Defaults to `false` (plain text field, as before).
692
+ */
693
+ emailUsername?: boolean;
679
694
  }
680
695
 
681
696
  /**
@@ -693,7 +708,7 @@ interface LoginFormProps {
693
708
  */
694
709
 
695
710
  /** Themeable password-login form built on `useBffAuth`. */
696
- declare function LoginForm({ client, theme: themeProp, labels: labelsProp, onSuccess, onForgotPassword, onSignUp, testIdPrefix, chromeless, initialUsername, initialPassword, prefillNonce, prefillIntent, }: Readonly<LoginFormProps>): ReactElement;
711
+ declare function LoginForm({ client, theme: themeProp, labels: labelsProp, onSuccess, onForgotPassword, onSignUp, testIdPrefix, chromeless, initialUsername, initialPassword, prefillNonce, prefillIntent, emailUsername, }: Readonly<LoginFormProps>): ReactElement;
697
712
 
698
713
  /**
699
714
  * `<ForgotPasswordForm>` — the ready-made, themeable "request a reset link"
package/dist/index.d.ts CHANGED
@@ -525,10 +525,19 @@ declare const enum RegisterErrorCode {
525
525
  PasswordMismatch = "passwordMismatch",
526
526
  /** The server reported `USERNAME_TAKEN`. */
527
527
  UsernameTaken = "usernameTaken",
528
- /** The server reported `EMAIL_TAKEN`. */
528
+ /** The server reported `EMAIL_TAKEN` or `USER_EXISTS` (409). */
529
529
  EmailTaken = "emailTaken",
530
530
  /** The server reported `REALM_REQUIRED` or `REALM_INVALID`. */
531
531
  RealmInvalid = "realmInvalid",
532
+ /** The server reported `TENANT_NAME_TAKEN` (409): the organisation / shop name is in use. */
533
+ TenantNameTaken = "tenantNameTaken",
534
+ /** The server rate-limited the request (HTTP 429). */
535
+ RateLimited = "rateLimited",
536
+ /**
537
+ * The account WAS created but the automatic sign-in failed (`AUTO_LOGIN_FAILED`).
538
+ * Tell the user to sign in; do not ask them to register again.
539
+ */
540
+ AutoLoginFailed = "autoLoginFailed",
532
541
  /** The server rejected the request with an unrecognised message. */
533
542
  ValidationFailed = "validationFailed",
534
543
  /** Generic failure: network error, empty message, or a filled honeypot (never revealed). */
@@ -676,6 +685,12 @@ interface LoginFormProps {
676
685
  * unconditional — omit it and every nonce bump applies.
677
686
  */
678
687
  prefillIntent?: PrefillIntent;
688
+ /**
689
+ * When `true`, the username field is an email field: `type="email"` +
690
+ * `autocomplete="username"` on web, the email keyboard + `username` content
691
+ * type on native. Defaults to `false` (plain text field, as before).
692
+ */
693
+ emailUsername?: boolean;
679
694
  }
680
695
 
681
696
  /**
@@ -693,7 +708,7 @@ interface LoginFormProps {
693
708
  */
694
709
 
695
710
  /** Themeable password-login form built on `useBffAuth`. */
696
- declare function LoginForm({ client, theme: themeProp, labels: labelsProp, onSuccess, onForgotPassword, onSignUp, testIdPrefix, chromeless, initialUsername, initialPassword, prefillNonce, prefillIntent, }: Readonly<LoginFormProps>): ReactElement;
711
+ declare function LoginForm({ client, theme: themeProp, labels: labelsProp, onSuccess, onForgotPassword, onSignUp, testIdPrefix, chromeless, initialUsername, initialPassword, prefillNonce, prefillIntent, emailUsername, }: Readonly<LoginFormProps>): ReactElement;
697
712
 
698
713
  /**
699
714
  * `<ForgotPasswordForm>` — the ready-made, themeable "request a reset link"
package/dist/index.js CHANGED
@@ -661,6 +661,18 @@ function useSubmitOnEnter(submit) {
661
661
  [submit]
662
662
  );
663
663
  }
664
+
665
+ // src/components/usernameFieldProps.ts
666
+ var EMAIL_USERNAME_PROPS = {
667
+ autoComplete: "username",
668
+ inputMode: "email",
669
+ keyboardType: "email-address",
670
+ textContentType: "username"
671
+ };
672
+ var NO_EXTRA_PROPS = {};
673
+ function usernameFieldProps(emailUsername) {
674
+ return emailUsername ? EMAIL_USERNAME_PROPS : NO_EXTRA_PROPS;
675
+ }
664
676
  var BffAuthStatus = /* @__PURE__ */ ((BffAuthStatus2) => {
665
677
  BffAuthStatus2["Loading"] = "loading";
666
678
  BffAuthStatus2["Authenticated"] = "authenticated";
@@ -776,7 +788,8 @@ function LoginForm({
776
788
  initialUsername,
777
789
  initialPassword,
778
790
  prefillNonce,
779
- prefillIntent
791
+ prefillIntent,
792
+ emailUsername = false
780
793
  }) {
781
794
  const theme = useAuthTheme(themeProp);
782
795
  const styles3 = useAuthStyles(theme);
@@ -808,6 +821,7 @@ function LoginForm({
808
821
  /* @__PURE__ */ jsxRuntime.jsx(
809
822
  reactNative.TextInput,
810
823
  {
824
+ ...usernameFieldProps(emailUsername),
811
825
  accessibilityHint: labels.usernamePlaceholder,
812
826
  accessibilityLabel: labels.usernameLabel,
813
827
  autoCapitalize: "none",
@@ -4193,6 +4207,9 @@ var RegisterErrorCode = /* @__PURE__ */ ((RegisterErrorCode2) => {
4193
4207
  RegisterErrorCode2["UsernameTaken"] = "usernameTaken";
4194
4208
  RegisterErrorCode2["EmailTaken"] = "emailTaken";
4195
4209
  RegisterErrorCode2["RealmInvalid"] = "realmInvalid";
4210
+ RegisterErrorCode2["TenantNameTaken"] = "tenantNameTaken";
4211
+ RegisterErrorCode2["RateLimited"] = "rateLimited";
4212
+ RegisterErrorCode2["AutoLoginFailed"] = "autoLoginFailed";
4196
4213
  RegisterErrorCode2["ValidationFailed"] = "validationFailed";
4197
4214
  RegisterErrorCode2["Failed"] = "failed";
4198
4215
  RegisterErrorCode2["InFlight"] = "inFlight";
@@ -4284,6 +4301,41 @@ function validateRegisterValues(values, passwordPolicy) {
4284
4301
  }
4285
4302
  return null;
4286
4303
  }
4304
+ var HTTP_TOO_MANY_REQUESTS = 429;
4305
+ var HTTP_SERVER_ERROR_MIN = 500;
4306
+ var BODY_ERROR_CODES = {
4307
+ USER_EXISTS: "emailTaken" /* EmailTaken */,
4308
+ USERNAME_TAKEN: "usernameTaken" /* UsernameTaken */,
4309
+ EMAIL_TAKEN: "emailTaken" /* EmailTaken */,
4310
+ TENANT_NAME_TAKEN: "tenantNameTaken" /* TenantNameTaken */,
4311
+ AUTO_LOGIN_FAILED: "autoLoginFailed" /* AutoLoginFailed */,
4312
+ INVALID_REQUEST: "validationFailed" /* ValidationFailed */,
4313
+ REALM_REQUIRED: "realmInvalid" /* RealmInvalid */,
4314
+ REALM_INVALID: "realmInvalid" /* RealmInvalid */
4315
+ };
4316
+ function typedFailureOf(error) {
4317
+ if (typeof error !== "object" || error === null) {
4318
+ return null;
4319
+ }
4320
+ const { status, errorCode } = error;
4321
+ const hasStatus = typeof status === "number";
4322
+ const hasCode = typeof errorCode === "string";
4323
+ if (!hasStatus && !hasCode) {
4324
+ return null;
4325
+ }
4326
+ return { status: hasStatus ? status : null, errorCode: hasCode ? errorCode : null };
4327
+ }
4328
+ function mapTypedFailure(failure) {
4329
+ const byCode = failure.errorCode === null ? void 0 : BODY_ERROR_CODES[failure.errorCode];
4330
+ if (byCode !== void 0) {
4331
+ return byCode;
4332
+ }
4333
+ if (failure.status === HTTP_TOO_MANY_REQUESTS) {
4334
+ return "rateLimited" /* RateLimited */;
4335
+ }
4336
+ const isServerError = failure.status !== null && failure.status >= HTTP_SERVER_ERROR_MIN;
4337
+ return isServerError ? "failed" /* Failed */ : null;
4338
+ }
4287
4339
  function messageOf(error) {
4288
4340
  if (error instanceof Error) {
4289
4341
  return error.message;
@@ -4291,6 +4343,11 @@ function messageOf(error) {
4291
4343
  return typeof error === "string" ? error : "";
4292
4344
  }
4293
4345
  function mapRegisterErrorCode(error) {
4346
+ const failure = typedFailureOf(error);
4347
+ const typed = failure === null ? null : mapTypedFailure(failure);
4348
+ if (typed !== null) {
4349
+ return typed;
4350
+ }
4294
4351
  const message = messageOf(error);
4295
4352
  if (message === "") {
4296
4353
  return "failed" /* Failed */;