cauthy-auth 0.25.0 → 0.27.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/react.d.mts CHANGED
@@ -277,6 +277,30 @@ interface AuthMethods {
277
277
  * found by their work address (`signIn.ssoDiscover`, `signIn.sso`).
278
278
  */
279
279
  sso: boolean;
280
+ /**
281
+ * Set when the workspace asks something of a sign-up: the legal documents
282
+ * to accept (the terms, the privacy policy: show the links and a box, send
283
+ * `acceptLegal: true`) and the consents to ask (one box each, sent as
284
+ * `consents`; a required one must be ticked). The ready-made form shows them.
285
+ */
286
+ legal?: {
287
+ documents: {
288
+ kind: string;
289
+ version: string;
290
+ url: string;
291
+ }[];
292
+ consentPurposes: {
293
+ key: string;
294
+ label: string;
295
+ required: boolean;
296
+ }[];
297
+ };
298
+ }
299
+ /** A legal document the person owes: not yet accepted in its current version. */
300
+ interface PendingLegal {
301
+ kind: string;
302
+ version: string;
303
+ url: string;
280
304
  }
281
305
  /** A company's sign-in (an SSO connection of the workspace). */
282
306
  interface SSOConnection {
@@ -457,6 +481,18 @@ interface AccountClient {
457
481
  }): Promise<AuthResult<'changed', {
458
482
  signedIn: boolean;
459
483
  }>>;
484
+ /**
485
+ * The legal documents the person has not accepted in their current version
486
+ * (a new version of the terms, say): show them and call `acceptLegal`.
487
+ * Nothing stops the person meanwhile; the application decides what waits.
488
+ */
489
+ legal(): Promise<AuthResult<'ok', {
490
+ pending: PendingLegal[];
491
+ }>>;
492
+ /** Records the person's acceptance of the documents in force (the kinds named, or every one). */
493
+ acceptLegal(form?: {
494
+ kinds?: string[];
495
+ }): Promise<AuthResult<'accepted'>>;
460
496
  mfa: {
461
497
  /** Starts turning the second step on: show `secret` (or `otpauthUri` as a QR code) to add to an authenticator app, then call `verify`. */
462
498
  setup(form: {
@@ -597,21 +633,34 @@ interface AuthClient {
597
633
  }): Promise<AuthResult<'signed_in', {
598
634
  session: PublicSession;
599
635
  }>>;
600
- /** With address and password. `mfa_required`: ask for the code and call `signIn.mfa`. */
636
+ /**
637
+ * With address and password. `mfa_required`: ask for the code and call
638
+ * `signIn.mfa`. `method: 'email'` says the code was just mailed to the
639
+ * account's address (it has no factor of its own and the workspace, or
640
+ * the sign-in's risk, asked a second step): say so, and offer
641
+ * `mfaSendEmail` for another.
642
+ */
601
643
  email(form: {
602
644
  email: string;
603
645
  password: string;
604
646
  captchaToken?: string;
605
647
  }): Promise<AuthResult<'signed_in', {
606
648
  session: PublicSession;
607
- }> | AuthResult<'mfa_required'>>;
608
- /** The second step: the code of the authenticator app, or a recovery code. */
649
+ }> | AuthResult<'mfa_required', {
650
+ method?: 'email';
651
+ }>>;
652
+ /** The second step: the code of the authenticator app, the phone, the email, or a recovery code. */
609
653
  mfa(form: {
610
654
  code: string;
611
655
  }): Promise<AuthResult<'signed_in', {
612
656
  session: PublicSession;
613
657
  }>>;
614
- /** While the second step is asked for: whether the account has an authenticator app, the phone (masked) a code can be sent to, and phones that approve sign-ins. */
658
+ /**
659
+ * While the second step is asked for: whether the account has an
660
+ * authenticator app, the phone (masked) a code can be sent to, phones
661
+ * that approve sign-ins, and the address (masked) a code went to when
662
+ * the step is by email.
663
+ */
615
664
  mfaMethods(): Promise<AuthResult<'ok', {
616
665
  totp: boolean;
617
666
  phone: {
@@ -621,6 +670,13 @@ interface AuthClient {
621
670
  push: {
622
671
  devices: number;
623
672
  } | null;
673
+ email: {
674
+ to: string;
675
+ } | null;
676
+ }>>;
677
+ /** Mails the sign-in's code again, when its second step is by email; `mfa` takes it. A few per sign-in. */
678
+ mfaSendEmail(): Promise<AuthResult<'sent', {
679
+ sentTo: string;
624
680
  }>>;
625
681
  /**
626
682
  * Sends a push to the account's phones (the application's app, with
@@ -764,12 +820,17 @@ interface AuthClient {
764
820
  }): string;
765
821
  };
766
822
  signUp: {
767
- /** `verification_required`: the account exists and must open the link Cauthy mailed before it can sign in. */
823
+ /**
824
+ * `verification_required`: the account exists and must open the link Cauthy mailed before it can sign in.
825
+ * `acceptLegal` and `consents` answer what `methods().legal` asks; a sign-up that leaves them out is refused.
826
+ */
768
827
  email(form: {
769
828
  email: string;
770
829
  password: string;
771
830
  name?: string;
772
831
  organization?: string;
832
+ acceptLegal?: boolean;
833
+ consents?: Record<string, boolean>;
773
834
  captchaToken?: string;
774
835
  }): Promise<AuthResult<'signed_in', {
775
836
  session: PublicSession;
@@ -837,12 +898,20 @@ interface AuthTexts {
837
898
  createAccount: string;
838
899
  /** The label of the company's name, asked when the application's system makes an organization per sign-up. */
839
900
  company: string;
901
+ /** The legal box: "I have read and accept" + "the Terms of Service" + "and" + "the Privacy Policy", linked. */
902
+ iAccept: string;
903
+ and: string;
904
+ termsOfService: string;
905
+ privacyPolicy: string;
840
906
  haveAccount: string;
841
907
  sendLink: string;
842
908
  linkSent: string;
843
909
  codeHelp: string;
844
910
  /** The second step when it is a phone only. */
845
911
  codeHelpPhone: string;
912
+ /** The second step by email (the account has no factor): "{to}" is the address, masked. */
913
+ codeHelpEmail: string;
914
+ sendEmailAgain: string;
846
915
  /** "{to}" is the phone, masked. */
847
916
  sendCodeSms: string;
848
917
  sendCodeWhatsapp: string;
@@ -937,7 +1006,7 @@ interface AuthTexts {
937
1006
  /** By error code; one missing shows what the server said. */
938
1007
  errors: Record<string, string>;
939
1008
  }
940
- type Slot = 'form' | 'field' | 'label' | 'input' | 'button' | 'providerButton' | 'link' | 'error' | 'fieldError' | 'notice' | 'separator' | 'footer' | 'account' | 'section' | 'heading' | 'secret' | 'codes' | 'sessions' | 'session';
1009
+ type Slot = 'form' | 'field' | 'label' | 'input' | 'button' | 'providerButton' | 'link' | 'error' | 'fieldError' | 'notice' | 'separator' | 'footer' | 'check' | 'account' | 'section' | 'heading' | 'secret' | 'codes' | 'sessions' | 'session';
941
1010
  interface AuthFormProps {
942
1011
  /** The language of the built-in sentences. Default: `en`. */
943
1012
  locale?: 'en' | 'es';
package/dist/react.d.ts CHANGED
@@ -277,6 +277,30 @@ interface AuthMethods {
277
277
  * found by their work address (`signIn.ssoDiscover`, `signIn.sso`).
278
278
  */
279
279
  sso: boolean;
280
+ /**
281
+ * Set when the workspace asks something of a sign-up: the legal documents
282
+ * to accept (the terms, the privacy policy: show the links and a box, send
283
+ * `acceptLegal: true`) and the consents to ask (one box each, sent as
284
+ * `consents`; a required one must be ticked). The ready-made form shows them.
285
+ */
286
+ legal?: {
287
+ documents: {
288
+ kind: string;
289
+ version: string;
290
+ url: string;
291
+ }[];
292
+ consentPurposes: {
293
+ key: string;
294
+ label: string;
295
+ required: boolean;
296
+ }[];
297
+ };
298
+ }
299
+ /** A legal document the person owes: not yet accepted in its current version. */
300
+ interface PendingLegal {
301
+ kind: string;
302
+ version: string;
303
+ url: string;
280
304
  }
281
305
  /** A company's sign-in (an SSO connection of the workspace). */
282
306
  interface SSOConnection {
@@ -457,6 +481,18 @@ interface AccountClient {
457
481
  }): Promise<AuthResult<'changed', {
458
482
  signedIn: boolean;
459
483
  }>>;
484
+ /**
485
+ * The legal documents the person has not accepted in their current version
486
+ * (a new version of the terms, say): show them and call `acceptLegal`.
487
+ * Nothing stops the person meanwhile; the application decides what waits.
488
+ */
489
+ legal(): Promise<AuthResult<'ok', {
490
+ pending: PendingLegal[];
491
+ }>>;
492
+ /** Records the person's acceptance of the documents in force (the kinds named, or every one). */
493
+ acceptLegal(form?: {
494
+ kinds?: string[];
495
+ }): Promise<AuthResult<'accepted'>>;
460
496
  mfa: {
461
497
  /** Starts turning the second step on: show `secret` (or `otpauthUri` as a QR code) to add to an authenticator app, then call `verify`. */
462
498
  setup(form: {
@@ -597,21 +633,34 @@ interface AuthClient {
597
633
  }): Promise<AuthResult<'signed_in', {
598
634
  session: PublicSession;
599
635
  }>>;
600
- /** With address and password. `mfa_required`: ask for the code and call `signIn.mfa`. */
636
+ /**
637
+ * With address and password. `mfa_required`: ask for the code and call
638
+ * `signIn.mfa`. `method: 'email'` says the code was just mailed to the
639
+ * account's address (it has no factor of its own and the workspace, or
640
+ * the sign-in's risk, asked a second step): say so, and offer
641
+ * `mfaSendEmail` for another.
642
+ */
601
643
  email(form: {
602
644
  email: string;
603
645
  password: string;
604
646
  captchaToken?: string;
605
647
  }): Promise<AuthResult<'signed_in', {
606
648
  session: PublicSession;
607
- }> | AuthResult<'mfa_required'>>;
608
- /** The second step: the code of the authenticator app, or a recovery code. */
649
+ }> | AuthResult<'mfa_required', {
650
+ method?: 'email';
651
+ }>>;
652
+ /** The second step: the code of the authenticator app, the phone, the email, or a recovery code. */
609
653
  mfa(form: {
610
654
  code: string;
611
655
  }): Promise<AuthResult<'signed_in', {
612
656
  session: PublicSession;
613
657
  }>>;
614
- /** While the second step is asked for: whether the account has an authenticator app, the phone (masked) a code can be sent to, and phones that approve sign-ins. */
658
+ /**
659
+ * While the second step is asked for: whether the account has an
660
+ * authenticator app, the phone (masked) a code can be sent to, phones
661
+ * that approve sign-ins, and the address (masked) a code went to when
662
+ * the step is by email.
663
+ */
615
664
  mfaMethods(): Promise<AuthResult<'ok', {
616
665
  totp: boolean;
617
666
  phone: {
@@ -621,6 +670,13 @@ interface AuthClient {
621
670
  push: {
622
671
  devices: number;
623
672
  } | null;
673
+ email: {
674
+ to: string;
675
+ } | null;
676
+ }>>;
677
+ /** Mails the sign-in's code again, when its second step is by email; `mfa` takes it. A few per sign-in. */
678
+ mfaSendEmail(): Promise<AuthResult<'sent', {
679
+ sentTo: string;
624
680
  }>>;
625
681
  /**
626
682
  * Sends a push to the account's phones (the application's app, with
@@ -764,12 +820,17 @@ interface AuthClient {
764
820
  }): string;
765
821
  };
766
822
  signUp: {
767
- /** `verification_required`: the account exists and must open the link Cauthy mailed before it can sign in. */
823
+ /**
824
+ * `verification_required`: the account exists and must open the link Cauthy mailed before it can sign in.
825
+ * `acceptLegal` and `consents` answer what `methods().legal` asks; a sign-up that leaves them out is refused.
826
+ */
768
827
  email(form: {
769
828
  email: string;
770
829
  password: string;
771
830
  name?: string;
772
831
  organization?: string;
832
+ acceptLegal?: boolean;
833
+ consents?: Record<string, boolean>;
773
834
  captchaToken?: string;
774
835
  }): Promise<AuthResult<'signed_in', {
775
836
  session: PublicSession;
@@ -837,12 +898,20 @@ interface AuthTexts {
837
898
  createAccount: string;
838
899
  /** The label of the company's name, asked when the application's system makes an organization per sign-up. */
839
900
  company: string;
901
+ /** The legal box: "I have read and accept" + "the Terms of Service" + "and" + "the Privacy Policy", linked. */
902
+ iAccept: string;
903
+ and: string;
904
+ termsOfService: string;
905
+ privacyPolicy: string;
840
906
  haveAccount: string;
841
907
  sendLink: string;
842
908
  linkSent: string;
843
909
  codeHelp: string;
844
910
  /** The second step when it is a phone only. */
845
911
  codeHelpPhone: string;
912
+ /** The second step by email (the account has no factor): "{to}" is the address, masked. */
913
+ codeHelpEmail: string;
914
+ sendEmailAgain: string;
846
915
  /** "{to}" is the phone, masked. */
847
916
  sendCodeSms: string;
848
917
  sendCodeWhatsapp: string;
@@ -937,7 +1006,7 @@ interface AuthTexts {
937
1006
  /** By error code; one missing shows what the server said. */
938
1007
  errors: Record<string, string>;
939
1008
  }
940
- type Slot = 'form' | 'field' | 'label' | 'input' | 'button' | 'providerButton' | 'link' | 'error' | 'fieldError' | 'notice' | 'separator' | 'footer' | 'account' | 'section' | 'heading' | 'secret' | 'codes' | 'sessions' | 'session';
1009
+ type Slot = 'form' | 'field' | 'label' | 'input' | 'button' | 'providerButton' | 'link' | 'error' | 'fieldError' | 'notice' | 'separator' | 'footer' | 'check' | 'account' | 'section' | 'heading' | 'secret' | 'codes' | 'sessions' | 'session';
941
1010
  interface AuthFormProps {
942
1011
  /** The language of the built-in sentences. Default: `en`. */
943
1012
  locale?: 'en' | 'es';
package/dist/react.js CHANGED
@@ -324,6 +324,7 @@ function createAuthClient(options = {}) {
324
324
  mfa: (f) => post("/sign-in/mfa", { code: f.code }, checkCode(f.code)),
325
325
  mfaMethods: () => post("/sign-in/mfa/methods", {}, null),
326
326
  mfaSendCode: () => post("/sign-in/mfa/send", {}, null),
327
+ mfaSendEmail: () => post("/sign-in/mfa/email", {}, null),
327
328
  mfaPush: () => post("/sign-in/mfa/push", {}, null),
328
329
  async mfaPushWait(o = {}) {
329
330
  const status = await new Promise((resolve) => {
@@ -442,7 +443,7 @@ function createAuthClient(options = {}) {
442
443
  signUp: {
443
444
  email: (f) => post(
444
445
  "/sign-up/email",
445
- { email: f.email, password: f.password, name: f.name, organization: f.organization },
446
+ { email: f.email, password: f.password, name: f.name, organization: f.organization, acceptLegal: f.acceptLegal, consents: f.consents },
446
447
  firstProblem(checkName(f.name), checkEmail(f.email), checkNewPassword(f.password), checkOrganization(f.organization)),
447
448
  f.captchaToken
448
449
  )
@@ -475,6 +476,12 @@ function createAuthClient(options = {}) {
475
476
  return body && typeof body.account === "object" ? body.account : null;
476
477
  },
477
478
  update: (f) => post("/me", { name: f.name }, checkName(f.name)),
479
+ async legal() {
480
+ const body = await read("/me/legal");
481
+ if (!body) return { ok: false, error: { code: "not_signed_in", message: "Nobody is signed in." } };
482
+ return { ok: true, status: "ok", pending: Array.isArray(body.pending) ? body.pending : [] };
483
+ },
484
+ acceptLegal: (f = {}) => post("/me/legal/accept", { kinds: f.kinds ?? [] }, null),
478
485
  changePassword: (f) => {
479
486
  const bad = checkNewPassword(f.newPassword);
480
487
  return post("/me/password", { password: f.password, newPassword: f.newPassword }, bad ? { ...bad, field: "newPassword" } : null);
@@ -615,11 +622,17 @@ var TEXTS = {
615
622
  noAccount: "No account yet?",
616
623
  createAccount: "Create one",
617
624
  haveAccount: "Already have an account?",
625
+ iAccept: "I have read and accept",
626
+ and: "and",
627
+ termsOfService: "the Terms of Service",
628
+ privacyPolicy: "the Privacy Policy",
618
629
  sendLink: "Send the link",
619
630
  linkSent: "If that address has an account, a link to choose a new password is on its way.",
620
631
  codeHelp: "Enter the code from your authenticator app, or a recovery code.",
621
632
  verify: "Verify",
622
633
  codeHelpPhone: "We send a code to your phone. Ask for it, then type it here, or use a recovery code.",
634
+ codeHelpEmail: "We sent a code to {to}. Type it here.",
635
+ sendEmailAgain: "Send the code again",
623
636
  sendCodeSms: "Send a code by SMS to {to}",
624
637
  sendCodeWhatsapp: "Send a code by WhatsApp to {to}",
625
638
  codeSent: "We sent a code to {to}. Type it here.",
@@ -765,11 +778,17 @@ var TEXTS = {
765
778
  noAccount: "\xBFNo tienes cuenta?",
766
779
  createAccount: "Crear una",
767
780
  haveAccount: "\xBFYa tienes cuenta?",
781
+ iAccept: "He le\xEDdo y acepto",
782
+ and: "y",
783
+ termsOfService: "los T\xE9rminos del servicio",
784
+ privacyPolicy: "la Pol\xEDtica de privacidad",
768
785
  sendLink: "Enviar el enlace",
769
786
  linkSent: "Si ese correo tiene una cuenta, ya va en camino un enlace para elegir una contrase\xF1a nueva.",
770
787
  codeHelp: "Escribe el c\xF3digo de tu aplicaci\xF3n de autenticaci\xF3n, o un c\xF3digo de recuperaci\xF3n.",
771
788
  verify: "Verificar",
772
789
  codeHelpPhone: "Te enviamos un c\xF3digo a tu tel\xE9fono. P\xEDdelo y escr\xEDbelo aqu\xED, o usa un c\xF3digo de recuperaci\xF3n.",
790
+ codeHelpEmail: "Te enviamos un c\xF3digo a {to}. Escr\xEDbelo aqu\xED.",
791
+ sendEmailAgain: "Enviar el c\xF3digo de nuevo",
773
792
  sendCodeSms: "Enviar un c\xF3digo por SMS a {to}",
774
793
  sendCodeWhatsapp: "Enviar un c\xF3digo por WhatsApp a {to}",
775
794
  codeSent: "Te enviamos un c\xF3digo a {to}. Escr\xEDbelo aqu\xED.",
@@ -1088,9 +1107,17 @@ function SignIn(props) {
1088
1107
  (0, import_react.useEffect)(() => {
1089
1108
  if (step !== "code") return;
1090
1109
  void auth.signIn.mfaMethods().then((r) => {
1091
- if (r.ok) setPhoneWay({ totp: r.totp, phone: r.phone, push: r.push });
1110
+ if (r.ok) setPhoneWay({ totp: r.totp, phone: r.phone, push: r.push, email: r.email });
1092
1111
  });
1093
1112
  }, [step]);
1113
+ const sendEmail = async () => {
1114
+ f.setBusy(true);
1115
+ f.setError(null);
1116
+ const r = await auth.signIn.mfaSendEmail();
1117
+ f.setBusy(false);
1118
+ if (!r.ok) return f.setError(r.error);
1119
+ setPhoneSent(r.sentTo);
1120
+ };
1094
1121
  const [pushNumber, setPushNumber] = (0, import_react.useState)(0);
1095
1122
  const pushWait = (0, import_react.useRef)(null);
1096
1123
  (0, import_react.useEffect)(() => () => pushWait.current?.abort(), []);
@@ -1219,8 +1246,9 @@ function SignIn(props) {
1219
1246
  if (step === "code") {
1220
1247
  const to = phoneWay?.phone?.number ?? "";
1221
1248
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1222
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: f.cx("notice"), children: phoneSent ? f.t.codeSent.replace("{to}", phoneSent) : phoneWay?.phone && !phoneWay.totp ? f.t.codeHelpPhone : f.t.codeHelp }),
1249
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: f.cx("notice"), children: phoneSent ? f.t.codeSent.replace("{to}", phoneSent) : phoneWay?.email ? f.t.codeHelpEmail.replace("{to}", phoneWay.email.to) : phoneWay?.phone && !phoneWay.totp ? f.t.codeHelpPhone : f.t.codeHelp }),
1223
1250
  general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1251
+ phoneWay?.email && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendEmail(), children: f.t.sendEmailAgain }),
1224
1252
  pushNumber > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: f.cx("notice"), role: "status", "aria-live": "polite", children: [
1225
1253
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: f.t.pushPick.replace("{n}", String(pushNumber)) }),
1226
1254
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: 48, fontWeight: 700, margin: "4px 0", textAlign: "center" }, children: pushNumber }),
@@ -1301,11 +1329,21 @@ function SignUp(props) {
1301
1329
  const [sent, setSent] = (0, import_react.useState)(false);
1302
1330
  const methods = useMethods(auth);
1303
1331
  const challenge = useChallenge(methods?.captchaSiteKey, props.locale);
1332
+ const [acceptLegal, setAcceptLegal] = (0, import_react.useState)(false);
1333
+ const [consents, setConsents] = (0, import_react.useState)({});
1334
+ const legal = methods?.legal;
1304
1335
  const submit = async (e) => {
1305
1336
  e.preventDefault();
1306
1337
  f.setBusy(true);
1307
1338
  f.setError(null);
1308
- const r = auth.session?.user.isAnonymous === true ? await auth.account.upgrade({ name, email, password }) : await auth.signUp.email({ name, email, password, ...methods?.organization?.ask ? { organization } : {}, captchaToken: challenge.token });
1339
+ const r = auth.session?.user.isAnonymous === true ? await auth.account.upgrade({ name, email, password }) : await auth.signUp.email({
1340
+ name,
1341
+ email,
1342
+ password,
1343
+ ...methods?.organization?.ask ? { organization } : {},
1344
+ ...legal ? { acceptLegal, consents } : {},
1345
+ captchaToken: challenge.token
1346
+ });
1309
1347
  f.setBusy(false);
1310
1348
  challenge.renew();
1311
1349
  if (!r.ok) return f.setError(r.error);
@@ -1325,6 +1363,25 @@ function SignUp(props) {
1325
1363
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
1326
1364
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
1327
1365
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "password", type: "password", label: f.t.password, value: password, autoComplete: "new-password", required: true, onChange: setPassword }),
1366
+ legal && legal.documents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: f.cx("check"), children: [
1367
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", name: "acceptLegal", checked: acceptLegal, required: true, onChange: (e) => setAcceptLegal(e.target.checked) }),
1368
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
1369
+ f.t.iAccept,
1370
+ " ",
1371
+ legal.documents.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
1372
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1373
+ f.t.and,
1374
+ " "
1375
+ ] }),
1376
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { className: f.cx("link"), href: d.url, target: "_blank", rel: "noopener", children: d.kind === "terms" ? f.t.termsOfService : f.t.privacyPolicy }),
1377
+ " "
1378
+ ] }, d.kind))
1379
+ ] })
1380
+ ] }),
1381
+ legal?.consentPurposes.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: f.cx("check"), children: [
1382
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", name: `consent_${p.key}`, checked: consents[p.key] === true, required: p.required, onChange: (e) => setConsents({ ...consents, [p.key]: e.target.checked }) }),
1383
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: p.label })
1384
+ ] }, p.key)),
1328
1385
  challenge.node,
1329
1386
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.signUp }),
1330
1387
  props.links?.signIn && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: f.cx("footer"), children: [