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.
- package/README.md +61 -3
- package/dist/{cauthy-CTVg4kvo.d.mts → cauthy-2jtP2LVQ.d.mts} +19 -1
- package/dist/{cauthy-BAwAJChs.d.ts → cauthy-CKfvvv_i.d.ts} +19 -1
- package/dist/cli.js +163 -59
- package/dist/client.d.mts +91 -10
- package/dist/client.d.ts +91 -10
- package/dist/client.js +39 -3
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +39 -3
- package/dist/client.mjs.map +1 -1
- package/dist/express.d.mts +2 -2
- package/dist/express.d.ts +2 -2
- package/dist/fastify.d.mts +2 -2
- package/dist/fastify.d.ts +2 -2
- package/dist/hono.d.mts +2 -2
- package/dist/hono.d.ts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +387 -148
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +385 -148
- package/dist/index.mjs.map +1 -1
- package/dist/next.d.mts +2 -2
- package/dist/next.d.ts +2 -2
- package/dist/react.d.mts +275 -23
- package/dist/react.d.ts +275 -23
- package/dist/react.js +312 -78
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +311 -78
- package/dist/react.mjs.map +1 -1
- package/dist/styles.css +8 -0
- package/dist/svelte.d.mts +2 -2
- package/dist/svelte.d.ts +2 -2
- package/dist/svelte.js +53 -4
- package/dist/svelte.js.map +1 -1
- package/dist/svelte.mjs +53 -4
- package/dist/svelte.mjs.map +1 -1
- package/dist/{system-CVBW_AV8.d.mts → system-BrrJsrFW.d.mts} +321 -109
- package/dist/{system-Bn8uckvQ.d.ts → system-BvvoNs2y.d.ts} +321 -109
- package/dist/vue.d.mts +2 -2
- package/dist/vue.d.ts +2 -2
- package/dist/vue.js +53 -4
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs +53 -4
- package/dist/vue.mjs.map +1 -1
- 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(
|
|
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
|
|
1183
|
-
const auth =
|
|
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
|
-
}, [
|
|
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
|
-
|
|
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
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 ?
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
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
|
-
|
|
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 ?
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
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 &&
|
|
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:
|
|
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,
|