cauthy-auth 0.33.0 → 0.35.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 +14 -4
- package/dist/{cauthy-CKfvvv_i.d.ts → cauthy-BUozWD72.d.ts} +1 -1
- package/dist/{cauthy-2jtP2LVQ.d.mts → cauthy-C-GoRXy9.d.mts} +1 -1
- package/dist/cli.js +1 -1
- package/dist/client.d.mts +7 -3
- package/dist/client.d.ts +7 -3
- package/dist/client.js.map +1 -1
- 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 +3 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -1
- 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 +27 -9
- package/dist/react.d.ts +27 -9
- package/dist/react.js +120 -42
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +120 -42
- package/dist/react.mjs.map +1 -1
- package/dist/styles.css +43 -0
- package/dist/svelte.d.mts +2 -2
- package/dist/svelte.d.ts +2 -2
- package/dist/svelte.js.map +1 -1
- package/dist/svelte.mjs.map +1 -1
- package/dist/{system-BvvoNs2y.d.ts → system-Bz4haPrI.d.ts} +10 -2
- package/dist/{system-BrrJsrFW.d.mts → system-DUGV040y.d.mts} +10 -2
- package/dist/vue.d.mts +2 -2
- package/dist/vue.d.ts +2 -2
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs.map +1 -1
- package/package.json +1 -1
package/dist/next.d.mts
CHANGED
package/dist/next.d.ts
CHANGED
package/dist/react.d.mts
CHANGED
|
@@ -620,7 +620,11 @@ interface OrganizationsClient {
|
|
|
620
620
|
members(organizationId: string): Promise<OrganizationPerson[] | null>;
|
|
621
621
|
/** The roles a member may be given, or null when the person may not see them. */
|
|
622
622
|
roles(organizationId: string): Promise<OrganizationRoleChoice[] | null>;
|
|
623
|
-
/**
|
|
623
|
+
/**
|
|
624
|
+
* Adds a person by their address; an address with no account gets one and
|
|
625
|
+
* its invitation. It only adds: a person who already belongs keeps their
|
|
626
|
+
* role and the result is the error `member_exists` (change it with `setRole`).
|
|
627
|
+
*/
|
|
624
628
|
add(organizationId: string, form: {
|
|
625
629
|
email: string;
|
|
626
630
|
role: string;
|
|
@@ -1193,6 +1197,8 @@ interface AuthTexts {
|
|
|
1193
1197
|
savePassword: string;
|
|
1194
1198
|
passwordChanged: string;
|
|
1195
1199
|
confirming: string;
|
|
1200
|
+
/** While a form waits on what the workspace offers, or on the account it shows. */
|
|
1201
|
+
loading: string;
|
|
1196
1202
|
emailConfirmed: string;
|
|
1197
1203
|
invitedTo: string;
|
|
1198
1204
|
invitedToOrganization: string;
|
|
@@ -1279,7 +1285,7 @@ interface AuthTexts {
|
|
|
1279
1285
|
/** By error code; one missing shows what the server said. */
|
|
1280
1286
|
errors: Record<string, string>;
|
|
1281
1287
|
}
|
|
1282
|
-
type Slot = 'form' | 'field' | 'label' | 'input' | 'button' | 'providerButton' | 'providerIcon' | 'link' | 'error' | 'fieldError' | 'hint' | 'notice' | 'separator' | 'footer' | 'check' | 'account' | 'section' | 'heading' | 'secret' | 'codes' | 'sessions' | 'session';
|
|
1288
|
+
type Slot = 'form' | 'field' | 'label' | 'input' | 'button' | 'providerButton' | 'providerIcon' | 'link' | 'error' | 'fieldError' | 'hint' | 'notice' | 'pending' | 'separator' | 'footer' | 'check' | 'account' | 'section' | 'heading' | 'secret' | 'codes' | 'sessions' | 'session';
|
|
1283
1289
|
interface AuthFormProps {
|
|
1284
1290
|
/** The language of the built-in sentences. Default: `en`. */
|
|
1285
1291
|
locale?: 'en' | 'es';
|
|
@@ -1287,8 +1293,14 @@ interface AuthFormProps {
|
|
|
1287
1293
|
texts?: Partial<Omit<AuthTexts, 'errors'>> & {
|
|
1288
1294
|
errors?: Record<string, string>;
|
|
1289
1295
|
};
|
|
1290
|
-
/**
|
|
1291
|
-
|
|
1296
|
+
/**
|
|
1297
|
+
* Called once the person is signed in, instead of going to `returnTo`. The
|
|
1298
|
+
* form stays busy (its button loading, every control disabled) until it
|
|
1299
|
+
* leaves the page. When the application keeps the form on screen while it
|
|
1300
|
+
* moves on (a router's navigation, loading the session), return a Promise:
|
|
1301
|
+
* the form waits for it, then is free again if it is still shown.
|
|
1302
|
+
*/
|
|
1303
|
+
onSuccess?: () => void | Promise<unknown>;
|
|
1292
1304
|
/** Where to go after signing in, and where a provider returns to. Default: `/`. */
|
|
1293
1305
|
returnTo?: string;
|
|
1294
1306
|
/**
|
|
@@ -1331,7 +1343,9 @@ interface AuthFormProps {
|
|
|
1331
1343
|
* other action (a provider, a passkey, a sign-in link, cancel, send again);
|
|
1332
1344
|
* `danger` removes, leaves, deletes, disconnects or turns something off.
|
|
1333
1345
|
* `loading` is true on the one button whose action is under way; every
|
|
1334
|
-
* button is `disabled` meanwhile
|
|
1346
|
+
* button is `disabled` meanwhile. Draw a spinner (or the like) on the button
|
|
1347
|
+
* while `loading` is true, and keep its label: after a sign-in it stays true
|
|
1348
|
+
* until the page is left, so the person sees the work go on.
|
|
1335
1349
|
*/
|
|
1336
1350
|
interface AuthButtonProps {
|
|
1337
1351
|
type: 'submit' | 'button';
|
|
@@ -1372,6 +1386,7 @@ interface AuthInputProps {
|
|
|
1372
1386
|
value: string;
|
|
1373
1387
|
autoComplete?: string;
|
|
1374
1388
|
required?: boolean;
|
|
1389
|
+
disabled?: boolean;
|
|
1375
1390
|
className?: string;
|
|
1376
1391
|
'aria-invalid'?: boolean;
|
|
1377
1392
|
'aria-describedby'?: string;
|
|
@@ -1529,8 +1544,11 @@ interface AcceptInviteProps extends AuthFormProps {
|
|
|
1529
1544
|
}
|
|
1530
1545
|
declare function AcceptInvite(props: AcceptInviteProps): react.JSX.Element;
|
|
1531
1546
|
interface PendingTermsProps extends Omit<AuthFormProps, 'links' | 'returnTo' | 'createAccounts'> {
|
|
1532
|
-
/**
|
|
1533
|
-
|
|
1547
|
+
/**
|
|
1548
|
+
* Called once the person accepted. Nothing else happens: the application
|
|
1549
|
+
* decides what follows. A Promise keeps the button loading until it settles.
|
|
1550
|
+
*/
|
|
1551
|
+
onSuccess?: () => void | Promise<unknown>;
|
|
1534
1552
|
}
|
|
1535
1553
|
/**
|
|
1536
1554
|
* The legal documents the signed-in person still owes (a new version of the
|
|
@@ -1583,8 +1601,8 @@ type AccountEvent = {
|
|
|
1583
1601
|
kind: 'sessions.ended';
|
|
1584
1602
|
};
|
|
1585
1603
|
interface AccountProps extends Omit<AuthFormProps, 'links' | 'returnTo' | 'onSuccess'> {
|
|
1586
|
-
/** Called after "sign out everywhere". Default: go to `/`. */
|
|
1587
|
-
onSignedOut?: () => void
|
|
1604
|
+
/** Called after "sign out everywhere". Default: go to `/`. A Promise keeps the button loading until it settles. */
|
|
1605
|
+
onSignedOut?: () => void | Promise<unknown>;
|
|
1588
1606
|
/** The moment of a session, as the application writes dates. Default: the browser's own way, in the reader's time zone. */
|
|
1589
1607
|
formatDate?: (iso: string) => string;
|
|
1590
1608
|
/**
|
package/dist/react.d.ts
CHANGED
|
@@ -620,7 +620,11 @@ interface OrganizationsClient {
|
|
|
620
620
|
members(organizationId: string): Promise<OrganizationPerson[] | null>;
|
|
621
621
|
/** The roles a member may be given, or null when the person may not see them. */
|
|
622
622
|
roles(organizationId: string): Promise<OrganizationRoleChoice[] | null>;
|
|
623
|
-
/**
|
|
623
|
+
/**
|
|
624
|
+
* Adds a person by their address; an address with no account gets one and
|
|
625
|
+
* its invitation. It only adds: a person who already belongs keeps their
|
|
626
|
+
* role and the result is the error `member_exists` (change it with `setRole`).
|
|
627
|
+
*/
|
|
624
628
|
add(organizationId: string, form: {
|
|
625
629
|
email: string;
|
|
626
630
|
role: string;
|
|
@@ -1193,6 +1197,8 @@ interface AuthTexts {
|
|
|
1193
1197
|
savePassword: string;
|
|
1194
1198
|
passwordChanged: string;
|
|
1195
1199
|
confirming: string;
|
|
1200
|
+
/** While a form waits on what the workspace offers, or on the account it shows. */
|
|
1201
|
+
loading: string;
|
|
1196
1202
|
emailConfirmed: string;
|
|
1197
1203
|
invitedTo: string;
|
|
1198
1204
|
invitedToOrganization: string;
|
|
@@ -1279,7 +1285,7 @@ interface AuthTexts {
|
|
|
1279
1285
|
/** By error code; one missing shows what the server said. */
|
|
1280
1286
|
errors: Record<string, string>;
|
|
1281
1287
|
}
|
|
1282
|
-
type Slot = 'form' | 'field' | 'label' | 'input' | 'button' | 'providerButton' | 'providerIcon' | 'link' | 'error' | 'fieldError' | 'hint' | 'notice' | 'separator' | 'footer' | 'check' | 'account' | 'section' | 'heading' | 'secret' | 'codes' | 'sessions' | 'session';
|
|
1288
|
+
type Slot = 'form' | 'field' | 'label' | 'input' | 'button' | 'providerButton' | 'providerIcon' | 'link' | 'error' | 'fieldError' | 'hint' | 'notice' | 'pending' | 'separator' | 'footer' | 'check' | 'account' | 'section' | 'heading' | 'secret' | 'codes' | 'sessions' | 'session';
|
|
1283
1289
|
interface AuthFormProps {
|
|
1284
1290
|
/** The language of the built-in sentences. Default: `en`. */
|
|
1285
1291
|
locale?: 'en' | 'es';
|
|
@@ -1287,8 +1293,14 @@ interface AuthFormProps {
|
|
|
1287
1293
|
texts?: Partial<Omit<AuthTexts, 'errors'>> & {
|
|
1288
1294
|
errors?: Record<string, string>;
|
|
1289
1295
|
};
|
|
1290
|
-
/**
|
|
1291
|
-
|
|
1296
|
+
/**
|
|
1297
|
+
* Called once the person is signed in, instead of going to `returnTo`. The
|
|
1298
|
+
* form stays busy (its button loading, every control disabled) until it
|
|
1299
|
+
* leaves the page. When the application keeps the form on screen while it
|
|
1300
|
+
* moves on (a router's navigation, loading the session), return a Promise:
|
|
1301
|
+
* the form waits for it, then is free again if it is still shown.
|
|
1302
|
+
*/
|
|
1303
|
+
onSuccess?: () => void | Promise<unknown>;
|
|
1292
1304
|
/** Where to go after signing in, and where a provider returns to. Default: `/`. */
|
|
1293
1305
|
returnTo?: string;
|
|
1294
1306
|
/**
|
|
@@ -1331,7 +1343,9 @@ interface AuthFormProps {
|
|
|
1331
1343
|
* other action (a provider, a passkey, a sign-in link, cancel, send again);
|
|
1332
1344
|
* `danger` removes, leaves, deletes, disconnects or turns something off.
|
|
1333
1345
|
* `loading` is true on the one button whose action is under way; every
|
|
1334
|
-
* button is `disabled` meanwhile
|
|
1346
|
+
* button is `disabled` meanwhile. Draw a spinner (or the like) on the button
|
|
1347
|
+
* while `loading` is true, and keep its label: after a sign-in it stays true
|
|
1348
|
+
* until the page is left, so the person sees the work go on.
|
|
1335
1349
|
*/
|
|
1336
1350
|
interface AuthButtonProps {
|
|
1337
1351
|
type: 'submit' | 'button';
|
|
@@ -1372,6 +1386,7 @@ interface AuthInputProps {
|
|
|
1372
1386
|
value: string;
|
|
1373
1387
|
autoComplete?: string;
|
|
1374
1388
|
required?: boolean;
|
|
1389
|
+
disabled?: boolean;
|
|
1375
1390
|
className?: string;
|
|
1376
1391
|
'aria-invalid'?: boolean;
|
|
1377
1392
|
'aria-describedby'?: string;
|
|
@@ -1529,8 +1544,11 @@ interface AcceptInviteProps extends AuthFormProps {
|
|
|
1529
1544
|
}
|
|
1530
1545
|
declare function AcceptInvite(props: AcceptInviteProps): react.JSX.Element;
|
|
1531
1546
|
interface PendingTermsProps extends Omit<AuthFormProps, 'links' | 'returnTo' | 'createAccounts'> {
|
|
1532
|
-
/**
|
|
1533
|
-
|
|
1547
|
+
/**
|
|
1548
|
+
* Called once the person accepted. Nothing else happens: the application
|
|
1549
|
+
* decides what follows. A Promise keeps the button loading until it settles.
|
|
1550
|
+
*/
|
|
1551
|
+
onSuccess?: () => void | Promise<unknown>;
|
|
1534
1552
|
}
|
|
1535
1553
|
/**
|
|
1536
1554
|
* The legal documents the signed-in person still owes (a new version of the
|
|
@@ -1583,8 +1601,8 @@ type AccountEvent = {
|
|
|
1583
1601
|
kind: 'sessions.ended';
|
|
1584
1602
|
};
|
|
1585
1603
|
interface AccountProps extends Omit<AuthFormProps, 'links' | 'returnTo' | 'onSuccess'> {
|
|
1586
|
-
/** Called after "sign out everywhere". Default: go to `/`. */
|
|
1587
|
-
onSignedOut?: () => void
|
|
1604
|
+
/** Called after "sign out everywhere". Default: go to `/`. A Promise keeps the button loading until it settles. */
|
|
1605
|
+
onSignedOut?: () => void | Promise<unknown>;
|
|
1588
1606
|
/** The moment of a session, as the application writes dates. Default: the browser's own way, in the reader's time zone. */
|
|
1589
1607
|
formatDate?: (iso: string) => string;
|
|
1590
1608
|
/**
|
package/dist/react.js
CHANGED
|
@@ -823,6 +823,7 @@ var TEXTS = {
|
|
|
823
823
|
savePassword: "Save the password",
|
|
824
824
|
passwordChanged: "Your password was changed. You can sign in with it now.",
|
|
825
825
|
confirming: "Confirming your address\u2026",
|
|
826
|
+
loading: "Loading\u2026",
|
|
826
827
|
emailConfirmed: "Your address is confirmed. You can sign in now.",
|
|
827
828
|
invitedTo: "You've been invited to {workspace}",
|
|
828
829
|
invitedToOrganization: "You've been invited to {organization} on {workspace}",
|
|
@@ -910,6 +911,7 @@ var TEXTS = {
|
|
|
910
911
|
last_manager: "Somebody else must manage the members first: give that role to another member.",
|
|
911
912
|
last_owner: "An organization keeps at least one owner: make another member owner first.",
|
|
912
913
|
organization_not_found: "That organization no longer exists.",
|
|
914
|
+
member_exists: "That person already belongs to the organization; their role was not changed. Change it in the list instead.",
|
|
913
915
|
already_member: "That person already belongs to the organization. Change their role instead.",
|
|
914
916
|
unknown_role: "Choose one of the roles offered.",
|
|
915
917
|
user_not_active: "That account is disabled.",
|
|
@@ -1003,6 +1005,7 @@ var TEXTS = {
|
|
|
1003
1005
|
savePassword: "Guardar la contrase\xF1a",
|
|
1004
1006
|
passwordChanged: "Tu contrase\xF1a se cambi\xF3. Ya puedes entrar con ella.",
|
|
1005
1007
|
confirming: "Confirmando tu correo\u2026",
|
|
1008
|
+
loading: "Cargando\u2026",
|
|
1006
1009
|
emailConfirmed: "Tu correo qued\xF3 confirmado. Ya puedes entrar.",
|
|
1007
1010
|
invitedTo: "Te invitaron a {workspace}",
|
|
1008
1011
|
invitedToOrganization: "Te invitaron a {organization} en {workspace}",
|
|
@@ -1090,6 +1093,7 @@ var TEXTS = {
|
|
|
1090
1093
|
last_manager: "Primero alguien m\xE1s debe administrar los miembros: dale ese rol a otro miembro.",
|
|
1091
1094
|
last_owner: "Una organizaci\xF3n conserva al menos un propietario: primero haz propietario a otro miembro.",
|
|
1092
1095
|
organization_not_found: "Esa organizaci\xF3n ya no existe.",
|
|
1096
|
+
member_exists: "Esa persona ya pertenece a la organizaci\xF3n; su rol no cambi\xF3. C\xE1mbialo en la lista.",
|
|
1093
1097
|
already_member: "Esa persona ya pertenece a la organizaci\xF3n. Cambia su rol.",
|
|
1094
1098
|
unknown_role: "Escoge uno de los roles ofrecidos.",
|
|
1095
1099
|
user_not_active: "Esa cuenta est\xE1 desactivada.",
|
|
@@ -1134,7 +1138,14 @@ var TEXTS = {
|
|
|
1134
1138
|
}
|
|
1135
1139
|
}
|
|
1136
1140
|
};
|
|
1137
|
-
var PlainButton = ({ variant: _variant, loading
|
|
1141
|
+
var PlainButton = ({ variant: _variant, loading, children, ...p }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { ...p, "aria-busy": loading || void 0, children: [
|
|
1142
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cauthy-spinner", "aria-hidden": "true" }),
|
|
1143
|
+
children
|
|
1144
|
+
] });
|
|
1145
|
+
var UnstyledButton = ({ variant: _variant, loading, children, ...p }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { ...p, "aria-busy": loading || void 0, children: [
|
|
1146
|
+
children,
|
|
1147
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", children: "\u2026" })
|
|
1148
|
+
] });
|
|
1138
1149
|
var PlainInput = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { ...p });
|
|
1139
1150
|
var looks = /* @__PURE__ */ new Map();
|
|
1140
1151
|
var loaded = /* @__PURE__ */ new Set();
|
|
@@ -1242,12 +1253,15 @@ function sameOrigin(to) {
|
|
|
1242
1253
|
return void 0;
|
|
1243
1254
|
}
|
|
1244
1255
|
}
|
|
1245
|
-
function
|
|
1256
|
+
function isPending(v) {
|
|
1257
|
+
return typeof v?.then === "function";
|
|
1258
|
+
}
|
|
1259
|
+
function useForm(props, opts = {}) {
|
|
1246
1260
|
const t = { ...TEXTS[props.locale ?? "en"], ...props.texts, errors: { ...TEXTS[props.locale ?? "en"].errors, ...props.texts?.errors } };
|
|
1247
1261
|
const cx = (slot) => props.classNames?.[slot] ?? `cauthy-${slot}`;
|
|
1248
1262
|
const own = (slot) => props.classNames?.[slot];
|
|
1249
1263
|
const C = props.components ?? {};
|
|
1250
|
-
const Button = C.Button ?? PlainButton;
|
|
1264
|
+
const Button = C.Button ?? (props.unstyled ? UnstyledButton : PlainButton);
|
|
1251
1265
|
const Input = C.Input ?? PlainInput;
|
|
1252
1266
|
const [error, setOnlyError] = (0, import_react.useState)(null);
|
|
1253
1267
|
const [problems, setProblems] = (0, import_react.useState)({ list: [], round: 0 });
|
|
@@ -1264,9 +1278,32 @@ function useForm(props) {
|
|
|
1264
1278
|
const fieldError = (name) => problems.list.find((e) => e.field === name) ?? (error?.field === name ? error : null);
|
|
1265
1279
|
const firstWrong = (name) => problems.list[0]?.field === name ? problems.round : 0;
|
|
1266
1280
|
const [acting, setActing] = (0, import_react.useState)(null);
|
|
1267
|
-
const busy = acting !== null;
|
|
1281
|
+
const busy = acting !== null || opts.waiting === true;
|
|
1268
1282
|
const setBusy = (0, import_react.useCallback)((on) => setActing(on === false ? null : on === true ? SUBMIT : on), []);
|
|
1269
1283
|
const loading = (key = SUBMIT) => acting === key;
|
|
1284
|
+
const shown = (0, import_react.useRef)(true);
|
|
1285
|
+
(0, import_react.useEffect)(() => {
|
|
1286
|
+
shown.current = true;
|
|
1287
|
+
const back = (e) => {
|
|
1288
|
+
if (e.persisted) setActing(null);
|
|
1289
|
+
};
|
|
1290
|
+
window.addEventListener("pageshow", back);
|
|
1291
|
+
return () => {
|
|
1292
|
+
shown.current = false;
|
|
1293
|
+
window.removeEventListener("pageshow", back);
|
|
1294
|
+
};
|
|
1295
|
+
}, []);
|
|
1296
|
+
const hold = (after) => {
|
|
1297
|
+
if (!isPending(after)) return;
|
|
1298
|
+
const free = () => {
|
|
1299
|
+
if (shown.current) setActing(null);
|
|
1300
|
+
};
|
|
1301
|
+
after.then(free, free);
|
|
1302
|
+
};
|
|
1303
|
+
const fail = (e) => {
|
|
1304
|
+
setActing(null);
|
|
1305
|
+
setError(e);
|
|
1306
|
+
};
|
|
1270
1307
|
const [policy, setPolicy] = (0, import_react.useState)(void 0);
|
|
1271
1308
|
const locale = props.locale ?? "en";
|
|
1272
1309
|
const say = (e) => {
|
|
@@ -1275,15 +1312,18 @@ function useForm(props) {
|
|
|
1275
1312
|
};
|
|
1276
1313
|
const passwordRule = describePasswordPolicy(policy, locale);
|
|
1277
1314
|
const done = (to) => {
|
|
1278
|
-
|
|
1315
|
+
setActing((a) => a ?? SUBMIT);
|
|
1316
|
+
if (props.onSuccess) hold(props.onSuccess());
|
|
1279
1317
|
else window.location.assign(sitePath(to) ?? sameOrigin(props.returnTo) ?? "/");
|
|
1280
1318
|
};
|
|
1281
|
-
const root = useRoot(props);
|
|
1282
|
-
|
|
1319
|
+
const root = useRoot(opts.part ? { ...props, unstyled: true } : props);
|
|
1320
|
+
const plain = props.unstyled === true;
|
|
1321
|
+
return { t, cx, own, C, Button, Input, error, setError, fail, check, fieldError, firstWrong, busy, setBusy, loading, hold, say, done, root, plain, policy, setPolicy, passwordRule };
|
|
1283
1322
|
}
|
|
1284
1323
|
var SUBMIT = "submit";
|
|
1285
1324
|
function Wrap(p) {
|
|
1286
1325
|
const { Form: OwnForm } = p.f.C;
|
|
1326
|
+
const busy = p.busy ?? (p.f.busy || void 0);
|
|
1287
1327
|
if (OwnForm) {
|
|
1288
1328
|
const own = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1289
1329
|
OwnForm,
|
|
@@ -1291,7 +1331,7 @@ function Wrap(p) {
|
|
|
1291
1331
|
as: p.as === "form" ? "form" : "div",
|
|
1292
1332
|
onSubmit: p.onSubmit,
|
|
1293
1333
|
noValidate: p.noValidate,
|
|
1294
|
-
"aria-busy":
|
|
1334
|
+
"aria-busy": busy,
|
|
1295
1335
|
className: p.slot ? p.f.own(p.slot) : void 0,
|
|
1296
1336
|
section: p.section,
|
|
1297
1337
|
children: p.children
|
|
@@ -1300,7 +1340,16 @@ function Wrap(p) {
|
|
|
1300
1340
|
return p.root?.["data-cauthy"] !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...p.root, children: own }) : own;
|
|
1301
1341
|
}
|
|
1302
1342
|
const Tag2 = p.as;
|
|
1303
|
-
|
|
1343
|
+
const children = p.busy && p.children === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pending, { f: p.f }) : p.children;
|
|
1344
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tag2, { className: p.slot ? p.f.cx(p.slot) : void 0, ...p.root, onSubmit: p.onSubmit, noValidate: p.noValidate, "aria-busy": busy, children });
|
|
1345
|
+
}
|
|
1346
|
+
function Pending({ f }) {
|
|
1347
|
+
if (f.plain) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "status", children: f.t.loading });
|
|
1348
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { role: "status", className: f.cx("pending"), children: [
|
|
1349
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cauthy-spinner", "aria-hidden": "true" }),
|
|
1350
|
+
" ",
|
|
1351
|
+
f.t.loading
|
|
1352
|
+
] });
|
|
1304
1353
|
}
|
|
1305
1354
|
function Note({ f, children, footer }) {
|
|
1306
1355
|
const { Text } = f.C;
|
|
@@ -1341,10 +1390,10 @@ function Check(p) {
|
|
|
1341
1390
|
const { f } = p;
|
|
1342
1391
|
const { Checkbox } = f.C;
|
|
1343
1392
|
if (Checkbox) {
|
|
1344
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Checkbox, { id, name: p.name, checked: p.checked, required: p.required, className: f.own("check"), onChange: p.onChange, children: p.children });
|
|
1393
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Checkbox, { id, name: p.name, checked: p.checked, required: p.required, disabled: f.busy, className: f.own("check"), onChange: p.onChange, children: p.children });
|
|
1345
1394
|
}
|
|
1346
1395
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: f.cx("check"), children: [
|
|
1347
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", name: p.name, checked: p.checked, required: p.required, onChange: (e) => p.onChange(e.target.checked) }),
|
|
1396
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", name: p.name, checked: p.checked, required: p.required, disabled: f.busy, onChange: (e) => p.onChange(e.target.checked) }),
|
|
1348
1397
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: p.children })
|
|
1349
1398
|
] });
|
|
1350
1399
|
}
|
|
@@ -1353,10 +1402,11 @@ function Pick(p) {
|
|
|
1353
1402
|
const id = p.id ?? made;
|
|
1354
1403
|
const { f } = p;
|
|
1355
1404
|
const { Select } = f.C;
|
|
1405
|
+
const disabled = p.disabled || f.busy;
|
|
1356
1406
|
if (Select) {
|
|
1357
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Select, { id, name: p.name, value: p.value, options: p.options, disabled
|
|
1407
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Select, { id, name: p.name, value: p.value, options: p.options, disabled, "aria-label": p.label, className: f.own("input"), onChange: p.onChange });
|
|
1358
1408
|
}
|
|
1359
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { id, name: p.name, "aria-label": p.label, className: f.cx("input"), value: p.value, disabled
|
|
1409
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { id, name: p.name, "aria-label": p.label, className: f.cx("input"), value: p.value, disabled, onChange: (e) => p.onChange(e.target.value), children: p.options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: o.value, children: o.label }, o.value)) });
|
|
1360
1410
|
}
|
|
1361
1411
|
function Labelled({ f, id, label, children }) {
|
|
1362
1412
|
const { Field: OwnField } = f.C;
|
|
@@ -1410,6 +1460,7 @@ function Field(p) {
|
|
|
1410
1460
|
value: p.value,
|
|
1411
1461
|
autoComplete: p.autoComplete,
|
|
1412
1462
|
required: p.required,
|
|
1463
|
+
disabled: f.busy,
|
|
1413
1464
|
className: f.cx("input"),
|
|
1414
1465
|
"aria-invalid": bad ? true : void 0,
|
|
1415
1466
|
"aria-describedby": described || void 0,
|
|
@@ -1499,6 +1550,7 @@ function SecondStepForm(p) {
|
|
|
1499
1550
|
if (ctl.signal.aborted) return;
|
|
1500
1551
|
setPushNumber(0);
|
|
1501
1552
|
if (!done.ok) return f.setError(done.error);
|
|
1553
|
+
f.setBusy("push");
|
|
1502
1554
|
f.done();
|
|
1503
1555
|
};
|
|
1504
1556
|
const sendCode = async () => {
|
|
@@ -1514,8 +1566,7 @@ function SecondStepForm(p) {
|
|
|
1514
1566
|
f.setBusy(true);
|
|
1515
1567
|
f.setError(null);
|
|
1516
1568
|
const r = await auth.signIn.mfa({ code });
|
|
1517
|
-
f.
|
|
1518
|
-
if (!r.ok) return f.setError(r.error);
|
|
1569
|
+
if (!r.ok) return f.fail(r.error);
|
|
1519
1570
|
f.done();
|
|
1520
1571
|
};
|
|
1521
1572
|
const general = f.error && !f.error.field ? f.error : null;
|
|
@@ -1543,7 +1594,11 @@ function SecondStepForm(p) {
|
|
|
1543
1594
|
}
|
|
1544
1595
|
function ProviderButtons(p) {
|
|
1545
1596
|
const { f } = p;
|
|
1546
|
-
|
|
1597
|
+
const pick = (id) => {
|
|
1598
|
+
f.setBusy(`provider:${id}`);
|
|
1599
|
+
p.onPick(id);
|
|
1600
|
+
};
|
|
1601
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: p.providers.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(f.Button, { type: "button", variant: "secondary", loading: f.loading(`provider:${provider.id}`), disabled: f.busy, className: f.cx("providerButton"), onClick: () => pick(provider.id), children: [
|
|
1547
1602
|
provider.iconUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: provider.iconUrl, alt: "", width: 18, height: 18, className: f.cx("providerIcon") }),
|
|
1548
1603
|
f.t.continueWith,
|
|
1549
1604
|
" ",
|
|
@@ -1556,8 +1611,8 @@ function signInOffers(methods) {
|
|
|
1556
1611
|
}
|
|
1557
1612
|
function SignIn(props) {
|
|
1558
1613
|
const auth = useAuth();
|
|
1559
|
-
const f = useForm(props);
|
|
1560
1614
|
const [methods, setMethods] = (0, import_react.useState)(null);
|
|
1615
|
+
const f = useForm(props, { waiting: methods === null });
|
|
1561
1616
|
const [email, setEmail] = (0, import_react.useState)("");
|
|
1562
1617
|
const [password, setPassword] = (0, import_react.useState)("");
|
|
1563
1618
|
const [code, setCode] = (0, import_react.useState)("");
|
|
@@ -1629,14 +1684,16 @@ function SignIn(props) {
|
|
|
1629
1684
|
f.setBusy(true);
|
|
1630
1685
|
f.setError(null);
|
|
1631
1686
|
const r = step === "sent" ? await auth.signIn.emailCode({ code }) : await auth.signIn.email({ email, password, captchaToken: challenge.token });
|
|
1632
|
-
f.setBusy(false);
|
|
1633
1687
|
if (step === "password") challenge.renew();
|
|
1634
1688
|
if (!r.ok && r.error.code === "sso_required") return toCompany();
|
|
1635
1689
|
if (!r.ok) {
|
|
1636
1690
|
setOffer((n) => n + 1);
|
|
1637
|
-
return f.
|
|
1691
|
+
return f.fail(r.error);
|
|
1692
|
+
}
|
|
1693
|
+
if (r.status === "mfa_required") {
|
|
1694
|
+
f.setBusy(false);
|
|
1695
|
+
return setStep("code");
|
|
1638
1696
|
}
|
|
1639
|
-
if (r.status === "mfa_required") return setStep("code");
|
|
1640
1697
|
f.done("returnTo" in r && typeof r.returnTo === "string" ? r.returnTo : void 0);
|
|
1641
1698
|
};
|
|
1642
1699
|
const usePasskey = async () => {
|
|
@@ -1645,10 +1702,10 @@ function SignIn(props) {
|
|
|
1645
1702
|
f.setError(null);
|
|
1646
1703
|
const r = await auth.signIn.passkey({ returnTo: props.returnTo, locale: props.locale, email });
|
|
1647
1704
|
if (r.ok && r.status === "redirected") return;
|
|
1705
|
+
if (r.ok) return f.done();
|
|
1648
1706
|
f.setBusy(false);
|
|
1649
|
-
|
|
1650
|
-
if (
|
|
1651
|
-
f.done();
|
|
1707
|
+
setOffer((n) => n + 1);
|
|
1708
|
+
if (r.error.code !== "cancelled") f.setError(r.error);
|
|
1652
1709
|
};
|
|
1653
1710
|
const sendLink = async () => {
|
|
1654
1711
|
autofill.current?.abort();
|
|
@@ -1765,10 +1822,12 @@ function SignUp(props) {
|
|
|
1765
1822
|
...legal ? { acceptLegal, consents } : {},
|
|
1766
1823
|
captchaToken: challenge.token
|
|
1767
1824
|
});
|
|
1768
|
-
f.setBusy(false);
|
|
1769
1825
|
challenge.renew();
|
|
1770
|
-
if (!r.ok) return f.
|
|
1771
|
-
if (r.status === "verification_required")
|
|
1826
|
+
if (!r.ok) return f.fail(r.error);
|
|
1827
|
+
if (r.status === "verification_required") {
|
|
1828
|
+
f.setBusy(false);
|
|
1829
|
+
return setSent(true);
|
|
1830
|
+
}
|
|
1772
1831
|
f.done();
|
|
1773
1832
|
};
|
|
1774
1833
|
const general = f.error && !f.error.field ? f.error : null;
|
|
@@ -1931,13 +1990,16 @@ function AcceptInvite(props) {
|
|
|
1931
1990
|
f.setBusy(true);
|
|
1932
1991
|
f.setError(null);
|
|
1933
1992
|
const r = await auth.acceptInvitation(token, password);
|
|
1934
|
-
f.setBusy(false);
|
|
1935
1993
|
if (!r.ok) {
|
|
1994
|
+
f.setBusy(false);
|
|
1936
1995
|
if (r.error.code === "invalid_token") return setState("invalid");
|
|
1937
1996
|
return f.setError(r.error);
|
|
1938
1997
|
}
|
|
1939
1998
|
props.onSaved?.({ kind: "invitation.accepted", email: invitation?.email ?? "", ...invitation?.organization ? { organization: invitation.organization } : {} });
|
|
1940
|
-
if (r.status === "mfa_required")
|
|
1999
|
+
if (r.status === "mfa_required") {
|
|
2000
|
+
f.setBusy(false);
|
|
2001
|
+
return setState("code");
|
|
2002
|
+
}
|
|
1941
2003
|
f.done();
|
|
1942
2004
|
};
|
|
1943
2005
|
const general = f.error && !f.error.field ? f.error : null;
|
|
@@ -1975,10 +2037,11 @@ function PendingTerms(props) {
|
|
|
1975
2037
|
f.setBusy(true);
|
|
1976
2038
|
f.setError(null);
|
|
1977
2039
|
const r = await auth.account.acceptLegal({ kinds: owed.map((d) => d.kind) });
|
|
2040
|
+
if (!r.ok) return f.fail(r.error);
|
|
2041
|
+
const after = props.onSuccess?.();
|
|
2042
|
+
if (isPending(after)) await Promise.resolve(after).catch(() => void 0);
|
|
1978
2043
|
f.setBusy(false);
|
|
1979
|
-
if (!r.ok) return f.setError(r.error);
|
|
1980
2044
|
setOwed([]);
|
|
1981
|
-
props.onSuccess?.();
|
|
1982
2045
|
};
|
|
1983
2046
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "div", slot: "form", root: f.root, children: [
|
|
1984
2047
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.termsChanged }),
|
|
@@ -1993,15 +2056,15 @@ function PendingTerms(props) {
|
|
|
1993
2056
|
}
|
|
1994
2057
|
var ACCOUNT_SECTIONS = ["profile", "email", "password", "linked", "secondStep", "phone", "passkeys", "agents", "sessions"];
|
|
1995
2058
|
function useSection(props) {
|
|
1996
|
-
const f = useForm(
|
|
2059
|
+
const f = useForm(props, { part: true });
|
|
1997
2060
|
const [done, setDone] = (0, import_react.useState)(null);
|
|
1998
|
-
const run = async (action, key = SUBMIT) => {
|
|
2061
|
+
const run = async (action, key = SUBMIT, leaves = false) => {
|
|
1999
2062
|
f.setBusy(key);
|
|
2000
2063
|
f.setError(null);
|
|
2001
2064
|
setDone(null);
|
|
2002
2065
|
const r = await action();
|
|
2003
|
-
f.
|
|
2004
|
-
if (!
|
|
2066
|
+
if (!r.ok) f.fail(r.error);
|
|
2067
|
+
else if (!leaves) f.setBusy(false);
|
|
2005
2068
|
return r;
|
|
2006
2069
|
};
|
|
2007
2070
|
const general = f.error && !f.error.field ? f.error : null;
|
|
@@ -2414,11 +2477,26 @@ function LinkedPart({ props }) {
|
|
|
2414
2477
|
" ",
|
|
2415
2478
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading(`unlink:${x.provider}`), disabled: f.busy, className: f.cx("providerButton"), onClick: () => void unlink(x.provider), children: f.t.unlink })
|
|
2416
2479
|
] }, x.provider)) }),
|
|
2417
|
-
offered.filter((p) => !linked.some((x) => x.provider === p.id)).map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
2418
|
-
f.
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2480
|
+
offered.filter((p) => !linked.some((x) => x.provider === p.id)).map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
2481
|
+
f.Button,
|
|
2482
|
+
{
|
|
2483
|
+
type: "button",
|
|
2484
|
+
variant: "secondary",
|
|
2485
|
+
loading: f.loading(`link:${p.id}`),
|
|
2486
|
+
disabled: f.busy,
|
|
2487
|
+
className: f.cx("providerButton"),
|
|
2488
|
+
onClick: () => {
|
|
2489
|
+
f.setBusy(`link:${p.id}`);
|
|
2490
|
+
auth.account.link(p.id, { returnTo: here });
|
|
2491
|
+
},
|
|
2492
|
+
children: [
|
|
2493
|
+
f.t.linkWith,
|
|
2494
|
+
" ",
|
|
2495
|
+
p.name
|
|
2496
|
+
]
|
|
2497
|
+
},
|
|
2498
|
+
p.id
|
|
2499
|
+
))
|
|
2422
2500
|
] });
|
|
2423
2501
|
}
|
|
2424
2502
|
function PasswordPart({ props }) {
|
|
@@ -2576,7 +2654,7 @@ function PhonePart({ props, account, onChanged }) {
|
|
|
2576
2654
|
!ways.phone && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "phone", type: "tel", label: f.t.phone, value: number, autoComplete: "tel", required: true, onChange: setNumber }),
|
|
2577
2655
|
!ways.phone && ways.phoneChannels.length > 1 && f.C.Select && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChannelPick, { f, value: channel, channels: ways.phoneChannels, onChange: setChannel }),
|
|
2578
2656
|
!ways.phone && ways.phoneChannels.length > 1 && !f.C.Select && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: f.cx("field"), role: "radiogroup", children: ways.phoneChannels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: f.cx("label"), children: [
|
|
2579
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "radio", name: "channel", value: c, checked: channel === c, onChange: () => setChannel(c) }),
|
|
2657
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "radio", name: "channel", value: c, checked: channel === c, disabled: f.busy, onChange: () => setChannel(c) }),
|
|
2580
2658
|
" ",
|
|
2581
2659
|
c === "whatsapp" ? f.t.byWhatsapp : f.t.bySms
|
|
2582
2660
|
] }, c)) }),
|
|
@@ -2623,10 +2701,10 @@ function SessionsPart({ props, when }) {
|
|
|
2623
2701
|
void auth.account.sessions().then(setSessions);
|
|
2624
2702
|
}, []);
|
|
2625
2703
|
const end = async () => {
|
|
2626
|
-
const r = await run(() => auth.account.signOutEverywhere());
|
|
2704
|
+
const r = await run(() => auth.account.signOutEverywhere(), SUBMIT, true);
|
|
2627
2705
|
if (!r.ok) return;
|
|
2628
2706
|
props.onSaved?.({ kind: "sessions.ended" });
|
|
2629
|
-
if (props.onSignedOut) props.onSignedOut();
|
|
2707
|
+
if (props.onSignedOut) f.hold(props.onSignedOut());
|
|
2630
2708
|
else window.location.assign("/");
|
|
2631
2709
|
};
|
|
2632
2710
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "section", slot: "section", section: "sessions", children: [
|