cauthy-auth 0.30.0 → 0.32.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.
Files changed (46) hide show
  1. package/README.md +50 -5
  2. package/dist/{cauthy-BXgsZ-Um.d.mts → cauthy-2jtP2LVQ.d.mts} +1 -1
  3. package/dist/{cauthy-CHENs452.d.ts → cauthy-CKfvvv_i.d.ts} +1 -1
  4. package/dist/cli.js +8 -5
  5. package/dist/client.d.mts +47 -6
  6. package/dist/client.d.ts +47 -6
  7. package/dist/client.js +16 -2
  8. package/dist/client.js.map +1 -1
  9. package/dist/client.mjs +16 -2
  10. package/dist/client.mjs.map +1 -1
  11. package/dist/express.d.mts +2 -2
  12. package/dist/express.d.ts +2 -2
  13. package/dist/fastify.d.mts +2 -2
  14. package/dist/fastify.d.ts +2 -2
  15. package/dist/hono.d.mts +2 -2
  16. package/dist/hono.d.ts +2 -2
  17. package/dist/index.d.mts +2 -2
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.js +64 -21
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +64 -21
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/next.d.mts +2 -2
  24. package/dist/next.d.ts +2 -2
  25. package/dist/react.d.mts +339 -31
  26. package/dist/react.d.ts +339 -31
  27. package/dist/react.js +616 -225
  28. package/dist/react.js.map +1 -1
  29. package/dist/react.mjs +610 -230
  30. package/dist/react.mjs.map +1 -1
  31. package/dist/styles.css +8 -0
  32. package/dist/svelte.d.mts +2 -2
  33. package/dist/svelte.d.ts +2 -2
  34. package/dist/svelte.js +16 -2
  35. package/dist/svelte.js.map +1 -1
  36. package/dist/svelte.mjs +16 -2
  37. package/dist/svelte.mjs.map +1 -1
  38. package/dist/{system-0mHrdAgO.d.mts → system-BrrJsrFW.d.mts} +14 -0
  39. package/dist/{system-BIYbS7h2.d.ts → system-BvvoNs2y.d.ts} +14 -0
  40. package/dist/vue.d.mts +2 -2
  41. package/dist/vue.d.ts +2 -2
  42. package/dist/vue.js +16 -2
  43. package/dist/vue.js.map +1 -1
  44. package/dist/vue.mjs +16 -2
  45. package/dist/vue.mjs.map +1 -1
  46. package/package.json +2 -1
package/dist/react.mjs CHANGED
@@ -373,11 +373,11 @@ function createAuthClient(options = {}) {
373
373
  if (res.ok) {
374
374
  const m = await res.json();
375
375
  if (m.password) policy = passwordPolicyOf(m.password);
376
- return { providers: [], signUp: true, magicLink: false, passkey: false, ...m, ...policy ? { password: policy } : {}, passkeyHere: m.passkeyHere === true, passkeyOnCauthy: m.passkeyOnCauthy ?? m.passkey === true, sso: m.sso === true };
376
+ return { providers: [], signUp: true, magicLink: false, passkey: false, ...m, ...policy ? { password: policy } : {}, passwordSignIn: m.passwordSignIn !== false, passkeyHere: m.passkeyHere === true, passkeyOnCauthy: m.passkeyOnCauthy ?? m.passkey === true, sso: m.sso === true };
377
377
  }
378
378
  } catch {
379
379
  }
380
- return { providers: [], signUp: true, magicLink: false, passkey: false, passkeyHere: false, passkeyOnCauthy: false, sso: false };
380
+ return { providers: [], signUp: true, passwordSignIn: true, magicLink: false, passkey: false, passkeyHere: false, passkeyOnCauthy: false, sso: false };
381
381
  }
382
382
  async function ceremony(begin, finish, form, run, more = {}) {
383
383
  const begun = await post(begin, form, null);
@@ -524,6 +524,20 @@ function createAuthClient(options = {}) {
524
524
  forgotPassword: (f) => post("/forgot-password", { email: f.email }, checkEmail(f.email), f.captchaToken),
525
525
  resetPassword: (f) => post("/reset-password", { token: f.token, password: f.password }, checkNewPassword(f.password, policy)),
526
526
  verifyEmail: (f) => post("/verify-email", { token: f.token }, null),
527
+ async invitation(token) {
528
+ const bad = { ok: false, error: { code: "invalid_token", message: "This invitation is not valid, or it has expired." } };
529
+ if (typeof token !== "string" || token.trim() === "") return bad;
530
+ try {
531
+ const res = await doFetch(`${base}/invitation?token=${encodeURIComponent(token.trim())}`, { credentials: "same-origin", headers: { accept: "application/json" } });
532
+ const body = await res.json().catch(() => null);
533
+ if (res.ok && body?.invitation) return { ok: true, status: "ok", invitation: body.invitation };
534
+ const e = body?.error;
535
+ return { ok: false, error: e && typeof e.code === "string" ? { code: e.code, message: String(e.message ?? "") } : UNAVAILABLE };
536
+ } catch {
537
+ return { ok: false, error: UNAVAILABLE };
538
+ }
539
+ },
540
+ acceptInvitation: (token, password) => post("/invitation/accept", { token, password }, checkNewPassword(password, policy)),
527
541
  signOut: () => post("/sign-out", {}, null),
528
542
  organizations: {
529
543
  async list(system) {
@@ -707,8 +721,8 @@ function definePolicy(given) {
707
721
  }
708
722
 
709
723
  // src/components.tsx
710
- import { useEffect, useId, useRef, useState } from "react";
711
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
724
+ import { Fragment, useEffect, useId, useRef, useState } from "react";
725
+ import { Fragment as Fragment2, jsx, jsxs } from "react/jsx-runtime";
712
726
  var TEXTS = {
713
727
  en: {
714
728
  email: "Email",
@@ -749,6 +763,7 @@ var TEXTS = {
749
763
  removePhone: "Remove phone",
750
764
  bySms: "SMS",
751
765
  byWhatsapp: "WhatsApp",
766
+ channel: "Send codes by",
752
767
  checkEmail: "Almost there: open the link we sent to confirm your address \u2014 it signs you in.",
753
768
  backToSignIn: "Back to sign in",
754
769
  emailMeALink: "Email me a sign-in link",
@@ -760,6 +775,13 @@ var TEXTS = {
760
775
  passwordChanged: "Your password was changed. You can sign in with it now.",
761
776
  confirming: "Confirming your address\u2026",
762
777
  emailConfirmed: "Your address is confirmed. You can sign in now.",
778
+ invitedTo: "You've been invited to {workspace}",
779
+ invitedToOrganization: "You've been invited to {organization} on {workspace}",
780
+ invitedAs: "You will sign in as {email}.",
781
+ choosePassword: "Choose a password",
782
+ acceptInvite: "Accept and sign in",
783
+ openingInvitation: "Opening your invitation\u2026",
784
+ invitationInvalid: "This invitation is not valid: it was already used, or it has expired. Ask whoever invited you to send it again.",
763
785
  profile: "Profile",
764
786
  save: "Save",
765
787
  saved: "Saved.",
@@ -831,6 +853,9 @@ var TEXTS = {
831
853
  organizationDeleted: "{org} was deleted.",
832
854
  yes: "Yes",
833
855
  cancel: "Cancel",
856
+ termsChanged: "Our terms changed",
857
+ termsChangedHelp: "To go on, read and accept",
858
+ acceptTerms: "Accept",
834
859
  errors: {
835
860
  not_allowed: "Your role in this organization does not allow that.",
836
861
  last_manager: "Somebody else must manage the members first: give that role to another member.",
@@ -874,7 +899,9 @@ var TEXTS = {
874
899
  invalid_assertion: "Your company's answer could not be checked. Try again.",
875
900
  provisioning_disabled: "Your company's sign-in worked, but this workspace has no account for you. Ask its admin to add you.",
876
901
  connection_inactive: "Your company's sign-in is turned off for this workspace.",
877
- invalid_grant: "That sign-in expired. Try again."
902
+ invalid_grant: "That sign-in expired. Try again.",
903
+ password_disabled: "This workspace does not sign in with a password. Use one of the other ways.",
904
+ passkeys_disabled: "Passkeys are turned off for this workspace."
878
905
  }
879
906
  },
880
907
  es: {
@@ -916,6 +943,7 @@ var TEXTS = {
916
943
  removePhone: "Quitar tel\xE9fono",
917
944
  bySms: "SMS",
918
945
  byWhatsapp: "WhatsApp",
946
+ channel: "Enviar los c\xF3digos por",
919
947
  checkEmail: "Casi listo: abre el enlace que te enviamos para confirmar tu correo; te deja adentro.",
920
948
  backToSignIn: "Volver a entrar",
921
949
  emailMeALink: "Env\xEDame un enlace para entrar",
@@ -927,6 +955,13 @@ var TEXTS = {
927
955
  passwordChanged: "Tu contrase\xF1a se cambi\xF3. Ya puedes entrar con ella.",
928
956
  confirming: "Confirmando tu correo\u2026",
929
957
  emailConfirmed: "Tu correo qued\xF3 confirmado. Ya puedes entrar.",
958
+ invitedTo: "Te invitaron a {workspace}",
959
+ invitedToOrganization: "Te invitaron a {organization} en {workspace}",
960
+ invitedAs: "Vas a entrar como {email}.",
961
+ choosePassword: "Elige una contrase\xF1a",
962
+ acceptInvite: "Aceptar y entrar",
963
+ openingInvitation: "Abriendo tu invitaci\xF3n\u2026",
964
+ invitationInvalid: "Esta invitaci\xF3n no es v\xE1lida: ya se us\xF3 o venci\xF3. P\xEDdele a quien te invit\xF3 que te la env\xEDe de nuevo.",
930
965
  profile: "Perfil",
931
966
  save: "Guardar",
932
967
  saved: "Guardado.",
@@ -998,6 +1033,9 @@ var TEXTS = {
998
1033
  organizationDeleted: "{org} qued\xF3 eliminada.",
999
1034
  yes: "S\xED",
1000
1035
  cancel: "Cancelar",
1036
+ termsChanged: "Nuestros t\xE9rminos cambiaron",
1037
+ termsChangedHelp: "Para seguir, lee y acepta",
1038
+ acceptTerms: "Aceptar",
1001
1039
  errors: {
1002
1040
  not_allowed: "Tu rol en esta organizaci\xF3n no permite eso.",
1003
1041
  last_manager: "Primero alguien m\xE1s debe administrar los miembros: dale ese rol a otro miembro.",
@@ -1041,7 +1079,9 @@ var TEXTS = {
1041
1079
  invalid_assertion: "No se pudo verificar la respuesta de tu empresa. Intenta de nuevo.",
1042
1080
  provisioning_disabled: "El ingreso con tu empresa funcion\xF3, pero este workspace no tiene una cuenta para ti. P\xEDdele a su admin que te agregue.",
1043
1081
  connection_inactive: "El inicio de sesi\xF3n de tu empresa est\xE1 apagado en este workspace.",
1044
- invalid_grant: "Ese ingreso venci\xF3. Intenta de nuevo."
1082
+ invalid_grant: "Ese ingreso venci\xF3. Intenta de nuevo.",
1083
+ password_disabled: "En este workspace no se entra con contrase\xF1a. Usa una de las otras formas.",
1084
+ passkeys_disabled: "Las llaves de acceso est\xE1n desactivadas en este workspace."
1045
1085
  }
1046
1086
  }
1047
1087
  };
@@ -1156,8 +1196,10 @@ function sameOrigin(to) {
1156
1196
  function useForm(props) {
1157
1197
  const t = { ...TEXTS[props.locale ?? "en"], ...props.texts, errors: { ...TEXTS[props.locale ?? "en"].errors, ...props.texts?.errors } };
1158
1198
  const cx = (slot) => props.classNames?.[slot] ?? `cauthy-${slot}`;
1159
- const Button = props.components?.Button ?? PlainButton;
1160
- const Input = props.components?.Input ?? PlainInput;
1199
+ const own = (slot) => props.classNames?.[slot];
1200
+ const C = props.components ?? {};
1201
+ const Button = C.Button ?? PlainButton;
1202
+ const Input = C.Input ?? PlainInput;
1161
1203
  const [error, setError] = useState(null);
1162
1204
  const [busy, setBusy] = useState(false);
1163
1205
  const [policy, setPolicy] = useState(void 0);
@@ -1172,7 +1214,81 @@ function useForm(props) {
1172
1214
  else window.location.assign(sitePath(to) ?? sameOrigin(props.returnTo) ?? "/");
1173
1215
  };
1174
1216
  const root = useRoot(props);
1175
- return { t, cx, Button, Input, error, setError, busy, setBusy, say, done, root, policy, setPolicy, passwordRule };
1217
+ return { t, cx, own, C, Button, Input, error, setError, busy, setBusy, say, done, root, policy, setPolicy, passwordRule };
1218
+ }
1219
+ function Note({ f, children, footer }) {
1220
+ const { Text } = f.C;
1221
+ if (Text) return /* @__PURE__ */ jsx(Text, { as: "p", tone: "muted", size: footer ? "sm" : "md", children });
1222
+ return /* @__PURE__ */ jsx("p", { className: f.cx(footer ? "footer" : "notice"), children });
1223
+ }
1224
+ function Heading({ f, children }) {
1225
+ const { Text } = f.C;
1226
+ if (Text) return /* @__PURE__ */ jsx(Text, { as: "h2", size: "lg", children });
1227
+ return /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children });
1228
+ }
1229
+ function Say({ f, tone, children }) {
1230
+ const { Alert } = f.C;
1231
+ if (Alert) return /* @__PURE__ */ jsx(Alert, { tone, children });
1232
+ if (tone === "danger") return /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children });
1233
+ return /* @__PURE__ */ jsx("p", { role: "status", className: f.cx("notice"), children });
1234
+ }
1235
+ function Or({ f, children }) {
1236
+ const { Divider } = f.C;
1237
+ if (Divider) return /* @__PURE__ */ jsx(Divider, { label: children });
1238
+ return /* @__PURE__ */ jsx("p", { className: f.cx("separator"), children });
1239
+ }
1240
+ function A({ f, href, newTab, children }) {
1241
+ const { Link } = f.C;
1242
+ if (Link) return /* @__PURE__ */ jsx(Link, { href, newTab, children });
1243
+ return /* @__PURE__ */ jsx("a", { className: f.cx("link"), href, target: newTab ? "_blank" : void 0, rel: newTab ? "noopener" : void 0, children });
1244
+ }
1245
+ function Tag({ f, tone, children, plain }) {
1246
+ const { Badge } = f.C;
1247
+ if (Badge) return /* @__PURE__ */ jsxs(Fragment2, { children: [
1248
+ " ",
1249
+ /* @__PURE__ */ jsx(Badge, { tone, children })
1250
+ ] });
1251
+ return /* @__PURE__ */ jsx(Fragment2, { children: plain });
1252
+ }
1253
+ function Check(p) {
1254
+ const id = useId();
1255
+ const { f } = p;
1256
+ const { Checkbox } = f.C;
1257
+ if (Checkbox) {
1258
+ return /* @__PURE__ */ jsx(Checkbox, { id, name: p.name, checked: p.checked, required: p.required, className: f.own("check"), onChange: p.onChange, children: p.children });
1259
+ }
1260
+ return /* @__PURE__ */ jsxs("label", { className: f.cx("check"), children: [
1261
+ /* @__PURE__ */ jsx("input", { type: "checkbox", name: p.name, checked: p.checked, required: p.required, onChange: (e) => p.onChange(e.target.checked) }),
1262
+ /* @__PURE__ */ jsx("span", { children: p.children })
1263
+ ] });
1264
+ }
1265
+ function Pick(p) {
1266
+ const made = useId();
1267
+ const id = p.id ?? made;
1268
+ const { f } = p;
1269
+ const { Select } = f.C;
1270
+ if (Select) {
1271
+ return /* @__PURE__ */ jsx(Select, { id, name: p.name, value: p.value, options: p.options, disabled: p.disabled, "aria-label": p.label, className: f.own("input"), onChange: p.onChange });
1272
+ }
1273
+ return /* @__PURE__ */ jsx("select", { id, name: p.name, "aria-label": p.label, className: f.cx("input"), value: p.value, disabled: p.disabled, onChange: (e) => p.onChange(e.target.value), children: p.options.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value)) });
1274
+ }
1275
+ function Labelled({ f, id, label, children }) {
1276
+ const { Field: OwnField } = f.C;
1277
+ if (OwnField) return /* @__PURE__ */ jsx(OwnField, { id, label, className: f.own("field"), children });
1278
+ return /* @__PURE__ */ jsxs("label", { className: f.cx("field"), children: [
1279
+ /* @__PURE__ */ jsx("span", { className: f.cx("label"), children: label }),
1280
+ children
1281
+ ] });
1282
+ }
1283
+ function Documents({ f, documents }) {
1284
+ return /* @__PURE__ */ jsx(Fragment2, { children: documents.map((d, i) => /* @__PURE__ */ jsxs("span", { children: [
1285
+ i > 0 && /* @__PURE__ */ jsxs(Fragment2, { children: [
1286
+ f.t.and,
1287
+ " "
1288
+ ] }),
1289
+ /* @__PURE__ */ jsx(A, { f, href: d.url, newTab: true, children: d.kind === "terms" ? f.t.termsOfService : f.t.privacyPolicy }),
1290
+ " "
1291
+ ] }, d.kind)) });
1176
1292
  }
1177
1293
  var PASSWORD_RULES = ["needs_lowercase", "needs_uppercase", "needs_digit", "needs_symbol", "needs_classes", "breached"];
1178
1294
  function isPasswordRule(e) {
@@ -1190,26 +1306,43 @@ function Field(p) {
1190
1306
  const { f } = p;
1191
1307
  const bad = f.error?.field === p.name ? f.error : null;
1192
1308
  const described = [bad ? `${id}-error` : "", p.hint ? `${id}-hint` : ""].filter(Boolean).join(" ");
1309
+ const input = /* @__PURE__ */ jsx(
1310
+ f.Input,
1311
+ {
1312
+ id,
1313
+ name: p.name,
1314
+ type: p.type,
1315
+ value: p.value,
1316
+ autoComplete: p.autoComplete,
1317
+ required: p.required,
1318
+ className: f.cx("input"),
1319
+ "aria-invalid": bad ? true : void 0,
1320
+ "aria-describedby": described || void 0,
1321
+ onChange: (e) => p.onChange(e.target.value)
1322
+ }
1323
+ );
1324
+ const { Field: OwnField } = f.C;
1325
+ if (OwnField) {
1326
+ return /* @__PURE__ */ jsx(
1327
+ OwnField,
1328
+ {
1329
+ id,
1330
+ label: p.label,
1331
+ aside: p.aside,
1332
+ help: p.hint && !bad ? p.hint : void 0,
1333
+ error: bad ? f.say(bad) : void 0,
1334
+ required: p.required,
1335
+ className: f.own("field"),
1336
+ children: input
1337
+ }
1338
+ );
1339
+ }
1193
1340
  return /* @__PURE__ */ jsxs("div", { className: f.cx("field"), children: [
1194
1341
  /* @__PURE__ */ jsxs("label", { className: f.cx("label"), htmlFor: id, children: [
1195
1342
  p.label,
1196
1343
  p.aside
1197
1344
  ] }),
1198
- /* @__PURE__ */ jsx(
1199
- f.Input,
1200
- {
1201
- id,
1202
- name: p.name,
1203
- type: p.type,
1204
- value: p.value,
1205
- autoComplete: p.autoComplete,
1206
- required: p.required,
1207
- className: f.cx("input"),
1208
- "aria-invalid": bad ? true : void 0,
1209
- "aria-describedby": described || void 0,
1210
- onChange: (e) => p.onChange(e.target.value)
1211
- }
1212
- ),
1345
+ input,
1213
1346
  p.hint && !bad && /* @__PURE__ */ jsx("span", { id: `${id}-hint`, className: f.cx("hint"), children: p.hint }),
1214
1347
  bad && /* @__PURE__ */ jsx("span", { id: `${id}-error`, role: "alert", className: f.cx("fieldError"), children: f.say(bad) })
1215
1348
  ] });
@@ -1236,23 +1369,16 @@ function useMailedToken(name, open) {
1236
1369
  open(takeToken(name));
1237
1370
  }, []);
1238
1371
  }
1239
- function SignIn(props) {
1240
- const auth = useAuth();
1241
- const f = useForm(props);
1242
- const [methods, setMethods] = useState(null);
1243
- const [email, setEmail] = useState("");
1244
- const [password, setPassword] = useState("");
1372
+ function SecondStepForm(p) {
1373
+ const { f, auth } = p;
1245
1374
  const [code, setCode] = useState("");
1246
- const [step, setStep] = useState("password");
1247
- const challenge = useChallenge(methods?.captchaSiteKey, props.locale);
1248
1375
  const [phoneWay, setPhoneWay] = useState(null);
1249
1376
  const [phoneSent, setPhoneSent] = useState("");
1250
1377
  useEffect(() => {
1251
- if (step !== "code") return;
1252
1378
  void auth.signIn.mfaMethods().then((r) => {
1253
1379
  if (r.ok) setPhoneWay({ totp: r.totp, phone: r.phone, push: r.push, email: r.email });
1254
1380
  });
1255
- }, [step]);
1381
+ }, []);
1256
1382
  const sendEmail = async () => {
1257
1383
  f.setBusy(true);
1258
1384
  f.setError(null);
@@ -1288,6 +1414,62 @@ function SignIn(props) {
1288
1414
  if (!r.ok) return f.setError(r.error);
1289
1415
  setPhoneSent(r.sentTo);
1290
1416
  };
1417
+ const submit = async (e) => {
1418
+ e.preventDefault();
1419
+ f.setBusy(true);
1420
+ f.setError(null);
1421
+ const r = await auth.signIn.mfa({ code });
1422
+ f.setBusy(false);
1423
+ if (!r.ok) return f.setError(r.error);
1424
+ f.done();
1425
+ };
1426
+ const general = f.error && !f.error.field ? f.error : null;
1427
+ const to = phoneWay?.phone?.number ?? "";
1428
+ return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1429
+ /* @__PURE__ */ jsx(Note, { f, 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 }),
1430
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
1431
+ phoneWay?.email && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendEmail(), children: f.t.sendEmailAgain }),
1432
+ pushNumber > 0 ? f.C.Text ? (
1433
+ // The application's text: the number to pick drawn large, by its own rules.
1434
+ /* @__PURE__ */ jsxs("div", { role: "status", "aria-live": "polite", children: [
1435
+ /* @__PURE__ */ jsx(f.C.Text, { as: "p", children: f.t.pushPick.replace("{n}", String(pushNumber)) }),
1436
+ /* @__PURE__ */ jsx(f.C.Text, { as: "p", size: "lg", children: pushNumber }),
1437
+ /* @__PURE__ */ jsx(f.C.Text, { as: "p", tone: "muted", children: f.t.pushWaiting })
1438
+ ] })
1439
+ ) : /* @__PURE__ */ jsxs("div", { className: f.cx("notice"), role: "status", "aria-live": "polite", children: [
1440
+ /* @__PURE__ */ jsx("p", { children: f.t.pushPick.replace("{n}", String(pushNumber)) }),
1441
+ /* @__PURE__ */ jsx("p", { style: { fontSize: 48, fontWeight: 700, margin: "4px 0", textAlign: "center" }, children: pushNumber }),
1442
+ /* @__PURE__ */ jsx("p", { children: f.t.pushWaiting })
1443
+ ] }) : phoneWay?.push && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("button"), onClick: () => void sendPush(), children: f.t.pushSend }),
1444
+ phoneWay?.phone && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendCode(), children: (phoneWay.phone.channel === "whatsapp" ? f.t.sendCodeWhatsapp : f.t.sendCodeSms).replace("{to}", to) }),
1445
+ /* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
1446
+ /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
1447
+ ] });
1448
+ }
1449
+ function ProviderButtons(p) {
1450
+ const { f } = p;
1451
+ return /* @__PURE__ */ jsx(Fragment2, { children: p.providers.map((provider) => /* @__PURE__ */ jsxs(f.Button, { type: "button", className: f.cx("providerButton"), onClick: () => p.onPick(provider.id), children: [
1452
+ provider.iconUrl && /* @__PURE__ */ jsx("img", { src: provider.iconUrl, alt: "", width: 18, height: 18, className: f.cx("providerIcon") }),
1453
+ f.t.continueWith,
1454
+ " ",
1455
+ provider.name
1456
+ ] }, provider.id)) });
1457
+ }
1458
+ function signInOffers(methods) {
1459
+ const password = methods?.passwordSignIn !== false;
1460
+ return { password, email: password || methods?.magicLink === true || methods?.sso === true, passkey: methods?.passkey === true };
1461
+ }
1462
+ function SignIn(props) {
1463
+ const auth = useAuth();
1464
+ const f = useForm(props);
1465
+ const [methods, setMethods] = useState(null);
1466
+ const [email, setEmail] = useState("");
1467
+ const [password, setPassword] = useState("");
1468
+ const [code, setCode] = useState("");
1469
+ const [step, setStep] = useState("password");
1470
+ const challenge = useChallenge(methods?.captchaSiteKey, props.locale);
1471
+ const offers = signInOffers(methods);
1472
+ const passwordOn = offers.password;
1291
1473
  const autofill = useRef(null);
1292
1474
  const [offer, setOffer] = useState(0);
1293
1475
  const [company, setCompany] = useState(null);
@@ -1339,10 +1521,18 @@ function SignIn(props) {
1339
1521
  const submit = async (e) => {
1340
1522
  e.preventDefault();
1341
1523
  autofill.current?.abort();
1524
+ if (step === "password" && company?.enforced) {
1525
+ f.setError(null);
1526
+ return toCompany();
1527
+ }
1528
+ if (step === "password" && !passwordOn) {
1529
+ if (company) return toCompany();
1530
+ if (methods?.magicLink) return sendLink();
1531
+ return;
1532
+ }
1342
1533
  f.setBusy(true);
1343
1534
  f.setError(null);
1344
- if (step === "password" && company?.enforced) return toCompany();
1345
- const r = step === "code" ? await auth.signIn.mfa({ code }) : step === "sent" ? await auth.signIn.emailCode({ code }) : await auth.signIn.email({ email, password, captchaToken: challenge.token });
1535
+ const r = step === "sent" ? await auth.signIn.emailCode({ code }) : await auth.signIn.email({ email, password, captchaToken: challenge.token });
1346
1536
  f.setBusy(false);
1347
1537
  if (step === "password") challenge.renew();
1348
1538
  if (!r.ok && r.error.code === "sso_required") return toCompany();
@@ -1376,49 +1566,31 @@ function SignIn(props) {
1376
1566
  setStep("sent");
1377
1567
  };
1378
1568
  const general = f.error && !f.error.field ? f.error : null;
1569
+ const asksEmail = offers.email;
1379
1570
  if (step === "opening") return /* @__PURE__ */ jsx("div", { className: f.cx("form"), ...f.root, "aria-busy": "true" });
1380
1571
  if (step === "sent") {
1381
1572
  return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1382
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.signInLinkSent }),
1383
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1384
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.codeFromMail }),
1385
- /* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
1386
- /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
1387
- ] });
1388
- }
1389
- if (step === "code") {
1390
- const to = phoneWay?.phone?.number ?? "";
1391
- return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1392
- /* @__PURE__ */ 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 }),
1393
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1394
- phoneWay?.email && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendEmail(), children: f.t.sendEmailAgain }),
1395
- pushNumber > 0 ? /* @__PURE__ */ jsxs("div", { className: f.cx("notice"), role: "status", "aria-live": "polite", children: [
1396
- /* @__PURE__ */ jsx("p", { children: f.t.pushPick.replace("{n}", String(pushNumber)) }),
1397
- /* @__PURE__ */ jsx("p", { style: { fontSize: 48, fontWeight: 700, margin: "4px 0", textAlign: "center" }, children: pushNumber }),
1398
- /* @__PURE__ */ jsx("p", { children: f.t.pushWaiting })
1399
- ] }) : phoneWay?.push && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("button"), onClick: () => void sendPush(), children: f.t.pushSend }),
1400
- phoneWay?.phone && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendCode(), children: (phoneWay.phone.channel === "whatsapp" ? f.t.sendCodeWhatsapp : f.t.sendCodeSms).replace("{to}", to) }),
1573
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.signInLinkSent }),
1574
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
1575
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.codeFromMail }),
1401
1576
  /* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
1402
1577
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
1403
1578
  ] });
1404
1579
  }
1580
+ if (step === "code") return /* @__PURE__ */ jsx(SecondStepForm, { f, auth });
1405
1581
  return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1406
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1407
- (methods?.providers ?? []).map((p) => /* @__PURE__ */ jsxs(f.Button, { type: "button", className: f.cx("providerButton"), onClick: () => auth.signIn.social(p.id, { returnTo: props.returnTo }), children: [
1408
- f.t.continueWith,
1409
- " ",
1410
- p.name
1411
- ] }, p.id)),
1412
- methods?.passkey && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void usePasskey(), children: f.t.usePasskey }),
1413
- ((methods?.providers.length ?? 0) > 0 || methods?.passkey) && /* @__PURE__ */ jsx("p", { className: f.cx("separator"), children: f.t.orWithEmail }),
1414
- /* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: methods?.passkeyHere ? "username webauthn" : "username", required: true, onChange: setEmail }),
1582
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
1583
+ /* @__PURE__ */ jsx(ProviderButtons, { f, providers: methods?.providers ?? [], onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
1584
+ offers.passkey && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void usePasskey(), children: f.t.usePasskey }),
1585
+ asksEmail && ((methods?.providers.length ?? 0) > 0 || offers.passkey) && /* @__PURE__ */ jsx(Or, { f, children: f.t.orWithEmail }),
1586
+ asksEmail && /* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: methods?.passkeyHere ? "username webauthn" : "username", required: true, onChange: setEmail }),
1415
1587
  company && /* @__PURE__ */ jsxs(f.Button, { type: "button", disabled: f.busy, className: f.cx(company.enforced ? "button" : "providerButton"), onClick: toCompany, children: [
1416
1588
  f.t.continueWith,
1417
1589
  " ",
1418
1590
  company.name
1419
1591
  ] }),
1420
- company?.enforced && /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.ssoOnly }),
1421
- !company?.enforced && /* @__PURE__ */ jsxs(Fragment, { children: [
1592
+ company?.enforced && /* @__PURE__ */ jsx(Note, { f, children: f.t.ssoOnly }),
1593
+ !company?.enforced && passwordOn && /* @__PURE__ */ jsxs(Fragment2, { children: [
1422
1594
  /* @__PURE__ */ jsx(
1423
1595
  Field,
1424
1596
  {
@@ -1430,17 +1602,18 @@ function SignIn(props) {
1430
1602
  autoComplete: "current-password",
1431
1603
  required: true,
1432
1604
  onChange: setPassword,
1433
- aside: props.links?.forgotPassword ? /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.forgotPassword, children: f.t.forgotPassword }) : void 0
1605
+ aside: props.links?.forgotPassword ? /* @__PURE__ */ jsx(A, { f, href: props.links.forgotPassword, children: f.t.forgotPassword }) : void 0
1434
1606
  }
1435
1607
  ),
1436
1608
  challenge.node,
1437
1609
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.signIn })
1438
1610
  ] }),
1611
+ !company?.enforced && !passwordOn && methods?.magicLink && challenge.node,
1439
1612
  methods?.magicLink && !company?.enforced && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendLink(), children: f.t.emailMeALink }),
1440
- methods?.signUp !== false && props.links?.signUp && /* @__PURE__ */ jsxs("p", { className: f.cx("footer"), children: [
1613
+ methods?.signUp !== false && props.links?.signUp && /* @__PURE__ */ jsxs(Note, { f, footer: true, children: [
1441
1614
  f.t.noAccount,
1442
1615
  " ",
1443
- /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signUp, children: f.t.createAccount })
1616
+ /* @__PURE__ */ jsx(A, { f, href: props.links.signUp, children: f.t.createAccount })
1444
1617
  ] })
1445
1618
  ] });
1446
1619
  }
@@ -1495,44 +1668,43 @@ function SignUp(props) {
1495
1668
  f.done();
1496
1669
  };
1497
1670
  const general = f.error && !f.error.field ? f.error : null;
1671
+ const passwordOn = methods?.passwordSignIn !== false;
1672
+ const providers = auth.session?.user.isAnonymous === true || methods?.organization?.required ? [] : methods?.providers ?? [];
1498
1673
  if (sent) {
1499
1674
  return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
1500
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.checkEmail }),
1501
- props.links?.signIn && /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.backToSignIn })
1675
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.checkEmail }),
1676
+ props.links?.signIn && /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn })
1677
+ ] });
1678
+ }
1679
+ const footer = props.links?.signIn && /* @__PURE__ */ jsxs(Note, { f, footer: true, children: [
1680
+ f.t.haveAccount,
1681
+ " ",
1682
+ /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.signIn })
1683
+ ] });
1684
+ if (!passwordOn) {
1685
+ return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
1686
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
1687
+ /* @__PURE__ */ jsx(ProviderButtons, { f, providers, onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
1688
+ footer
1502
1689
  ] });
1503
1690
  }
1504
1691
  return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1505
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1692
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
1693
+ /* @__PURE__ */ jsx(ProviderButtons, { f, providers, onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
1694
+ providers.length > 0 && /* @__PURE__ */ jsx(Or, { f, children: f.t.orWithEmail }),
1506
1695
  methods?.organization?.ask && /* @__PURE__ */ jsx(Field, { f, name: "organization", type: "text", label: f.t.company, value: organization, autoComplete: "organization", required: methods.organization.required, onChange: setOrganization }),
1507
1696
  /* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
1508
1697
  /* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
1509
1698
  /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.password, value: password, autoComplete: "new-password", required: true, onChange: setPassword, hint: f.passwordRule }),
1510
- legal && legal.documents.length > 0 && /* @__PURE__ */ jsxs("label", { className: f.cx("check"), children: [
1511
- /* @__PURE__ */ jsx("input", { type: "checkbox", name: "acceptLegal", checked: acceptLegal, required: true, onChange: (e) => setAcceptLegal(e.target.checked) }),
1512
- /* @__PURE__ */ jsxs("span", { children: [
1513
- f.t.iAccept,
1514
- " ",
1515
- legal.documents.map((d, i) => /* @__PURE__ */ jsxs("span", { children: [
1516
- i > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1517
- f.t.and,
1518
- " "
1519
- ] }),
1520
- /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: d.url, target: "_blank", rel: "noopener", children: d.kind === "terms" ? f.t.termsOfService : f.t.privacyPolicy }),
1521
- " "
1522
- ] }, d.kind))
1523
- ] })
1699
+ legal && legal.documents.length > 0 && /* @__PURE__ */ jsxs(Check, { f, name: "acceptLegal", checked: acceptLegal, required: true, onChange: setAcceptLegal, children: [
1700
+ f.t.iAccept,
1701
+ " ",
1702
+ /* @__PURE__ */ jsx(Documents, { f, documents: legal.documents })
1524
1703
  ] }),
1525
- legal?.consentPurposes.map((p) => /* @__PURE__ */ jsxs("label", { className: f.cx("check"), children: [
1526
- /* @__PURE__ */ 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 }) }),
1527
- /* @__PURE__ */ jsx("span", { children: p.label })
1528
- ] }, p.key)),
1704
+ legal?.consentPurposes.map((p) => /* @__PURE__ */ jsx(Check, { f, name: `consent_${p.key}`, checked: consents[p.key] === true, required: p.required, onChange: (on) => setConsents({ ...consents, [p.key]: on }), children: p.label }, p.key)),
1529
1705
  challenge.node,
1530
1706
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.signUp }),
1531
- props.links?.signIn && /* @__PURE__ */ jsxs("p", { className: f.cx("footer"), children: [
1532
- f.t.haveAccount,
1533
- " ",
1534
- /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.signIn })
1535
- ] })
1707
+ footer
1536
1708
  ] });
1537
1709
  }
1538
1710
  function ForgotPassword(props) {
@@ -1554,16 +1726,16 @@ function ForgotPassword(props) {
1554
1726
  const general = f.error && !f.error.field ? f.error : null;
1555
1727
  if (sent) {
1556
1728
  return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
1557
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.linkSent }),
1558
- props.links?.signIn && /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.backToSignIn })
1729
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.linkSent }),
1730
+ props.links?.signIn && /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn })
1559
1731
  ] });
1560
1732
  }
1561
1733
  return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1562
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1734
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
1563
1735
  /* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
1564
1736
  challenge.node,
1565
1737
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.sendLink }),
1566
- props.links?.signIn && /* @__PURE__ */ jsx("p", { className: f.cx("footer"), children: /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.backToSignIn }) })
1738
+ props.links?.signIn && /* @__PURE__ */ jsx(Note, { f, footer: true, children: /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn }) })
1567
1739
  ] });
1568
1740
  }
1569
1741
  function ResetPassword(props) {
@@ -1587,21 +1759,21 @@ function ResetPassword(props) {
1587
1759
  setChanged(true);
1588
1760
  };
1589
1761
  const general = f.error && !f.error.field ? f.error : null;
1590
- const back = props.links?.signIn && /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.backToSignIn });
1762
+ const back = props.links?.signIn && /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn });
1591
1763
  if (changed) {
1592
1764
  return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
1593
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.passwordChanged }),
1765
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.passwordChanged }),
1594
1766
  back
1595
1767
  ] });
1596
1768
  }
1597
1769
  if (token === "") {
1598
1770
  return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
1599
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1600
- props.links?.forgotPassword && /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.forgotPassword, children: f.t.forgotPassword })
1771
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
1772
+ props.links?.forgotPassword && /* @__PURE__ */ jsx(A, { f, href: props.links.forgotPassword, children: f.t.forgotPassword })
1601
1773
  ] });
1602
1774
  }
1603
1775
  return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1604
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1776
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
1605
1777
  /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.newPassword, value: password, autoComplete: "new-password", required: true, onChange: setPassword, hint: f.passwordRule }),
1606
1778
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy || token === null, className: f.cx("button"), children: f.t.savePassword })
1607
1779
  ] });
@@ -1623,12 +1795,98 @@ function VerifyEmail(props) {
1623
1795
  });
1624
1796
  });
1625
1797
  return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, "aria-busy": state === "confirming", children: [
1626
- state === "confirming" && /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.confirming }),
1627
- state === "confirmed" && /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.emailConfirmed }),
1628
- state === "failed" && f.error && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(f.error) }),
1629
- state !== "confirming" && props.links?.signIn && /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.backToSignIn })
1798
+ state === "confirming" && /* @__PURE__ */ jsx(Note, { f, children: f.t.confirming }),
1799
+ state === "confirmed" && /* @__PURE__ */ jsx(Note, { f, children: f.t.emailConfirmed }),
1800
+ state === "failed" && f.error && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(f.error) }),
1801
+ state !== "confirming" && props.links?.signIn && /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn })
1630
1802
  ] });
1631
1803
  }
1804
+ function AcceptInvite(props) {
1805
+ const auth = useAuth();
1806
+ const f = useForm(props);
1807
+ const [token, setToken] = useState("");
1808
+ const [invitation, setInvitation] = useState(null);
1809
+ const [state, setState] = useState("opening");
1810
+ const [password, setPassword] = useState("");
1811
+ usePasswordPolicy(f, useMethods(auth));
1812
+ useMailedToken("token", (t) => {
1813
+ if (!t) return setState("invalid");
1814
+ setToken(t);
1815
+ void auth.invitation(t).then((r) => {
1816
+ if (r.ok) {
1817
+ setInvitation(r.invitation);
1818
+ return setState("ready");
1819
+ }
1820
+ if (r.error.code !== "invalid_token") f.setError(r.error);
1821
+ setState("invalid");
1822
+ });
1823
+ });
1824
+ const submit = async (e) => {
1825
+ e.preventDefault();
1826
+ f.setBusy(true);
1827
+ f.setError(null);
1828
+ const r = await auth.acceptInvitation(token, password);
1829
+ f.setBusy(false);
1830
+ if (!r.ok) {
1831
+ if (r.error.code === "invalid_token") return setState("invalid");
1832
+ return f.setError(r.error);
1833
+ }
1834
+ props.onSaved?.({ kind: "invitation.accepted", email: invitation?.email ?? "", ...invitation?.organization ? { organization: invitation.organization } : {} });
1835
+ if (r.status === "mfa_required") return setState("code");
1836
+ f.done();
1837
+ };
1838
+ const general = f.error && !f.error.field ? f.error : null;
1839
+ const back = props.links?.signIn && /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn });
1840
+ if (state === "opening") {
1841
+ return /* @__PURE__ */ jsx("div", { className: f.cx("form"), ...f.root, "aria-busy": "true", children: /* @__PURE__ */ jsx(Note, { f, children: f.t.openingInvitation }) });
1842
+ }
1843
+ if (state === "invalid") {
1844
+ return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
1845
+ /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: general ? f.say(general) : f.t.invitationInvalid }),
1846
+ back
1847
+ ] });
1848
+ }
1849
+ if (state === "code") return /* @__PURE__ */ jsx(SecondStepForm, { f, auth });
1850
+ const workspace = invitation?.workspace ?? "";
1851
+ const heading = invitation?.organization ? f.t.invitedToOrganization.replace("{organization}", invitation.organization).replace("{workspace}", workspace) : f.t.invitedTo.replace("{workspace}", workspace);
1852
+ return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1853
+ /* @__PURE__ */ jsx(Heading, { f, children: heading }),
1854
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.invitedAs.replace("{email}", invitation?.email ?? "") }),
1855
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
1856
+ /* @__PURE__ */ jsx("input", { type: "email", name: "username", autoComplete: "username", value: invitation?.email ?? "", readOnly: true, hidden: true }),
1857
+ /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.choosePassword, value: password, autoComplete: "new-password", required: true, onChange: setPassword, hint: f.passwordRule }),
1858
+ /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.acceptInvite })
1859
+ ] });
1860
+ }
1861
+ function PendingTerms(props) {
1862
+ const auth = useAuth();
1863
+ const f = useForm(props);
1864
+ const [owed, setOwed] = useState(null);
1865
+ useEffect(() => {
1866
+ void auth.account.legal().then((r) => setOwed(r.ok ? r.pending : []));
1867
+ }, []);
1868
+ if (!owed || owed.length === 0) return null;
1869
+ const accept = async () => {
1870
+ f.setBusy(true);
1871
+ f.setError(null);
1872
+ const r = await auth.account.acceptLegal({ kinds: owed.map((d) => d.kind) });
1873
+ f.setBusy(false);
1874
+ if (!r.ok) return f.setError(r.error);
1875
+ setOwed([]);
1876
+ props.onSuccess?.();
1877
+ };
1878
+ return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
1879
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.termsChanged }),
1880
+ /* @__PURE__ */ jsxs(Note, { f, children: [
1881
+ f.t.termsChangedHelp,
1882
+ " ",
1883
+ /* @__PURE__ */ jsx(Documents, { f, documents: owed })
1884
+ ] }),
1885
+ f.error && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(f.error) }),
1886
+ /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("button"), onClick: () => void accept(), children: f.t.acceptTerms })
1887
+ ] });
1888
+ }
1889
+ var ACCOUNT_SECTIONS = ["profile", "email", "password", "linked", "secondStep", "phone", "passkeys", "agents", "sessions"];
1632
1890
  function useSection(props) {
1633
1891
  const f = useForm({ ...props, unstyled: true });
1634
1892
  const [done, setDone] = useState(null);
@@ -1647,37 +1905,65 @@ function useSection(props) {
1647
1905
  function Account(props) {
1648
1906
  const auth = useAuth();
1649
1907
  const { accountUrl } = useSession();
1650
- const { t, root } = useForm(props);
1908
+ const { root } = useForm(props);
1651
1909
  const cx = (slot) => props.classNames?.[slot] ?? `cauthy-${slot}`;
1652
1910
  const [account, setAccount] = useState(null);
1653
- const [sessions, setSessions] = useState([]);
1654
1911
  useEffect(() => {
1655
1912
  void auth.account.get().then(setAccount);
1656
- void auth.account.sessions().then(setSessions);
1657
1913
  }, []);
1658
1914
  if (account === null) return /* @__PURE__ */ jsx("div", { className: cx("account"), ...root, "aria-busy": "true" });
1659
1915
  const when = props.formatDate ?? ((iso) => new Date(iso).toLocaleString());
1660
- return /* @__PURE__ */ jsxs("div", { className: cx("account"), ...root, children: [
1661
- /* @__PURE__ */ jsx(ProfilePart, { props, account, onSaved: setAccount }),
1662
- /* @__PURE__ */ jsx(EmailPart, { props, account }),
1663
- account.hasPassword && /* @__PURE__ */ jsx(PasswordPart, { props }),
1664
- /* @__PURE__ */ jsx(LinkedPart, { props }),
1665
- /* @__PURE__ */ jsx(SecondStepPart, { props, account, onChanged: (mfaEnabled) => setAccount({ ...account, mfaEnabled }) }),
1666
- /* @__PURE__ */ jsx(PhonePart, { props, account, onChanged: (mfaEnabled) => setAccount({ ...account, mfaEnabled }) }),
1667
- /* @__PURE__ */ jsx(PasskeysPart, { props, account, accountUrl: accountUrl(), when }),
1668
- /* @__PURE__ */ jsx(AgentsPart, { props, when }),
1669
- /* @__PURE__ */ jsxs("section", { className: cx("section"), children: [
1670
- /* @__PURE__ */ jsx("h2", { className: cx("heading"), children: t.sessions }),
1671
- /* @__PURE__ */ jsx("ul", { className: cx("sessions"), children: sessions.map((s, i) => /* @__PURE__ */ jsxs("li", { className: cx("session"), children: [
1672
- s.device || t.unknownDevice,
1673
- " \xB7 ",
1674
- s.ip,
1675
- " \xB7 ",
1676
- when(s.createdAt)
1677
- ] }, i)) }),
1678
- /* @__PURE__ */ jsx(SignOutEverywhere, { props })
1679
- ] })
1680
- ] });
1916
+ const mfa = (mfaEnabled) => setAccount({ ...account, mfaEnabled });
1917
+ const part = (section) => {
1918
+ switch (section) {
1919
+ case "profile":
1920
+ return /* @__PURE__ */ jsx(ProfilePart, { props, account, onSaved: setAccount });
1921
+ case "email":
1922
+ return /* @__PURE__ */ jsx(EmailPart, { props, account });
1923
+ case "password":
1924
+ return account.hasPassword ? /* @__PURE__ */ jsx(PasswordPart, { props }) : null;
1925
+ case "linked":
1926
+ return /* @__PURE__ */ jsx(LinkedPart, { props });
1927
+ case "secondStep":
1928
+ return /* @__PURE__ */ jsx(SecondStepPart, { props, account, onChanged: mfa });
1929
+ case "phone":
1930
+ return /* @__PURE__ */ jsx(PhonePart, { props, account, onChanged: mfa });
1931
+ case "passkeys":
1932
+ return /* @__PURE__ */ jsx(PasskeysPart, { props, account, accountUrl: accountUrl(), when });
1933
+ case "agents":
1934
+ return /* @__PURE__ */ jsx(AgentsPart, { props, when });
1935
+ case "sessions":
1936
+ return /* @__PURE__ */ jsx(SessionsPart, { props, when });
1937
+ }
1938
+ };
1939
+ return /* @__PURE__ */ jsx("div", { className: cx("account"), ...root, children: (props.sections ?? ACCOUNT_SECTIONS).map((section) => /* @__PURE__ */ jsx(Fragment, { children: part(section) }, section)) });
1940
+ }
1941
+ function AccountProfile(props) {
1942
+ return /* @__PURE__ */ jsx(Account, { ...props, sections: ["profile"] });
1943
+ }
1944
+ function AccountEmail(props) {
1945
+ return /* @__PURE__ */ jsx(Account, { ...props, sections: ["email"] });
1946
+ }
1947
+ function AccountPassword(props) {
1948
+ return /* @__PURE__ */ jsx(Account, { ...props, sections: ["password"] });
1949
+ }
1950
+ function AccountLinked(props) {
1951
+ return /* @__PURE__ */ jsx(Account, { ...props, sections: ["linked"] });
1952
+ }
1953
+ function AccountSecondStep(props) {
1954
+ return /* @__PURE__ */ jsx(Account, { ...props, sections: ["secondStep"] });
1955
+ }
1956
+ function AccountPhone(props) {
1957
+ return /* @__PURE__ */ jsx(Account, { ...props, sections: ["phone"] });
1958
+ }
1959
+ function AccountPasskeys(props) {
1960
+ return /* @__PURE__ */ jsx(Account, { ...props, sections: ["passkeys"] });
1961
+ }
1962
+ function AccountAgents(props) {
1963
+ return /* @__PURE__ */ jsx(Account, { ...props, sections: ["agents"] });
1964
+ }
1965
+ function AccountSessions(props) {
1966
+ return /* @__PURE__ */ jsx(Account, { ...props, sections: ["sessions"] });
1681
1967
  }
1682
1968
  var OWNER = "owner";
1683
1969
  function memberActions(seat, m) {
@@ -1689,8 +1975,9 @@ function memberActions(seat, m) {
1689
1975
  inviteAgain: seat.can.manageMembers && m.invited
1690
1976
  };
1691
1977
  }
1692
- function rolesToGive(seat, roles) {
1693
- return seat.role === OWNER ? roles : roles.filter((c) => c.role !== OWNER);
1978
+ function rolesToGive(seat, roles, only) {
1979
+ const mine = seat.role === OWNER ? roles : roles.filter((c) => c.role !== OWNER);
1980
+ return only ? mine.filter((c) => only(c.role, c)) : mine;
1694
1981
  }
1695
1982
  function OrganizationMembers(props) {
1696
1983
  const auth = useAuth();
@@ -1707,6 +1994,8 @@ function OrganizationMembers(props) {
1707
1994
  const [gone, setGone] = useState(null);
1708
1995
  const id = props.organizationId;
1709
1996
  const when = props.formatDate ?? ((iso) => new Date(iso).toLocaleDateString());
1997
+ const hidden = (action) => props.hide?.includes(action) === true;
1998
+ const saved = (event) => props.onSaved?.(event);
1710
1999
  const load = async () => {
1711
2000
  const [list, people, choices] = await Promise.all([auth.organizations.list(), auth.organizations.members(id), auth.organizations.roles(id)]);
1712
2001
  const mine = list.find((o) => o.id === id) ?? null;
@@ -1714,17 +2003,17 @@ function OrganizationMembers(props) {
1714
2003
  if (mine) setName(mine.name);
1715
2004
  setMembers(people);
1716
2005
  setRoles(choices ?? []);
1717
- const offered = mine ? rolesToGive(mine, choices ?? []) : [];
2006
+ const offered = mine ? rolesToGive(mine, choices ?? [], props.roles) : [];
1718
2007
  if (offered.length > 0 && !offered.some((c) => c.role === role)) setRole(offered[0].role);
1719
2008
  };
1720
2009
  useEffect(() => {
1721
2010
  void load();
1722
2011
  }, [id]);
1723
- if (gone !== null) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, children: /* @__PURE__ */ jsx("p", { role: "status", className: f.cx("notice"), children: gone }) });
2012
+ if (gone !== null) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, children: /* @__PURE__ */ jsx(Say, { f, tone: "success", children: gone }) });
1724
2013
  if (seat === void 0) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, "aria-busy": "true" });
1725
- if (seat === null) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, children: /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.organizationMissing }) });
2014
+ if (seat === null) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, children: /* @__PURE__ */ jsx(Note, { f, children: f.t.organizationMissing }) });
1726
2015
  const manage = seat.can.manageMembers;
1727
- const giveable = rolesToGive(seat, roles);
2016
+ const giveable = rolesToGive(seat, roles, props.roles);
1728
2017
  const label = (r) => roles.find((c) => c.role === r)?.name || r;
1729
2018
  const add = async (e) => {
1730
2019
  e.preventDefault();
@@ -1732,22 +2021,28 @@ function OrganizationMembers(props) {
1732
2021
  if (!r.ok) return;
1733
2022
  setEmail("");
1734
2023
  setDone(f.t.memberAdded.replace("{email}", r.member.email));
2024
+ saved({ kind: "member.added", organizationId: id, userId: r.member.userId, email: r.member.email, role: r.member.role || role });
1735
2025
  await load();
1736
2026
  };
1737
2027
  const change = async (m, next) => {
1738
2028
  const r = await run(() => auth.organizations.setRole(id, m.userId, next));
1739
- if (r.ok) await load();
2029
+ if (!r.ok) return;
2030
+ saved({ kind: "member.role_changed", organizationId: id, userId: m.userId, role: next, previousRole: m.role });
2031
+ await load();
1740
2032
  };
1741
2033
  const remove = async (m) => {
1742
2034
  setAsking(null);
1743
2035
  const r = await run(() => auth.organizations.remove(id, m.userId));
1744
2036
  if (!r.ok) return;
2037
+ saved({ kind: m.you ? "member.left" : "member.removed", organizationId: id, userId: m.userId });
1745
2038
  if (m.you) setSeat(null);
1746
2039
  else await load();
1747
2040
  };
1748
2041
  const inviteAgain = async (m) => {
1749
2042
  const r = await run(() => auth.organizations.inviteAgain(id, m.userId, { locale: props.locale }));
1750
- if (r.ok) setDone(f.t.memberInvitationSent);
2043
+ if (!r.ok) return;
2044
+ setDone(f.t.memberInvitationSent);
2045
+ saved({ kind: "member.invited_again", organizationId: id, userId: m.userId });
1751
2046
  };
1752
2047
  const rename = async (e) => {
1753
2048
  e.preventDefault();
@@ -1756,11 +2051,21 @@ function OrganizationMembers(props) {
1756
2051
  setSeat(r.organization);
1757
2052
  setName(r.organization.name);
1758
2053
  setDone(f.t.organizationRenamed.replace("{name}", r.organization.name));
2054
+ saved({ kind: "organization.renamed", organizationId: id, name: r.organization.name });
1759
2055
  };
1760
2056
  const close = async (how) => {
1761
2057
  setAsking(null);
1762
2058
  const r = await run(() => how === "archive" ? auth.organizations.archive(id) : auth.organizations.delete(id));
1763
- if (r.ok) setGone((how === "archive" ? f.t.organizationArchived : f.t.organizationDeleted).replace("{org}", seat.name));
2059
+ if (!r.ok) return;
2060
+ setGone((how === "archive" ? f.t.organizationArchived : f.t.organizationDeleted).replace("{org}", seat.name));
2061
+ saved({ kind: how === "archive" ? "organization.archived" : "organization.deleted", organizationId: id });
2062
+ };
2063
+ const ask = (key, title, question, yes) => {
2064
+ const { Confirm } = f.C;
2065
+ if (!Confirm) return setAsking(key);
2066
+ void Confirm({ title, body: question, confirmLabel: title, cancelLabel: f.t.cancel, danger: true }).then((ok) => {
2067
+ if (ok) yes();
2068
+ });
1764
2069
  };
1765
2070
  const confirming = (text2, label2, yes) => /* @__PURE__ */ jsxs("span", { role: "group", "aria-label": label2, children: [
1766
2071
  /* @__PURE__ */ jsx("span", { children: text2 }),
@@ -1768,81 +2073,96 @@ function OrganizationMembers(props) {
1768
2073
  /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: yes, children: f.t.yes }),
1769
2074
  /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking(null), children: f.t.cancel })
1770
2075
  ] });
2076
+ const leaveQuestion = f.t.memberLeaveConfirm.replace("{org}", seat.name);
2077
+ const archiveQuestion = f.t.organizationArchiveConfirm.replace("{org}", seat.name);
2078
+ const deleteQuestion = f.t.organizationDeleteConfirm.replace("{org}", seat.name);
2079
+ const archiving = seat.can.archive && !hidden("archive");
2080
+ const deleting = seat.can.delete && !hidden("delete");
2081
+ const renaming = seat.can.update && !hidden("rename");
1771
2082
  return /* @__PURE__ */ jsxs("div", { className: f.cx("account"), ...root, children: [
1772
2083
  /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
1773
- /* @__PURE__ */ jsxs("h2", { className: f.cx("heading"), children: [
2084
+ /* @__PURE__ */ jsxs(Heading, { f, children: [
1774
2085
  f.t.members,
1775
2086
  " \xB7 ",
1776
2087
  seat.name
1777
2088
  ] }),
1778
- problem && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(problem) }),
1779
- members === null ? /* @__PURE__ */ jsxs(Fragment, { children: [
1780
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.membersHidden }),
1781
- auth.session && (asking === auth.session.user.id ? confirming(
1782
- f.t.memberLeaveConfirm.replace("{org}", seat.name),
1783
- f.t.memberLeave,
1784
- () => void remove({ userId: auth.session.user.id, you: true })
1785
- ) : /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking(auth.session.user.id), children: f.t.memberLeave }))
2089
+ problem && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(problem) }),
2090
+ members === null ? /* @__PURE__ */ jsxs(Fragment2, { children: [
2091
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.membersHidden }),
2092
+ auth.session && !hidden("leave") && (asking === auth.session.user.id ? confirming(leaveQuestion, f.t.memberLeave, () => void remove({ userId: auth.session.user.id, you: true })) : /* @__PURE__ */ jsx(
2093
+ f.Button,
2094
+ {
2095
+ type: "button",
2096
+ disabled: f.busy,
2097
+ className: f.cx("providerButton"),
2098
+ onClick: () => ask(auth.session.user.id, f.t.memberLeave, leaveQuestion, () => void remove({ userId: auth.session.user.id, you: true })),
2099
+ children: f.t.memberLeave
2100
+ }
2101
+ ))
1786
2102
  ] }) : /* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: members.map((m) => {
1787
2103
  const who = m.name || m.email;
1788
2104
  const may = memberActions(seat, m);
2105
+ const removable = may.remove && !(m.you && hidden("leave"));
2106
+ const question = m.you ? leaveQuestion : f.t.memberRemoveConfirm.replace("{who}", who);
2107
+ const action = m.you ? f.t.memberLeave : f.t.memberRemove;
2108
+ const choices = giveable.some((c) => c.role === m.role) ? giveable : [...roles.filter((c) => c.role === m.role), ...giveable];
1789
2109
  return /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
1790
2110
  /* @__PURE__ */ jsxs("span", { children: [
1791
2111
  who,
1792
2112
  m.name ? ` \xB7 ${m.email}` : "",
1793
- m.you ? ` (${f.t.memberYou})` : "",
1794
- m.invited ? ` \xB7 ${f.t.memberInvited}` : "",
1795
- m.manager ? ` \xB7 ${f.t.memberManager}` : "",
2113
+ m.you && /* @__PURE__ */ jsx(Tag, { f, plain: ` (${f.t.memberYou})`, children: f.t.memberYou }),
2114
+ f.C.Badge ? /* @__PURE__ */ jsxs(Fragment2, { children: [
2115
+ m.invited && /* @__PURE__ */ jsx(Tag, { f, tone: "warning", plain: "", children: f.t.memberInvited }),
2116
+ m.manager && /* @__PURE__ */ jsx(Tag, { f, tone: "success", plain: "", children: f.t.memberManager })
2117
+ ] }) : `${m.invited ? ` \xB7 ${f.t.memberInvited}` : ""}${m.manager ? ` \xB7 ${f.t.memberManager}` : ""}`,
1796
2118
  " \xB7 ",
1797
2119
  when(m.since)
1798
2120
  ] }),
1799
2121
  " ",
1800
2122
  may.changeRole && giveable.length > 0 ? /* @__PURE__ */ jsx(
1801
- "select",
2123
+ Pick,
1802
2124
  {
1803
- "aria-label": `${f.t.memberRole}: ${who}`,
1804
- className: f.cx("input"),
2125
+ f,
2126
+ name: `role_${m.userId}`,
2127
+ label: `${f.t.memberRole}: ${who}`,
1805
2128
  value: m.role,
1806
2129
  disabled: f.busy,
1807
- onChange: (e) => void change(m, e.target.value),
1808
- children: (giveable.some((c) => c.role === m.role) ? giveable : [...roles.filter((c) => c.role === m.role), ...giveable]).map((c) => /* @__PURE__ */ jsx("option", { value: c.role, children: c.name || c.role }, c.role))
2130
+ options: choices.map((c) => ({ value: c.role, label: c.name || c.role })),
2131
+ onChange: (next) => void change(m, next)
1809
2132
  }
1810
- ) : /* @__PURE__ */ jsx("span", { children: label(m.role) }),
2133
+ ) : f.C.Badge ? /* @__PURE__ */ jsx(f.C.Badge, { tone: "neutral", children: label(m.role) }) : /* @__PURE__ */ jsx("span", { children: label(m.role) }),
1811
2134
  " ",
1812
- asking === m.userId ? confirming(
1813
- m.you ? f.t.memberLeaveConfirm.replace("{org}", seat.name) : f.t.memberRemoveConfirm.replace("{who}", who),
1814
- m.you ? f.t.memberLeave : f.t.memberRemove,
1815
- () => void remove(m)
1816
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2135
+ asking === m.userId ? confirming(question, action, () => void remove(m)) : /* @__PURE__ */ jsxs(Fragment2, { children: [
1817
2136
  may.inviteAgain && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void inviteAgain(m), children: f.t.memberInviteAgain }),
1818
- may.remove && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking(m.userId), children: m.you ? f.t.memberLeave : f.t.memberRemove })
2137
+ removable && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => ask(m.userId, action, question, () => void remove(m)), children: action })
1819
2138
  ] })
1820
2139
  ] }, m.userId);
1821
2140
  }) }),
1822
- done && /* @__PURE__ */ jsx("p", { role: "status", className: f.cx("notice"), children: done })
2141
+ done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
1823
2142
  ] }),
1824
2143
  manage && giveable.length > 0 && /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: add, noValidate: true, children: [
1825
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.memberAdd }),
2144
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.memberAdd }),
1826
2145
  /* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "off", required: true, onChange: setEmail }),
1827
- /* @__PURE__ */ jsxs("label", { className: f.cx("field"), children: [
1828
- /* @__PURE__ */ jsx("span", { className: f.cx("label"), children: f.t.memberRole }),
1829
- /* @__PURE__ */ jsx("select", { name: "role", className: f.cx("input"), value: role, onChange: (e) => setRole(e.target.value), children: giveable.map((c) => /* @__PURE__ */ jsx("option", { value: c.role, children: c.name || c.role }, c.role)) })
1830
- ] }),
2146
+ /* @__PURE__ */ jsx(AddRole, { f, value: role, options: giveable.map((c) => ({ value: c.role, label: c.name || c.role })), onChange: setRole }),
1831
2147
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.memberAdd })
1832
2148
  ] }),
1833
- (seat.can.update || seat.can.archive || seat.can.delete) && /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
1834
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.organization }),
1835
- seat.can.update && /* @__PURE__ */ jsxs("form", { onSubmit: rename, noValidate: true, children: [
2149
+ (renaming || archiving || deleting) && /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
2150
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.organization }),
2151
+ renaming && /* @__PURE__ */ jsxs("form", { onSubmit: rename, noValidate: true, children: [
1836
2152
  /* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "organization", required: true, onChange: setName }),
1837
2153
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.organizationRename })
1838
2154
  ] }),
1839
- asking === "archive" ? confirming(f.t.organizationArchiveConfirm.replace("{org}", seat.name), f.t.organizationArchive, () => void close("archive")) : asking === "delete" ? confirming(f.t.organizationDeleteConfirm.replace("{org}", seat.name), f.t.organizationDelete, () => void close("delete")) : /* @__PURE__ */ jsxs(Fragment, { children: [
1840
- seat.can.archive && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking("archive"), children: f.t.organizationArchive }),
1841
- seat.can.delete && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking("delete"), children: f.t.organizationDelete })
2155
+ asking === "archive" ? confirming(archiveQuestion, f.t.organizationArchive, () => void close("archive")) : asking === "delete" ? confirming(deleteQuestion, f.t.organizationDelete, () => void close("delete")) : /* @__PURE__ */ jsxs(Fragment2, { children: [
2156
+ archiving && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => ask("archive", f.t.organizationArchive, archiveQuestion, () => void close("archive")), children: f.t.organizationArchive }),
2157
+ deleting && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => ask("delete", f.t.organizationDelete, deleteQuestion, () => void close("delete")), children: f.t.organizationDelete })
1842
2158
  ] })
1843
2159
  ] })
1844
2160
  ] });
1845
2161
  }
2162
+ function AddRole({ f, value, options, onChange }) {
2163
+ const id = useId();
2164
+ return /* @__PURE__ */ jsx(Labelled, { f, id, label: f.t.memberRole, children: /* @__PURE__ */ jsx(Pick, { f, id, name: "role", value, options, onChange }) });
2165
+ }
1846
2166
  function PasskeysPart({ props, account, accountUrl, when }) {
1847
2167
  const auth = useAuth();
1848
2168
  const { f, done, setDone, run, general } = useSection(props);
@@ -1860,8 +2180,8 @@ function PasskeysPart({ props, account, accountUrl, when }) {
1860
2180
  if (here === null) return null;
1861
2181
  if (!here) {
1862
2182
  return /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
1863
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.passkeys }),
1864
- /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: accountUrl, children: f.t.managePasskeys })
2183
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.passkeys }),
2184
+ /* @__PURE__ */ jsx(A, { f, href: accountUrl, children: f.t.managePasskeys })
1865
2185
  ] });
1866
2186
  }
1867
2187
  const add = async (e, kind = "device") => {
@@ -1875,18 +2195,21 @@ function PasskeysPart({ props, account, accountUrl, when }) {
1875
2195
  setName("");
1876
2196
  setPassword("");
1877
2197
  setDone(f.t.passkeyAdded);
2198
+ props.onSaved?.({ kind: "passkey.added", id: r.passkey.id });
1878
2199
  };
1879
2200
  const remove = async (id) => {
1880
2201
  const r = await run(() => auth.account.removePasskey(id));
1881
- if (r.ok) setList(list.filter((p) => p.id !== id));
2202
+ if (!r.ok) return;
2203
+ setList(list.filter((p) => p.id !== id));
2204
+ props.onSaved?.({ kind: "passkey.removed", id });
1882
2205
  };
1883
2206
  return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: add, noValidate: true, children: [
1884
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.passkeys }),
1885
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.passkeysHelp }),
1886
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1887
- list.length === 0 ? /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.noPasskeys }) : /* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: list.map((p) => /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
2207
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.passkeys }),
2208
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.passkeysHelp }),
2209
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
2210
+ list.length === 0 ? /* @__PURE__ */ jsx(Note, { f, children: f.t.noPasskeys }) : /* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: list.map((p) => /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
1888
2211
  p.name || f.t.passkeyUnnamed,
1889
- p.kind !== "unknown" ? ` \xB7 ${f.t.passkeyKinds[p.kind]}` : "",
2212
+ p.kind !== "unknown" && /* @__PURE__ */ jsx(Tag, { f, plain: ` \xB7 ${f.t.passkeyKinds[p.kind]}`, children: f.t.passkeyKinds[p.kind] }),
1890
2213
  " \xB7 ",
1891
2214
  when(p.createdAt),
1892
2215
  " ",
@@ -1896,7 +2219,7 @@ function PasskeysPart({ props, account, accountUrl, when }) {
1896
2219
  account.hasPassword && /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
1897
2220
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.addPasskeyDevice }),
1898
2221
  /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void add(null, "security_key"), children: f.t.addSecurityKey }),
1899
- done && /* @__PURE__ */ jsx("p", { role: "status", className: f.cx("notice"), children: done })
2222
+ done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
1900
2223
  ] });
1901
2224
  }
1902
2225
  function ProfilePart({ props, account, onSaved }) {
@@ -1909,14 +2232,15 @@ function ProfilePart({ props, account, onSaved }) {
1909
2232
  if (!r.ok) return;
1910
2233
  onSaved(r.account);
1911
2234
  setDone(f.t.saved);
2235
+ props.onSaved?.({ kind: "profile.saved", name: r.account.name });
1912
2236
  };
1913
2237
  return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: submit, noValidate: true, children: [
1914
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.profile }),
1915
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: account.email }),
1916
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
2238
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.profile }),
2239
+ /* @__PURE__ */ jsx(Note, { f, children: account.email }),
2240
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
1917
2241
  /* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
1918
2242
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.save }),
1919
- done && /* @__PURE__ */ jsx("p", { role: "status", className: f.cx("notice"), children: done })
2243
+ done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
1920
2244
  ] });
1921
2245
  }
1922
2246
  function EmailPart({ props, account }) {
@@ -1930,15 +2254,16 @@ function EmailPart({ props, account }) {
1930
2254
  if (!r.ok) return;
1931
2255
  setPassword("");
1932
2256
  setDone(f.t.emailSent.replace("{email}", r.email));
2257
+ props.onSaved?.({ kind: "email.change_requested", email: r.email });
1933
2258
  };
1934
2259
  return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: submit, noValidate: true, children: [
1935
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.emailAddress }),
1936
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: account.email }),
1937
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
2260
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.emailAddress }),
2261
+ /* @__PURE__ */ jsx(Note, { f, children: account.email }),
2262
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
1938
2263
  /* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.newEmail, value: email, autoComplete: "email", required: true, onChange: setEmail }),
1939
2264
  account.hasPassword && /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
1940
2265
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.changeEmail }),
1941
- done && /* @__PURE__ */ jsx("p", { role: "status", className: f.cx("notice"), children: done })
2266
+ done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
1942
2267
  ] });
1943
2268
  }
1944
2269
  function LinkedPart({ props }) {
@@ -1951,21 +2276,26 @@ function LinkedPart({ props }) {
1951
2276
  void auth.account.identities().then(setLinked);
1952
2277
  void auth.methods().then((m) => setOffered(m.providers));
1953
2278
  const back = typeof window === "undefined" ? null : new URLSearchParams(window.location.search);
1954
- if (back?.get("linked")) setCame(back.get("linked"));
1955
- else if (back?.get("auth_error")) f.setError({ code: back.get("auth_error"), message: "That account could not be linked. Try again." });
2279
+ const provider = back?.get("linked");
2280
+ if (provider) {
2281
+ setCame(provider);
2282
+ props.onSaved?.({ kind: "identity.linked", provider });
2283
+ } else if (back?.get("auth_error")) f.setError({ code: back.get("auth_error"), message: "That account could not be linked. Try again." });
1956
2284
  }, []);
1957
2285
  if (linked === null) return null;
1958
2286
  const name = (id) => offered.find((p) => p.id === id)?.name ?? id;
1959
2287
  const unlink = async (provider) => {
1960
2288
  const r = await run(() => auth.account.unlink(provider));
1961
- if (r.ok) setLinked(linked.filter((x) => x.provider !== provider));
2289
+ if (!r.ok) return;
2290
+ setLinked(linked.filter((x) => x.provider !== provider));
2291
+ props.onSaved?.({ kind: "identity.unlinked", provider });
1962
2292
  };
1963
2293
  const here = typeof window === "undefined" ? void 0 : window.location.pathname;
1964
2294
  return /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
1965
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.linkedAccounts }),
1966
- came && /* @__PURE__ */ jsx("p", { role: "status", className: f.cx("notice"), children: f.t.linked }),
1967
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1968
- linked.length === 0 ? /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.noLinkedAccounts }) : /* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: linked.map((x) => /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
2295
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.linkedAccounts }),
2296
+ came && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: f.t.linked }),
2297
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
2298
+ linked.length === 0 ? /* @__PURE__ */ jsx(Note, { f, children: f.t.noLinkedAccounts }) : /* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: linked.map((x) => /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
1969
2299
  name(x.provider),
1970
2300
  x.email ? ` \xB7 ${x.email}` : "",
1971
2301
  " ",
@@ -1991,14 +2321,15 @@ function PasswordPart({ props }) {
1991
2321
  setPassword("");
1992
2322
  setNewPassword("");
1993
2323
  setDone(f.t.passwordChangedHere);
2324
+ props.onSaved?.({ kind: "password.changed" });
1994
2325
  };
1995
2326
  return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: submit, noValidate: true, children: [
1996
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.changePassword }),
1997
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
2327
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.changePassword }),
2328
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
1998
2329
  /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
1999
2330
  /* @__PURE__ */ jsx(Field, { f, name: "newPassword", type: "password", label: f.t.newPassword, value: newPassword, autoComplete: "new-password", required: true, onChange: setNewPassword, hint: f.passwordRule }),
2000
2331
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.changePassword }),
2001
- done && /* @__PURE__ */ jsx("p", { role: "status", className: f.cx("notice"), children: done })
2332
+ done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
2002
2333
  ] });
2003
2334
  }
2004
2335
  function SecondStepPart({ props, account, onChanged }) {
@@ -2022,6 +2353,7 @@ function SecondStepPart({ props, account, onChanged }) {
2022
2353
  setPassword("");
2023
2354
  setCodes(r.recoveryCodes);
2024
2355
  onChanged(true);
2356
+ props.onSaved?.({ kind: "mfa.enabled" });
2025
2357
  };
2026
2358
  const turnOff = async (e) => {
2027
2359
  e.preventDefault();
@@ -2030,32 +2362,35 @@ function SecondStepPart({ props, account, onChanged }) {
2030
2362
  setPassword("");
2031
2363
  setCodes(null);
2032
2364
  onChanged(false);
2365
+ props.onSaved?.({ kind: "mfa.disabled" });
2033
2366
  };
2034
2367
  const renew = async () => {
2035
2368
  const r = await run(() => auth.account.mfa.recoveryCodes({ password }));
2036
- if (r.ok) setCodes(r.recoveryCodes);
2369
+ if (!r.ok) return;
2370
+ setCodes(r.recoveryCodes);
2371
+ props.onSaved?.({ kind: "recovery_codes.regenerated" });
2037
2372
  };
2038
2373
  const passwordField = account.hasPassword && /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword });
2039
- const shown = codes && /* @__PURE__ */ jsxs(Fragment, { children: [
2040
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.keepCodes }),
2374
+ const shown = codes && /* @__PURE__ */ jsxs(Fragment2, { children: [
2375
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.keepCodes }),
2041
2376
  /* @__PURE__ */ jsx("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: c }) }, c)) })
2042
2377
  ] });
2043
2378
  if (setup) {
2044
2379
  return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: confirm, noValidate: true, children: [
2045
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.secondStep }),
2046
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.addToApp }),
2380
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.secondStep }),
2381
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.addToApp }),
2047
2382
  /* @__PURE__ */ jsx("code", { className: f.cx("secret"), children: setup.secret }),
2048
- /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: setup.otpauthUri, children: f.t.openInApp }),
2049
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
2383
+ /* @__PURE__ */ jsx(A, { f, href: setup.otpauthUri, children: f.t.openInApp }),
2384
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
2050
2385
  /* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
2051
2386
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
2052
2387
  ] });
2053
2388
  }
2054
2389
  return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: account.mfaEnabled ? turnOff : start, noValidate: true, children: [
2055
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.secondStep }),
2056
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: account.mfaEnabled ? f.t.secondStepOn : f.t.secondStepOff }),
2390
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.secondStep }),
2391
+ /* @__PURE__ */ jsx(Note, { f, children: account.mfaEnabled ? f.t.secondStepOn : f.t.secondStepOff }),
2057
2392
  shown,
2058
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
2393
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
2059
2394
  passwordField,
2060
2395
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: account.mfaEnabled ? f.t.turnOff : f.t.turnOn }),
2061
2396
  account.mfaEnabled && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void renew(), children: f.t.newRecoveryCodes })
@@ -2093,6 +2428,7 @@ function PhonePart({ props, account, onChanged }) {
2093
2428
  setPassword("");
2094
2429
  if (r.recoveryCodes.length > 0) setCodes(r.recoveryCodes);
2095
2430
  onChanged(true);
2431
+ props.onSaved?.({ kind: "phone.added", channel });
2096
2432
  await load();
2097
2433
  };
2098
2434
  const remove = async (e) => {
@@ -2103,27 +2439,29 @@ function PhonePart({ props, account, onChanged }) {
2103
2439
  await load();
2104
2440
  const left = await auth.account.mfa.factors();
2105
2441
  onChanged(Boolean(left?.totp));
2442
+ props.onSaved?.({ kind: "phone.removed" });
2106
2443
  };
2107
2444
  const passwordField = account.hasPassword && /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword });
2108
2445
  if (sentTo) {
2109
2446
  return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: confirm, noValidate: true, children: [
2110
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.phone }),
2111
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.codeSent.replace("{to}", sentTo) }),
2112
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
2447
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.phone }),
2448
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.codeSent.replace("{to}", sentTo) }),
2449
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
2113
2450
  /* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
2114
2451
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
2115
2452
  ] });
2116
2453
  }
2117
2454
  return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: ways.phone ? remove : add, noValidate: true, children: [
2118
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.phone }),
2119
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: ways.phone ? f.t.phoneOn.replace("{to}", ways.phone.number) : `${f.t.phoneOff} ${f.t.phoneHelp}` }),
2120
- codes && /* @__PURE__ */ jsxs(Fragment, { children: [
2121
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.keepCodes }),
2455
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.phone }),
2456
+ /* @__PURE__ */ jsx(Note, { f, children: ways.phone ? f.t.phoneOn.replace("{to}", ways.phone.number) : `${f.t.phoneOff} ${f.t.phoneHelp}` }),
2457
+ codes && /* @__PURE__ */ jsxs(Fragment2, { children: [
2458
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.keepCodes }),
2122
2459
  /* @__PURE__ */ jsx("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: c }) }, c)) })
2123
2460
  ] }),
2124
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
2461
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
2125
2462
  !ways.phone && /* @__PURE__ */ jsx(Field, { f, name: "phone", type: "tel", label: f.t.phone, value: number, autoComplete: "tel", required: true, onChange: setNumber }),
2126
- !ways.phone && ways.phoneChannels.length > 1 && /* @__PURE__ */ jsx("div", { className: f.cx("field"), role: "radiogroup", children: ways.phoneChannels.map((c) => /* @__PURE__ */ jsxs("label", { className: f.cx("label"), children: [
2463
+ !ways.phone && ways.phoneChannels.length > 1 && f.C.Select && /* @__PURE__ */ jsx(ChannelPick, { f, value: channel, channels: ways.phoneChannels, onChange: setChannel }),
2464
+ !ways.phone && ways.phoneChannels.length > 1 && !f.C.Select && /* @__PURE__ */ jsx("div", { className: f.cx("field"), role: "radiogroup", children: ways.phoneChannels.map((c) => /* @__PURE__ */ jsxs("label", { className: f.cx("label"), children: [
2127
2465
  /* @__PURE__ */ jsx("input", { type: "radio", name: "channel", value: c, checked: channel === c, onChange: () => setChannel(c) }),
2128
2466
  " ",
2129
2467
  c === "whatsapp" ? f.t.byWhatsapp : f.t.bySms
@@ -2142,12 +2480,14 @@ function AgentsPart({ props, when }) {
2142
2480
  if (list.length === 0) return null;
2143
2481
  const disconnect = async (id) => {
2144
2482
  const r = await run(() => auth.account.disconnectAgent(id));
2145
- if (r.ok) setList(list.filter((a) => a.id !== id));
2483
+ if (!r.ok) return;
2484
+ setList(list.filter((a) => a.id !== id));
2485
+ props.onSaved?.({ kind: "agent.disconnected", id });
2146
2486
  };
2147
2487
  return /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
2148
- /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.agents }),
2149
- /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.agentsHelp }),
2150
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
2488
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.agents }),
2489
+ /* @__PURE__ */ jsx(Note, { f, children: f.t.agentsHelp }),
2490
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
2151
2491
  /* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: list.map((a) => /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
2152
2492
  a.name || f.t.anAgent,
2153
2493
  a.redirectHost ? ` (${a.redirectHost})` : "",
@@ -2161,20 +2501,47 @@ function AgentsPart({ props, when }) {
2161
2501
  ] }, a.id)) })
2162
2502
  ] });
2163
2503
  }
2164
- function SignOutEverywhere({ props }) {
2504
+ function SessionsPart({ props, when }) {
2165
2505
  const auth = useAuth();
2166
2506
  const { f, run, general } = useSection(props);
2507
+ const [sessions, setSessions] = useState([]);
2508
+ useEffect(() => {
2509
+ void auth.account.sessions().then(setSessions);
2510
+ }, []);
2167
2511
  const end = async () => {
2168
2512
  const r = await run(() => auth.account.signOutEverywhere());
2169
2513
  if (!r.ok) return;
2514
+ props.onSaved?.({ kind: "sessions.ended" });
2170
2515
  if (props.onSignedOut) props.onSignedOut();
2171
2516
  else window.location.assign("/");
2172
2517
  };
2173
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2174
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
2518
+ return /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
2519
+ /* @__PURE__ */ jsx(Heading, { f, children: f.t.sessions }),
2520
+ /* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: sessions.map((s, i) => /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
2521
+ s.device || f.t.unknownDevice,
2522
+ " \xB7 ",
2523
+ s.ip,
2524
+ " \xB7 ",
2525
+ when(s.createdAt)
2526
+ ] }, i)) }),
2527
+ general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
2175
2528
  /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("button"), onClick: () => void end(), children: f.t.signOutEverywhere })
2176
2529
  ] });
2177
2530
  }
2531
+ function ChannelPick({ f, value, channels, onChange }) {
2532
+ const id = useId();
2533
+ return /* @__PURE__ */ jsx(Labelled, { f, id, label: f.t.channel, children: /* @__PURE__ */ jsx(
2534
+ Pick,
2535
+ {
2536
+ f,
2537
+ id,
2538
+ name: "channel",
2539
+ value,
2540
+ options: channels.map((c) => ({ value: c, label: c === "whatsapp" ? f.t.byWhatsapp : f.t.bySms })),
2541
+ onChange: (c) => onChange(c)
2542
+ }
2543
+ ) });
2544
+ }
2178
2545
 
2179
2546
  // src/react.tsx
2180
2547
  import { jsx as jsx2 } from "react/jsx-runtime";
@@ -2276,6 +2643,8 @@ function useAuth() {
2276
2643
  googleOneTap: (o) => then(client.signIn.googleOneTap(o))
2277
2644
  },
2278
2645
  signUp: { email: (f) => then(client.signUp.email(f)) },
2646
+ // The invited person is signed in once they accept.
2647
+ acceptInvitation: (token, password) => then(client.acceptInvitation(token, password)),
2279
2648
  signOut: () => then(client.signOut()),
2280
2649
  account: {
2281
2650
  ...client.account,
@@ -2293,11 +2662,22 @@ function useAuth() {
2293
2662
  }, [basePath, refresh, session, status]);
2294
2663
  }
2295
2664
  export {
2665
+ AcceptInvite,
2296
2666
  Account,
2667
+ AccountAgents,
2668
+ AccountEmail,
2669
+ AccountLinked,
2670
+ AccountPasskeys,
2671
+ AccountPassword,
2672
+ AccountPhone,
2673
+ AccountProfile,
2674
+ AccountSecondStep,
2675
+ AccountSessions,
2297
2676
  CauthyProvider,
2298
2677
  ForgotPassword,
2299
2678
  GoogleOneTap,
2300
2679
  OrganizationMembers,
2680
+ PendingTerms,
2301
2681
  ResetPassword,
2302
2682
  SignIn,
2303
2683
  SignUp,