@cauthyhq/react 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,2694 @@
1
+ 'use client';
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var src_exports = {};
23
+ __export(src_exports, {
24
+ AcceptInvite: () => AcceptInvite,
25
+ Account: () => Account,
26
+ AccountAgents: () => AccountAgents,
27
+ AccountEmail: () => AccountEmail,
28
+ AccountLinked: () => AccountLinked,
29
+ AccountPasskeys: () => AccountPasskeys,
30
+ AccountPassword: () => AccountPassword,
31
+ AccountPhone: () => AccountPhone,
32
+ AccountProfile: () => AccountProfile,
33
+ AccountSecondStep: () => AccountSecondStep,
34
+ AccountSessions: () => AccountSessions,
35
+ CauthyError: () => import_js5.CauthyError,
36
+ CauthyProvider: () => CauthyProvider,
37
+ ForgotPassword: () => ForgotPassword,
38
+ GoogleOneTap: () => GoogleOneTap,
39
+ OrganizationMembers: () => OrganizationMembers,
40
+ Organizations: () => Organizations,
41
+ PendingTerms: () => PendingTerms,
42
+ ResetPassword: () => ResetPassword,
43
+ SignIn: () => SignIn,
44
+ SignUp: () => SignUp,
45
+ UserButton: () => UserButton,
46
+ VerifyEmail: () => VerifyEmail,
47
+ can: () => import_js5.can,
48
+ canAutofillPasskeys: () => import_js5.canAutofillPasskeys,
49
+ canUsePasskeys: () => import_js5.canUsePasskeys,
50
+ createAuthClient: () => import_js5.createAuthClient,
51
+ createSessionStore: () => import_js5.createSessionStore,
52
+ createSignInFlow: () => import_js5.createSignInFlow,
53
+ definePolicy: () => import_js5.definePolicy,
54
+ initialsOf: () => initialsOf,
55
+ themeFromCss: () => import_theme3.themeFromCss,
56
+ themeFromStackmyth: () => import_theme3.themeFromStackmyth,
57
+ themeVariables: () => import_theme3.themeVariables,
58
+ tokensFromStackmyth: () => import_theme3.tokensFromStackmyth,
59
+ unwrap: () => import_js5.unwrap,
60
+ useAuth: () => useAuth,
61
+ useOrganizations: () => useOrganizations,
62
+ useSession: () => useSession,
63
+ useSignInFlow: () => useSignInFlow
64
+ });
65
+ module.exports = __toCommonJS(src_exports);
66
+
67
+ // src/react.tsx
68
+ var import_react = require("react");
69
+ var import_js = require("@cauthyhq/js");
70
+ var import_theme = require("@cauthyhq/js/theme");
71
+ var import_jsx_runtime = require("react/jsx-runtime");
72
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? import_react.useEffect : import_react.useLayoutEffect;
73
+ var StoreCtx = (0, import_react.createContext)(null);
74
+ var OutcomesCtx = (0, import_react.createContext)(null);
75
+ var ThemeCtx = (0, import_react.createContext)(void 0);
76
+ function CauthyProvider({ children, basePath = "/api/auth", initialSession, locale, theme, fetch, onProtocolMismatch }) {
77
+ const latest = (0, import_react.useRef)({ locale, fetch, onProtocolMismatch });
78
+ useIsomorphicLayoutEffect(() => {
79
+ latest.current = { locale, fetch, onProtocolMismatch };
80
+ });
81
+ const readLocale = (0, import_react.useCallback)(() => {
82
+ const l = latest.current.locale;
83
+ return typeof l === "function" ? l() : l;
84
+ }, []);
85
+ const first = (0, import_react.useRef)(initialSession);
86
+ const handsMismatch = (0, import_react.useRef)(onProtocolMismatch !== void 0);
87
+ const [outcomes] = (0, import_react.useState)(() => /* @__PURE__ */ new Set());
88
+ const store = (0, import_react.useMemo)(
89
+ () => (0, import_js.createSessionStore)({
90
+ basePath,
91
+ initialSession: first.current,
92
+ locale: readLocale,
93
+ fetch: async (...args) => {
94
+ const [input] = args;
95
+ const path = (typeof input === "string" ? input : input instanceof URL ? input.href : input.url).split("?")[0];
96
+ try {
97
+ const res = await (latest.current.fetch ?? globalThis.fetch)(...args);
98
+ if (outcomes.size > 0) {
99
+ const error = res.ok ? null : (0, import_js.errorFrom)(res.status, await res.clone().json().catch(() => null));
100
+ for (const o of [...outcomes]) o(path, error);
101
+ }
102
+ return res;
103
+ } catch (e) {
104
+ for (const o of [...outcomes]) o(path, import_js.UNAVAILABLE);
105
+ throw e;
106
+ }
107
+ },
108
+ ...handsMismatch.current ? { onProtocolMismatch: (seen) => latest.current.onProtocolMismatch?.(seen) } : {}
109
+ }),
110
+ [basePath, readLocale, outcomes]
111
+ );
112
+ (0, import_react.useEffect)(() => store.subscribe(() => {
113
+ }), [store]);
114
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StoreCtx.Provider, { value: store, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OutcomesCtx.Provider, { value: outcomes, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeCtx.Provider, { value: theme, children }) }) });
115
+ }
116
+ function useSessionStore() {
117
+ const store = (0, import_react.useContext)(StoreCtx);
118
+ if (store === null) throw new Error("@cauthyhq/react: useSession needs <CauthyProvider> above it");
119
+ return store;
120
+ }
121
+ function useRequestOutcome() {
122
+ const outcomes = (0, import_react.useContext)(OutcomesCtx);
123
+ const store = useSessionStore();
124
+ return (0, import_react.useCallback)(async (route, call) => {
125
+ let error = null;
126
+ const hear = (path, e) => {
127
+ if (path === `${store.basePath}${route}`) error = e;
128
+ };
129
+ outcomes?.add(hear);
130
+ try {
131
+ return { value: await call(), error };
132
+ } finally {
133
+ outcomes?.delete(hear);
134
+ }
135
+ }, [outcomes, store]);
136
+ }
137
+ function useProviderTheme() {
138
+ return (0, import_react.useContext)(ThemeCtx);
139
+ }
140
+ function useThemeVariables() {
141
+ const theme = (0, import_react.useContext)(ThemeCtx);
142
+ return (0, import_react.useMemo)(() => theme ? (0, import_theme.themeVariables)(theme) : void 0, [theme]);
143
+ }
144
+ function useSession() {
145
+ const store = useSessionStore();
146
+ const state = (0, import_react.useSyncExternalStore)(store.subscribe, store.get, store.get);
147
+ return (0, import_react.useMemo)(
148
+ () => ({ session: state.session, status: state.status, refresh: store.refresh, signIn: store.signIn, signOut: store.signOut, accountUrl: store.accountUrl, basePath: store.basePath }),
149
+ [state, store]
150
+ );
151
+ }
152
+ function useAuth() {
153
+ const store = useSessionStore();
154
+ const { session, status, refresh } = useSession();
155
+ return (0, import_react.useMemo)(() => ({ ...store.auth, session, status, refresh }), [store, session, status, refresh]);
156
+ }
157
+
158
+ // src/organizations.ts
159
+ var import_react2 = require("react");
160
+ function useOrganizations(options = {}) {
161
+ const auth = useAuth();
162
+ const client = auth.organizations;
163
+ const who = auth.session?.user.id ?? null;
164
+ const system = options.system;
165
+ const [list, setList] = (0, import_react2.useState)([]);
166
+ const [loading, setLoading] = (0, import_react2.useState)(who !== null);
167
+ const [error, setError] = (0, import_react2.useState)(null);
168
+ const outcome = useRequestOutcome();
169
+ const asked = (0, import_react2.useRef)(0);
170
+ const reload = (0, import_react2.useCallback)(async () => {
171
+ const n = ++asked.current;
172
+ if (who === null) {
173
+ setList([]);
174
+ setError(null);
175
+ setLoading(false);
176
+ return;
177
+ }
178
+ setLoading(true);
179
+ const { value: seats, error: failed } = await outcome("/me/organizations", () => client.list(system));
180
+ if (n !== asked.current) return;
181
+ setList(seats);
182
+ setError(failed);
183
+ setLoading(false);
184
+ }, [client, who, system, outcome]);
185
+ (0, import_react2.useEffect)(() => {
186
+ void reload();
187
+ }, [reload]);
188
+ return (0, import_react2.useMemo)(() => {
189
+ const after = async (running) => {
190
+ const r = await running;
191
+ await reload();
192
+ return r;
193
+ };
194
+ return {
195
+ ...client,
196
+ organizations: list,
197
+ loading,
198
+ error,
199
+ reload,
200
+ add: (id, f) => after(client.add(id, f)),
201
+ setRole: (id, userId, role) => after(client.setRole(id, userId, role)),
202
+ remove: (id, userId) => after(client.remove(id, userId)),
203
+ rename: (id, name) => after(client.rename(id, name)),
204
+ archive: (id) => after(client.archive(id)),
205
+ delete: (id) => after(client.delete(id))
206
+ };
207
+ }, [client, list, loading, error, reload]);
208
+ }
209
+
210
+ // src/headless.ts
211
+ var import_react4 = require("react");
212
+ var import_js2 = require("@cauthyhq/js");
213
+ function useSignInFlow() {
214
+ const store = useSessionStore();
215
+ const flow = (0, import_react4.useMemo)(() => (0, import_js2.createSignInFlow)(store.auth), [store]);
216
+ const state = (0, import_react4.useSyncExternalStore)(flow.subscribe, flow.get, flow.get);
217
+ return (0, import_react4.useMemo)(() => ({ ...flow, ...state }), [flow, state]);
218
+ }
219
+
220
+ // src/user-button.tsx
221
+ var import_react6 = require("react");
222
+ var import_jsx_runtime2 = require("react/jsx-runtime");
223
+ var TEXTS = {
224
+ en: { signIn: "Sign in", menu: "Account menu for {name}", manageAccount: "Manage account", signOut: "Sign out" },
225
+ es: { signIn: "Entrar", menu: "Men\xFA de la cuenta de {name}", manageAccount: "Administrar la cuenta", signOut: "Cerrar sesi\xF3n" }
226
+ };
227
+ function initialsOf(name, email) {
228
+ const words = name.trim().split(/\s+/).filter(Boolean);
229
+ const first = (w) => Array.from(w)[0] ?? "";
230
+ if (words.length >= 2) return (first(words[0]) + first(words[words.length - 1])).toUpperCase();
231
+ if (words.length === 1) return Array.from(words[0]).slice(0, 2).join("").toUpperCase();
232
+ return (first(email.trim()) || "?").toUpperCase();
233
+ }
234
+ function UserButton(props) {
235
+ const { session, status, signIn, signOut: hostedSignOut, accountUrl } = useSession();
236
+ const auth = useAuth();
237
+ const look = useThemeVariables();
238
+ const t = { ...TEXTS[props.locale ?? "en"], ...props.texts };
239
+ const cx = (part) => props.classNames?.[part] ?? (props.unstyled ? void 0 : `cauthy-user-${part}`);
240
+ const root = props.unstyled ? {} : { "data-cauthy": "", style: look };
241
+ const [open, setOpen] = (0, import_react6.useState)(false);
242
+ const [leaving, setLeaving] = (0, import_react6.useState)(false);
243
+ const menuId = (0, import_react6.useId)();
244
+ const trigger = (0, import_react6.useRef)(null);
245
+ const menu = (0, import_react6.useRef)(null);
246
+ (0, import_react6.useEffect)(() => {
247
+ if (!open) return;
248
+ menu.current?.querySelector('[role="menuitem"]')?.focus();
249
+ const outside = (e) => {
250
+ const target = e.target;
251
+ if (!menu.current?.contains(target) && !trigger.current?.contains(target)) setOpen(false);
252
+ };
253
+ document.addEventListener("mousedown", outside);
254
+ return () => document.removeEventListener("mousedown", outside);
255
+ }, [open]);
256
+ if (status !== "authenticated" || session === null) {
257
+ const waiting = status === "loading";
258
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cx("root"), ...root, children: props.signInHref && !waiting ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { className: cx("trigger"), href: props.signInHref, children: t.signIn }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: cx("trigger"), disabled: waiting, "aria-busy": waiting || void 0, onClick: () => signIn(), children: t.signIn }) });
259
+ }
260
+ const name = session.user.name || session.user.email;
261
+ const close = (focus) => {
262
+ setOpen(false);
263
+ if (focus) trigger.current?.focus();
264
+ };
265
+ const items = () => [...menu.current?.querySelectorAll('[role="menuitem"]') ?? []];
266
+ const onMenuKey = (e) => {
267
+ const list = items();
268
+ const at = list.indexOf(document.activeElement);
269
+ const go = (i) => {
270
+ e.preventDefault();
271
+ list[(i + list.length) % list.length]?.focus();
272
+ };
273
+ if (e.key === "Escape") {
274
+ e.preventDefault();
275
+ close(true);
276
+ } else if (e.key === "ArrowDown") go(at + 1);
277
+ else if (e.key === "ArrowUp") go(at - 1);
278
+ else if (e.key === "Home") go(0);
279
+ else if (e.key === "End") go(list.length - 1);
280
+ else if (e.key === "Tab") close(false);
281
+ };
282
+ const signOut = async () => {
283
+ setLeaving(true);
284
+ const r = await auth.signOut();
285
+ if (!r.ok && r.error.code === "not_configured") return hostedSignOut();
286
+ setLeaving(false);
287
+ if (!r.ok) return;
288
+ setOpen(false);
289
+ if (props.onSignOut) props.onSignOut();
290
+ else window.location.assign("/");
291
+ };
292
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: cx("root"), ...root, children: [
293
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
294
+ "button",
295
+ {
296
+ ref: trigger,
297
+ type: "button",
298
+ className: cx("trigger"),
299
+ "aria-haspopup": "menu",
300
+ "aria-expanded": open,
301
+ "aria-controls": open ? menuId : void 0,
302
+ "aria-label": t.menu.replace("{name}", name),
303
+ onClick: () => setOpen((o) => !o),
304
+ onKeyDown: (e) => {
305
+ if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
306
+ e.preventDefault();
307
+ setOpen(true);
308
+ }
309
+ },
310
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: cx("avatar"), "aria-hidden": "true", children: initialsOf(session.user.name, session.user.email) })
311
+ }
312
+ ),
313
+ open && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ref: menu, id: menuId, role: "menu", "aria-label": name, className: cx("menu"), onKeyDown: onMenuKey, children: [
314
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: cx("identity"), role: "presentation", children: [
315
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: session.user.name }),
316
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: session.user.email })
317
+ ] }),
318
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { role: "menuitem", tabIndex: -1, className: cx("item"), href: props.accountHref ?? accountUrl(), children: t.manageAccount }),
319
+ props.children,
320
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { role: "menuitem", tabIndex: -1, type: "button", className: cx("item"), disabled: leaving, "aria-busy": leaving || void 0, onClick: () => void signOut(), children: t.signOut })
321
+ ] })
322
+ ] });
323
+ }
324
+
325
+ // src/organizations-view.tsx
326
+ var import_react10 = require("react");
327
+
328
+ // src/components.tsx
329
+ var import_react8 = require("react");
330
+ var import_js3 = require("@cauthyhq/js");
331
+ var import_theme2 = require("@cauthyhq/js/theme");
332
+ var import_js4 = require("@cauthyhq/js");
333
+ var import_jsx_runtime3 = require("react/jsx-runtime");
334
+ var TEXTS2 = {
335
+ en: {
336
+ email: "Email",
337
+ password: "Password",
338
+ name: "Name",
339
+ company: "Your company's name",
340
+ code: "Code",
341
+ signIn: "Sign in",
342
+ signUp: "Create account",
343
+ continueWith: "Continue with",
344
+ orWithEmail: "or with your email",
345
+ keepSignedIn: "Keep me signed in",
346
+ forgotPassword: "Forgot your password?",
347
+ noAccount: "No account yet?",
348
+ createAccount: "Create one",
349
+ haveAccount: "Already have an account?",
350
+ iAccept: "I have read and accept",
351
+ and: "and",
352
+ termsOfService: "the Terms of Service",
353
+ privacyPolicy: "the Privacy Policy",
354
+ sendLink: "Send the link",
355
+ linkSent: "If that address has an account, a link to choose a new password is on its way.",
356
+ codeHelp: "Enter the code from your authenticator app, or a recovery code.",
357
+ verify: "Verify",
358
+ codeHelpPhone: "We send a code to your phone. Ask for it, then type it here, or use a recovery code.",
359
+ codeHelpEmail: "We sent a code to {to}. Type it here.",
360
+ sendEmailAgain: "Send the code again",
361
+ sendCodeSms: "Send a code by SMS to {to}",
362
+ sendCodeWhatsapp: "Send a code by WhatsApp to {to}",
363
+ codeSent: "We sent a code to {to}. Type it here.",
364
+ pushSend: "Approve on my phone",
365
+ pushPick: "On your phone, pick {n}",
366
+ pushWaiting: "We sent a notification to your phone. Open it and pick this number.",
367
+ phone: "Phone, with its country code",
368
+ phoneHelp: "Get your codes by SMS or WhatsApp instead of an app.",
369
+ phoneOn: "Codes go to {to}.",
370
+ phoneOff: "No phone yet.",
371
+ addPhone: "Add phone",
372
+ removePhone: "Remove phone",
373
+ bySms: "SMS",
374
+ byWhatsapp: "WhatsApp",
375
+ channel: "Send codes by",
376
+ checkEmail: "Almost there: open the link we sent to confirm your address \u2014 it signs you in.",
377
+ backToSignIn: "Back to sign in",
378
+ emailMeALink: "Email me a sign-in link",
379
+ linkHelp: "We will email you a link that signs you in, no password needed.",
380
+ sendMeTheLink: "Send me the link",
381
+ back: "Back",
382
+ usePasskey: "Sign in with a passkey",
383
+ codeFromMail: "Reading it on another device? Enter the code from the email.",
384
+ signInLinkSent: "If that address has an account, a link to sign in is on its way.",
385
+ newPassword: "New password",
386
+ savePassword: "Save the password",
387
+ passwordChanged: "Your password was changed. You can sign in with it now.",
388
+ confirming: "Confirming your address\u2026",
389
+ emailConfirmed: "Your address is confirmed. You can sign in now.",
390
+ invitedTo: "You've been invited to {workspace}",
391
+ invitedToOrganization: "You've been invited to {organization} on {workspace}",
392
+ invitedAs: "You will sign in as {email}.",
393
+ choosePassword: "Choose a password",
394
+ acceptInvite: "Accept and sign in",
395
+ openingInvitation: "Opening your invitation\u2026",
396
+ invitationInvalid: "This invitation is not valid: it was already used, or it has expired. Ask whoever invited you to send it again.",
397
+ profile: "Profile",
398
+ save: "Save",
399
+ saved: "Saved.",
400
+ currentPassword: "Current password",
401
+ changePassword: "Change password",
402
+ passwordChangedHere: "Your password was changed. Every other session of your account was signed out.",
403
+ secondStep: "Second step",
404
+ secondStepOn: "On: signing in also asks for a code from your authenticator app.",
405
+ secondStepOff: "Off: signing in asks only for your password.",
406
+ turnOn: "Turn on",
407
+ turnOff: "Turn off",
408
+ addToApp: "Scan this code with your authenticator app, or add the key below by hand, then enter the code it shows.",
409
+ openInApp: "Open in an authenticator app",
410
+ qrAlt: "QR code to add this account to an authenticator app",
411
+ recoveryCodes: "Recovery codes",
412
+ newRecoveryCodes: "New recovery codes",
413
+ keepCodes: "Keep these codes somewhere safe. Each works once, and they are not shown again.",
414
+ copyCodes: "Copy all",
415
+ downloadCodes: "Download .txt",
416
+ codesCopied: "The codes were copied.",
417
+ codesNotCopied: "The codes could not be copied. Select them and copy them by hand.",
418
+ change: "Change",
419
+ passwordSet: "Your account has a password.",
420
+ addAnotherPasskey: "Add a passkey",
421
+ passkeys: "Passkeys",
422
+ managePasskeys: "Add or remove a passkey",
423
+ passkeysHelp: "Sign in with your fingerprint, your face or your device's lock, without a password.",
424
+ noPasskeys: "No passkey yet.",
425
+ passkeyName: "A name for this device (optional)",
426
+ addPasskey: "Add a passkey on this device",
427
+ removePasskey: "Remove",
428
+ addPasskeyDevice: "Add this device (fingerprint or face)",
429
+ addSecurityKey: "Add a security key",
430
+ passkeyKinds: { security_key: "Security key", synced: "Synced across your devices", device: "On this device only" },
431
+ passkeyAdded: "The passkey was added. Next time, sign in with it.",
432
+ passkeyUnnamed: "Passkey",
433
+ sessions: "Where you are signed in",
434
+ signOutEverywhere: "Sign out everywhere",
435
+ agents: "AI agents",
436
+ agentsHelp: "Agents you allowed to act for you. Disconnect one and it loses its access within minutes.",
437
+ disconnect: "Disconnect",
438
+ anAgent: "An AI agent",
439
+ unknownDevice: "Unknown device",
440
+ emailAddress: "Email address",
441
+ newEmail: "New email address",
442
+ changeEmail: "Change email",
443
+ emailSent: "We sent a link to {email}. Your address changes once you open it.",
444
+ linkedAccounts: "Linked accounts",
445
+ noLinkedAccounts: "No account is linked.",
446
+ linkWith: "Link",
447
+ unlink: "Unlink",
448
+ linked: "The account was linked.",
449
+ ssoOnly: "Your company signs you in to this account.",
450
+ members: "Members",
451
+ membersHidden: "Your role here does not let you see the members.",
452
+ organizationMissing: "You do not belong to this organization.",
453
+ memberYou: "you",
454
+ memberInvited: "invited",
455
+ memberManager: "manages members",
456
+ memberRole: "Role",
457
+ memberAdd: "Add member",
458
+ memberAdded: "{email} is a member now.",
459
+ memberRemove: "Remove",
460
+ memberRemoveConfirm: "Remove {who}?",
461
+ memberLeave: "Leave",
462
+ memberLeaveConfirm: "Leave {org}? You will need an invitation to come back.",
463
+ memberInviteAgain: "Send the invitation again",
464
+ memberInvitationSent: "The invitation is on its way.",
465
+ organization: "Organization",
466
+ organizationRename: "Rename",
467
+ organizationRenamed: "The organization is now called {name}.",
468
+ organizationArchive: "Archive",
469
+ organizationArchiveConfirm: "Archive {org}? Its members will no longer reach it, and only the workspace can restore it.",
470
+ organizationArchived: "{org} was archived.",
471
+ organizationDelete: "Delete organization",
472
+ organizationDeleteConfirm: "Delete {org} for good? Its members lose it and this cannot be undone.",
473
+ organizationDeleted: "{org} was deleted.",
474
+ yes: "Yes",
475
+ cancel: "Cancel",
476
+ termsChanged: "Our terms changed",
477
+ termsChangedHelp: "To go on, read and accept",
478
+ acceptTerms: "Accept",
479
+ errors: {
480
+ not_allowed: "Your role in this organization does not allow that.",
481
+ last_manager: "Somebody else must manage the members first: give that role to another member.",
482
+ last_owner: "An organization keeps at least one owner: make another member owner first.",
483
+ organization_not_found: "That organization no longer exists.",
484
+ member_exists: "That person already belongs to the organization; their role was not changed. Change it in the list instead.",
485
+ already_member: "That person already belongs to the organization. Change their role instead.",
486
+ unknown_role: "Choose one of the roles offered.",
487
+ user_not_active: "That account is disabled.",
488
+ required: "This is required.",
489
+ invalid_email: "That does not look like an email address.",
490
+ too_short: `Use at least ${import_js3.MIN_PASSWORD} characters.`,
491
+ invalid_credentials: "The address or the password is not right.",
492
+ unavailable: "Sign-in is unavailable right now. Try again in a moment.",
493
+ state_mismatch: "That sign-in could not be completed. Try again.",
494
+ cancelled: "The sign-in was cancelled.",
495
+ email_taken: "That address already has an account.",
496
+ email_unchanged: "That is already your address.",
497
+ last_sign_in_method: "Add a password or link another account first: it is your only way to sign in.",
498
+ identity_already_linked: "That account is linked to someone else.",
499
+ manual_linking_disabled: "Linking accounts is turned off for this workspace.",
500
+ invalid_token: "This link is not valid, or it has expired. Ask for a new one.",
501
+ invalid_code: "That code is not right, or it has expired.",
502
+ wrong_password: "The current password is not right.",
503
+ step_up_required: "Enter your current password.",
504
+ weak_password: "Choose a stronger password.",
505
+ unauthenticated: "Sign in first.",
506
+ phone_refused: "The code could not be sent to that number.",
507
+ too_many_codes: "Enough codes were sent. Use the last one, or sign in again.",
508
+ phone_unavailable: "Codes cannot be sent that way here.",
509
+ phone_already_set: "Remove the phone you have first.",
510
+ phone_codes_unavailable: "Codes cannot be sent right now. Try again in a moment.",
511
+ captcha_required: "Complete the check that you are not a bot, then try again.",
512
+ captcha_failed: "The check that you are not a bot did not pass. Try it again.",
513
+ passkey_failed: "The passkey could not be used. Try again, or sign in another way.",
514
+ passkey_exists: "This device already has a passkey for your account.",
515
+ passkey_unavailable: "Passkeys cannot be used here.",
516
+ sso_required: "This address signs in through its company.",
517
+ sso_not_found: "No company sign-in answers for this address.",
518
+ sso_failed: "The sign-in with your company could not be completed. Try again.",
519
+ sso_unavailable: "Your company's sign-in cannot be reached right now. Try again in a moment.",
520
+ invalid_assertion: "Your company's answer could not be checked. Try again.",
521
+ provisioning_disabled: "Your company's sign-in worked, but this workspace has no account for you. Ask its admin to add you.",
522
+ connection_inactive: "Your company's sign-in is turned off for this workspace.",
523
+ invalid_grant: "That sign-in expired. Try again.",
524
+ password_disabled: "This workspace does not sign in with a password. Use one of the other ways.",
525
+ passkeys_disabled: "Passkeys are turned off for this workspace."
526
+ }
527
+ },
528
+ es: {
529
+ email: "Correo",
530
+ password: "Contrase\xF1a",
531
+ name: "Nombre",
532
+ company: "Nombre de tu empresa",
533
+ code: "C\xF3digo",
534
+ signIn: "Entrar",
535
+ signUp: "Crear cuenta",
536
+ continueWith: "Continuar con",
537
+ orWithEmail: "o con tu correo",
538
+ keepSignedIn: "Mantener la sesi\xF3n abierta",
539
+ forgotPassword: "\xBFOlvidaste tu contrase\xF1a?",
540
+ noAccount: "\xBFNo tienes cuenta?",
541
+ createAccount: "Crear una",
542
+ haveAccount: "\xBFYa tienes cuenta?",
543
+ iAccept: "He le\xEDdo y acepto",
544
+ and: "y",
545
+ termsOfService: "los T\xE9rminos del servicio",
546
+ privacyPolicy: "la Pol\xEDtica de privacidad",
547
+ sendLink: "Enviar el enlace",
548
+ linkSent: "Si ese correo tiene una cuenta, ya va en camino un enlace para elegir una contrase\xF1a nueva.",
549
+ codeHelp: "Escribe el c\xF3digo de tu aplicaci\xF3n de autenticaci\xF3n, o un c\xF3digo de recuperaci\xF3n.",
550
+ verify: "Verificar",
551
+ codeHelpPhone: "Te enviamos un c\xF3digo a tu tel\xE9fono. P\xEDdelo y escr\xEDbelo aqu\xED, o usa un c\xF3digo de recuperaci\xF3n.",
552
+ codeHelpEmail: "Te enviamos un c\xF3digo a {to}. Escr\xEDbelo aqu\xED.",
553
+ sendEmailAgain: "Enviar el c\xF3digo de nuevo",
554
+ sendCodeSms: "Enviar un c\xF3digo por SMS a {to}",
555
+ sendCodeWhatsapp: "Enviar un c\xF3digo por WhatsApp a {to}",
556
+ codeSent: "Te enviamos un c\xF3digo a {to}. Escr\xEDbelo aqu\xED.",
557
+ pushSend: "Aprobar en mi tel\xE9fono",
558
+ pushPick: "En tu tel\xE9fono, elige el {n}",
559
+ pushWaiting: "Enviamos una notificaci\xF3n a tu tel\xE9fono. \xC1brela y elige este n\xFAmero.",
560
+ phone: "Tel\xE9fono, con su c\xF3digo de pa\xEDs",
561
+ phoneHelp: "Recibe tus c\xF3digos por SMS o WhatsApp en vez de una app.",
562
+ phoneOn: "Los c\xF3digos van a {to}.",
563
+ phoneOff: "Todav\xEDa no tienes un tel\xE9fono.",
564
+ addPhone: "Agregar tel\xE9fono",
565
+ removePhone: "Quitar tel\xE9fono",
566
+ bySms: "SMS",
567
+ byWhatsapp: "WhatsApp",
568
+ channel: "Enviar los c\xF3digos por",
569
+ checkEmail: "Casi listo: abre el enlace que te enviamos para confirmar tu correo; te deja adentro.",
570
+ backToSignIn: "Volver a entrar",
571
+ emailMeALink: "Env\xEDame un enlace para entrar",
572
+ linkHelp: "Te enviamos un enlace al correo que te deja entrar, sin contrase\xF1a.",
573
+ sendMeTheLink: "Env\xEDame el enlace",
574
+ back: "Volver",
575
+ usePasskey: "Entrar con una llave de acceso",
576
+ codeFromMail: "\xBFLo est\xE1s leyendo en otro dispositivo? Escribe el c\xF3digo que trae el correo.",
577
+ signInLinkSent: "Si ese correo tiene una cuenta, ya va en camino un enlace para entrar.",
578
+ newPassword: "Contrase\xF1a nueva",
579
+ savePassword: "Guardar la contrase\xF1a",
580
+ passwordChanged: "Tu contrase\xF1a se cambi\xF3. Ya puedes entrar con ella.",
581
+ confirming: "Confirmando tu correo\u2026",
582
+ emailConfirmed: "Tu correo qued\xF3 confirmado. Ya puedes entrar.",
583
+ invitedTo: "Te invitaron a {workspace}",
584
+ invitedToOrganization: "Te invitaron a {organization} en {workspace}",
585
+ invitedAs: "Vas a entrar como {email}.",
586
+ choosePassword: "Elige una contrase\xF1a",
587
+ acceptInvite: "Aceptar y entrar",
588
+ openingInvitation: "Abriendo tu invitaci\xF3n\u2026",
589
+ 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.",
590
+ profile: "Perfil",
591
+ save: "Guardar",
592
+ saved: "Guardado.",
593
+ currentPassword: "Contrase\xF1a actual",
594
+ changePassword: "Cambiar contrase\xF1a",
595
+ passwordChangedHere: "Tu contrase\xF1a se cambi\xF3. Se cerraron todas las dem\xE1s sesiones de tu cuenta.",
596
+ secondStep: "Segundo paso",
597
+ secondStepOn: "Activo: al entrar tambi\xE9n se pide un c\xF3digo de tu aplicaci\xF3n de autenticaci\xF3n.",
598
+ secondStepOff: "Inactivo: al entrar solo se pide tu contrase\xF1a.",
599
+ turnOn: "Activar",
600
+ turnOff: "Desactivar",
601
+ addToApp: "Escanea este c\xF3digo con tu aplicaci\xF3n de autenticaci\xF3n, o agrega a mano la clave de abajo, y escribe el c\xF3digo que muestra.",
602
+ openInApp: "Abrir en una aplicaci\xF3n de autenticaci\xF3n",
603
+ qrAlt: "C\xF3digo QR para agregar esta cuenta a una aplicaci\xF3n de autenticaci\xF3n",
604
+ recoveryCodes: "C\xF3digos de recuperaci\xF3n",
605
+ newRecoveryCodes: "Nuevos c\xF3digos de recuperaci\xF3n",
606
+ keepCodes: "Guarda estos c\xF3digos en un lugar seguro. Cada uno sirve una vez y no se vuelven a mostrar.",
607
+ copyCodes: "Copiar todos",
608
+ downloadCodes: "Descargar .txt",
609
+ codesCopied: "Los c\xF3digos quedaron copiados.",
610
+ codesNotCopied: "No se pudieron copiar los c\xF3digos. Selecci\xF3nalos y c\xF3pialos a mano.",
611
+ change: "Cambiar",
612
+ passwordSet: "Tu cuenta tiene contrase\xF1a.",
613
+ addAnotherPasskey: "Agregar una llave de acceso",
614
+ passkeys: "Llaves de acceso",
615
+ managePasskeys: "Agregar o quitar una llave de acceso",
616
+ passkeysHelp: "Entra con tu huella, tu rostro o el bloqueo de tu dispositivo, sin contrase\xF1a.",
617
+ noPasskeys: "Todav\xEDa no tienes llaves de acceso.",
618
+ passkeyName: "Un nombre para este dispositivo (opcional)",
619
+ addPasskey: "Agregar una llave en este dispositivo",
620
+ removePasskey: "Quitar",
621
+ addPasskeyDevice: "Agregar este dispositivo (huella o rostro)",
622
+ addSecurityKey: "Agregar una llave f\xEDsica",
623
+ passkeyKinds: { security_key: "Llave f\xEDsica", synced: "Sincronizada entre tus dispositivos", device: "Solo en un dispositivo" },
624
+ passkeyAdded: "La llave de acceso qued\xF3 agregada. La pr\xF3xima vez, entra con ella.",
625
+ passkeyUnnamed: "Llave de acceso",
626
+ sessions: "D\xF3nde tienes la sesi\xF3n abierta",
627
+ signOutEverywhere: "Cerrar sesi\xF3n en todas partes",
628
+ agents: "Agentes de IA",
629
+ agentsHelp: "Los agentes a los que permitiste actuar por ti. Si desconectas uno, pierde el acceso en pocos minutos.",
630
+ disconnect: "Desconectar",
631
+ anAgent: "Un agente de IA",
632
+ unknownDevice: "Dispositivo desconocido",
633
+ emailAddress: "Correo",
634
+ newEmail: "Correo nuevo",
635
+ changeEmail: "Cambiar el correo",
636
+ emailSent: "Enviamos un enlace a {email}. Tu correo cambia cuando lo abras.",
637
+ linkedAccounts: "Cuentas vinculadas",
638
+ noLinkedAccounts: "No hay cuentas vinculadas.",
639
+ linkWith: "Vincular",
640
+ unlink: "Desvincular",
641
+ linked: "La cuenta qued\xF3 vinculada.",
642
+ ssoOnly: "A esta cuenta entras con el inicio de sesi\xF3n de tu empresa.",
643
+ members: "Miembros",
644
+ membersHidden: "Tu rol aqu\xED no te deja ver los miembros.",
645
+ organizationMissing: "No perteneces a esta organizaci\xF3n.",
646
+ memberYou: "t\xFA",
647
+ memberInvited: "invitado",
648
+ memberManager: "administra los miembros",
649
+ memberRole: "Rol",
650
+ memberAdd: "Agregar miembro",
651
+ memberAdded: "{email} ya es miembro.",
652
+ memberRemove: "Quitar",
653
+ memberRemoveConfirm: "\xBFQuitar a {who}?",
654
+ memberLeave: "Salir",
655
+ memberLeaveConfirm: "\xBFSalir de {org}? Necesitar\xE1s una invitaci\xF3n para volver.",
656
+ memberInviteAgain: "Enviar la invitaci\xF3n de nuevo",
657
+ memberInvitationSent: "La invitaci\xF3n va en camino.",
658
+ organization: "Organizaci\xF3n",
659
+ organizationRename: "Cambiar nombre",
660
+ organizationRenamed: "La organizaci\xF3n ahora se llama {name}.",
661
+ organizationArchive: "Archivar",
662
+ organizationArchiveConfirm: "\xBFArchivar {org}? Sus miembros ya no podr\xE1n entrar y solo el espacio de trabajo puede restaurarla.",
663
+ organizationArchived: "{org} qued\xF3 archivada.",
664
+ organizationDelete: "Eliminar organizaci\xF3n",
665
+ organizationDeleteConfirm: "\xBFEliminar {org} para siempre? Sus miembros la pierden y no se puede deshacer.",
666
+ organizationDeleted: "{org} qued\xF3 eliminada.",
667
+ yes: "S\xED",
668
+ cancel: "Cancelar",
669
+ termsChanged: "Nuestros t\xE9rminos cambiaron",
670
+ termsChangedHelp: "Para seguir, lee y acepta",
671
+ acceptTerms: "Aceptar",
672
+ errors: {
673
+ not_allowed: "Tu rol en esta organizaci\xF3n no permite eso.",
674
+ last_manager: "Primero alguien m\xE1s debe administrar los miembros: dale ese rol a otro miembro.",
675
+ last_owner: "Una organizaci\xF3n conserva al menos un propietario: primero haz propietario a otro miembro.",
676
+ organization_not_found: "Esa organizaci\xF3n ya no existe.",
677
+ member_exists: "Esa persona ya pertenece a la organizaci\xF3n; su rol no cambi\xF3. C\xE1mbialo en la lista.",
678
+ already_member: "Esa persona ya pertenece a la organizaci\xF3n. Cambia su rol.",
679
+ unknown_role: "Escoge uno de los roles ofrecidos.",
680
+ user_not_active: "Esa cuenta est\xE1 desactivada.",
681
+ required: "Este dato es obligatorio.",
682
+ invalid_email: "Eso no parece un correo.",
683
+ too_short: `Usa al menos ${import_js3.MIN_PASSWORD} caracteres.`,
684
+ invalid_credentials: "El correo o la contrase\xF1a no son correctos.",
685
+ unavailable: "No se puede entrar en este momento. Intenta de nuevo en un momento.",
686
+ state_mismatch: "No se pudo completar el ingreso. Intenta de nuevo.",
687
+ cancelled: "El ingreso se cancel\xF3.",
688
+ email_taken: "Ese correo ya tiene una cuenta.",
689
+ email_unchanged: "Ese ya es tu correo.",
690
+ last_sign_in_method: "Primero agrega una contrase\xF1a o vincula otra cuenta: es tu \xFAnica forma de entrar.",
691
+ identity_already_linked: "Esa cuenta est\xE1 vinculada a otra persona.",
692
+ manual_linking_disabled: "Vincular cuentas est\xE1 desactivado en este workspace.",
693
+ invalid_token: "Este enlace no es v\xE1lido o ya venci\xF3. Pide uno nuevo.",
694
+ invalid_code: "Ese c\xF3digo no es correcto o ya venci\xF3.",
695
+ wrong_password: "La contrase\xF1a actual no es correcta.",
696
+ step_up_required: "Escribe tu contrase\xF1a actual.",
697
+ weak_password: "Elige una contrase\xF1a m\xE1s fuerte.",
698
+ unauthenticated: "Inicia sesi\xF3n primero.",
699
+ phone_refused: "No se pudo enviar el c\xF3digo a ese n\xFAmero.",
700
+ too_many_codes: "Ya se enviaron suficientes c\xF3digos. Usa el \xFAltimo o vuelve a entrar.",
701
+ phone_unavailable: "Aqu\xED no se pueden enviar c\xF3digos de esa forma.",
702
+ phone_already_set: "Primero quita el tel\xE9fono que tienes.",
703
+ phone_codes_unavailable: "Ahora no se pueden enviar c\xF3digos. Int\xE9ntalo en un momento.",
704
+ captcha_required: "Completa la verificaci\xF3n de que no eres un robot y vuelve a intentarlo.",
705
+ captcha_failed: "La verificaci\xF3n de que no eres un robot no pas\xF3. Int\xE9ntalo de nuevo.",
706
+ passkey_failed: "No se pudo usar la llave de acceso. Intenta de nuevo o entra de otra forma.",
707
+ passkey_exists: "Este dispositivo ya tiene una llave de acceso de tu cuenta.",
708
+ passkey_unavailable: "Aqu\xED no se pueden usar llaves de acceso.",
709
+ sso_required: "Este correo entra con el inicio de sesi\xF3n de su empresa.",
710
+ sso_not_found: "Ninguna empresa usa inicio de sesi\xF3n propio con este correo.",
711
+ sso_failed: "No se pudo completar el ingreso con tu empresa. Intenta de nuevo.",
712
+ sso_unavailable: "Ahora no se puede llegar al inicio de sesi\xF3n de tu empresa. Intenta en un momento.",
713
+ invalid_assertion: "No se pudo verificar la respuesta de tu empresa. Intenta de nuevo.",
714
+ 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.",
715
+ connection_inactive: "El inicio de sesi\xF3n de tu empresa est\xE1 apagado en este workspace.",
716
+ invalid_grant: "Ese ingreso venci\xF3. Intenta de nuevo.",
717
+ password_disabled: "En este workspace no se entra con contrase\xF1a. Usa una de las otras formas.",
718
+ passkeys_disabled: "Las llaves de acceso est\xE1n desactivadas en este workspace."
719
+ }
720
+ }
721
+ };
722
+ var PlainButton = ({ variant: _variant, loading, children, ...p }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { ...p, "aria-busy": loading || void 0, children: [
723
+ loading && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Spinner, {}),
724
+ children
725
+ ] });
726
+ var UnstyledButton = ({ variant: _variant, loading, children, ...p }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { ...p, "aria-busy": loading || void 0, children: [
727
+ loading && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
728
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Spinner, { plain: true }),
729
+ " "
730
+ ] }),
731
+ children
732
+ ] });
733
+ function Spinner({ plain }) {
734
+ if (!plain) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "cauthy-spinner", "aria-hidden": "true" });
735
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SpinnerIcon, {});
736
+ }
737
+ var LESS_MOTION = "(prefers-reduced-motion: reduce)";
738
+ function watchMotion(changed) {
739
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return () => {
740
+ };
741
+ const query = window.matchMedia(LESS_MOTION);
742
+ query.addEventListener?.("change", changed);
743
+ return () => query.removeEventListener?.("change", changed);
744
+ }
745
+ var stillHere = () => typeof window.matchMedia === "function" && window.matchMedia(LESS_MOTION).matches;
746
+ var stillOnServer = () => true;
747
+ function SpinnerIcon() {
748
+ const still = (0, import_react8.useSyncExternalStore)(watchMotion, stillHere, stillOnServer);
749
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { className: "cauthy-spinner-icon", width: "1em", height: "1em", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", focusable: "false", children: [
750
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "8", cy: "8", r: "6.5", stroke: "currentColor", strokeOpacity: "0.25", strokeWidth: "2" }),
751
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M14.5 8A6.5 6.5 0 0 0 8 1.5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: !still && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("animateTransform", { attributeName: "transform", type: "rotate", from: "0 8 8", to: "360 8 8", dur: "0.7s", repeatCount: "indefinite" }) })
752
+ ] });
753
+ }
754
+ var PlainInput = (p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { ...p });
755
+ var looks = /* @__PURE__ */ new Map();
756
+ var loaded = /* @__PURE__ */ new Set();
757
+ function loadFonts(fonts) {
758
+ if (typeof document === "undefined" || typeof FontFace === "undefined") return;
759
+ for (const f of fonts ?? []) {
760
+ const key = `${f.family}|${f.url}|${f.weight ?? ""}|${f.style ?? ""}`;
761
+ if (loaded.has(key) || !/^[A-Za-z0-9][A-Za-z0-9 _-]*$/.test(f.family) || !/^https:\/\/[^\s"'()]+\.woff2$/i.test(f.url)) continue;
762
+ loaded.add(key);
763
+ const face = new FontFace(f.family, `url("${f.url}") format("woff2")`, { weight: String(f.weight ?? "400"), style: f.style === "italic" ? "italic" : "normal", display: "swap" });
764
+ void face.load().then((ready) => document.fonts.add(ready), () => loaded.delete(key));
765
+ }
766
+ }
767
+ function useRoot(props) {
768
+ const { basePath } = useSession();
769
+ const store = useSessionStore();
770
+ const given = useProviderTheme();
771
+ const [workspace, setWorkspace] = (0, import_react8.useState)(null);
772
+ const wanted = !props.unstyled && props.workspaceLook !== false;
773
+ (0, import_react8.useEffect)(() => {
774
+ if (!props.unstyled && given) loadFonts(given.fonts);
775
+ }, [given, props.unstyled]);
776
+ (0, import_react8.useEffect)(() => {
777
+ if (!wanted) return;
778
+ let live = true;
779
+ let look = looks.get(basePath);
780
+ if (!look) {
781
+ look = store.auth.look();
782
+ looks.set(basePath, look);
783
+ }
784
+ void look.then((theme) => {
785
+ if (!live || !theme) return;
786
+ setWorkspace(theme);
787
+ loadFonts(theme.fonts);
788
+ });
789
+ return () => {
790
+ live = false;
791
+ };
792
+ }, [basePath, store, wanted]);
793
+ if (props.unstyled) return {};
794
+ const shown = wanted ? workspace : null;
795
+ return { "data-cauthy": "", style: (0, import_theme2.themeVariables)({ ...shown, ...given }) };
796
+ }
797
+ var turnstileScript = null;
798
+ function loadTurnstile() {
799
+ const ready = () => window.turnstile;
800
+ if (ready()) return Promise.resolve(ready());
801
+ turnstileScript ?? (turnstileScript = new Promise((resolve, reject) => {
802
+ const script = document.createElement("script");
803
+ script.src = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit";
804
+ script.async = true;
805
+ script.onload = () => ready() ? resolve(ready()) : reject(new Error("turnstile did not load"));
806
+ script.onerror = () => {
807
+ turnstileScript = null;
808
+ reject(new Error("turnstile did not load"));
809
+ };
810
+ document.head.appendChild(script);
811
+ }));
812
+ return turnstileScript;
813
+ }
814
+ function useChallenge(siteKey, locale) {
815
+ const box = (0, import_react8.useRef)(null);
816
+ const widget = (0, import_react8.useRef)(null);
817
+ const [token, setToken] = (0, import_react8.useState)("");
818
+ (0, import_react8.useEffect)(() => {
819
+ if (!siteKey || !box.current) return;
820
+ let gone = false;
821
+ void loadTurnstile().then((api) => {
822
+ if (gone || !box.current) return;
823
+ const id = api.render(box.current, {
824
+ sitekey: siteKey,
825
+ language: locale ?? "auto",
826
+ size: "flexible",
827
+ callback: (t) => setToken(t),
828
+ "expired-callback": () => setToken(""),
829
+ "error-callback": () => setToken("")
830
+ });
831
+ widget.current = { api, id };
832
+ }).catch(() => {
833
+ });
834
+ return () => {
835
+ gone = true;
836
+ if (widget.current) widget.current.api.remove(widget.current.id);
837
+ widget.current = null;
838
+ };
839
+ }, [siteKey, locale]);
840
+ const renew = () => {
841
+ setToken("");
842
+ if (widget.current) widget.current.api.reset(widget.current.id);
843
+ };
844
+ const node = siteKey ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: box, className: "cauthy-challenge" }) : null;
845
+ return { node, token: token || void 0, renew };
846
+ }
847
+ function useMethods(auth) {
848
+ const [methods, setMethods] = (0, import_react8.useState)(null);
849
+ (0, import_react8.useEffect)(() => {
850
+ void auth.methods().then(setMethods);
851
+ }, []);
852
+ return methods;
853
+ }
854
+ function sitePath(to) {
855
+ return to && to.startsWith("/") && !to.startsWith("//") && !to.includes("\\") ? to : void 0;
856
+ }
857
+ function sameOrigin(to) {
858
+ const path = sitePath(to);
859
+ if (path || !to) return path;
860
+ try {
861
+ const url = new URL(to);
862
+ return url.origin === window.location.origin ? url.pathname + url.search + url.hash : void 0;
863
+ } catch {
864
+ return void 0;
865
+ }
866
+ }
867
+ function isPending(v) {
868
+ return typeof v?.then === "function";
869
+ }
870
+ function useForm(props, opts = {}) {
871
+ const t = { ...TEXTS2[props.locale ?? "en"], ...props.texts, errors: { ...TEXTS2[props.locale ?? "en"].errors, ...props.texts?.errors } };
872
+ const cx = (slot) => props.classNames?.[slot] ?? `cauthy-${slot}`;
873
+ const own = (slot) => props.classNames?.[slot];
874
+ const C = props.components ?? {};
875
+ const Button = C.Button ?? (props.unstyled ? UnstyledButton : PlainButton);
876
+ const Input = C.Input ?? PlainInput;
877
+ const [error, setOnlyError] = (0, import_react8.useState)(null);
878
+ const [problems, setProblems] = (0, import_react8.useState)({ list: [], round: 0 });
879
+ const setError = (0, import_react8.useCallback)((e) => {
880
+ setOnlyError(e);
881
+ setProblems((p) => p.list.length === 0 ? p : { list: [], round: p.round });
882
+ }, []);
883
+ const check = (...found) => {
884
+ const list = found.filter((e) => Boolean(e));
885
+ setOnlyError(null);
886
+ setProblems((p) => ({ list, round: list.length > 0 ? p.round + 1 : p.round }));
887
+ return list.length === 0;
888
+ };
889
+ const fieldError = (name) => problems.list.find((e) => e.field === name) ?? (error?.field === name ? error : null);
890
+ const firstWrong = (name) => problems.list[0]?.field === name ? problems.round : 0;
891
+ const [acting, setActing] = (0, import_react8.useState)(null);
892
+ const busy = acting !== null || opts.waiting === true;
893
+ const setBusy = (0, import_react8.useCallback)((on) => setActing(on === false ? null : on === true ? SUBMIT : on), []);
894
+ const loading = (key = SUBMIT) => acting === key;
895
+ const shown = (0, import_react8.useRef)(true);
896
+ (0, import_react8.useEffect)(() => {
897
+ shown.current = true;
898
+ const back = (e) => {
899
+ if (e.persisted) setActing(null);
900
+ };
901
+ window.addEventListener("pageshow", back);
902
+ return () => {
903
+ shown.current = false;
904
+ window.removeEventListener("pageshow", back);
905
+ };
906
+ }, []);
907
+ const hold = (after) => {
908
+ if (!isPending(after)) return;
909
+ const free = () => {
910
+ if (shown.current) setActing(null);
911
+ };
912
+ after.then(free, free);
913
+ };
914
+ const fail = (e) => {
915
+ setActing(null);
916
+ setError(e);
917
+ };
918
+ const [policy, setPolicy] = (0, import_react8.useState)(void 0);
919
+ const locale = props.locale ?? "en";
920
+ const say = (e) => {
921
+ if (props.texts?.errors?.[e.code] === void 0 && isPasswordRule(e)) return (0, import_js3.explainPasswordProblems)(e.reasons ?? [e.code], policy, locale);
922
+ return t.errors[e.code] ?? e.message;
923
+ };
924
+ const passwordRule = (0, import_js3.describePasswordPolicy)(policy, locale);
925
+ const done = (to) => {
926
+ setActing((a) => a ?? SUBMIT);
927
+ if (props.onSuccess) hold(props.onSuccess());
928
+ else window.location.assign(sitePath(to) ?? sameOrigin(props.returnTo) ?? "/");
929
+ };
930
+ const root = useRoot(opts.part ? { ...props, unstyled: true } : props);
931
+ const plain = props.unstyled === true;
932
+ return { t, cx, own, C, Button, Input, error, setError, fail, check, fieldError, firstWrong, busy, setBusy, loading, hold, say, done, root, plain, policy, setPolicy, passwordRule };
933
+ }
934
+ var SUBMIT = "submit";
935
+ function Wrap(p) {
936
+ const { Form: OwnForm } = p.f.C;
937
+ const busy = p.busy ?? (p.f.busy || void 0);
938
+ if (OwnForm) {
939
+ const own = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
940
+ OwnForm,
941
+ {
942
+ as: p.as === "form" ? "form" : "div",
943
+ onSubmit: p.onSubmit,
944
+ noValidate: p.noValidate,
945
+ "aria-busy": busy,
946
+ className: p.slot ? p.f.own(p.slot) : void 0,
947
+ section: p.section,
948
+ children: p.children
949
+ }
950
+ );
951
+ return p.root?.["data-cauthy"] !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ...p.root, children: own }) : own;
952
+ }
953
+ const Tag2 = p.as;
954
+ const children = p.busy && p.children === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Pending, { f: p.f }) : p.children;
955
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Tag2, { className: p.slot ? p.f.cx(p.slot) : void 0, ...p.root, onSubmit: p.onSubmit, noValidate: p.noValidate, "aria-busy": busy, children });
956
+ }
957
+ function Pending({ f }) {
958
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: f.cx("pending"), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Spinner, { plain: f.plain }) });
959
+ }
960
+ function Note({ f, children, footer }) {
961
+ const { Text } = f.C;
962
+ if (Text) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { as: "p", tone: "muted", size: footer ? "sm" : "md", children });
963
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: f.cx(footer ? "footer" : "notice"), children });
964
+ }
965
+ function Heading({ f, children }) {
966
+ const { Text } = f.C;
967
+ if (Text) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { as: "h2", size: "lg", children });
968
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { className: f.cx("heading"), children });
969
+ }
970
+ function Say({ f, tone, children }) {
971
+ const { Alert } = f.C;
972
+ if (Alert) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Alert, { tone, children });
973
+ if (tone === "danger") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", "aria-live": "assertive", "aria-atomic": "true", className: f.cx("error"), children });
974
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "status", "aria-live": "polite", "aria-atomic": "true", className: f.cx("notice"), children });
975
+ }
976
+ function Or({ f, children }) {
977
+ const { Divider } = f.C;
978
+ if (Divider) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Divider, { label: children });
979
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: f.cx("separator"), children });
980
+ }
981
+ function A({ f, href, newTab, children }) {
982
+ const { Link } = f.C;
983
+ if (Link) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Link, { href, newTab, children });
984
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { className: f.cx("link"), href, target: newTab ? "_blank" : void 0, rel: newTab ? "noopener" : void 0, children });
985
+ }
986
+ function Tag({ f, tone, children, plain }) {
987
+ const { Badge } = f.C;
988
+ if (Badge) return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
989
+ " ",
990
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Badge, { tone, children })
991
+ ] });
992
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: plain });
993
+ }
994
+ function Check(p) {
995
+ const id = (0, import_react8.useId)();
996
+ const { f } = p;
997
+ const { Checkbox } = f.C;
998
+ if (Checkbox) {
999
+ return /* @__PURE__ */ (0, import_jsx_runtime3.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 });
1000
+ }
1001
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: f.cx("check"), children: [
1002
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "checkbox", name: p.name, checked: p.checked, required: p.required, disabled: f.busy, onChange: (e) => p.onChange(e.target.checked) }),
1003
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: p.children })
1004
+ ] });
1005
+ }
1006
+ function Pick(p) {
1007
+ const made = (0, import_react8.useId)();
1008
+ const id = p.id ?? made;
1009
+ const { f } = p;
1010
+ const { Select } = f.C;
1011
+ const disabled = p.disabled || f.busy;
1012
+ if (Select) {
1013
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Select, { id, name: p.name, value: p.value, options: p.options, disabled, "aria-label": p.label, className: f.own("input"), onChange: p.onChange });
1014
+ }
1015
+ return /* @__PURE__ */ (0, import_jsx_runtime3.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_runtime3.jsx)("option", { value: o.value, children: o.label }, o.value)) });
1016
+ }
1017
+ function Labelled({ f, id, label, children }) {
1018
+ const { Field: OwnField } = f.C;
1019
+ if (OwnField) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OwnField, { id, label, className: f.own("field"), children });
1020
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: f.cx("field"), children: [
1021
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: f.cx("label"), children: label }),
1022
+ children
1023
+ ] });
1024
+ }
1025
+ function Documents({ f, documents }) {
1026
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: documents.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
1027
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1028
+ f.t.and,
1029
+ " "
1030
+ ] }),
1031
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: d.url, newTab: true, children: d.kind === "terms" ? f.t.termsOfService : f.t.privacyPolicy }),
1032
+ " "
1033
+ ] }, d.kind)) });
1034
+ }
1035
+ var PASSWORD_RULES = ["needs_lowercase", "needs_uppercase", "needs_digit", "needs_symbol", "needs_classes", "breached"];
1036
+ function isPasswordRule(e) {
1037
+ if (e.code === "weak_password" || PASSWORD_RULES.includes(e.code)) return true;
1038
+ return (e.code === "too_short" || e.code === "too_long") && (e.field === "password" || e.field === "newPassword");
1039
+ }
1040
+ function newPasswordProblem(value, policy, field = "password") {
1041
+ const bad = (0, import_js3.checkNewPassword)(value, policy);
1042
+ if (!bad) return null;
1043
+ return { code: bad.code, message: bad.message, field, ...bad.code === "required" ? {} : { reasons: (0, import_js3.passwordProblems)(value, policy) } };
1044
+ }
1045
+ function usePasswordPolicy(f, methods) {
1046
+ const { setPolicy } = f;
1047
+ (0, import_react8.useEffect)(() => {
1048
+ if (methods?.password) setPolicy(methods.password);
1049
+ }, [methods, setPolicy]);
1050
+ }
1051
+ function Field(p) {
1052
+ const id = (0, import_react8.useId)();
1053
+ const { f } = p;
1054
+ const bad = f.fieldError(p.name);
1055
+ const focus = f.firstWrong(p.name);
1056
+ (0, import_react8.useEffect)(() => {
1057
+ if (focus > 0 && typeof document !== "undefined") document.getElementById(id)?.focus();
1058
+ }, [focus, id]);
1059
+ const described = [bad ? `${id}-error` : "", p.hint ? `${id}-hint` : ""].filter(Boolean).join(" ");
1060
+ const input = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1061
+ f.Input,
1062
+ {
1063
+ id,
1064
+ name: p.name,
1065
+ type: p.type,
1066
+ value: p.value,
1067
+ autoComplete: p.autoComplete,
1068
+ required: p.required,
1069
+ disabled: f.busy,
1070
+ className: f.cx("input"),
1071
+ "aria-invalid": bad ? true : void 0,
1072
+ "aria-describedby": described || void 0,
1073
+ onChange: (e) => p.onChange(e.target.value)
1074
+ }
1075
+ );
1076
+ const { Field: OwnField } = f.C;
1077
+ if (OwnField) {
1078
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1079
+ OwnField,
1080
+ {
1081
+ id,
1082
+ label: p.label,
1083
+ aside: p.aside,
1084
+ help: p.hint && !bad ? p.hint : void 0,
1085
+ error: bad ? f.say(bad) : void 0,
1086
+ required: p.required,
1087
+ className: f.own("field"),
1088
+ children: input
1089
+ }
1090
+ );
1091
+ }
1092
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: f.cx("field"), children: [
1093
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: f.cx("label"), htmlFor: id, children: [
1094
+ p.label,
1095
+ p.aside
1096
+ ] }),
1097
+ input,
1098
+ p.hint && !bad && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { id: `${id}-hint`, className: f.cx("hint"), children: p.hint }),
1099
+ bad && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { id: `${id}-error`, className: f.cx("fieldError"), children: f.say(bad) })
1100
+ ] });
1101
+ }
1102
+ function returnedError() {
1103
+ if (typeof window === "undefined") return null;
1104
+ const code = new URLSearchParams(window.location.search).get("auth_error");
1105
+ return code ? { code, message: "That sign-in could not be completed. Try again." } : null;
1106
+ }
1107
+ function takeToken(name) {
1108
+ if (typeof window === "undefined") return null;
1109
+ const url = new URL(window.location.href);
1110
+ const token = url.searchParams.get(name);
1111
+ if (token === null) return null;
1112
+ url.searchParams.delete(name);
1113
+ window.history.replaceState(window.history.state, "", url.pathname + url.search + url.hash);
1114
+ return token;
1115
+ }
1116
+ function useMailedToken(name, open) {
1117
+ const opened = (0, import_react8.useRef)(false);
1118
+ (0, import_react8.useEffect)(() => {
1119
+ if (opened.current) return;
1120
+ opened.current = true;
1121
+ open(takeToken(name));
1122
+ }, []);
1123
+ }
1124
+ function SecondStepForm(p) {
1125
+ const { f, auth } = p;
1126
+ const [code, setCode] = (0, import_react8.useState)("");
1127
+ const [phoneWay, setPhoneWay] = (0, import_react8.useState)(null);
1128
+ const [phoneSent, setPhoneSent] = (0, import_react8.useState)("");
1129
+ (0, import_react8.useEffect)(() => {
1130
+ void auth.signIn.mfaMethods().then((r) => {
1131
+ if (r.ok) setPhoneWay({ totp: r.totp, phone: r.phone, push: r.push, email: r.email });
1132
+ });
1133
+ }, []);
1134
+ const sendEmail = async () => {
1135
+ f.setBusy("email");
1136
+ f.setError(null);
1137
+ const r = await auth.signIn.mfaSendEmail();
1138
+ f.setBusy(false);
1139
+ if (!r.ok) return f.setError(r.error);
1140
+ setPhoneSent(r.sentTo);
1141
+ };
1142
+ const [pushNumber, setPushNumber] = (0, import_react8.useState)(0);
1143
+ const pushWait = (0, import_react8.useRef)(null);
1144
+ (0, import_react8.useEffect)(() => () => pushWait.current?.abort(), []);
1145
+ const sendPush = async () => {
1146
+ f.setBusy("push");
1147
+ f.setError(null);
1148
+ const r = await auth.signIn.mfaPush();
1149
+ f.setBusy(false);
1150
+ if (!r.ok) return f.setError(r.error);
1151
+ setPushNumber(r.number);
1152
+ pushWait.current?.abort();
1153
+ const ctl = new AbortController();
1154
+ pushWait.current = ctl;
1155
+ const done = await auth.signIn.mfaPushWait({ signal: ctl.signal });
1156
+ if (ctl.signal.aborted) return;
1157
+ setPushNumber(0);
1158
+ if (!done.ok) return f.setError(done.error);
1159
+ f.setBusy("push");
1160
+ f.done();
1161
+ };
1162
+ const sendCode = async () => {
1163
+ f.setBusy("phone");
1164
+ f.setError(null);
1165
+ const r = await auth.signIn.mfaSendCode();
1166
+ f.setBusy(false);
1167
+ if (!r.ok) return f.setError(r.error);
1168
+ setPhoneSent(r.sentTo);
1169
+ };
1170
+ const submit = async (e) => {
1171
+ e.preventDefault();
1172
+ f.setBusy(true);
1173
+ f.setError(null);
1174
+ const r = await auth.signIn.mfa({ code });
1175
+ if (!r.ok) return f.fail(r.error);
1176
+ f.done();
1177
+ };
1178
+ const general = f.error && !f.error.field ? f.error : null;
1179
+ const to = phoneWay?.phone?.number ?? "";
1180
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "form", root: f.root, onSubmit: submit, noValidate: true, children: [
1181
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: phoneSent ? f.t.codeSent.replace("{to}", phoneSent) : phoneWay?.email ? f.t.codeHelpEmail.replace("{to}", phoneWay.email.to) : phoneWay?.phone && !phoneWay.totp ? f.t.codeHelpPhone : f.t.codeHelp }),
1182
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
1183
+ phoneWay?.email && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", loading: f.loading("email"), disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendEmail(), children: f.t.sendEmailAgain }),
1184
+ pushNumber > 0 ? f.C.Text ? (
1185
+ // The application's text: the number to pick drawn large, by its own rules.
1186
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { role: "status", "aria-live": "polite", children: [
1187
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.C.Text, { as: "p", children: f.t.pushPick.replace("{n}", String(pushNumber)) }),
1188
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.C.Text, { as: "p", size: "lg", children: pushNumber }),
1189
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.C.Text, { as: "p", tone: "muted", children: f.t.pushWaiting })
1190
+ ] })
1191
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: f.cx("notice"), role: "status", "aria-live": "polite", children: [
1192
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: f.t.pushPick.replace("{n}", String(pushNumber)) }),
1193
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: { fontSize: 48, fontWeight: 700, margin: "4px 0", textAlign: "center" }, children: pushNumber }),
1194
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: f.t.pushWaiting })
1195
+ ] }) : phoneWay?.push && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", loading: f.loading("push"), disabled: f.busy, className: f.cx("button"), onClick: () => void sendPush(), children: f.t.pushSend }),
1196
+ phoneWay?.phone && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", loading: f.loading("phone"), disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendCode(), children: (phoneWay.phone.channel === "whatsapp" ? f.t.sendCodeWhatsapp : f.t.sendCodeSms).replace("{to}", to) }),
1197
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
1198
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.verify })
1199
+ ] });
1200
+ }
1201
+ function ProviderButtons(p) {
1202
+ const { f } = p;
1203
+ const pick = (id) => {
1204
+ f.setBusy(`provider:${id}`);
1205
+ p.onPick(id);
1206
+ };
1207
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: p.providers.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime3.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: [
1208
+ provider.iconUrl && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("img", { src: provider.iconUrl, alt: "", width: 18, height: 18, className: f.cx("providerIcon") }),
1209
+ f.t.continueWith,
1210
+ " ",
1211
+ provider.name
1212
+ ] }, provider.id)) });
1213
+ }
1214
+ function signInOffers(methods) {
1215
+ const password = methods?.passwordSignIn !== false;
1216
+ return { password, email: password || methods?.magicLink === true || methods?.sso === true, passkey: methods?.passkey === true };
1217
+ }
1218
+ function SignIn(props) {
1219
+ const auth = useAuth();
1220
+ const [methods, setMethods] = (0, import_react8.useState)(null);
1221
+ const f = useForm(props, { waiting: methods === null });
1222
+ const [email, setEmail] = (0, import_react8.useState)("");
1223
+ const [password, setPassword] = (0, import_react8.useState)("");
1224
+ const [code, setCode] = (0, import_react8.useState)("");
1225
+ const [remember, setRemember] = (0, import_react8.useState)(false);
1226
+ const rememberNow = (0, import_react8.useRef)(false);
1227
+ rememberNow.current = remember && methods?.persistentSessions === true;
1228
+ const [step, setStep] = (0, import_react8.useState)("password");
1229
+ const challenge = useChallenge(methods?.captchaSiteKey, props.locale);
1230
+ const offers = signInOffers(methods);
1231
+ const passwordOn = offers.password;
1232
+ const autofill = (0, import_react8.useRef)(null);
1233
+ const [offer, setOffer] = (0, import_react8.useState)(0);
1234
+ const [company, setCompany] = (0, import_react8.useState)(null);
1235
+ (0, import_react8.useEffect)(() => {
1236
+ if (!methods?.sso || (0, import_js3.checkEmail)(email) !== null) return setCompany(null);
1237
+ let current = true;
1238
+ const t = setTimeout(() => {
1239
+ void auth.signIn.ssoDiscover({ email }).then((r) => {
1240
+ if (current) setCompany(r.ok && r.status === "found" ? r.connection : null);
1241
+ });
1242
+ }, 350);
1243
+ return () => {
1244
+ current = false;
1245
+ clearTimeout(t);
1246
+ };
1247
+ }, [email, methods]);
1248
+ const toCompany = () => {
1249
+ autofill.current?.abort();
1250
+ f.setBusy("sso");
1251
+ auth.signIn.sso({ email }, { returnTo: props.returnTo, remember: rememberNow.current });
1252
+ };
1253
+ (0, import_react8.useEffect)(() => {
1254
+ void auth.methods().then(setMethods);
1255
+ const back = returnedError();
1256
+ if (back) f.setError(back);
1257
+ }, []);
1258
+ useMailedToken("ml_token", (token) => {
1259
+ if (!token) return;
1260
+ setStep("opening");
1261
+ const query = new URLSearchParams(window.location.search);
1262
+ void auth.signIn.magicLinkVerify({ token, remember: query.get("remember") === "1" }).then((r) => {
1263
+ if (r.ok) return f.done(query.get("return_to") ?? void 0);
1264
+ f.setError(r.error);
1265
+ setStep("password");
1266
+ });
1267
+ });
1268
+ (0, import_react8.useEffect)(() => {
1269
+ if (step !== "password" || !methods?.passkeyHere) return;
1270
+ const ctl = new AbortController();
1271
+ autofill.current = ctl;
1272
+ void auth.signIn.passkeyAutofill({ signal: ctl.signal, remember: () => rememberNow.current }).then((r) => {
1273
+ if (ctl.signal.aborted) return;
1274
+ if (r.ok) return f.done();
1275
+ if (r.error.code === "cancelled") return;
1276
+ f.setError(r.error);
1277
+ if (r.error.code === "passkey_failed" || r.error.code === "step_expired") setOffer((n) => n + 1);
1278
+ });
1279
+ return () => ctl.abort();
1280
+ }, [step, methods, offer]);
1281
+ const submit = async (e) => {
1282
+ e.preventDefault();
1283
+ autofill.current?.abort();
1284
+ if (step === "password" && company?.enforced) {
1285
+ f.setError(null);
1286
+ return toCompany();
1287
+ }
1288
+ if (step === "link") {
1289
+ if (company?.enforced) return toCompany();
1290
+ if (f.check((0, import_js3.checkEmail)(email))) return sendLink();
1291
+ return;
1292
+ }
1293
+ if (step === "password" && !passwordOn) {
1294
+ if (company) return toCompany();
1295
+ if (methods?.magicLink && f.check((0, import_js3.checkEmail)(email))) return sendLink();
1296
+ return;
1297
+ }
1298
+ if (step === "password" && !f.check((0, import_js3.checkEmail)(email), (0, import_js3.checkPassword)(password))) return;
1299
+ f.setBusy(true);
1300
+ f.setError(null);
1301
+ const r = step === "sent" ? await auth.signIn.emailCode({ code }) : await auth.signIn.email({ email, password, captchaToken: challenge.token, remember: rememberNow.current });
1302
+ if (step === "password") challenge.renew();
1303
+ if (!r.ok && r.error.code === "sso_required") return toCompany();
1304
+ if (!r.ok) {
1305
+ setOffer((n) => n + 1);
1306
+ return f.fail(r.error);
1307
+ }
1308
+ if (r.status === "mfa_required") {
1309
+ setPassword("");
1310
+ f.setBusy(false);
1311
+ return setStep("code");
1312
+ }
1313
+ f.done("returnTo" in r && typeof r.returnTo === "string" ? r.returnTo : void 0);
1314
+ };
1315
+ const usePasskey = async () => {
1316
+ autofill.current?.abort();
1317
+ f.setBusy("passkey");
1318
+ f.setError(null);
1319
+ const r = await auth.signIn.passkey({ returnTo: props.returnTo, locale: props.locale, email, remember: rememberNow.current });
1320
+ if (r.ok && r.status === "redirected") return;
1321
+ if (r.ok) return f.done();
1322
+ f.setBusy(false);
1323
+ setOffer((n) => n + 1);
1324
+ if (r.error.code !== "cancelled") f.setError(r.error);
1325
+ };
1326
+ const sendLink = async () => {
1327
+ autofill.current?.abort();
1328
+ f.setBusy("link");
1329
+ f.setError(null);
1330
+ const r = await auth.signIn.magicLink({ email, captchaToken: challenge.token, create: props.createAccounts, returnTo: props.returnTo, remember: rememberNow.current });
1331
+ f.setBusy(false);
1332
+ challenge.renew();
1333
+ if (!r.ok && r.error.code === "sso_required") return toCompany();
1334
+ if (!r.ok) return f.setError(r.error);
1335
+ setStep("sent");
1336
+ };
1337
+ const openLink = () => {
1338
+ autofill.current?.abort();
1339
+ f.setError(null);
1340
+ setStep("link");
1341
+ };
1342
+ const general = f.error && !f.error.field ? f.error : null;
1343
+ const asksEmail = offers.email;
1344
+ if (step === "opening") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wrap, { f, as: "div", slot: "form", root: f.root, busy: true });
1345
+ if (step === "sent") {
1346
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "form", root: f.root, onSubmit: submit, noValidate: true, children: [
1347
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.signInLinkSent }),
1348
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
1349
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.codeFromMail }),
1350
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
1351
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.verify })
1352
+ ] });
1353
+ }
1354
+ if (step === "code") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SecondStepForm, { f, auth });
1355
+ if (step === "link") {
1356
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "form", root: f.root, onSubmit: submit, noValidate: true, children: [
1357
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
1358
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.linkHelp }),
1359
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
1360
+ challenge.node,
1361
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading("link"), disabled: f.busy, className: f.cx("button"), children: f.t.sendMeTheLink }),
1362
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
1363
+ f.setError(null);
1364
+ setStep("password");
1365
+ }, children: f.t.back })
1366
+ ] });
1367
+ }
1368
+ const quickLink = methods?.magicLink === true && passwordOn;
1369
+ const keep = methods?.persistentSessions === true && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Check, { f, name: "remember", checked: remember, onChange: setRemember, children: f.t.keepSignedIn });
1370
+ const quick = offers.passkey || (methods?.providers.length ?? 0) > 0 || quickLink;
1371
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "form", root: f.root, onSubmit: submit, noValidate: true, children: [
1372
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
1373
+ keep,
1374
+ offers.passkey && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", loading: f.loading("passkey"), disabled: f.busy, className: f.cx("providerButton"), onClick: () => void usePasskey(), children: f.t.usePasskey }),
1375
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ProviderButtons, { f, providers: methods?.providers ?? [], onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo, remember: rememberNow.current }) }),
1376
+ quickLink && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: openLink, children: f.t.emailMeALink }),
1377
+ asksEmail && quick && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Or, { f, children: f.t.orWithEmail }),
1378
+ asksEmail && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: methods?.passkeyHere ? "username webauthn" : "username", required: true, onChange: setEmail }),
1379
+ company && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(f.Button, { type: "button", variant: company.enforced ? "primary" : "secondary", loading: f.loading("sso"), disabled: f.busy, className: f.cx(company.enforced ? "button" : "providerButton"), onClick: toCompany, children: [
1380
+ f.t.continueWith,
1381
+ " ",
1382
+ company.name
1383
+ ] }),
1384
+ company?.enforced && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.ssoOnly }),
1385
+ !company?.enforced && passwordOn && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1386
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1387
+ Field,
1388
+ {
1389
+ f,
1390
+ name: "password",
1391
+ type: "password",
1392
+ label: f.t.password,
1393
+ value: password,
1394
+ autoComplete: "current-password",
1395
+ required: true,
1396
+ onChange: setPassword,
1397
+ aside: props.links?.forgotPassword ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: props.links.forgotPassword, children: f.t.forgotPassword }) : void 0
1398
+ }
1399
+ ),
1400
+ challenge.node,
1401
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.signIn })
1402
+ ] }),
1403
+ !company?.enforced && !passwordOn && methods?.magicLink && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1404
+ challenge.node,
1405
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading("link"), disabled: f.busy, className: f.cx("button"), children: f.t.sendMeTheLink })
1406
+ ] }),
1407
+ methods?.signUp !== false && props.links?.signUp && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Note, { f, footer: true, children: [
1408
+ f.t.noAccount,
1409
+ " ",
1410
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: props.links.signUp, children: f.t.createAccount })
1411
+ ] })
1412
+ ] });
1413
+ }
1414
+ function GoogleOneTap(props) {
1415
+ const auth = useAuth();
1416
+ const unauthenticated = auth.status === "unauthenticated";
1417
+ (0, import_react8.useEffect)(() => {
1418
+ if (!unauthenticated) return;
1419
+ const ctl = new AbortController();
1420
+ void auth.signIn.googleOneTap({ signal: ctl.signal, context: props.context, remember: props.remember }).then((r) => {
1421
+ if (!r.ok || ctl.signal.aborted) return;
1422
+ if (props.onSuccess) props.onSuccess();
1423
+ else {
1424
+ const to = sameOrigin(props.returnTo);
1425
+ if (to) window.location.assign(to);
1426
+ }
1427
+ });
1428
+ return () => ctl.abort();
1429
+ }, [unauthenticated]);
1430
+ return null;
1431
+ }
1432
+ function SignUp(props) {
1433
+ const auth = useAuth();
1434
+ const f = useForm(props);
1435
+ const [name, setName] = (0, import_react8.useState)("");
1436
+ const [organization, setOrganization] = (0, import_react8.useState)("");
1437
+ const [email, setEmail] = (0, import_react8.useState)("");
1438
+ const [password, setPassword] = (0, import_react8.useState)("");
1439
+ const [sent, setSent] = (0, import_react8.useState)(false);
1440
+ const methods = useMethods(auth);
1441
+ usePasswordPolicy(f, methods);
1442
+ const challenge = useChallenge(methods?.captchaSiteKey, props.locale);
1443
+ const [acceptLegal, setAcceptLegal] = (0, import_react8.useState)(false);
1444
+ const [consents, setConsents] = (0, import_react8.useState)({});
1445
+ const legal = methods?.legal;
1446
+ const guest = auth.session?.user.isAnonymous === true;
1447
+ const submit = async (e) => {
1448
+ e.preventDefault();
1449
+ const asksCompany = methods?.organization?.ask === true;
1450
+ if (!f.check(
1451
+ asksCompany && (0, import_js4.checkOrganization)(organization, methods?.organization?.required === true),
1452
+ (0, import_js3.checkName)(name),
1453
+ (0, import_js3.checkEmail)(email),
1454
+ newPasswordProblem(password, f.policy)
1455
+ )) return;
1456
+ f.setBusy(true);
1457
+ f.setError(null);
1458
+ const r = guest ? await auth.account.upgrade({ name, email, password }) : await auth.signUp.email({
1459
+ name,
1460
+ email,
1461
+ password,
1462
+ ...methods?.organization?.ask ? { organization } : {},
1463
+ ...legal ? { acceptLegal, consents } : {},
1464
+ captchaToken: challenge.token
1465
+ });
1466
+ challenge.renew();
1467
+ if (!r.ok) return f.fail(r.error);
1468
+ if (r.status === "verification_required") {
1469
+ f.setBusy(false);
1470
+ return setSent(true);
1471
+ }
1472
+ f.done();
1473
+ };
1474
+ const general = f.error && !f.error.field ? f.error : null;
1475
+ const passwordOn = methods?.passwordSignIn !== false;
1476
+ const providers = guest || methods?.organization?.required ? [] : methods?.providers ?? [];
1477
+ if (sent) {
1478
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "form", root: f.root, children: [
1479
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.checkEmail }),
1480
+ props.links?.signIn && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: props.links.signIn, children: f.t.backToSignIn })
1481
+ ] });
1482
+ }
1483
+ if (methods === null) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wrap, { f, as: "div", slot: "form", root: f.root, busy: true });
1484
+ const footer = props.links?.signIn && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Note, { f, footer: true, children: [
1485
+ f.t.haveAccount,
1486
+ " ",
1487
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: props.links.signIn, children: f.t.signIn })
1488
+ ] });
1489
+ if (!passwordOn) {
1490
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "form", root: f.root, children: [
1491
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
1492
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ProviderButtons, { f, providers, onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
1493
+ footer
1494
+ ] });
1495
+ }
1496
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "form", root: f.root, onSubmit: submit, noValidate: true, children: [
1497
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
1498
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ProviderButtons, { f, providers, onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
1499
+ providers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Or, { f, children: f.t.orWithEmail }),
1500
+ methods.organization?.ask && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "organization", type: "text", label: f.t.company, value: organization, autoComplete: "organization", required: methods.organization.required, onChange: setOrganization }),
1501
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
1502
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
1503
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "password", type: "password", label: f.t.password, value: password, autoComplete: "new-password", required: true, onChange: setPassword, hint: f.passwordRule }),
1504
+ legal && legal.documents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Check, { f, name: "acceptLegal", checked: acceptLegal, required: true, onChange: setAcceptLegal, children: [
1505
+ f.t.iAccept,
1506
+ " ",
1507
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Documents, { f, documents: legal.documents })
1508
+ ] }),
1509
+ legal?.consentPurposes.map((p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Check, { f, name: `consent_${p.key}`, checked: consents[p.key] === true, required: p.required, onChange: (on) => setConsents({ ...consents, [p.key]: on }), children: p.label }, p.key)),
1510
+ challenge.node,
1511
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.signUp }),
1512
+ footer
1513
+ ] });
1514
+ }
1515
+ function ForgotPassword(props) {
1516
+ const auth = useAuth();
1517
+ const f = useForm(props);
1518
+ const [email, setEmail] = (0, import_react8.useState)("");
1519
+ const [sent, setSent] = (0, import_react8.useState)(false);
1520
+ const challenge = useChallenge(useMethods(auth)?.captchaSiteKey, props.locale);
1521
+ const submit = async (e) => {
1522
+ e.preventDefault();
1523
+ f.setBusy(true);
1524
+ f.setError(null);
1525
+ const r = await auth.forgotPassword({ email, captchaToken: challenge.token });
1526
+ f.setBusy(false);
1527
+ challenge.renew();
1528
+ if (!r.ok) return f.setError(r.error);
1529
+ setSent(true);
1530
+ };
1531
+ const general = f.error && !f.error.field ? f.error : null;
1532
+ if (sent) {
1533
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "form", root: f.root, children: [
1534
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.linkSent }),
1535
+ props.links?.signIn && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: props.links.signIn, children: f.t.backToSignIn })
1536
+ ] });
1537
+ }
1538
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "form", root: f.root, onSubmit: submit, noValidate: true, children: [
1539
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
1540
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
1541
+ challenge.node,
1542
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.sendLink }),
1543
+ props.links?.signIn && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, footer: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: props.links.signIn, children: f.t.backToSignIn }) })
1544
+ ] });
1545
+ }
1546
+ function ResetPassword(props) {
1547
+ const auth = useAuth();
1548
+ const f = useForm(props);
1549
+ const [token, setToken] = (0, import_react8.useState)(null);
1550
+ const [password, setPassword] = (0, import_react8.useState)("");
1551
+ const [changed, setChanged] = (0, import_react8.useState)(false);
1552
+ usePasswordPolicy(f, useMethods(auth));
1553
+ useMailedToken("token", (t) => {
1554
+ setToken(t ?? "");
1555
+ if (!t) f.setError({ code: "invalid_token", message: "This link is not valid, or it has expired." });
1556
+ });
1557
+ const submit = async (e) => {
1558
+ e.preventDefault();
1559
+ f.setBusy(true);
1560
+ f.setError(null);
1561
+ const r = await auth.resetPassword({ token: token ?? "", password });
1562
+ f.setBusy(false);
1563
+ if (!r.ok) return f.setError(r.error);
1564
+ setChanged(true);
1565
+ };
1566
+ const general = f.error && !f.error.field ? f.error : null;
1567
+ const back = props.links?.signIn && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: props.links.signIn, children: f.t.backToSignIn });
1568
+ if (changed) {
1569
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "form", root: f.root, children: [
1570
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.passwordChanged }),
1571
+ back
1572
+ ] });
1573
+ }
1574
+ if (token === "") {
1575
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "form", root: f.root, children: [
1576
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
1577
+ props.links?.forgotPassword && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: props.links.forgotPassword, children: f.t.forgotPassword })
1578
+ ] });
1579
+ }
1580
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "form", root: f.root, onSubmit: submit, noValidate: true, children: [
1581
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
1582
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "password", type: "password", label: f.t.newPassword, value: password, autoComplete: "new-password", required: true, onChange: setPassword, hint: f.passwordRule }),
1583
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy || token === null, className: f.cx("button"), children: f.t.savePassword })
1584
+ ] });
1585
+ }
1586
+ function VerifyEmail(props) {
1587
+ const auth = useAuth();
1588
+ const f = useForm(props);
1589
+ const [state, setState] = (0, import_react8.useState)("confirming");
1590
+ useMailedToken("token", (token) => {
1591
+ if (!token) {
1592
+ f.setError({ code: "invalid_token", message: "This link is not valid, or it has expired." });
1593
+ return setState("failed");
1594
+ }
1595
+ void auth.verifyEmail({ token }).then((r) => {
1596
+ if (r.ok && r.status === "signed_in") return f.done();
1597
+ if (r.ok) return setState("confirmed");
1598
+ f.setError(r.error);
1599
+ setState("failed");
1600
+ });
1601
+ });
1602
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "form", root: f.root, busy: state === "confirming", children: [
1603
+ state === "confirming" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.confirming }),
1604
+ state === "confirmed" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.emailConfirmed }),
1605
+ state === "failed" && f.error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(f.error) }),
1606
+ state !== "confirming" && props.links?.signIn && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: props.links.signIn, children: f.t.backToSignIn })
1607
+ ] });
1608
+ }
1609
+ function AcceptInvite(props) {
1610
+ const auth = useAuth();
1611
+ const f = useForm(props);
1612
+ const [token, setToken] = (0, import_react8.useState)("");
1613
+ const [invitation, setInvitation] = (0, import_react8.useState)(null);
1614
+ const [state, setState] = (0, import_react8.useState)("opening");
1615
+ const [password, setPassword] = (0, import_react8.useState)("");
1616
+ usePasswordPolicy(f, useMethods(auth));
1617
+ useMailedToken("token", (t) => {
1618
+ if (!t) return setState("invalid");
1619
+ setToken(t);
1620
+ void auth.invitation(t).then((r) => {
1621
+ if (r.ok) {
1622
+ setInvitation(r.invitation);
1623
+ return setState("ready");
1624
+ }
1625
+ if (r.error.code !== "invalid_token") f.setError(r.error);
1626
+ setState("invalid");
1627
+ });
1628
+ });
1629
+ const submit = async (e) => {
1630
+ e.preventDefault();
1631
+ f.setBusy(true);
1632
+ f.setError(null);
1633
+ const r = await auth.acceptInvitation(token, password);
1634
+ if (!r.ok) {
1635
+ f.setBusy(false);
1636
+ if (r.error.code === "invalid_token") return setState("invalid");
1637
+ return f.setError(r.error);
1638
+ }
1639
+ props.onSaved?.({ kind: "invitation.accepted", email: invitation?.email ?? "", ...invitation?.organization ? { organization: invitation.organization } : {} });
1640
+ if (r.status === "mfa_required") {
1641
+ f.setBusy(false);
1642
+ return setState("code");
1643
+ }
1644
+ f.done();
1645
+ };
1646
+ const general = f.error && !f.error.field ? f.error : null;
1647
+ const back = props.links?.signIn && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: props.links.signIn, children: f.t.backToSignIn });
1648
+ if (state === "opening") {
1649
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wrap, { f, as: "div", slot: "form", root: f.root, busy: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.openingInvitation }) });
1650
+ }
1651
+ if (state === "invalid") {
1652
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "form", root: f.root, children: [
1653
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: general ? f.say(general) : f.t.invitationInvalid }),
1654
+ back
1655
+ ] });
1656
+ }
1657
+ if (state === "code") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SecondStepForm, { f, auth });
1658
+ const workspace = invitation?.workspace ?? "";
1659
+ const heading = invitation?.organization ? f.t.invitedToOrganization.replace("{organization}", invitation.organization).replace("{workspace}", workspace) : f.t.invitedTo.replace("{workspace}", workspace);
1660
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "form", root: f.root, onSubmit: submit, noValidate: true, children: [
1661
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: heading }),
1662
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.invitedAs.replace("{email}", invitation?.email ?? "") }),
1663
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
1664
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "email", name: "username", autoComplete: "username", value: invitation?.email ?? "", readOnly: true, hidden: true }),
1665
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "password", type: "password", label: f.t.choosePassword, value: password, autoComplete: "new-password", required: true, onChange: setPassword, hint: f.passwordRule }),
1666
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.acceptInvite })
1667
+ ] });
1668
+ }
1669
+ function PendingTerms(props) {
1670
+ const auth = useAuth();
1671
+ const f = useForm(props);
1672
+ const [owed, setOwed] = (0, import_react8.useState)(null);
1673
+ (0, import_react8.useEffect)(() => {
1674
+ void auth.account.legal().then((r) => setOwed(r.ok ? r.pending : []));
1675
+ }, []);
1676
+ if (!owed || owed.length === 0) return null;
1677
+ const accept = async () => {
1678
+ f.setBusy(true);
1679
+ f.setError(null);
1680
+ const r = await auth.account.acceptLegal({ kinds: owed.map((d) => d.kind) });
1681
+ if (!r.ok) return f.fail(r.error);
1682
+ const after = props.onSuccess?.();
1683
+ if (isPending(after)) await Promise.resolve(after).catch(() => void 0);
1684
+ f.setBusy(false);
1685
+ setOwed([]);
1686
+ };
1687
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "form", root: f.root, children: [
1688
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.termsChanged }),
1689
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Note, { f, children: [
1690
+ f.t.termsChangedHelp,
1691
+ " ",
1692
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Documents, { f, documents: owed })
1693
+ ] }),
1694
+ f.error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(f.error) }),
1695
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), onClick: () => void accept(), children: f.t.acceptTerms })
1696
+ ] });
1697
+ }
1698
+ var ACCOUNT_SECTIONS = ["profile", "email", "password", "linked", "secondStep", "phone", "passkeys", "agents", "sessions"];
1699
+ function useSection(props) {
1700
+ const f = useForm(props, { part: true });
1701
+ const [done, setDone] = (0, import_react8.useState)(null);
1702
+ const run = async (action, key = SUBMIT, leaves = false) => {
1703
+ f.setBusy(key);
1704
+ f.setError(null);
1705
+ setDone(null);
1706
+ const r = await action();
1707
+ if (!r.ok) f.fail(r.error);
1708
+ else if (!leaves) f.setBusy(false);
1709
+ return r;
1710
+ };
1711
+ const general = f.error && !f.error.field ? f.error : null;
1712
+ return { f, done, setDone, run, general };
1713
+ }
1714
+ function Account(props) {
1715
+ const auth = useAuth();
1716
+ const { accountUrl } = useSession();
1717
+ const f = useForm(props);
1718
+ const [account, setAccount] = (0, import_react8.useState)(null);
1719
+ (0, import_react8.useEffect)(() => {
1720
+ void auth.account.get().then(setAccount);
1721
+ }, []);
1722
+ if (account === null) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wrap, { f, as: "div", slot: "account", root: f.root, busy: true });
1723
+ const when = props.formatDate ?? ((iso) => new Date(iso).toLocaleString());
1724
+ const mfa = (mfaEnabled) => setAccount({ ...account, mfaEnabled });
1725
+ const part = (section) => {
1726
+ switch (section) {
1727
+ case "profile":
1728
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ProfilePart, { props, account, onSaved: setAccount });
1729
+ case "email":
1730
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(EmailPart, { props, account });
1731
+ case "password":
1732
+ return account.hasPassword ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PasswordPart, { props }) : null;
1733
+ case "linked":
1734
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LinkedPart, { props });
1735
+ case "secondStep":
1736
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SecondStepPart, { props, account, onChanged: mfa });
1737
+ case "phone":
1738
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PhonePart, { props, account, onChanged: mfa });
1739
+ case "passkeys":
1740
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PasskeysPart, { props, account, accountUrl: accountUrl(), when });
1741
+ case "agents":
1742
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AgentsPart, { props, when });
1743
+ case "sessions":
1744
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SessionsPart, { props, when });
1745
+ }
1746
+ };
1747
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wrap, { f, as: "div", slot: "account", root: f.root, children: (props.sections ?? ACCOUNT_SECTIONS).map((section) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react8.Fragment, { children: part(section) }, section)) });
1748
+ }
1749
+ function AccountProfile(props) {
1750
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Account, { ...props, sections: ["profile"] });
1751
+ }
1752
+ function AccountEmail(props) {
1753
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Account, { ...props, sections: ["email"] });
1754
+ }
1755
+ function AccountPassword(props) {
1756
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Account, { ...props, sections: ["password"] });
1757
+ }
1758
+ function AccountLinked(props) {
1759
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Account, { ...props, sections: ["linked"] });
1760
+ }
1761
+ function AccountSecondStep(props) {
1762
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Account, { ...props, sections: ["secondStep"] });
1763
+ }
1764
+ function AccountPhone(props) {
1765
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Account, { ...props, sections: ["phone"] });
1766
+ }
1767
+ function AccountPasskeys(props) {
1768
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Account, { ...props, sections: ["passkeys"] });
1769
+ }
1770
+ function AccountAgents(props) {
1771
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Account, { ...props, sections: ["agents"] });
1772
+ }
1773
+ function AccountSessions(props) {
1774
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Account, { ...props, sections: ["sessions"] });
1775
+ }
1776
+ var OWNER = "owner";
1777
+ function memberActions(seat, m) {
1778
+ const reachable = m.role !== OWNER || seat.role === OWNER;
1779
+ return {
1780
+ changeRole: seat.can.manageMembers && reachable,
1781
+ // Leaving is anybody's; removing somebody else is cauthy:members:remove.
1782
+ remove: m.you || seat.can.removeMembers && reachable,
1783
+ inviteAgain: seat.can.manageMembers && m.invited
1784
+ };
1785
+ }
1786
+ function rolesToGive(seat, roles, only) {
1787
+ const mine = seat.role === OWNER ? roles : roles.filter((c) => c.role !== OWNER);
1788
+ return only ? mine.filter((c) => only(c.role, c)) : mine;
1789
+ }
1790
+ function OrganizationMembers(props) {
1791
+ const auth = useAuth();
1792
+ const { root } = useForm(props);
1793
+ const { f, done, setDone, run } = useSection(props);
1794
+ const problem = f.error && f.error.field !== "email" && f.error.field !== "name" ? f.error : null;
1795
+ const [seat, setSeat] = (0, import_react8.useState)(void 0);
1796
+ const [members, setMembers] = (0, import_react8.useState)(null);
1797
+ const [roles, setRoles] = (0, import_react8.useState)([]);
1798
+ const [email, setEmail] = (0, import_react8.useState)("");
1799
+ const [role, setRole] = (0, import_react8.useState)("");
1800
+ const [name, setName] = (0, import_react8.useState)("");
1801
+ const [asking, setAsking] = (0, import_react8.useState)(null);
1802
+ const [adding, setAdding] = (0, import_react8.useState)(false);
1803
+ const [renamingOpen, setRenamingOpen] = (0, import_react8.useState)(false);
1804
+ const [gone, setGone] = (0, import_react8.useState)(null);
1805
+ const id = props.organizationId;
1806
+ const when = props.formatDate ?? ((iso) => new Date(iso).toLocaleDateString());
1807
+ const hidden = (action) => props.hide?.includes(action) === true;
1808
+ const saved = (event) => props.onSaved?.(event);
1809
+ const load = async () => {
1810
+ const [list, people, choices] = await Promise.all([auth.organizations.list(), auth.organizations.members(id), auth.organizations.roles(id)]);
1811
+ const mine = list.find((o) => o.id === id) ?? null;
1812
+ setSeat(mine);
1813
+ if (mine) setName(mine.name);
1814
+ setMembers(people);
1815
+ setRoles(choices ?? []);
1816
+ const offered = mine ? rolesToGive(mine, choices ?? [], props.roles) : [];
1817
+ if (offered.length > 0 && !offered.some((c) => c.role === role)) setRole(offered[0].role);
1818
+ };
1819
+ (0, import_react8.useEffect)(() => {
1820
+ void load();
1821
+ }, [id]);
1822
+ if (gone !== null) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wrap, { f, as: "div", slot: "account", root, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "success", children: gone }) });
1823
+ if (seat === void 0) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wrap, { f, as: "div", slot: "account", root, busy: true });
1824
+ if (seat === null) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wrap, { f, as: "div", slot: "account", root, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.organizationMissing }) });
1825
+ const manage = seat.can.manageMembers;
1826
+ const giveable = rolesToGive(seat, roles, props.roles);
1827
+ const roleName = (c) => props.roleLabel?.(c) || c.name || c.role;
1828
+ const label = (r) => {
1829
+ const c = roles.find((x) => x.role === r);
1830
+ return c ? roleName(c) : r;
1831
+ };
1832
+ const add = async (e) => {
1833
+ e.preventDefault();
1834
+ if (!f.check((0, import_js3.checkEmail)(email))) return;
1835
+ const r = await run(() => auth.organizations.add(id, { email, role, locale: props.locale }), "add");
1836
+ if (!r.ok) return;
1837
+ setEmail("");
1838
+ setAdding(false);
1839
+ setDone(f.t.memberAdded.replace("{email}", r.member.email));
1840
+ saved({ kind: "member.added", organizationId: id, userId: r.member.userId, email: r.member.email, role: r.member.role || role });
1841
+ await load();
1842
+ };
1843
+ const change = async (m, next) => {
1844
+ const r = await run(() => auth.organizations.setRole(id, m.userId, next), `role:${m.userId}`);
1845
+ if (!r.ok) return;
1846
+ saved({ kind: "member.role_changed", organizationId: id, userId: m.userId, role: next, previousRole: m.role });
1847
+ await load();
1848
+ };
1849
+ const remove = async (m) => {
1850
+ setAsking(null);
1851
+ const r = await run(() => auth.organizations.remove(id, m.userId), `remove:${m.userId}`);
1852
+ if (!r.ok) return;
1853
+ saved({ kind: m.you ? "member.left" : "member.removed", organizationId: id, userId: m.userId });
1854
+ if (m.you) setSeat(null);
1855
+ else await load();
1856
+ };
1857
+ const inviteAgain = async (m) => {
1858
+ const r = await run(() => auth.organizations.inviteAgain(id, m.userId, { locale: props.locale }), `invite:${m.userId}`);
1859
+ if (!r.ok) return;
1860
+ setDone(f.t.memberInvitationSent);
1861
+ saved({ kind: "member.invited_again", organizationId: id, userId: m.userId });
1862
+ };
1863
+ const rename = async (e) => {
1864
+ e.preventDefault();
1865
+ const r = await run(() => auth.organizations.rename(id, name), "rename");
1866
+ if (!r.ok) return;
1867
+ setSeat(r.organization);
1868
+ setName(r.organization.name);
1869
+ setRenamingOpen(false);
1870
+ setDone(f.t.organizationRenamed.replace("{name}", r.organization.name));
1871
+ saved({ kind: "organization.renamed", organizationId: id, name: r.organization.name });
1872
+ };
1873
+ const close = async (how) => {
1874
+ setAsking(null);
1875
+ const r = await run(() => how === "archive" ? auth.organizations.archive(id) : auth.organizations.delete(id), how);
1876
+ if (!r.ok) return;
1877
+ setGone((how === "archive" ? f.t.organizationArchived : f.t.organizationDeleted).replace("{org}", seat.name));
1878
+ saved({ kind: how === "archive" ? "organization.archived" : "organization.deleted", organizationId: id });
1879
+ };
1880
+ const ask = (key, title, question, yes) => {
1881
+ const { Confirm } = f.C;
1882
+ if (!Confirm) return setAsking(key);
1883
+ void Confirm({ title, body: question, confirmLabel: title, cancelLabel: f.t.cancel, danger: true }).then((ok) => {
1884
+ if (ok) yes();
1885
+ });
1886
+ };
1887
+ const confirming = (text, label2, yes) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { role: "group", "aria-label": label2, children: [
1888
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: text }),
1889
+ " ",
1890
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "danger", disabled: f.busy, className: f.cx("providerButton"), onClick: yes, children: f.t.yes }),
1891
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking(null), children: f.t.cancel })
1892
+ ] });
1893
+ const leaveQuestion = f.t.memberLeaveConfirm.replace("{org}", seat.name);
1894
+ const archiveQuestion = f.t.organizationArchiveConfirm.replace("{org}", seat.name);
1895
+ const deleteQuestion = f.t.organizationDeleteConfirm.replace("{org}", seat.name);
1896
+ const archiving = seat.can.archive && !hidden("archive");
1897
+ const deleting = seat.can.delete && !hidden("delete");
1898
+ const renaming = seat.can.update && !hidden("rename");
1899
+ const alone = members !== null && members.every((m) => m.you);
1900
+ const addOpen = adding || alone;
1901
+ const open = (form) => {
1902
+ setDone(null);
1903
+ f.setError(null);
1904
+ if (form === "add") setAdding(true);
1905
+ else setRenamingOpen(true);
1906
+ };
1907
+ const cancelAdd = () => {
1908
+ setEmail("");
1909
+ f.setError(null);
1910
+ setAdding(false);
1911
+ };
1912
+ const cancelRename = () => {
1913
+ setName(seat.name);
1914
+ f.setError(null);
1915
+ setRenamingOpen(false);
1916
+ };
1917
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "account", root, children: [
1918
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "section", slot: "section", section: "members", children: [
1919
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Heading, { f, children: [
1920
+ f.t.members,
1921
+ " \xB7 ",
1922
+ seat.name
1923
+ ] }),
1924
+ problem && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(problem) }),
1925
+ members === null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1926
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.membersHidden }),
1927
+ auth.session && !hidden("leave") && (asking === auth.session.user.id ? confirming(leaveQuestion, f.t.memberLeave, () => void remove({ userId: auth.session.user.id, you: true })) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1928
+ f.Button,
1929
+ {
1930
+ type: "button",
1931
+ variant: "danger",
1932
+ loading: f.loading(`remove:${auth.session.user.id}`),
1933
+ disabled: f.busy,
1934
+ className: f.cx("providerButton"),
1935
+ onClick: () => ask(auth.session.user.id, f.t.memberLeave, leaveQuestion, () => void remove({ userId: auth.session.user.id, you: true })),
1936
+ children: f.t.memberLeave
1937
+ }
1938
+ ))
1939
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: f.cx("sessions"), children: members.map((m) => {
1940
+ const who = m.name || m.email;
1941
+ const may = memberActions(seat, m);
1942
+ const removable = may.remove && !(m.you && hidden("leave"));
1943
+ const question = m.you ? leaveQuestion : f.t.memberRemoveConfirm.replace("{who}", who);
1944
+ const action = m.you ? f.t.memberLeave : f.t.memberRemove;
1945
+ const choices = giveable.some((c) => c.role === m.role) ? giveable : [...roles.filter((c) => c.role === m.role), ...giveable];
1946
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: f.cx("session"), children: [
1947
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
1948
+ who,
1949
+ m.name ? ` \xB7 ${m.email}` : "",
1950
+ m.you && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Tag, { f, plain: ` (${f.t.memberYou})`, children: f.t.memberYou }),
1951
+ f.C.Badge ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1952
+ m.invited && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Tag, { f, tone: "warning", plain: "", children: f.t.memberInvited }),
1953
+ m.manager && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Tag, { f, tone: "success", plain: "", children: f.t.memberManager })
1954
+ ] }) : `${m.invited ? ` \xB7 ${f.t.memberInvited}` : ""}${m.manager ? ` \xB7 ${f.t.memberManager}` : ""}`,
1955
+ " \xB7 ",
1956
+ when(m.since)
1957
+ ] }),
1958
+ " ",
1959
+ may.changeRole && giveable.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1960
+ Pick,
1961
+ {
1962
+ f,
1963
+ name: `role_${m.userId}`,
1964
+ label: `${f.t.memberRole}: ${who}`,
1965
+ value: m.role,
1966
+ disabled: f.busy,
1967
+ options: choices.map((c) => ({ value: c.role, label: roleName(c) })),
1968
+ onChange: (next) => void change(m, next)
1969
+ }
1970
+ ) : f.C.Badge ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.C.Badge, { tone: "neutral", children: label(m.role) }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: label(m.role) }),
1971
+ " ",
1972
+ asking === m.userId ? confirming(question, action, () => void remove(m)) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1973
+ may.inviteAgain && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", loading: f.loading(`invite:${m.userId}`), disabled: f.busy, className: f.cx("providerButton"), onClick: () => void inviteAgain(m), children: f.t.memberInviteAgain }),
1974
+ removable && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading(`remove:${m.userId}`), disabled: f.busy, className: f.cx("providerButton"), onClick: () => ask(m.userId, action, question, () => void remove(m)), children: action })
1975
+ ] })
1976
+ ] }, m.userId);
1977
+ }) }),
1978
+ done && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "success", children: done })
1979
+ ] }),
1980
+ manage && giveable.length > 0 && (addOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "section", section: "add-member", onSubmit: add, noValidate: true, children: [
1981
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.memberAdd }),
1982
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "off", required: true, onChange: setEmail }),
1983
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AddRole, { f, value: role, options: giveable.map((c) => ({ value: c.role, label: roleName(c) })), onChange: setRole }),
1984
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading("add"), disabled: f.busy, className: f.cx("button"), children: f.t.memberAdd }),
1985
+ !alone && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Cancel, { f, onClick: cancelAdd })
1986
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wrap, { f, as: "div", slot: "section", section: "add-member", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => open("add"), children: f.t.memberAdd }) })),
1987
+ (renaming || archiving || deleting) && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "section", slot: "section", section: "organization", children: [
1988
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.organization }),
1989
+ renaming && (renamingOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", section: "rename", onSubmit: rename, noValidate: true, children: [
1990
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "organization", required: true, onChange: setName }),
1991
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading("rename"), disabled: f.busy, className: f.cx("button"), children: f.t.organizationRename }),
1992
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Cancel, { f, onClick: cancelRename })
1993
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1994
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: seat.name }),
1995
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => open("rename"), children: f.t.organizationRename })
1996
+ ] })),
1997
+ asking === "archive" ? confirming(archiveQuestion, f.t.organizationArchive, () => void close("archive")) : asking === "delete" ? confirming(deleteQuestion, f.t.organizationDelete, () => void close("delete")) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1998
+ archiving && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading("archive"), disabled: f.busy, className: f.cx("providerButton"), onClick: () => ask("archive", f.t.organizationArchive, archiveQuestion, () => void close("archive")), children: f.t.organizationArchive }),
1999
+ deleting && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading("delete"), disabled: f.busy, className: f.cx("providerButton"), onClick: () => ask("delete", f.t.organizationDelete, deleteQuestion, () => void close("delete")), children: f.t.organizationDelete })
2000
+ ] })
2001
+ ] })
2002
+ ] });
2003
+ }
2004
+ function AddRole({ f, value, options, onChange }) {
2005
+ const id = (0, import_react8.useId)();
2006
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Labelled, { f, id, label: f.t.memberRole, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Pick, { f, id, name: "role", value, options, onChange }) });
2007
+ }
2008
+ function PasskeysPart({ props, account, accountUrl, when }) {
2009
+ const auth = useAuth();
2010
+ const { f, done, setDone, run, general } = useSection(props);
2011
+ const [here, setHere] = (0, import_react8.useState)(null);
2012
+ const [list, setList] = (0, import_react8.useState)([]);
2013
+ const [name, setName] = (0, import_react8.useState)("");
2014
+ const [password, setPassword] = (0, import_react8.useState)("");
2015
+ const [adding, setAdding] = (0, import_react8.useState)(false);
2016
+ (0, import_react8.useEffect)(() => {
2017
+ void auth.methods().then((m) => {
2018
+ const can2 = m.passkeyHere && (0, import_js3.canUsePasskeys)();
2019
+ setHere(can2);
2020
+ if (can2) void auth.account.passkeys().then(setList);
2021
+ });
2022
+ }, []);
2023
+ if (here === null) return null;
2024
+ if (!here) {
2025
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "section", slot: "section", section: "passkeys", children: [
2026
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.passkeys }),
2027
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: accountUrl, children: f.t.managePasskeys })
2028
+ ] });
2029
+ }
2030
+ const add = async (e, kind = "device") => {
2031
+ e?.preventDefault();
2032
+ if (account.hasPassword && !f.check((0, import_js3.checkPassword)(password))) return;
2033
+ const r = await run(() => auth.account.addPasskey({ name, password, kind }), kind === "security_key" ? "security_key" : SUBMIT);
2034
+ if (!r.ok) {
2035
+ if (r.error.code === "cancelled") f.setError(null);
2036
+ return;
2037
+ }
2038
+ setList([...list, r.passkey]);
2039
+ setName("");
2040
+ setPassword("");
2041
+ setAdding(false);
2042
+ setDone(f.t.passkeyAdded);
2043
+ props.onSaved?.({ kind: "passkey.added", id: r.passkey.id });
2044
+ };
2045
+ const remove = async (id) => {
2046
+ const r = await run(() => auth.account.removePasskey(id), `remove:${id}`);
2047
+ if (!r.ok) return;
2048
+ setList(list.filter((p) => p.id !== id));
2049
+ props.onSaved?.({ kind: "passkey.removed", id });
2050
+ };
2051
+ const cancel = () => {
2052
+ setName("");
2053
+ setPassword("");
2054
+ f.setError(null);
2055
+ setAdding(false);
2056
+ };
2057
+ const listed = list.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.noPasskeys }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: f.cx("sessions"), children: list.map((p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: f.cx("session"), children: [
2058
+ p.name || f.t.passkeyUnnamed,
2059
+ p.kind !== "unknown" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Tag, { f, plain: ` \xB7 ${f.t.passkeyKinds[p.kind]}`, children: f.t.passkeyKinds[p.kind] }),
2060
+ " \xB7 ",
2061
+ when(p.createdAt),
2062
+ " ",
2063
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading(`remove:${p.id}`), disabled: f.busy, className: f.cx("providerButton"), onClick: () => void remove(p.id), children: f.t.removePasskey })
2064
+ ] }, p.id)) });
2065
+ if (list.length > 0 && !adding) {
2066
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "section", section: "passkeys", children: [
2067
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.passkeys }),
2068
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.passkeysHelp }),
2069
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2070
+ listed,
2071
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
2072
+ setDone(null);
2073
+ f.setError(null);
2074
+ setAdding(true);
2075
+ }, children: f.t.addAnotherPasskey }),
2076
+ done && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "success", children: done })
2077
+ ] });
2078
+ }
2079
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "section", section: "passkeys", onSubmit: add, noValidate: true, children: [
2080
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.passkeys }),
2081
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.passkeysHelp }),
2082
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2083
+ listed,
2084
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "name", type: "text", label: f.t.passkeyName, value: name, autoComplete: "off", onChange: setName }),
2085
+ account.hasPassword && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
2086
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.addPasskeyDevice }),
2087
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", loading: f.loading("security_key"), disabled: f.busy, className: f.cx("providerButton"), onClick: () => void add(null, "security_key"), children: f.t.addSecurityKey }),
2088
+ list.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Cancel, { f, onClick: cancel }),
2089
+ done && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "success", children: done })
2090
+ ] });
2091
+ }
2092
+ function Cancel({ f, onClick }) {
2093
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick, children: f.t.cancel });
2094
+ }
2095
+ function RecoveryCodes({ f, codes }) {
2096
+ const [copied, setCopied] = (0, import_react8.useState)(null);
2097
+ (0, import_react8.useEffect)(() => setCopied(null), [codes]);
2098
+ const copy = async () => {
2099
+ try {
2100
+ await navigator.clipboard.writeText(codes.join("\n"));
2101
+ setCopied(true);
2102
+ } catch {
2103
+ setCopied(false);
2104
+ }
2105
+ };
2106
+ const download = () => {
2107
+ const file = new Blob([`${f.t.recoveryCodes}
2108
+
2109
+ ${codes.join("\n")}
2110
+ `], { type: "text/plain;charset=utf-8" });
2111
+ const url = URL.createObjectURL(file);
2112
+ const a = document.createElement("a");
2113
+ a.href = url;
2114
+ a.download = "recovery-codes.txt";
2115
+ document.body.appendChild(a);
2116
+ a.click();
2117
+ a.remove();
2118
+ setTimeout(() => URL.revokeObjectURL(url), 0);
2119
+ };
2120
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
2121
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.keepCodes }),
2122
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { children: c }) }, c)) }),
2123
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", className: f.cx("providerButton"), onClick: () => void copy(), children: f.t.copyCodes }),
2124
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", className: f.cx("providerButton"), onClick: download, children: f.t.downloadCodes }),
2125
+ copied === true && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "success", children: f.t.codesCopied }),
2126
+ copied === false && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.t.codesNotCopied })
2127
+ ] });
2128
+ }
2129
+ function ProfilePart({ props, account, onSaved }) {
2130
+ const auth = useAuth();
2131
+ const { f, done, setDone, run, general } = useSection(props);
2132
+ const [name, setName] = (0, import_react8.useState)(account.name);
2133
+ const [editing, setEditing] = (0, import_react8.useState)(account.name.trim() === "");
2134
+ const submit = async (e) => {
2135
+ e.preventDefault();
2136
+ const r = await run(() => auth.account.update({ name }));
2137
+ if (!r.ok) return;
2138
+ onSaved(r.account);
2139
+ setName(r.account.name);
2140
+ setEditing(r.account.name.trim() === "");
2141
+ setDone(f.t.saved);
2142
+ props.onSaved?.({ kind: "profile.saved", name: r.account.name });
2143
+ };
2144
+ const cancel = () => {
2145
+ setName(account.name);
2146
+ f.setError(null);
2147
+ setEditing(false);
2148
+ };
2149
+ if (!editing) {
2150
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "section", section: "profile", children: [
2151
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.profile }),
2152
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: account.name }),
2153
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: account.email }),
2154
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
2155
+ setDone(null);
2156
+ setEditing(true);
2157
+ }, children: f.t.change }),
2158
+ done && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "success", children: done })
2159
+ ] });
2160
+ }
2161
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "section", section: "profile", onSubmit: submit, noValidate: true, children: [
2162
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.profile }),
2163
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: account.email }),
2164
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2165
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
2166
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.save }),
2167
+ account.name.trim() !== "" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Cancel, { f, onClick: cancel }),
2168
+ done && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "success", children: done })
2169
+ ] });
2170
+ }
2171
+ function EmailPart({ props, account }) {
2172
+ const auth = useAuth();
2173
+ const { f, done, setDone, run, general } = useSection(props);
2174
+ const [email, setEmail] = (0, import_react8.useState)("");
2175
+ const [password, setPassword] = (0, import_react8.useState)("");
2176
+ const [editing, setEditing] = (0, import_react8.useState)(false);
2177
+ const submit = async (e) => {
2178
+ e.preventDefault();
2179
+ if (!f.check((0, import_js3.checkEmail)(email), account.hasPassword && (0, import_js3.checkPassword)(password))) return;
2180
+ const r = await run(() => auth.account.changeEmail({ email, password }));
2181
+ if (!r.ok) return;
2182
+ setEmail("");
2183
+ setPassword("");
2184
+ setEditing(false);
2185
+ setDone(f.t.emailSent.replace("{email}", r.email));
2186
+ props.onSaved?.({ kind: "email.change_requested", email: r.email });
2187
+ };
2188
+ const cancel = () => {
2189
+ setEmail("");
2190
+ setPassword("");
2191
+ f.setError(null);
2192
+ setEditing(false);
2193
+ };
2194
+ if (!editing) {
2195
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "section", section: "email", children: [
2196
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.emailAddress }),
2197
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: account.email }),
2198
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
2199
+ setDone(null);
2200
+ setEditing(true);
2201
+ }, children: f.t.changeEmail }),
2202
+ done && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "success", children: done })
2203
+ ] });
2204
+ }
2205
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "section", section: "email", onSubmit: submit, noValidate: true, children: [
2206
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.emailAddress }),
2207
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: account.email }),
2208
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2209
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "email", type: "email", label: f.t.newEmail, value: email, autoComplete: "email", required: true, onChange: setEmail }),
2210
+ account.hasPassword && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
2211
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.changeEmail }),
2212
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Cancel, { f, onClick: cancel })
2213
+ ] });
2214
+ }
2215
+ function LinkedPart({ props }) {
2216
+ const auth = useAuth();
2217
+ const { f, run, general } = useSection(props);
2218
+ const [linked, setLinked] = (0, import_react8.useState)(null);
2219
+ const [offered, setOffered] = (0, import_react8.useState)([]);
2220
+ const [came, setCame] = (0, import_react8.useState)(null);
2221
+ (0, import_react8.useEffect)(() => {
2222
+ void auth.account.identities().then(setLinked);
2223
+ void auth.methods().then((m) => setOffered(m.providers));
2224
+ const back = typeof window === "undefined" ? null : new URLSearchParams(window.location.search);
2225
+ const provider = back?.get("linked");
2226
+ if (provider) {
2227
+ setCame(provider);
2228
+ props.onSaved?.({ kind: "identity.linked", provider });
2229
+ } else if (back?.get("auth_error")) f.setError({ code: back.get("auth_error"), message: "That account could not be linked. Try again." });
2230
+ }, []);
2231
+ if (linked === null) return null;
2232
+ const name = (id) => offered.find((p) => p.id === id)?.name ?? id;
2233
+ const unlink = async (provider) => {
2234
+ const r = await run(() => auth.account.unlink(provider), `unlink:${provider}`);
2235
+ if (!r.ok) return;
2236
+ setLinked(linked.filter((x) => x.provider !== provider));
2237
+ props.onSaved?.({ kind: "identity.unlinked", provider });
2238
+ };
2239
+ const here = typeof window === "undefined" ? void 0 : window.location.pathname;
2240
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "section", slot: "section", section: "linked", children: [
2241
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.linkedAccounts }),
2242
+ came && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "success", children: f.t.linked }),
2243
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2244
+ linked.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.noLinkedAccounts }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: f.cx("sessions"), children: linked.map((x) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: f.cx("session"), children: [
2245
+ name(x.provider),
2246
+ x.email ? ` \xB7 ${x.email}` : "",
2247
+ " ",
2248
+ /* @__PURE__ */ (0, import_jsx_runtime3.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 })
2249
+ ] }, x.provider)) }),
2250
+ offered.filter((p) => !linked.some((x) => x.provider === p.id)).map((p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2251
+ f.Button,
2252
+ {
2253
+ type: "button",
2254
+ variant: "secondary",
2255
+ loading: f.loading(`link:${p.id}`),
2256
+ disabled: f.busy,
2257
+ className: f.cx("providerButton"),
2258
+ onClick: () => {
2259
+ f.setBusy(`link:${p.id}`);
2260
+ auth.account.link(p.id, { returnTo: here });
2261
+ },
2262
+ children: [
2263
+ f.t.linkWith,
2264
+ " ",
2265
+ p.name
2266
+ ]
2267
+ },
2268
+ p.id
2269
+ ))
2270
+ ] });
2271
+ }
2272
+ function PasswordPart({ props }) {
2273
+ const auth = useAuth();
2274
+ const { f, done, setDone, run, general } = useSection(props);
2275
+ const [password, setPassword] = (0, import_react8.useState)("");
2276
+ const [newPassword, setNewPassword] = (0, import_react8.useState)("");
2277
+ const [editing, setEditing] = (0, import_react8.useState)(false);
2278
+ usePasswordPolicy(f, useMethods(auth));
2279
+ const submit = async (e) => {
2280
+ e.preventDefault();
2281
+ if (!f.check((0, import_js3.checkPassword)(password), newPasswordProblem(newPassword, f.policy, "newPassword"))) return;
2282
+ const r = await run(() => auth.account.changePassword({ password, newPassword }));
2283
+ if (!r.ok) return;
2284
+ setPassword("");
2285
+ setNewPassword("");
2286
+ setEditing(false);
2287
+ setDone(f.t.passwordChangedHere);
2288
+ props.onSaved?.({ kind: "password.changed" });
2289
+ };
2290
+ const cancel = () => {
2291
+ setPassword("");
2292
+ setNewPassword("");
2293
+ f.setError(null);
2294
+ setEditing(false);
2295
+ };
2296
+ if (!editing) {
2297
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "section", section: "password", children: [
2298
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.password }),
2299
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.passwordSet }),
2300
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
2301
+ setDone(null);
2302
+ setEditing(true);
2303
+ }, children: f.t.changePassword }),
2304
+ done && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "success", children: done })
2305
+ ] });
2306
+ }
2307
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "section", section: "password", onSubmit: submit, noValidate: true, children: [
2308
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.password }),
2309
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2310
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
2311
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "newPassword", type: "password", label: f.t.newPassword, value: newPassword, autoComplete: "new-password", required: true, onChange: setNewPassword, hint: f.passwordRule }),
2312
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.changePassword }),
2313
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Cancel, { f, onClick: cancel })
2314
+ ] });
2315
+ }
2316
+ function SecondStepPart({ props, account, onChanged }) {
2317
+ const auth = useAuth();
2318
+ const { f, run, general } = useSection(props);
2319
+ const [password, setPassword] = (0, import_react8.useState)("");
2320
+ const [code, setCode] = (0, import_react8.useState)("");
2321
+ const [setup, setSetup] = (0, import_react8.useState)(null);
2322
+ const [codes, setCodes] = (0, import_react8.useState)(null);
2323
+ const [asking, setAsking] = (0, import_react8.useState)(null);
2324
+ const start = async (e) => {
2325
+ e.preventDefault();
2326
+ const r = await run(() => auth.account.mfa.setup({ password }));
2327
+ if (r.ok) setSetup({ secret: r.secret, otpauthUri: r.otpauthUri, qr: r.qr ?? "" });
2328
+ };
2329
+ const confirm = async (e) => {
2330
+ e.preventDefault();
2331
+ const r = await run(() => auth.account.mfa.verify({ code }));
2332
+ if (!r.ok) return;
2333
+ setSetup(null);
2334
+ setCode("");
2335
+ setPassword("");
2336
+ setCodes(r.recoveryCodes);
2337
+ onChanged(true);
2338
+ props.onSaved?.({ kind: "mfa.enabled" });
2339
+ };
2340
+ const turnOff = async (key) => {
2341
+ const r = await run(() => auth.account.mfa.disable({ password }), key);
2342
+ if (!r.ok) return;
2343
+ setPassword("");
2344
+ setAsking(null);
2345
+ setCodes(null);
2346
+ onChanged(false);
2347
+ props.onSaved?.({ kind: "mfa.disabled" });
2348
+ };
2349
+ const renew = async (key) => {
2350
+ const r = await run(() => auth.account.mfa.recoveryCodes({ password }), key);
2351
+ if (!r.ok) return;
2352
+ setPassword("");
2353
+ setAsking(null);
2354
+ setCodes(r.recoveryCodes);
2355
+ props.onSaved?.({ kind: "recovery_codes.regenerated" });
2356
+ };
2357
+ const press = (what) => {
2358
+ f.setError(null);
2359
+ if (!account.hasPassword) return void (what === "off" ? turnOff(what) : renew(what));
2360
+ setPassword("");
2361
+ setCodes(null);
2362
+ setAsking(what);
2363
+ };
2364
+ const cancel = () => {
2365
+ setPassword("");
2366
+ f.setError(null);
2367
+ setAsking(null);
2368
+ };
2369
+ const passwordField = account.hasPassword && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword });
2370
+ if (setup) {
2371
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "section", section: "secondStep", onSubmit: confirm, noValidate: true, children: [
2372
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.secondStep }),
2373
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.addToApp }),
2374
+ setup.qr && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("img", { className: f.cx("qr"), src: setup.qr, width: 220, height: 220, alt: f.t.qrAlt }),
2375
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { className: f.cx("secret"), children: setup.secret }),
2376
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(A, { f, href: setup.otpauthUri, children: f.t.openInApp }),
2377
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2378
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
2379
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.verify })
2380
+ ] });
2381
+ }
2382
+ if (!account.mfaEnabled) {
2383
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "section", section: "secondStep", onSubmit: start, noValidate: true, children: [
2384
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.secondStep }),
2385
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.secondStepOff }),
2386
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2387
+ passwordField,
2388
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.turnOn })
2389
+ ] });
2390
+ }
2391
+ if (asking) {
2392
+ const submit = (e) => {
2393
+ e.preventDefault();
2394
+ void (asking === "off" ? turnOff(SUBMIT) : renew(SUBMIT));
2395
+ };
2396
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "section", section: "secondStep", onSubmit: submit, noValidate: true, children: [
2397
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.secondStep }),
2398
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.secondStepOn }),
2399
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2400
+ passwordField,
2401
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: asking === "off" ? "danger" : "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: asking === "off" ? f.t.turnOff : f.t.newRecoveryCodes }),
2402
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Cancel, { f, onClick: cancel })
2403
+ ] });
2404
+ }
2405
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "section", section: "secondStep", children: [
2406
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.secondStep }),
2407
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.secondStepOn }),
2408
+ codes && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RecoveryCodes, { f, codes }),
2409
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2410
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading("off"), disabled: f.busy, className: f.cx("button"), onClick: () => press("off"), children: f.t.turnOff }),
2411
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "secondary", loading: f.loading("codes"), disabled: f.busy, className: f.cx("providerButton"), onClick: () => press("codes"), children: f.t.newRecoveryCodes })
2412
+ ] });
2413
+ }
2414
+ function PhonePart({ props, account, onChanged }) {
2415
+ const auth = useAuth();
2416
+ const { f, run, general } = useSection(props);
2417
+ const [ways, setWays] = (0, import_react8.useState)(null);
2418
+ const [number, setNumber] = (0, import_react8.useState)("");
2419
+ const [channel, setChannel] = (0, import_react8.useState)("sms");
2420
+ const [password, setPassword] = (0, import_react8.useState)("");
2421
+ const [code, setCode] = (0, import_react8.useState)("");
2422
+ const [sentTo, setSentTo] = (0, import_react8.useState)("");
2423
+ const [codes, setCodes] = (0, import_react8.useState)(null);
2424
+ const [removing, setRemoving] = (0, import_react8.useState)(false);
2425
+ const load = () => auth.account.mfa.factors().then((w) => {
2426
+ setWays(w);
2427
+ if (w && w.phoneChannels.length > 0 && !w.phoneChannels.includes(channel)) setChannel(w.phoneChannels[0]);
2428
+ });
2429
+ (0, import_react8.useEffect)(() => {
2430
+ void load();
2431
+ }, []);
2432
+ if (!ways || ways.phoneChannels.length === 0) return null;
2433
+ const add = async (e) => {
2434
+ e.preventDefault();
2435
+ const r = await run(() => auth.account.mfa.addPhone({ phone: number, channel, password }));
2436
+ if (r.ok) setSentTo(r.sentTo);
2437
+ };
2438
+ const confirm = async (e) => {
2439
+ e.preventDefault();
2440
+ const r = await run(() => auth.account.mfa.verifyPhone({ code }));
2441
+ if (!r.ok) return;
2442
+ setSentTo("");
2443
+ setCode("");
2444
+ setPassword("");
2445
+ setNumber("");
2446
+ if (r.recoveryCodes.length > 0) setCodes(r.recoveryCodes);
2447
+ onChanged(true);
2448
+ props.onSaved?.({ kind: "phone.added", channel });
2449
+ await load();
2450
+ };
2451
+ const remove = async (key) => {
2452
+ const r = await run(() => auth.account.mfa.removePhone({ password }), key);
2453
+ if (!r.ok) return;
2454
+ setPassword("");
2455
+ setRemoving(false);
2456
+ setCodes(null);
2457
+ await load();
2458
+ const left = await auth.account.mfa.factors();
2459
+ onChanged(Boolean(left?.totp));
2460
+ props.onSaved?.({ kind: "phone.removed" });
2461
+ };
2462
+ const press = () => {
2463
+ f.setError(null);
2464
+ if (!account.hasPassword) return void remove("remove");
2465
+ setPassword("");
2466
+ setRemoving(true);
2467
+ };
2468
+ const cancel = () => {
2469
+ setPassword("");
2470
+ f.setError(null);
2471
+ setRemoving(false);
2472
+ };
2473
+ const passwordField = account.hasPassword && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword });
2474
+ if (sentTo) {
2475
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "section", section: "phone", onSubmit: confirm, noValidate: true, children: [
2476
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.phone }),
2477
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.codeSent.replace("{to}", sentTo) }),
2478
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2479
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
2480
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.verify })
2481
+ ] });
2482
+ }
2483
+ if (ways.phone) {
2484
+ const by = ways.phone.channel === "whatsapp" ? f.t.byWhatsapp : ways.phone.channel === "sms" ? f.t.bySms : "";
2485
+ const on = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Note, { f, children: [
2486
+ f.t.phoneOn.replace("{to}", ways.phone.number),
2487
+ by && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Tag, { f, plain: ` \xB7 ${by}`, children: by })
2488
+ ] });
2489
+ if (removing) {
2490
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "section", section: "phone", onSubmit: (e) => {
2491
+ e.preventDefault();
2492
+ void remove(SUBMIT);
2493
+ }, noValidate: true, children: [
2494
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.phone }),
2495
+ on,
2496
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2497
+ passwordField,
2498
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "danger", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.removePhone }),
2499
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Cancel, { f, onClick: cancel })
2500
+ ] });
2501
+ }
2502
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "div", slot: "section", section: "phone", children: [
2503
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.phone }),
2504
+ on,
2505
+ codes && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RecoveryCodes, { f, codes }),
2506
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2507
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading("remove"), disabled: f.busy, className: f.cx("button"), onClick: press, children: f.t.removePhone })
2508
+ ] });
2509
+ }
2510
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "form", slot: "section", section: "phone", onSubmit: add, noValidate: true, children: [
2511
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.phone }),
2512
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: `${f.t.phoneOff} ${f.t.phoneHelp}` }),
2513
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2514
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Field, { f, name: "phone", type: "tel", label: f.t.phone, value: number, autoComplete: "tel", required: true, onChange: setNumber }),
2515
+ ways.phoneChannels.length > 1 && f.C.Select && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChannelPick, { f, value: channel, channels: ways.phoneChannels, onChange: setChannel }),
2516
+ ways.phoneChannels.length > 1 && !f.C.Select && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: f.cx("field"), role: "radiogroup", children: ways.phoneChannels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: f.cx("label"), children: [
2517
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "radio", name: "channel", value: c, checked: channel === c, disabled: f.busy, onChange: () => setChannel(c) }),
2518
+ " ",
2519
+ c === "whatsapp" ? f.t.byWhatsapp : f.t.bySms
2520
+ ] }, c)) }),
2521
+ passwordField,
2522
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.addPhone })
2523
+ ] });
2524
+ }
2525
+ function AgentsPart({ props, when }) {
2526
+ const auth = useAuth();
2527
+ const { f, run, general } = useSection(props);
2528
+ const [list, setList] = (0, import_react8.useState)([]);
2529
+ (0, import_react8.useEffect)(() => {
2530
+ void auth.account.agents().then(setList);
2531
+ }, []);
2532
+ if (list.length === 0) return null;
2533
+ const disconnect = async (id) => {
2534
+ const r = await run(() => auth.account.disconnectAgent(id), `disconnect:${id}`);
2535
+ if (!r.ok) return;
2536
+ setList(list.filter((a) => a.id !== id));
2537
+ props.onSaved?.({ kind: "agent.disconnected", id });
2538
+ };
2539
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "section", slot: "section", section: "agents", children: [
2540
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.agents }),
2541
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { f, children: f.t.agentsHelp }),
2542
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2543
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: f.cx("sessions"), children: list.map((a) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: f.cx("session"), children: [
2544
+ a.name || f.t.anAgent,
2545
+ a.redirectHost ? ` (${a.redirectHost})` : "",
2546
+ " \u2192 ",
2547
+ a.resource.name,
2548
+ a.scopes.length > 0 ? ` \xB7 ${a.scopes.map((s) => s.description || s.name).join(", ")}` : "",
2549
+ " \xB7 ",
2550
+ when(a.lastUsedAt),
2551
+ " ",
2552
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading(`disconnect:${a.id}`), disabled: f.busy, className: f.cx("providerButton"), onClick: () => void disconnect(a.id), children: f.t.disconnect })
2553
+ ] }, a.id)) })
2554
+ ] });
2555
+ }
2556
+ function SessionsPart({ props, when }) {
2557
+ const auth = useAuth();
2558
+ const { f, run, general } = useSection(props);
2559
+ const [sessions, setSessions] = (0, import_react8.useState)([]);
2560
+ (0, import_react8.useEffect)(() => {
2561
+ void auth.account.sessions().then(setSessions);
2562
+ }, []);
2563
+ const end = async () => {
2564
+ const r = await run(() => auth.account.signOutEverywhere(), SUBMIT, true);
2565
+ if (!r.ok) return;
2566
+ props.onSaved?.({ kind: "sessions.ended" });
2567
+ if (props.onSignedOut) f.hold(props.onSignedOut());
2568
+ else window.location.assign("/");
2569
+ };
2570
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Wrap, { f, as: "section", slot: "section", section: "sessions", children: [
2571
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Heading, { f, children: f.t.sessions }),
2572
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { className: f.cx("sessions"), children: sessions.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: f.cx("session"), children: [
2573
+ s.device || f.t.unknownDevice,
2574
+ " \xB7 ",
2575
+ s.ip,
2576
+ " \xB7 ",
2577
+ when(s.createdAt)
2578
+ ] }, i)) }),
2579
+ general && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
2580
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading(), disabled: f.busy, className: f.cx("button"), onClick: () => void end(), children: f.t.signOutEverywhere })
2581
+ ] });
2582
+ }
2583
+ function ChannelPick({ f, value, channels, onChange }) {
2584
+ const id = (0, import_react8.useId)();
2585
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Labelled, { f, id, label: f.t.channel, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2586
+ Pick,
2587
+ {
2588
+ f,
2589
+ id,
2590
+ name: "channel",
2591
+ value,
2592
+ options: channels.map((c) => ({ value: c, label: c === "whatsapp" ? f.t.byWhatsapp : f.t.bySms })),
2593
+ onChange: (c) => onChange(c)
2594
+ }
2595
+ ) });
2596
+ }
2597
+
2598
+ // src/organizations-view.tsx
2599
+ var import_jsx_runtime4 = require("react/jsx-runtime");
2600
+ var TEXTS3 = {
2601
+ en: { title: "Your organizations", none: "You do not belong to any organization yet.", loading: "Loading your organizations\u2026", failed: "Your organizations could not be loaded.", retry: "Try again" },
2602
+ es: { title: "Tus organizaciones", none: "Todav\xEDa no perteneces a ninguna organizaci\xF3n.", loading: "Cargando tus organizaciones\u2026", failed: "No se pudieron cargar tus organizaciones.", retry: "Intentar de nuevo" }
2603
+ };
2604
+ function Organizations(props) {
2605
+ const { system, defaultOrganizationId, onSelect, showMembers, listClassNames, ...members } = props;
2606
+ const { organizations, loading, error, reload } = useOrganizations({ system });
2607
+ const [picked, setPicked] = (0, import_react10.useState)(defaultOrganizationId ?? null);
2608
+ const heading = (0, import_react10.useId)();
2609
+ const look = useThemeVariables();
2610
+ const t = TEXTS3[props.locale ?? "en"];
2611
+ const cx = (part) => listClassNames?.[part] ?? (props.unstyled ? void 0 : `cauthy-${part}`);
2612
+ const root = props.unstyled ? {} : { "data-cauthy": "", style: look };
2613
+ const current = organizations.find((o) => o.id === picked) ?? organizations[0] ?? null;
2614
+ if (loading && organizations.length === 0) {
2615
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { className: cx("organizations"), ...root, "aria-busy": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: cx("notice"), role: "status", children: t.loading }) });
2616
+ }
2617
+ if (error && organizations.length === 0) {
2618
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: cx("organizations"), ...root, "aria-busy": loading || void 0, children: [
2619
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: cx("error"), role: "alert", "aria-live": "assertive", "aria-atomic": "true", children: t.failed }),
2620
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: cx("retry"), disabled: loading, onClick: () => void reload(), children: t.retry })
2621
+ ] });
2622
+ }
2623
+ if (organizations.length === 0) {
2624
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { className: cx("organizations"), ...root, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: cx("notice"), children: t.none }) });
2625
+ }
2626
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: cx("organizations"), ...root, "aria-labelledby": heading, children: [
2627
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { id: heading, className: cx("heading"), children: t.title }),
2628
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: cx("organizationList"), children: organizations.map((o) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2629
+ "button",
2630
+ {
2631
+ type: "button",
2632
+ className: cx("organization"),
2633
+ "aria-current": o.id === current?.id ? "true" : void 0,
2634
+ onClick: () => {
2635
+ setPicked(o.id);
2636
+ onSelect?.(o);
2637
+ },
2638
+ children: [
2639
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: o.name }),
2640
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: cx("organizationRole"), children: o.role })
2641
+ ]
2642
+ }
2643
+ ) }, o.id)) }),
2644
+ showMembers !== false && current && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(OrganizationMembers, { ...members, organizationId: current.id }, current.id)
2645
+ ] });
2646
+ }
2647
+
2648
+ // src/index.ts
2649
+ var import_js5 = require("@cauthyhq/js");
2650
+ var import_theme3 = require("@cauthyhq/js/theme");
2651
+ // Annotate the CommonJS export names for ESM import in node:
2652
+ 0 && (module.exports = {
2653
+ AcceptInvite,
2654
+ Account,
2655
+ AccountAgents,
2656
+ AccountEmail,
2657
+ AccountLinked,
2658
+ AccountPasskeys,
2659
+ AccountPassword,
2660
+ AccountPhone,
2661
+ AccountProfile,
2662
+ AccountSecondStep,
2663
+ AccountSessions,
2664
+ CauthyError,
2665
+ CauthyProvider,
2666
+ ForgotPassword,
2667
+ GoogleOneTap,
2668
+ OrganizationMembers,
2669
+ Organizations,
2670
+ PendingTerms,
2671
+ ResetPassword,
2672
+ SignIn,
2673
+ SignUp,
2674
+ UserButton,
2675
+ VerifyEmail,
2676
+ can,
2677
+ canAutofillPasskeys,
2678
+ canUsePasskeys,
2679
+ createAuthClient,
2680
+ createSessionStore,
2681
+ createSignInFlow,
2682
+ definePolicy,
2683
+ initialsOf,
2684
+ themeFromCss,
2685
+ themeFromStackmyth,
2686
+ themeVariables,
2687
+ tokensFromStackmyth,
2688
+ unwrap,
2689
+ useAuth,
2690
+ useOrganizations,
2691
+ useSession,
2692
+ useSignInFlow
2693
+ });
2694
+ //# sourceMappingURL=index.js.map