cauthy-auth 0.28.1 → 0.31.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 +61 -3
  2. package/dist/{cauthy-CTVg4kvo.d.mts → cauthy-2jtP2LVQ.d.mts} +19 -1
  3. package/dist/{cauthy-BAwAJChs.d.ts → cauthy-CKfvvv_i.d.ts} +19 -1
  4. package/dist/cli.js +163 -59
  5. package/dist/client.d.mts +91 -10
  6. package/dist/client.d.ts +91 -10
  7. package/dist/client.js +39 -3
  8. package/dist/client.js.map +1 -1
  9. package/dist/client.mjs +39 -3
  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 +387 -148
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +385 -148
  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 +275 -23
  26. package/dist/react.d.ts +275 -23
  27. package/dist/react.js +312 -78
  28. package/dist/react.js.map +1 -1
  29. package/dist/react.mjs +311 -78
  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 +53 -4
  35. package/dist/svelte.js.map +1 -1
  36. package/dist/svelte.mjs +53 -4
  37. package/dist/svelte.mjs.map +1 -1
  38. package/dist/{system-CVBW_AV8.d.mts → system-BrrJsrFW.d.mts} +321 -109
  39. package/dist/{system-Bn8uckvQ.d.ts → system-BvvoNs2y.d.ts} +321 -109
  40. package/dist/vue.d.mts +2 -2
  41. package/dist/vue.d.ts +2 -2
  42. package/dist/vue.js +53 -4
  43. package/dist/vue.js.map +1 -1
  44. package/dist/vue.mjs +53 -4
  45. package/dist/vue.mjs.map +1 -1
  46. package/package.json +1 -1
package/dist/react.mjs CHANGED
@@ -283,6 +283,12 @@ function checkOrganization(value, required = false) {
283
283
  if (v.length > MAX_ORGANIZATION) return { field: "organization", code: "too_long", message: `Use at most ${MAX_ORGANIZATION} characters.` };
284
284
  return null;
285
285
  }
286
+ function checkOrganizationName(value) {
287
+ const v = typeof value === "string" ? value.trim() : "";
288
+ if (v === "") return { field: "name", code: "required", message: "Enter the organization's name." };
289
+ if (v.length > MAX_ORGANIZATION) return { field: "name", code: "too_long", message: `Use at most ${MAX_ORGANIZATION} characters.` };
290
+ return null;
291
+ }
286
292
  function checkCode(value) {
287
293
  const v = typeof value === "string" ? value.trim() : "";
288
294
  if (v === "") return { field: "code", code: "required", message: "Enter the code." };
@@ -367,11 +373,11 @@ function createAuthClient(options = {}) {
367
373
  if (res.ok) {
368
374
  const m = await res.json();
369
375
  if (m.password) policy = passwordPolicyOf(m.password);
370
- 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 };
371
377
  }
372
378
  } catch {
373
379
  }
374
- 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 };
375
381
  }
376
382
  async function ceremony(begin, finish, form, run, more = {}) {
377
383
  const begun = await post(begin, form, null);
@@ -518,6 +524,20 @@ function createAuthClient(options = {}) {
518
524
  forgotPassword: (f) => post("/forgot-password", { email: f.email }, checkEmail(f.email), f.captchaToken),
519
525
  resetPassword: (f) => post("/reset-password", { token: f.token, password: f.password }, checkNewPassword(f.password, policy)),
520
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)),
521
541
  signOut: () => post("/sign-out", {}, null),
522
542
  organizations: {
523
543
  async list(system) {
@@ -535,7 +555,23 @@ function createAuthClient(options = {}) {
535
555
  add: (id, f) => post("/me/organizations/members/add", { organizationId: id, email: f.email, role: f.role, name: f.name ?? "", locale: f.locale ?? "" }, checkEmail(f.email)),
536
556
  setRole: (id, userId, role) => post("/me/organizations/members/role", { organizationId: id, userId, role }, null),
537
557
  remove: (id, userId) => post("/me/organizations/members/remove", { organizationId: id, userId }, null),
538
- inviteAgain: (id, userId, f = {}) => post("/me/organizations/members/invite", { organizationId: id, userId, locale: f.locale ?? "" }, null)
558
+ inviteAgain: (id, userId, f = {}) => post("/me/organizations/members/invite", { organizationId: id, userId, locale: f.locale ?? "" }, null),
559
+ rename: (id, name) => post("/me/organizations/rename", { organizationId: id, name }, checkOrganizationName(name)),
560
+ archive: (id) => post("/me/organizations/archive", { organizationId: id }, null),
561
+ delete: (id) => post("/me/organizations/delete", { organizationId: id }, null),
562
+ async check(q) {
563
+ const organizationId = typeof q.organization === "string" ? q.organization : q.organization?.id ?? "";
564
+ const r = await post("/me/organizations/check", {
565
+ organizationId,
566
+ resource: q.resource,
567
+ action: q.action,
568
+ ...q.attributes !== void 0 ? { attributes: q.attributes } : {},
569
+ ...q.resourceId !== void 0 ? { resourceId: q.resourceId } : {},
570
+ ...q.ownerId !== void 0 ? { ownerId: q.ownerId } : {}
571
+ }, null);
572
+ if (!r.ok) return { allowed: false, reason: r.error.message, error: r.error };
573
+ return { allowed: r.allowed === true, reason: String(r.reason ?? ""), ...r.rule ? { rule: r.rule } : {} };
574
+ }
539
575
  },
540
576
  account: {
541
577
  async get() {
@@ -631,7 +667,9 @@ function can(organization, resource, action) {
631
667
  if ((organization.denied ?? []).some((d) => matches(d, resource, action))) return false;
632
668
  return organization.permissions.some((p) => matches(p, resource, action));
633
669
  }
634
- function definePolicy(roles) {
670
+ function definePolicy(given) {
671
+ const roles = Array.isArray(given) ? given : given.roles;
672
+ const resources = Array.isArray(given) ? [] : given.catalog ?? [];
635
673
  const entry = (p) => `${p.resource}:${p.action}`;
636
674
  const byName = new Map(roles.map((r) => [r.role, r]));
637
675
  const split = (permission) => {
@@ -646,6 +684,12 @@ function definePolicy(roles) {
646
684
  ...r.inherits ? { inherits: [...r.inherits] } : {},
647
685
  ...r.permissions ? { permissions: r.permissions.map((p) => ({ ...p })) } : {}
648
686
  })),
687
+ catalog: resources.map((c) => ({
688
+ resource: c.resource,
689
+ ...c.description !== void 0 ? { description: c.description } : {},
690
+ actions: [...c.actions],
691
+ ...c.attributes ? { attributes: { ...c.attributes } } : {}
692
+ })),
649
693
  roleNames: roles.map((r) => r.role),
650
694
  permissions: [...new Set(roles.flatMap((r) => (r.permissions ?? []).map(entry)))],
651
695
  can(organization, permission) {
@@ -667,6 +711,11 @@ function definePolicy(roles) {
667
711
  };
668
712
  walk(role);
669
713
  return [...out];
714
+ },
715
+ // The types did the work; this only hands the question on, as a method of
716
+ // the asker so it keeps its `this`.
717
+ check(asker, ...args) {
718
+ return asker.check(...args);
670
719
  }
671
720
  };
672
721
  }
@@ -725,6 +774,13 @@ var TEXTS = {
725
774
  passwordChanged: "Your password was changed. You can sign in with it now.",
726
775
  confirming: "Confirming your address\u2026",
727
776
  emailConfirmed: "Your address is confirmed. You can sign in now.",
777
+ invitedTo: "You've been invited to {workspace}",
778
+ invitedToOrganization: "You've been invited to {organization} on {workspace}",
779
+ invitedAs: "You will sign in as {email}.",
780
+ choosePassword: "Choose a password",
781
+ acceptInvite: "Accept and sign in",
782
+ openingInvitation: "Opening your invitation\u2026",
783
+ invitationInvalid: "This invitation is not valid: it was already used, or it has expired. Ask whoever invited you to send it again.",
728
784
  profile: "Profile",
729
785
  save: "Save",
730
786
  saved: "Saved.",
@@ -785,11 +841,22 @@ var TEXTS = {
785
841
  memberLeaveConfirm: "Leave {org}? You will need an invitation to come back.",
786
842
  memberInviteAgain: "Send the invitation again",
787
843
  memberInvitationSent: "The invitation is on its way.",
844
+ organization: "Organization",
845
+ organizationRename: "Rename",
846
+ organizationRenamed: "The organization is now called {name}.",
847
+ organizationArchive: "Archive",
848
+ organizationArchiveConfirm: "Archive {org}? Its members will no longer reach it, and only the workspace can restore it.",
849
+ organizationArchived: "{org} was archived.",
850
+ organizationDelete: "Delete organization",
851
+ organizationDeleteConfirm: "Delete {org} for good? Its members lose it and this cannot be undone.",
852
+ organizationDeleted: "{org} was deleted.",
788
853
  yes: "Yes",
789
854
  cancel: "Cancel",
790
855
  errors: {
791
856
  not_allowed: "Your role in this organization does not allow that.",
792
857
  last_manager: "Somebody else must manage the members first: give that role to another member.",
858
+ last_owner: "An organization keeps at least one owner: make another member owner first.",
859
+ organization_not_found: "That organization no longer exists.",
793
860
  already_member: "That person already belongs to the organization. Change their role instead.",
794
861
  unknown_role: "Choose one of the roles offered.",
795
862
  user_not_active: "That account is disabled.",
@@ -828,7 +895,9 @@ var TEXTS = {
828
895
  invalid_assertion: "Your company's answer could not be checked. Try again.",
829
896
  provisioning_disabled: "Your company's sign-in worked, but this workspace has no account for you. Ask its admin to add you.",
830
897
  connection_inactive: "Your company's sign-in is turned off for this workspace.",
831
- invalid_grant: "That sign-in expired. Try again."
898
+ invalid_grant: "That sign-in expired. Try again.",
899
+ password_disabled: "This workspace does not sign in with a password. Use one of the other ways.",
900
+ passkeys_disabled: "Passkeys are turned off for this workspace."
832
901
  }
833
902
  },
834
903
  es: {
@@ -881,6 +950,13 @@ var TEXTS = {
881
950
  passwordChanged: "Tu contrase\xF1a se cambi\xF3. Ya puedes entrar con ella.",
882
951
  confirming: "Confirmando tu correo\u2026",
883
952
  emailConfirmed: "Tu correo qued\xF3 confirmado. Ya puedes entrar.",
953
+ invitedTo: "Te invitaron a {workspace}",
954
+ invitedToOrganization: "Te invitaron a {organization} en {workspace}",
955
+ invitedAs: "Vas a entrar como {email}.",
956
+ choosePassword: "Elige una contrase\xF1a",
957
+ acceptInvite: "Aceptar y entrar",
958
+ openingInvitation: "Abriendo tu invitaci\xF3n\u2026",
959
+ 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.",
884
960
  profile: "Perfil",
885
961
  save: "Guardar",
886
962
  saved: "Guardado.",
@@ -941,11 +1017,22 @@ var TEXTS = {
941
1017
  memberLeaveConfirm: "\xBFSalir de {org}? Necesitar\xE1s una invitaci\xF3n para volver.",
942
1018
  memberInviteAgain: "Enviar la invitaci\xF3n de nuevo",
943
1019
  memberInvitationSent: "La invitaci\xF3n va en camino.",
1020
+ organization: "Organizaci\xF3n",
1021
+ organizationRename: "Cambiar nombre",
1022
+ organizationRenamed: "La organizaci\xF3n ahora se llama {name}.",
1023
+ organizationArchive: "Archivar",
1024
+ organizationArchiveConfirm: "\xBFArchivar {org}? Sus miembros ya no podr\xE1n entrar y solo el espacio de trabajo puede restaurarla.",
1025
+ organizationArchived: "{org} qued\xF3 archivada.",
1026
+ organizationDelete: "Eliminar organizaci\xF3n",
1027
+ organizationDeleteConfirm: "\xBFEliminar {org} para siempre? Sus miembros la pierden y no se puede deshacer.",
1028
+ organizationDeleted: "{org} qued\xF3 eliminada.",
944
1029
  yes: "S\xED",
945
1030
  cancel: "Cancelar",
946
1031
  errors: {
947
1032
  not_allowed: "Tu rol en esta organizaci\xF3n no permite eso.",
948
1033
  last_manager: "Primero alguien m\xE1s debe administrar los miembros: dale ese rol a otro miembro.",
1034
+ last_owner: "Una organizaci\xF3n conserva al menos un propietario: primero haz propietario a otro miembro.",
1035
+ organization_not_found: "Esa organizaci\xF3n ya no existe.",
949
1036
  already_member: "Esa persona ya pertenece a la organizaci\xF3n. Cambia su rol.",
950
1037
  unknown_role: "Escoge uno de los roles ofrecidos.",
951
1038
  user_not_active: "Esa cuenta est\xE1 desactivada.",
@@ -984,7 +1071,9 @@ var TEXTS = {
984
1071
  invalid_assertion: "No se pudo verificar la respuesta de tu empresa. Intenta de nuevo.",
985
1072
  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.",
986
1073
  connection_inactive: "El inicio de sesi\xF3n de tu empresa est\xE1 apagado en este workspace.",
987
- invalid_grant: "Ese ingreso venci\xF3. Intenta de nuevo."
1074
+ invalid_grant: "Ese ingreso venci\xF3. Intenta de nuevo.",
1075
+ password_disabled: "En este workspace no se entra con contrase\xF1a. Usa una de las otras formas.",
1076
+ passkeys_disabled: "Las llaves de acceso est\xE1n desactivadas en este workspace."
988
1077
  }
989
1078
  }
990
1079
  };
@@ -1179,23 +1268,16 @@ function useMailedToken(name, open) {
1179
1268
  open(takeToken(name));
1180
1269
  }, []);
1181
1270
  }
1182
- function SignIn(props) {
1183
- const auth = useAuth();
1184
- const f = useForm(props);
1185
- const [methods, setMethods] = useState(null);
1186
- const [email, setEmail] = useState("");
1187
- const [password, setPassword] = useState("");
1271
+ function SecondStepForm(p) {
1272
+ const { f, auth } = p;
1188
1273
  const [code, setCode] = useState("");
1189
- const [step, setStep] = useState("password");
1190
- const challenge = useChallenge(methods?.captchaSiteKey, props.locale);
1191
1274
  const [phoneWay, setPhoneWay] = useState(null);
1192
1275
  const [phoneSent, setPhoneSent] = useState("");
1193
1276
  useEffect(() => {
1194
- if (step !== "code") return;
1195
1277
  void auth.signIn.mfaMethods().then((r) => {
1196
1278
  if (r.ok) setPhoneWay({ totp: r.totp, phone: r.phone, push: r.push, email: r.email });
1197
1279
  });
1198
- }, [step]);
1280
+ }, []);
1199
1281
  const sendEmail = async () => {
1200
1282
  f.setBusy(true);
1201
1283
  f.setError(null);
@@ -1231,6 +1313,55 @@ function SignIn(props) {
1231
1313
  if (!r.ok) return f.setError(r.error);
1232
1314
  setPhoneSent(r.sentTo);
1233
1315
  };
1316
+ const submit = async (e) => {
1317
+ e.preventDefault();
1318
+ f.setBusy(true);
1319
+ f.setError(null);
1320
+ const r = await auth.signIn.mfa({ code });
1321
+ f.setBusy(false);
1322
+ if (!r.ok) return f.setError(r.error);
1323
+ f.done();
1324
+ };
1325
+ const general = f.error && !f.error.field ? f.error : null;
1326
+ const to = phoneWay?.phone?.number ?? "";
1327
+ return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1328
+ /* @__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 }),
1329
+ general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1330
+ phoneWay?.email && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendEmail(), children: f.t.sendEmailAgain }),
1331
+ pushNumber > 0 ? /* @__PURE__ */ jsxs("div", { className: f.cx("notice"), role: "status", "aria-live": "polite", children: [
1332
+ /* @__PURE__ */ jsx("p", { children: f.t.pushPick.replace("{n}", String(pushNumber)) }),
1333
+ /* @__PURE__ */ jsx("p", { style: { fontSize: 48, fontWeight: 700, margin: "4px 0", textAlign: "center" }, children: pushNumber }),
1334
+ /* @__PURE__ */ jsx("p", { children: f.t.pushWaiting })
1335
+ ] }) : phoneWay?.push && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("button"), onClick: () => void sendPush(), children: f.t.pushSend }),
1336
+ 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) }),
1337
+ /* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
1338
+ /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
1339
+ ] });
1340
+ }
1341
+ function ProviderButtons(p) {
1342
+ const { f } = p;
1343
+ return /* @__PURE__ */ jsx(Fragment, { children: p.providers.map((provider) => /* @__PURE__ */ jsxs(f.Button, { type: "button", className: f.cx("providerButton"), onClick: () => p.onPick(provider.id), children: [
1344
+ provider.iconUrl && /* @__PURE__ */ jsx("img", { src: provider.iconUrl, alt: "", width: 18, height: 18, className: f.cx("providerIcon") }),
1345
+ f.t.continueWith,
1346
+ " ",
1347
+ provider.name
1348
+ ] }, provider.id)) });
1349
+ }
1350
+ function signInOffers(methods) {
1351
+ const password = methods?.passwordSignIn !== false;
1352
+ return { password, email: password || methods?.magicLink === true || methods?.sso === true, passkey: methods?.passkey === true };
1353
+ }
1354
+ function SignIn(props) {
1355
+ const auth = useAuth();
1356
+ const f = useForm(props);
1357
+ const [methods, setMethods] = useState(null);
1358
+ const [email, setEmail] = useState("");
1359
+ const [password, setPassword] = useState("");
1360
+ const [code, setCode] = useState("");
1361
+ const [step, setStep] = useState("password");
1362
+ const challenge = useChallenge(methods?.captchaSiteKey, props.locale);
1363
+ const offers = signInOffers(methods);
1364
+ const passwordOn = offers.password;
1234
1365
  const autofill = useRef(null);
1235
1366
  const [offer, setOffer] = useState(0);
1236
1367
  const [company, setCompany] = useState(null);
@@ -1282,10 +1413,18 @@ function SignIn(props) {
1282
1413
  const submit = async (e) => {
1283
1414
  e.preventDefault();
1284
1415
  autofill.current?.abort();
1416
+ if (step === "password" && company?.enforced) {
1417
+ f.setError(null);
1418
+ return toCompany();
1419
+ }
1420
+ if (step === "password" && !passwordOn) {
1421
+ if (company) return toCompany();
1422
+ if (methods?.magicLink) return sendLink();
1423
+ return;
1424
+ }
1285
1425
  f.setBusy(true);
1286
1426
  f.setError(null);
1287
- if (step === "password" && company?.enforced) return toCompany();
1288
- 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 });
1427
+ const r = step === "sent" ? await auth.signIn.emailCode({ code }) : await auth.signIn.email({ email, password, captchaToken: challenge.token });
1289
1428
  f.setBusy(false);
1290
1429
  if (step === "password") challenge.renew();
1291
1430
  if (!r.ok && r.error.code === "sso_required") return toCompany();
@@ -1319,6 +1458,7 @@ function SignIn(props) {
1319
1458
  setStep("sent");
1320
1459
  };
1321
1460
  const general = f.error && !f.error.field ? f.error : null;
1461
+ const asksEmail = offers.email;
1322
1462
  if (step === "opening") return /* @__PURE__ */ jsx("div", { className: f.cx("form"), ...f.root, "aria-busy": "true" });
1323
1463
  if (step === "sent") {
1324
1464
  return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
@@ -1329,39 +1469,20 @@ function SignIn(props) {
1329
1469
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
1330
1470
  ] });
1331
1471
  }
1332
- if (step === "code") {
1333
- const to = phoneWay?.phone?.number ?? "";
1334
- return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1335
- /* @__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 }),
1336
- general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1337
- phoneWay?.email && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendEmail(), children: f.t.sendEmailAgain }),
1338
- pushNumber > 0 ? /* @__PURE__ */ jsxs("div", { className: f.cx("notice"), role: "status", "aria-live": "polite", children: [
1339
- /* @__PURE__ */ jsx("p", { children: f.t.pushPick.replace("{n}", String(pushNumber)) }),
1340
- /* @__PURE__ */ jsx("p", { style: { fontSize: 48, fontWeight: 700, margin: "4px 0", textAlign: "center" }, children: pushNumber }),
1341
- /* @__PURE__ */ jsx("p", { children: f.t.pushWaiting })
1342
- ] }) : phoneWay?.push && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("button"), onClick: () => void sendPush(), children: f.t.pushSend }),
1343
- 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) }),
1344
- /* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
1345
- /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
1346
- ] });
1347
- }
1472
+ if (step === "code") return /* @__PURE__ */ jsx(SecondStepForm, { f, auth });
1348
1473
  return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1349
1474
  general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1350
- (methods?.providers ?? []).map((p) => /* @__PURE__ */ jsxs(f.Button, { type: "button", className: f.cx("providerButton"), onClick: () => auth.signIn.social(p.id, { returnTo: props.returnTo }), children: [
1351
- f.t.continueWith,
1352
- " ",
1353
- p.name
1354
- ] }, p.id)),
1355
- methods?.passkey && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void usePasskey(), children: f.t.usePasskey }),
1356
- ((methods?.providers.length ?? 0) > 0 || methods?.passkey) && /* @__PURE__ */ jsx("p", { className: f.cx("separator"), children: f.t.orWithEmail }),
1357
- /* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: methods?.passkeyHere ? "username webauthn" : "username", required: true, onChange: setEmail }),
1475
+ /* @__PURE__ */ jsx(ProviderButtons, { f, providers: methods?.providers ?? [], onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
1476
+ offers.passkey && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void usePasskey(), children: f.t.usePasskey }),
1477
+ asksEmail && ((methods?.providers.length ?? 0) > 0 || offers.passkey) && /* @__PURE__ */ jsx("p", { className: f.cx("separator"), children: f.t.orWithEmail }),
1478
+ 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 }),
1358
1479
  company && /* @__PURE__ */ jsxs(f.Button, { type: "button", disabled: f.busy, className: f.cx(company.enforced ? "button" : "providerButton"), onClick: toCompany, children: [
1359
1480
  f.t.continueWith,
1360
1481
  " ",
1361
1482
  company.name
1362
1483
  ] }),
1363
1484
  company?.enforced && /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.ssoOnly }),
1364
- !company?.enforced && /* @__PURE__ */ jsxs(Fragment, { children: [
1485
+ !company?.enforced && passwordOn && /* @__PURE__ */ jsxs(Fragment, { children: [
1365
1486
  /* @__PURE__ */ jsx(
1366
1487
  Field,
1367
1488
  {
@@ -1379,6 +1500,7 @@ function SignIn(props) {
1379
1500
  challenge.node,
1380
1501
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.signIn })
1381
1502
  ] }),
1503
+ !company?.enforced && !passwordOn && methods?.magicLink && challenge.node,
1382
1504
  methods?.magicLink && !company?.enforced && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendLink(), children: f.t.emailMeALink }),
1383
1505
  methods?.signUp !== false && props.links?.signUp && /* @__PURE__ */ jsxs("p", { className: f.cx("footer"), children: [
1384
1506
  f.t.noAccount,
@@ -1438,14 +1560,30 @@ function SignUp(props) {
1438
1560
  f.done();
1439
1561
  };
1440
1562
  const general = f.error && !f.error.field ? f.error : null;
1563
+ const passwordOn = methods?.passwordSignIn !== false;
1564
+ const providers = auth.session?.user.isAnonymous === true || methods?.organization?.required ? [] : methods?.providers ?? [];
1441
1565
  if (sent) {
1442
1566
  return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
1443
1567
  /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.checkEmail }),
1444
1568
  props.links?.signIn && /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.backToSignIn })
1445
1569
  ] });
1446
1570
  }
1571
+ const footer = props.links?.signIn && /* @__PURE__ */ jsxs("p", { className: f.cx("footer"), children: [
1572
+ f.t.haveAccount,
1573
+ " ",
1574
+ /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.signIn })
1575
+ ] });
1576
+ if (!passwordOn) {
1577
+ return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
1578
+ general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1579
+ /* @__PURE__ */ jsx(ProviderButtons, { f, providers, onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
1580
+ footer
1581
+ ] });
1582
+ }
1447
1583
  return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1448
1584
  general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1585
+ /* @__PURE__ */ jsx(ProviderButtons, { f, providers, onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
1586
+ providers.length > 0 && /* @__PURE__ */ jsx("p", { className: f.cx("separator"), children: f.t.orWithEmail }),
1449
1587
  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 }),
1450
1588
  /* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
1451
1589
  /* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
@@ -1471,11 +1609,7 @@ function SignUp(props) {
1471
1609
  ] }, p.key)),
1472
1610
  challenge.node,
1473
1611
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.signUp }),
1474
- props.links?.signIn && /* @__PURE__ */ jsxs("p", { className: f.cx("footer"), children: [
1475
- f.t.haveAccount,
1476
- " ",
1477
- /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.signIn })
1478
- ] })
1612
+ footer
1479
1613
  ] });
1480
1614
  }
1481
1615
  function ForgotPassword(props) {
@@ -1572,6 +1706,62 @@ function VerifyEmail(props) {
1572
1706
  state !== "confirming" && props.links?.signIn && /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.backToSignIn })
1573
1707
  ] });
1574
1708
  }
1709
+ function AcceptInvite(props) {
1710
+ const auth = useAuth();
1711
+ const f = useForm(props);
1712
+ const [token, setToken] = useState("");
1713
+ const [invitation, setInvitation] = useState(null);
1714
+ const [state, setState] = useState("opening");
1715
+ const [password, setPassword] = useState("");
1716
+ usePasswordPolicy(f, useMethods(auth));
1717
+ useMailedToken("token", (t) => {
1718
+ if (!t) return setState("invalid");
1719
+ setToken(t);
1720
+ void auth.invitation(t).then((r) => {
1721
+ if (r.ok) {
1722
+ setInvitation(r.invitation);
1723
+ return setState("ready");
1724
+ }
1725
+ if (r.error.code !== "invalid_token") f.setError(r.error);
1726
+ setState("invalid");
1727
+ });
1728
+ });
1729
+ const submit = async (e) => {
1730
+ e.preventDefault();
1731
+ f.setBusy(true);
1732
+ f.setError(null);
1733
+ const r = await auth.acceptInvitation(token, password);
1734
+ f.setBusy(false);
1735
+ if (!r.ok) {
1736
+ if (r.error.code === "invalid_token") return setState("invalid");
1737
+ return f.setError(r.error);
1738
+ }
1739
+ if (r.status === "mfa_required") return setState("code");
1740
+ f.done();
1741
+ };
1742
+ const general = f.error && !f.error.field ? f.error : null;
1743
+ const back = props.links?.signIn && /* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.backToSignIn });
1744
+ if (state === "opening") {
1745
+ return /* @__PURE__ */ jsx("div", { className: f.cx("form"), ...f.root, "aria-busy": "true", children: /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.openingInvitation }) });
1746
+ }
1747
+ if (state === "invalid") {
1748
+ return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
1749
+ /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: general ? f.say(general) : f.t.invitationInvalid }),
1750
+ back
1751
+ ] });
1752
+ }
1753
+ if (state === "code") return /* @__PURE__ */ jsx(SecondStepForm, { f, auth });
1754
+ const workspace = invitation?.workspace ?? "";
1755
+ const heading = invitation?.organization ? f.t.invitedToOrganization.replace("{organization}", invitation.organization).replace("{workspace}", workspace) : f.t.invitedTo.replace("{workspace}", workspace);
1756
+ return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
1757
+ /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: heading }),
1758
+ /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.invitedAs.replace("{email}", invitation?.email ?? "") }),
1759
+ general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
1760
+ /* @__PURE__ */ jsx("input", { type: "email", name: "username", autoComplete: "username", value: invitation?.email ?? "", readOnly: true, hidden: true }),
1761
+ /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.choosePassword, value: password, autoComplete: "new-password", required: true, onChange: setPassword, hint: f.passwordRule }),
1762
+ /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.acceptInvite })
1763
+ ] });
1764
+ }
1575
1765
  function useSection(props) {
1576
1766
  const f = useForm({ ...props, unstyled: true });
1577
1767
  const [done, setDone] = useState(null);
@@ -1622,32 +1812,52 @@ function Account(props) {
1622
1812
  ] })
1623
1813
  ] });
1624
1814
  }
1815
+ var OWNER = "owner";
1816
+ function memberActions(seat, m) {
1817
+ const reachable = m.role !== OWNER || seat.role === OWNER;
1818
+ return {
1819
+ changeRole: seat.can.manageMembers && reachable,
1820
+ // Leaving is anybody's; removing somebody else is cauthy:members:remove.
1821
+ remove: m.you || seat.can.removeMembers && reachable,
1822
+ inviteAgain: seat.can.manageMembers && m.invited
1823
+ };
1824
+ }
1825
+ function rolesToGive(seat, roles) {
1826
+ return seat.role === OWNER ? roles : roles.filter((c) => c.role !== OWNER);
1827
+ }
1625
1828
  function OrganizationMembers(props) {
1626
1829
  const auth = useAuth();
1627
1830
  const { root } = useForm(props);
1628
1831
  const { f, done, setDone, run } = useSection(props);
1629
- const problem = f.error && f.error.field !== "email" ? f.error : null;
1832
+ const problem = f.error && f.error.field !== "email" && f.error.field !== "name" ? f.error : null;
1630
1833
  const [seat, setSeat] = useState(void 0);
1631
1834
  const [members, setMembers] = useState(null);
1632
1835
  const [roles, setRoles] = useState([]);
1633
1836
  const [email, setEmail] = useState("");
1634
1837
  const [role, setRole] = useState("");
1838
+ const [name, setName] = useState("");
1635
1839
  const [asking, setAsking] = useState(null);
1840
+ const [gone, setGone] = useState(null);
1636
1841
  const id = props.organizationId;
1637
1842
  const when = props.formatDate ?? ((iso) => new Date(iso).toLocaleDateString());
1638
1843
  const load = async () => {
1639
1844
  const [list, people, choices] = await Promise.all([auth.organizations.list(), auth.organizations.members(id), auth.organizations.roles(id)]);
1640
- setSeat(list.find((o) => o.id === id) ?? null);
1845
+ const mine = list.find((o) => o.id === id) ?? null;
1846
+ setSeat(mine);
1847
+ if (mine) setName(mine.name);
1641
1848
  setMembers(people);
1642
1849
  setRoles(choices ?? []);
1643
- if (choices && choices.length > 0 && !choices.some((c) => c.role === role)) setRole(choices[0].role);
1850
+ const offered = mine ? rolesToGive(mine, choices ?? []) : [];
1851
+ if (offered.length > 0 && !offered.some((c) => c.role === role)) setRole(offered[0].role);
1644
1852
  };
1645
1853
  useEffect(() => {
1646
1854
  void load();
1647
1855
  }, [id]);
1856
+ if (gone !== null) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, children: /* @__PURE__ */ jsx("p", { role: "status", className: f.cx("notice"), children: gone }) });
1648
1857
  if (seat === void 0) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, "aria-busy": "true" });
1649
1858
  if (seat === null) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, children: /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.organizationMissing }) });
1650
1859
  const manage = seat.can.manageMembers;
1860
+ const giveable = rolesToGive(seat, roles);
1651
1861
  const label = (r) => roles.find((c) => c.role === r)?.name || r;
1652
1862
  const add = async (e) => {
1653
1863
  e.preventDefault();
@@ -1672,6 +1882,25 @@ function OrganizationMembers(props) {
1672
1882
  const r = await run(() => auth.organizations.inviteAgain(id, m.userId, { locale: props.locale }));
1673
1883
  if (r.ok) setDone(f.t.memberInvitationSent);
1674
1884
  };
1885
+ const rename = async (e) => {
1886
+ e.preventDefault();
1887
+ const r = await run(() => auth.organizations.rename(id, name));
1888
+ if (!r.ok) return;
1889
+ setSeat(r.organization);
1890
+ setName(r.organization.name);
1891
+ setDone(f.t.organizationRenamed.replace("{name}", r.organization.name));
1892
+ };
1893
+ const close = async (how) => {
1894
+ setAsking(null);
1895
+ const r = await run(() => how === "archive" ? auth.organizations.archive(id) : auth.organizations.delete(id));
1896
+ if (r.ok) setGone((how === "archive" ? f.t.organizationArchived : f.t.organizationDeleted).replace("{org}", seat.name));
1897
+ };
1898
+ const confirming = (text2, label2, yes) => /* @__PURE__ */ jsxs("span", { role: "group", "aria-label": label2, children: [
1899
+ /* @__PURE__ */ jsx("span", { children: text2 }),
1900
+ " ",
1901
+ /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: yes, children: f.t.yes }),
1902
+ /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking(null), children: f.t.cancel })
1903
+ ] });
1675
1904
  return /* @__PURE__ */ jsxs("div", { className: f.cx("account"), ...root, children: [
1676
1905
  /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
1677
1906
  /* @__PURE__ */ jsxs("h2", { className: f.cx("heading"), children: [
@@ -1682,23 +1911,14 @@ function OrganizationMembers(props) {
1682
1911
  problem && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(problem) }),
1683
1912
  members === null ? /* @__PURE__ */ jsxs(Fragment, { children: [
1684
1913
  /* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: f.t.membersHidden }),
1685
- auth.session && (asking === auth.session.user.id ? /* @__PURE__ */ jsxs("span", { role: "group", "aria-label": f.t.memberLeave, children: [
1686
- /* @__PURE__ */ jsx("span", { children: f.t.memberLeaveConfirm.replace("{org}", seat.name) }),
1687
- " ",
1688
- /* @__PURE__ */ jsx(
1689
- f.Button,
1690
- {
1691
- type: "button",
1692
- disabled: f.busy,
1693
- className: f.cx("providerButton"),
1694
- onClick: () => void remove({ userId: auth.session.user.id, you: true }),
1695
- children: f.t.yes
1696
- }
1697
- ),
1698
- /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking(null), children: f.t.cancel })
1699
- ] }) : /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking(auth.session.user.id), children: f.t.memberLeave }))
1914
+ auth.session && (asking === auth.session.user.id ? confirming(
1915
+ f.t.memberLeaveConfirm.replace("{org}", seat.name),
1916
+ f.t.memberLeave,
1917
+ () => void remove({ userId: auth.session.user.id, you: true })
1918
+ ) : /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking(auth.session.user.id), children: f.t.memberLeave }))
1700
1919
  ] }) : /* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: members.map((m) => {
1701
1920
  const who = m.name || m.email;
1921
+ const may = memberActions(seat, m);
1702
1922
  return /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
1703
1923
  /* @__PURE__ */ jsxs("span", { children: [
1704
1924
  who,
@@ -1710,7 +1930,7 @@ function OrganizationMembers(props) {
1710
1930
  when(m.since)
1711
1931
  ] }),
1712
1932
  " ",
1713
- manage && roles.length > 0 ? /* @__PURE__ */ jsx(
1933
+ may.changeRole && giveable.length > 0 ? /* @__PURE__ */ jsx(
1714
1934
  "select",
1715
1935
  {
1716
1936
  "aria-label": `${f.t.memberRole}: ${who}`,
@@ -1718,31 +1938,41 @@ function OrganizationMembers(props) {
1718
1938
  value: m.role,
1719
1939
  disabled: f.busy,
1720
1940
  onChange: (e) => void change(m, e.target.value),
1721
- children: roles.map((c) => /* @__PURE__ */ jsx("option", { value: c.role, children: c.name || c.role }, c.role))
1941
+ 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))
1722
1942
  }
1723
1943
  ) : /* @__PURE__ */ jsx("span", { children: label(m.role) }),
1724
1944
  " ",
1725
- asking === m.userId ? /* @__PURE__ */ jsxs("span", { role: "group", "aria-label": m.you ? f.t.memberLeave : f.t.memberRemove, children: [
1726
- /* @__PURE__ */ jsx("span", { children: m.you ? f.t.memberLeaveConfirm.replace("{org}", seat.name) : f.t.memberRemoveConfirm.replace("{who}", who) }),
1727
- " ",
1728
- /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void remove(m), children: f.t.yes }),
1729
- /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking(null), children: f.t.cancel })
1730
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1731
- manage && m.invited && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void inviteAgain(m), children: f.t.memberInviteAgain }),
1732
- (manage || m.you) && /* @__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 })
1945
+ asking === m.userId ? confirming(
1946
+ m.you ? f.t.memberLeaveConfirm.replace("{org}", seat.name) : f.t.memberRemoveConfirm.replace("{who}", who),
1947
+ m.you ? f.t.memberLeave : f.t.memberRemove,
1948
+ () => void remove(m)
1949
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
1950
+ may.inviteAgain && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void inviteAgain(m), children: f.t.memberInviteAgain }),
1951
+ 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 })
1733
1952
  ] })
1734
1953
  ] }, m.userId);
1735
1954
  }) }),
1736
1955
  done && /* @__PURE__ */ jsx("p", { role: "status", className: f.cx("notice"), children: done })
1737
1956
  ] }),
1738
- manage && roles.length > 0 && /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: add, noValidate: true, children: [
1957
+ manage && giveable.length > 0 && /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: add, noValidate: true, children: [
1739
1958
  /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.memberAdd }),
1740
1959
  /* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "off", required: true, onChange: setEmail }),
1741
1960
  /* @__PURE__ */ jsxs("label", { className: f.cx("field"), children: [
1742
1961
  /* @__PURE__ */ jsx("span", { className: f.cx("label"), children: f.t.memberRole }),
1743
- /* @__PURE__ */ jsx("select", { name: "role", className: f.cx("input"), value: role, onChange: (e) => setRole(e.target.value), children: roles.map((c) => /* @__PURE__ */ jsx("option", { value: c.role, children: c.name || c.role }, c.role)) })
1962
+ /* @__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)) })
1744
1963
  ] }),
1745
1964
  /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.memberAdd })
1965
+ ] }),
1966
+ (seat.can.update || seat.can.archive || seat.can.delete) && /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
1967
+ /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children: f.t.organization }),
1968
+ seat.can.update && /* @__PURE__ */ jsxs("form", { onSubmit: rename, noValidate: true, children: [
1969
+ /* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "organization", required: true, onChange: setName }),
1970
+ /* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.organizationRename })
1971
+ ] }),
1972
+ 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: [
1973
+ seat.can.archive && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking("archive"), children: f.t.organizationArchive }),
1974
+ seat.can.delete && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking("delete"), children: f.t.organizationDelete })
1975
+ ] })
1746
1976
  ] })
1747
1977
  ] });
1748
1978
  }
@@ -2179,6 +2409,8 @@ function useAuth() {
2179
2409
  googleOneTap: (o) => then(client.signIn.googleOneTap(o))
2180
2410
  },
2181
2411
  signUp: { email: (f) => then(client.signUp.email(f)) },
2412
+ // The invited person is signed in once they accept.
2413
+ acceptInvitation: (token, password) => then(client.acceptInvitation(token, password)),
2182
2414
  signOut: () => then(client.signOut()),
2183
2415
  account: {
2184
2416
  ...client.account,
@@ -2196,6 +2428,7 @@ function useAuth() {
2196
2428
  }, [basePath, refresh, session, status]);
2197
2429
  }
2198
2430
  export {
2431
+ AcceptInvite,
2199
2432
  Account,
2200
2433
  CauthyProvider,
2201
2434
  ForgotPassword,