@authowl/react 0.21.2 → 0.22.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/captcha-loader-VNULARCZ.js +68 -0
- package/dist/captcha-providers-STYFL25P.js +71 -0
- package/dist/index.cjs +389 -245
- package/dist/index.js +210 -220
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -356,104 +356,19 @@ function PasskeyButton({ redirectTo, onSignedIn }) {
|
|
|
356
356
|
}
|
|
357
357
|
|
|
358
358
|
// src/components/ForgotPassword.tsx
|
|
359
|
-
import * as React5 from "react";
|
|
360
|
-
|
|
361
|
-
// src/components/AuthChallenge.tsx
|
|
362
359
|
import * as React4 from "react";
|
|
363
360
|
|
|
364
|
-
// src/components/
|
|
361
|
+
// src/components/AuthChallenge.tsx
|
|
365
362
|
import * as React3 from "react";
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
var
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
function loadTurnstile() {
|
|
372
|
-
if (window.turnstile) return Promise.resolve(window.turnstile);
|
|
373
|
-
if (loader) return loader;
|
|
374
|
-
loader = new Promise((resolve, reject) => {
|
|
375
|
-
const existing = document.querySelector(`script[src="${SCRIPT_URL}"]`);
|
|
376
|
-
const script = existing ?? document.createElement("script");
|
|
377
|
-
const cleanup = () => {
|
|
378
|
-
clearTimeout(timeout);
|
|
379
|
-
script.removeEventListener("load", loaded);
|
|
380
|
-
script.removeEventListener("error", failed);
|
|
381
|
-
};
|
|
382
|
-
const loaded = () => {
|
|
383
|
-
cleanup();
|
|
384
|
-
if (window.turnstile) {
|
|
385
|
-
resolve(window.turnstile);
|
|
386
|
-
} else {
|
|
387
|
-
reject(new Error("Turnstile unavailable"));
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
const failed = () => {
|
|
391
|
-
cleanup();
|
|
392
|
-
if (!existing) script.remove();
|
|
393
|
-
reject(new Error("Turnstile failed to load"));
|
|
394
|
-
};
|
|
395
|
-
const timeout = setTimeout(failed, SCRIPT_LOAD_TIMEOUT_MS);
|
|
396
|
-
script.addEventListener("load", loaded, { once: true });
|
|
397
|
-
script.addEventListener("error", failed, { once: true });
|
|
398
|
-
if (!existing) {
|
|
399
|
-
script.src = SCRIPT_URL;
|
|
400
|
-
script.async = true;
|
|
401
|
-
script.defer = true;
|
|
402
|
-
const nonce = document.querySelector("script[nonce]")?.nonce;
|
|
403
|
-
if (nonce) script.nonce = nonce;
|
|
404
|
-
document.head.appendChild(script);
|
|
405
|
-
}
|
|
406
|
-
}).catch((error) => {
|
|
407
|
-
loader = null;
|
|
408
|
-
throw error;
|
|
409
|
-
});
|
|
410
|
-
return loader;
|
|
411
|
-
}
|
|
412
|
-
function Turnstile({
|
|
413
|
-
siteKey,
|
|
414
|
-
theme,
|
|
415
|
-
onToken,
|
|
416
|
-
onUnavailable
|
|
417
|
-
}) {
|
|
418
|
-
const container = React3.useRef(null);
|
|
419
|
-
const callbacks = React3.useRef({ onToken, onUnavailable });
|
|
420
|
-
callbacks.current = { onToken, onUnavailable };
|
|
421
|
-
React3.useEffect(() => {
|
|
422
|
-
callbacks.current.onToken(null);
|
|
423
|
-
if (!siteKey) {
|
|
424
|
-
callbacks.current.onToken(LOCAL_TURNSTILE_TEST_TOKEN);
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
let active = true;
|
|
428
|
-
let widget = null;
|
|
429
|
-
void loadTurnstile().then((api) => {
|
|
430
|
-
if (!active || !container.current) return;
|
|
431
|
-
const id = api.render(container.current, {
|
|
432
|
-
sitekey: siteKey,
|
|
433
|
-
theme: theme === "system" ? "auto" : theme,
|
|
434
|
-
size: "flexible",
|
|
435
|
-
callback: (token) => callbacks.current.onToken(token),
|
|
436
|
-
"expired-callback": () => callbacks.current.onToken(null),
|
|
437
|
-
"error-callback": () => {
|
|
438
|
-
callbacks.current.onToken(null);
|
|
439
|
-
callbacks.current.onUnavailable();
|
|
440
|
-
}
|
|
441
|
-
});
|
|
442
|
-
widget = { api, id };
|
|
443
|
-
}).catch(() => {
|
|
444
|
-
if (active) callbacks.current.onUnavailable();
|
|
445
|
-
});
|
|
446
|
-
return () => {
|
|
447
|
-
active = false;
|
|
448
|
-
if (widget) widget.api.remove(widget.id);
|
|
449
|
-
};
|
|
450
|
-
}, [siteKey, theme]);
|
|
451
|
-
if (!siteKey) return null;
|
|
452
|
-
return /* @__PURE__ */ jsx4("div", { className: "ba-turnstile", ref: container, "data-testid": "phoneotp-turnstile" });
|
|
363
|
+
|
|
364
|
+
// src/components/captcha-provider-ids.ts
|
|
365
|
+
var CAPTCHA_PROVIDER_IDS = ["turnstile", "hcaptcha", "recaptcha-v2"];
|
|
366
|
+
function isSupportedCaptchaProvider(provider) {
|
|
367
|
+
return CAPTCHA_PROVIDER_IDS.includes(provider);
|
|
453
368
|
}
|
|
454
369
|
|
|
455
370
|
// src/components/AuthChallenge.tsx
|
|
456
|
-
import { jsx as
|
|
371
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
457
372
|
var AUTH_CHALLENGE_ACTIONS = {
|
|
458
373
|
signUp: "auth_signup",
|
|
459
374
|
signIn: "auth_signin",
|
|
@@ -468,38 +383,53 @@ var challengeError = {
|
|
|
468
383
|
code: "BOT_CHALLENGE_FAILED",
|
|
469
384
|
message: "Human verification failed."
|
|
470
385
|
};
|
|
471
|
-
function
|
|
386
|
+
function captchaTheme(root, fallback) {
|
|
472
387
|
const rendered = root?.dataset.authowlTheme;
|
|
473
388
|
if (rendered === "light" || rendered === "dark") return rendered;
|
|
474
389
|
if (fallback === "light" || fallback === "dark") return fallback;
|
|
475
390
|
return "auto";
|
|
476
391
|
}
|
|
477
392
|
function useAuthChallenge() {
|
|
478
|
-
const { config, isLoading } = usePublicConfig();
|
|
393
|
+
const { config, isLoading, retry } = usePublicConfig();
|
|
479
394
|
const t = useT();
|
|
480
|
-
const container =
|
|
481
|
-
const active =
|
|
482
|
-
const [status, setStatus] =
|
|
483
|
-
const
|
|
484
|
-
const
|
|
395
|
+
const container = React3.useRef(null);
|
|
396
|
+
const active = React3.useRef(null);
|
|
397
|
+
const [status, setStatus] = React3.useState("idle");
|
|
398
|
+
const captcha = config?.captcha ?? null;
|
|
399
|
+
const providerSupported = captcha ? isSupportedCaptchaProvider(captcha.provider) : false;
|
|
400
|
+
const unavailableProvider = captcha && !providerSupported ? captcha.provider : null;
|
|
401
|
+
const refetched = React3.useRef(null);
|
|
402
|
+
const refetchIfConfigMayBeStale = React3.useCallback(() => {
|
|
403
|
+
if (!config || refetched.current === config) return;
|
|
404
|
+
refetched.current = config;
|
|
405
|
+
retry();
|
|
406
|
+
}, [config, retry]);
|
|
407
|
+
const removeActive = React3.useCallback((reason) => {
|
|
485
408
|
const current = active.current;
|
|
486
409
|
active.current = null;
|
|
487
410
|
if (!current) return;
|
|
488
|
-
current.
|
|
411
|
+
current.adapter.teardown(current.api, current.id);
|
|
489
412
|
if (reason) current.reject(reason);
|
|
490
413
|
}, []);
|
|
491
|
-
|
|
492
|
-
() => () => removeActive(new Error("
|
|
414
|
+
React3.useEffect(
|
|
415
|
+
() => () => removeActive(new Error("Captcha challenge was cancelled")),
|
|
493
416
|
[removeActive]
|
|
494
417
|
);
|
|
495
|
-
const tokenFor =
|
|
418
|
+
const tokenFor = React3.useCallback(
|
|
496
419
|
async (action) => {
|
|
497
|
-
if (!
|
|
420
|
+
if (!captcha) return null;
|
|
421
|
+
if (!providerSupported) throw new Error(`Unsupported captcha provider: ${captcha.provider}`);
|
|
498
422
|
setStatus("checking");
|
|
499
|
-
removeActive(new Error("
|
|
423
|
+
removeActive(new Error("Captcha challenge was replaced"));
|
|
500
424
|
try {
|
|
501
|
-
const
|
|
502
|
-
|
|
425
|
+
const [{ loadCaptcha }, { captchaAdapterFor }] = await Promise.all([
|
|
426
|
+
import("./captcha-loader-VNULARCZ.js"),
|
|
427
|
+
import("./captcha-providers-STYFL25P.js")
|
|
428
|
+
]);
|
|
429
|
+
const adapter = captchaAdapterFor(captcha.provider);
|
|
430
|
+
if (!adapter) throw new Error(`Unsupported captcha provider: ${captcha.provider}`);
|
|
431
|
+
const api = await loadCaptcha(adapter);
|
|
432
|
+
if (!container.current) throw new Error("Captcha container unavailable");
|
|
503
433
|
return await new Promise((resolve, reject) => {
|
|
504
434
|
let settled = false;
|
|
505
435
|
const finish = (outcome) => {
|
|
@@ -507,27 +437,29 @@ function useAuthChallenge() {
|
|
|
507
437
|
settled = true;
|
|
508
438
|
const current = active.current;
|
|
509
439
|
active.current = null;
|
|
510
|
-
if (current) current.
|
|
440
|
+
if (current) current.adapter.teardown(current.api, current.id);
|
|
511
441
|
if ("token" in outcome) resolve(outcome.token);
|
|
512
442
|
else reject(outcome.error);
|
|
513
443
|
};
|
|
514
|
-
const fail = () => finish({ error: new Error("
|
|
444
|
+
const fail = () => finish({ error: new Error("Captcha challenge failed") });
|
|
515
445
|
const root = container.current.closest(".authowl-root");
|
|
446
|
+
const optionalFailureCallbacks = captcha.provider === "turnstile" ? {
|
|
447
|
+
"timeout-callback": fail,
|
|
448
|
+
"unsupported-callback": fail
|
|
449
|
+
} : {};
|
|
516
450
|
const id = api.render(container.current, {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
language: root?.dataset.authowlLocale ?? config?.locale,
|
|
451
|
+
...adapter.invisibleRenderOptions({
|
|
452
|
+
siteKey: captcha.siteKey,
|
|
453
|
+
theme: captchaTheme(root, config?.branding?.theme),
|
|
454
|
+
action,
|
|
455
|
+
language: root?.dataset.authowlLocale ?? config?.locale
|
|
456
|
+
}),
|
|
524
457
|
callback: (token) => finish({ token }),
|
|
525
458
|
"expired-callback": fail,
|
|
526
459
|
"error-callback": fail,
|
|
527
|
-
|
|
528
|
-
"unsupported-callback": fail
|
|
460
|
+
...optionalFailureCallbacks
|
|
529
461
|
});
|
|
530
|
-
active.current = { api, id, reject };
|
|
462
|
+
active.current = { adapter, api, id, reject };
|
|
531
463
|
try {
|
|
532
464
|
api.execute(id);
|
|
533
465
|
} catch {
|
|
@@ -538,9 +470,9 @@ function useAuthChallenge() {
|
|
|
538
470
|
setStatus("idle");
|
|
539
471
|
}
|
|
540
472
|
},
|
|
541
|
-
[config?.branding?.theme, config?.locale,
|
|
473
|
+
[captcha, config?.branding?.theme, config?.locale, providerSupported, removeActive]
|
|
542
474
|
);
|
|
543
|
-
const run =
|
|
475
|
+
const run = React3.useCallback(
|
|
544
476
|
async (action, request) => {
|
|
545
477
|
if (isLoading) {
|
|
546
478
|
return {
|
|
@@ -550,37 +482,40 @@ function useAuthChallenge() {
|
|
|
550
482
|
}
|
|
551
483
|
try {
|
|
552
484
|
const token = await tokenFor(action);
|
|
553
|
-
|
|
485
|
+
const result = await request(token ? { authChallengeToken: token } : void 0);
|
|
486
|
+
if (result?.error?.code === challengeError.code) refetchIfConfigMayBeStale();
|
|
487
|
+
return result;
|
|
554
488
|
} catch {
|
|
555
489
|
setStatus("failed");
|
|
490
|
+
refetchIfConfigMayBeStale();
|
|
556
491
|
return {
|
|
557
492
|
data: null,
|
|
558
493
|
error: challengeError
|
|
559
494
|
};
|
|
560
495
|
}
|
|
561
496
|
},
|
|
562
|
-
[isLoading, tokenFor]
|
|
497
|
+
[isLoading, refetchIfConfigMayBeStale, tokenFor]
|
|
563
498
|
);
|
|
564
|
-
const control =
|
|
565
|
-
/* @__PURE__ */
|
|
566
|
-
/* @__PURE__ */
|
|
499
|
+
const control = captcha ? /* @__PURE__ */ jsxs4("div", { className: "ba-auth-challenge", "data-testid": "auth-challenge", children: [
|
|
500
|
+
providerSupported ? /* @__PURE__ */ jsx4("div", { className: "ba-turnstile", ref: container }) : null,
|
|
501
|
+
unavailableProvider ? /* @__PURE__ */ jsx4(FormError, { "data-testid": "auth-challenge-unsupported", children: t("authChallenge.error.unsupportedProvider", { provider: unavailableProvider }) }) : /* @__PURE__ */ jsx4("p", { className: "ba-sr-only", role: "status", "aria-live": "polite", children: status === "checking" ? t("authChallenge.checking") : status === "failed" ? t("authChallenge.error.failed") : "" })
|
|
567
502
|
] }) : null;
|
|
568
503
|
return { run, control, configPending: isLoading };
|
|
569
504
|
}
|
|
570
505
|
|
|
571
506
|
// src/components/ForgotPassword.tsx
|
|
572
|
-
import { jsx as
|
|
507
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
573
508
|
function ForgotPassword({ resetPasswordUrl, onBack }) {
|
|
574
509
|
const t = useT();
|
|
575
510
|
const { requestPasswordReset } = usePasswordReset();
|
|
576
511
|
const { pending, error, run } = useSubmitAction();
|
|
577
512
|
const authChallenge = useAuthChallenge();
|
|
578
|
-
const [email, setEmail] =
|
|
579
|
-
const [sent, setSent] =
|
|
513
|
+
const [email, setEmail] = React4.useState("");
|
|
514
|
+
const [sent, setSent] = React4.useState(false);
|
|
580
515
|
if (sent) {
|
|
581
516
|
return /* @__PURE__ */ jsxs5("div", { className: "ba-fields", "data-testid": "forgot-sent", children: [
|
|
582
|
-
/* @__PURE__ */
|
|
583
|
-
onBack && /* @__PURE__ */
|
|
517
|
+
/* @__PURE__ */ jsx5("p", { className: "ba-muted", children: richMessage(t("forgotPassword.sent"), { email: /* @__PURE__ */ jsx5(Bidi, { children: email }) }) }),
|
|
518
|
+
onBack && /* @__PURE__ */ jsx5("button", { type: "button", className: "ba-link-button", onClick: onBack, children: t("forgotPassword.backToSignIn") })
|
|
584
519
|
] });
|
|
585
520
|
}
|
|
586
521
|
return /* @__PURE__ */ jsxs5(
|
|
@@ -599,7 +534,7 @@ function ForgotPassword({ resetPasswordUrl, onBack }) {
|
|
|
599
534
|
children: [
|
|
600
535
|
/* @__PURE__ */ jsxs5("label", { className: "ba-label", children: [
|
|
601
536
|
t("common.emailLabel"),
|
|
602
|
-
/* @__PURE__ */
|
|
537
|
+
/* @__PURE__ */ jsx5(
|
|
603
538
|
"input",
|
|
604
539
|
{
|
|
605
540
|
className: "ba-input",
|
|
@@ -612,25 +547,25 @@ function ForgotPassword({ resetPasswordUrl, onBack }) {
|
|
|
612
547
|
)
|
|
613
548
|
] }),
|
|
614
549
|
authChallenge.control,
|
|
615
|
-
/* @__PURE__ */
|
|
616
|
-
/* @__PURE__ */
|
|
550
|
+
/* @__PURE__ */ jsx5(FormError, { children: error }),
|
|
551
|
+
/* @__PURE__ */ jsx5(
|
|
617
552
|
"button",
|
|
618
553
|
{
|
|
619
554
|
className: "ba-button",
|
|
620
555
|
type: "submit",
|
|
621
556
|
disabled: pending || authChallenge.configPending,
|
|
622
557
|
"aria-busy": pending || void 0,
|
|
623
|
-
children: /* @__PURE__ */
|
|
558
|
+
children: /* @__PURE__ */ jsx5(Busy, { busy: pending, label: t("common.sending"), children: t("forgotPassword.submit") })
|
|
624
559
|
}
|
|
625
560
|
),
|
|
626
|
-
onBack && /* @__PURE__ */
|
|
561
|
+
onBack && /* @__PURE__ */ jsx5("button", { type: "button", className: "ba-link-button", onClick: onBack, children: t("forgotPassword.backToSignIn") })
|
|
627
562
|
]
|
|
628
563
|
}
|
|
629
564
|
);
|
|
630
565
|
}
|
|
631
566
|
|
|
632
567
|
// src/components/OtpCodeForm.tsx
|
|
633
|
-
import { jsx as
|
|
568
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
634
569
|
function OtpCodeForm({
|
|
635
570
|
email,
|
|
636
571
|
code,
|
|
@@ -653,8 +588,8 @@ function OtpCodeForm({
|
|
|
653
588
|
},
|
|
654
589
|
children: [
|
|
655
590
|
/* @__PURE__ */ jsxs6("label", { className: "ba-label", children: [
|
|
656
|
-
richMessage(t("emailOtp.codeLabel"), { email: /* @__PURE__ */
|
|
657
|
-
/* @__PURE__ */
|
|
591
|
+
richMessage(t("emailOtp.codeLabel"), { email: /* @__PURE__ */ jsx6(Bidi, { children: email }) }),
|
|
592
|
+
/* @__PURE__ */ jsx6(
|
|
658
593
|
"input",
|
|
659
594
|
{
|
|
660
595
|
className: "ba-input",
|
|
@@ -667,24 +602,24 @@ function OtpCodeForm({
|
|
|
667
602
|
}
|
|
668
603
|
)
|
|
669
604
|
] }),
|
|
670
|
-
/* @__PURE__ */
|
|
671
|
-
/* @__PURE__ */
|
|
672
|
-
/* @__PURE__ */
|
|
605
|
+
/* @__PURE__ */ jsx6(FormError, { children: error }),
|
|
606
|
+
/* @__PURE__ */ jsx6("button", { className: "ba-button", type: "submit", disabled: pending, "aria-busy": pending || void 0, children: /* @__PURE__ */ jsx6(Busy, { busy: pending, label: t("common.verifying"), children: t("emailOtp.verifySubmit") }) }),
|
|
607
|
+
/* @__PURE__ */ jsx6("button", { type: "button", className: "ba-link-button", onClick: onChangeEmail, children: t("emailOtp.changeEmail") })
|
|
673
608
|
]
|
|
674
609
|
}
|
|
675
610
|
);
|
|
676
611
|
}
|
|
677
612
|
|
|
678
613
|
// src/components/MFAChallenge.tsx
|
|
679
|
-
import * as
|
|
680
|
-
import { jsx as
|
|
614
|
+
import * as React5 from "react";
|
|
615
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
681
616
|
function MFAChallenge({ onVerified, allowTrustDevice = true }) {
|
|
682
617
|
const t = useT();
|
|
683
618
|
const { verifyTotp, verifyBackupCode, sendOtp, verifyOtp } = useMFA();
|
|
684
619
|
const { pending, error, setError, run } = useSubmitAction();
|
|
685
|
-
const [mode, setMode] =
|
|
686
|
-
const [code, setCode] =
|
|
687
|
-
const [trustDevice, setTrustDevice] =
|
|
620
|
+
const [mode, setMode] = React5.useState("totp");
|
|
621
|
+
const [code, setCode] = React5.useState("");
|
|
622
|
+
const [trustDevice, setTrustDevice] = React5.useState(false);
|
|
688
623
|
const switchMode = (next) => {
|
|
689
624
|
setMode(next);
|
|
690
625
|
setCode("");
|
|
@@ -708,11 +643,11 @@ function MFAChallenge({ onVerified, allowTrustDevice = true }) {
|
|
|
708
643
|
const hint = mode === "totp" ? t("mfa.challenge.totpHint") : mode === "backup" ? t("mfa.challenge.backupHint") : t("mfa.challenge.otpHint");
|
|
709
644
|
const label2 = mode === "totp" ? t("mfa.challenge.totpLabel") : mode === "backup" ? t("mfa.challenge.backupLabel") : t("mfa.challenge.otpLabel");
|
|
710
645
|
return /* @__PURE__ */ jsxs7("form", { method: "post", className: "ba-fields", "data-testid": "mfa-challenge", onSubmit: submit, children: [
|
|
711
|
-
/* @__PURE__ */
|
|
712
|
-
/* @__PURE__ */
|
|
646
|
+
/* @__PURE__ */ jsx7("h2", { className: "ba-title", children: t("mfa.challenge.title") }),
|
|
647
|
+
/* @__PURE__ */ jsx7("p", { className: "ba-muted", children: hint }),
|
|
713
648
|
/* @__PURE__ */ jsxs7("label", { className: "ba-label", children: [
|
|
714
649
|
label2,
|
|
715
|
-
/* @__PURE__ */
|
|
650
|
+
/* @__PURE__ */ jsx7(
|
|
716
651
|
"input",
|
|
717
652
|
{
|
|
718
653
|
className: "ba-input",
|
|
@@ -730,24 +665,24 @@ function MFAChallenge({ onVerified, allowTrustDevice = true }) {
|
|
|
730
665
|
] }),
|
|
731
666
|
mode !== "backup" && allowTrustDevice && /* @__PURE__ */ jsxs7("label", { className: "ba-consent ba-consent-centered", children: [
|
|
732
667
|
/* @__PURE__ */ jsxs7("span", { className: "ba-checkbox-control", children: [
|
|
733
|
-
/* @__PURE__ */
|
|
734
|
-
/* @__PURE__ */
|
|
668
|
+
/* @__PURE__ */ jsx7("input", { className: "ba-checkbox", type: "checkbox", checked: trustDevice, onChange: (e) => setTrustDevice(e.target.checked) }),
|
|
669
|
+
/* @__PURE__ */ jsx7("span", { className: "ba-checkbox-visual", "aria-hidden": "true", children: /* @__PURE__ */ jsx7("span", { className: "ba-checkbox-check" }) })
|
|
735
670
|
] }),
|
|
736
|
-
/* @__PURE__ */
|
|
671
|
+
/* @__PURE__ */ jsx7("span", { children: t("mfa.challenge.trustDevice", { days: 30 }) })
|
|
737
672
|
] }),
|
|
738
|
-
/* @__PURE__ */
|
|
739
|
-
/* @__PURE__ */
|
|
740
|
-
mode !== "totp" && /* @__PURE__ */
|
|
741
|
-
mode !== "backup" && /* @__PURE__ */
|
|
742
|
-
/* @__PURE__ */
|
|
673
|
+
/* @__PURE__ */ jsx7(FormError, { children: error }),
|
|
674
|
+
/* @__PURE__ */ jsx7("button", { className: "ba-button", type: "submit", disabled: pending || !code, "aria-busy": pending || void 0, children: /* @__PURE__ */ jsx7(Busy, { busy: pending, label: t("common.verifying"), children: t("mfa.challenge.submit") }) }),
|
|
675
|
+
mode !== "totp" && /* @__PURE__ */ jsx7("button", { type: "button", className: "ba-link-button", onClick: () => switchMode("totp"), children: t("mfa.challenge.useTotp") }),
|
|
676
|
+
mode !== "backup" && /* @__PURE__ */ jsx7("button", { type: "button", className: "ba-link-button", onClick: () => switchMode("backup"), children: t("mfa.challenge.useBackup") }),
|
|
677
|
+
/* @__PURE__ */ jsx7("button", { type: "button", className: "ba-link-button", disabled: pending, onClick: requestOtp, children: t(mode === "otp" ? "mfa.challenge.resendOtp" : "mfa.challenge.useEmailOtp") })
|
|
743
678
|
] });
|
|
744
679
|
}
|
|
745
680
|
|
|
746
681
|
// src/components/mfa-enrollment-step.tsx
|
|
747
|
-
import * as
|
|
682
|
+
import * as React8 from "react";
|
|
748
683
|
|
|
749
684
|
// src/components/MFAEnrollment.tsx
|
|
750
|
-
import * as
|
|
685
|
+
import * as React7 from "react";
|
|
751
686
|
|
|
752
687
|
// src/components/mfa-enrollment.ts
|
|
753
688
|
function shouldDiscardSetup(args) {
|
|
@@ -756,12 +691,12 @@ function shouldDiscardSetup(args) {
|
|
|
756
691
|
}
|
|
757
692
|
|
|
758
693
|
// src/components/QrCode.tsx
|
|
759
|
-
import * as
|
|
760
|
-
import { jsx as
|
|
694
|
+
import * as React6 from "react";
|
|
695
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
761
696
|
function QrCode({ value, size = 200 }) {
|
|
762
697
|
const t = useT();
|
|
763
|
-
const [path, setPath] =
|
|
764
|
-
|
|
698
|
+
const [path, setPath] = React6.useState(null);
|
|
699
|
+
React6.useEffect(() => {
|
|
765
700
|
let active = true;
|
|
766
701
|
setPath(null);
|
|
767
702
|
void import("./qr-ZNG4MAV5.js").then(
|
|
@@ -790,15 +725,15 @@ function QrCode({ value, size = 200 }) {
|
|
|
790
725
|
shapeRendering: "crispEdges",
|
|
791
726
|
className: "ba-qr",
|
|
792
727
|
children: [
|
|
793
|
-
/* @__PURE__ */
|
|
794
|
-
/* @__PURE__ */
|
|
728
|
+
/* @__PURE__ */ jsx8("rect", { width: dim, height: dim, fill: "#ffffff" }),
|
|
729
|
+
/* @__PURE__ */ jsx8("g", { transform: `translate(${margin} ${margin})`, children: /* @__PURE__ */ jsx8("path", { d: path.d, fill: "#000000" }) })
|
|
795
730
|
]
|
|
796
731
|
}
|
|
797
732
|
);
|
|
798
733
|
}
|
|
799
734
|
|
|
800
735
|
// src/components/MFAEnrollment.tsx
|
|
801
|
-
import { jsx as
|
|
736
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
802
737
|
function secretFromUri(uri) {
|
|
803
738
|
try {
|
|
804
739
|
return new URL(uri).searchParams.get("secret");
|
|
@@ -811,11 +746,11 @@ function MFAEnrollment({ onEnrolled, title }) {
|
|
|
811
746
|
const { enable, verifyTotp } = useMFA();
|
|
812
747
|
const { user, isLoaded } = useUser();
|
|
813
748
|
const { pending, error, run } = useSubmitAction();
|
|
814
|
-
const [password, setPassword] =
|
|
815
|
-
const [setup, setSetup] =
|
|
816
|
-
const [code, setCode] =
|
|
817
|
-
const [done, setDone] =
|
|
818
|
-
const setupOwnerId =
|
|
749
|
+
const [password, setPassword] = React7.useState("");
|
|
750
|
+
const [setup, setSetup] = React7.useState(null);
|
|
751
|
+
const [code, setCode] = React7.useState("");
|
|
752
|
+
const [done, setDone] = React7.useState(false);
|
|
753
|
+
const setupOwnerId = React7.useRef(null);
|
|
819
754
|
const userId = user?.id ?? null;
|
|
820
755
|
const stale = shouldDiscardSetup({
|
|
821
756
|
isLoaded,
|
|
@@ -824,7 +759,7 @@ function MFAEnrollment({ onEnrolled, title }) {
|
|
|
824
759
|
currentUserId: userId
|
|
825
760
|
});
|
|
826
761
|
const activeSetup = stale ? null : setup;
|
|
827
|
-
|
|
762
|
+
React7.useEffect(() => {
|
|
828
763
|
if (stale) {
|
|
829
764
|
setSetup(null);
|
|
830
765
|
setPassword("");
|
|
@@ -833,18 +768,18 @@ function MFAEnrollment({ onEnrolled, title }) {
|
|
|
833
768
|
}, [stale]);
|
|
834
769
|
if (done) {
|
|
835
770
|
return /* @__PURE__ */ jsxs9("div", { className: "ba-fields", "data-testid": "mfa-enroll-done", children: [
|
|
836
|
-
/* @__PURE__ */
|
|
837
|
-
/* @__PURE__ */
|
|
771
|
+
/* @__PURE__ */ jsx9("h2", { className: "ba-title", children: t("mfa.enroll.doneTitle") }),
|
|
772
|
+
/* @__PURE__ */ jsx9("p", { className: "ba-muted", children: t("mfa.enroll.doneBody") })
|
|
838
773
|
] });
|
|
839
774
|
}
|
|
840
775
|
if (!activeSetup) {
|
|
841
776
|
if (!isLoaded) {
|
|
842
|
-
return /* @__PURE__ */
|
|
777
|
+
return /* @__PURE__ */ jsx9("div", { className: "ba-fields", "data-testid": "mfa-enroll-loading", "aria-busy": "true", children: /* @__PURE__ */ jsx9("div", { className: "ba-skeleton" }) });
|
|
843
778
|
}
|
|
844
779
|
if (user?.twoFactorEnabled) {
|
|
845
780
|
return /* @__PURE__ */ jsxs9("div", { className: "ba-fields", "data-testid": "mfa-enroll-active", children: [
|
|
846
|
-
/* @__PURE__ */
|
|
847
|
-
/* @__PURE__ */
|
|
781
|
+
/* @__PURE__ */ jsx9("h2", { className: "ba-title", children: t("mfa.enroll.activeTitle") }),
|
|
782
|
+
/* @__PURE__ */ jsx9("p", { className: "ba-muted", children: t("mfa.enroll.activeBody") })
|
|
848
783
|
] });
|
|
849
784
|
}
|
|
850
785
|
return /* @__PURE__ */ jsxs9(
|
|
@@ -864,11 +799,11 @@ function MFAEnrollment({ onEnrolled, title }) {
|
|
|
864
799
|
});
|
|
865
800
|
},
|
|
866
801
|
children: [
|
|
867
|
-
title !== null && /* @__PURE__ */
|
|
868
|
-
/* @__PURE__ */
|
|
802
|
+
title !== null && /* @__PURE__ */ jsx9("h2", { className: "ba-title", children: title ?? t("mfa.enroll.title") }),
|
|
803
|
+
/* @__PURE__ */ jsx9("p", { className: "ba-muted", children: t("mfa.enroll.passwordHint") }),
|
|
869
804
|
/* @__PURE__ */ jsxs9("label", { className: "ba-label", children: [
|
|
870
805
|
t("common.passwordLabel"),
|
|
871
|
-
/* @__PURE__ */
|
|
806
|
+
/* @__PURE__ */ jsx9(
|
|
872
807
|
"input",
|
|
873
808
|
{
|
|
874
809
|
className: "ba-input",
|
|
@@ -880,27 +815,27 @@ function MFAEnrollment({ onEnrolled, title }) {
|
|
|
880
815
|
}
|
|
881
816
|
)
|
|
882
817
|
] }),
|
|
883
|
-
/* @__PURE__ */
|
|
884
|
-
/* @__PURE__ */
|
|
818
|
+
/* @__PURE__ */ jsx9(FormError, { children: error }),
|
|
819
|
+
/* @__PURE__ */ jsx9("button", { className: "ba-button", type: "submit", disabled: pending || !password, "aria-busy": pending || void 0, children: /* @__PURE__ */ jsx9(Busy, { busy: pending, label: t("mfa.enroll.startPending"), children: t("common.continue") }) })
|
|
885
820
|
]
|
|
886
821
|
}
|
|
887
822
|
);
|
|
888
823
|
}
|
|
889
824
|
const secret = secretFromUri(activeSetup.totpURI);
|
|
890
825
|
return /* @__PURE__ */ jsxs9("div", { className: "ba-fields", "data-testid": "mfa-enroll-verify", children: [
|
|
891
|
-
/* @__PURE__ */
|
|
892
|
-
/* @__PURE__ */
|
|
893
|
-
/* @__PURE__ */
|
|
894
|
-
secret && /* @__PURE__ */
|
|
895
|
-
secret: /* @__PURE__ */
|
|
826
|
+
/* @__PURE__ */ jsx9("h2", { className: "ba-title", children: t("mfa.enroll.scanQrTitle") }),
|
|
827
|
+
/* @__PURE__ */ jsx9("p", { className: "ba-muted", children: t("mfa.enroll.scanQrHint") }),
|
|
828
|
+
/* @__PURE__ */ jsx9(QrCode, { value: activeSetup.totpURI }),
|
|
829
|
+
secret && /* @__PURE__ */ jsx9("p", { className: "ba-muted", children: richMessage(t("mfa.enroll.manualKey"), {
|
|
830
|
+
secret: /* @__PURE__ */ jsx9("code", { className: "ba-code", children: /* @__PURE__ */ jsx9(Bidi, { children: secret }) })
|
|
896
831
|
}) }),
|
|
897
832
|
/* @__PURE__ */ jsxs9("div", { children: [
|
|
898
833
|
/* @__PURE__ */ jsxs9("p", { className: "ba-muted", children: [
|
|
899
|
-
/* @__PURE__ */
|
|
834
|
+
/* @__PURE__ */ jsx9("strong", { children: t("mfa.enroll.backupCodesWarningStrong") }),
|
|
900
835
|
" ",
|
|
901
836
|
t("mfa.enroll.backupCodesWarningRest")
|
|
902
837
|
] }),
|
|
903
|
-
/* @__PURE__ */
|
|
838
|
+
/* @__PURE__ */ jsx9("ul", { className: "ba-backup-codes", "data-testid": "mfa-backup-codes", children: activeSetup.backupCodes.map((c) => /* @__PURE__ */ jsx9("li", { children: /* @__PURE__ */ jsx9("code", { className: "ba-code", children: c }) }, c)) })
|
|
904
839
|
] }),
|
|
905
840
|
/* @__PURE__ */ jsxs9(
|
|
906
841
|
"form",
|
|
@@ -922,7 +857,7 @@ function MFAEnrollment({ onEnrolled, title }) {
|
|
|
922
857
|
children: [
|
|
923
858
|
/* @__PURE__ */ jsxs9("label", { className: "ba-label", children: [
|
|
924
859
|
t("mfa.enroll.codeLabel"),
|
|
925
|
-
/* @__PURE__ */
|
|
860
|
+
/* @__PURE__ */ jsx9(
|
|
926
861
|
"input",
|
|
927
862
|
{
|
|
928
863
|
className: "ba-input",
|
|
@@ -934,8 +869,8 @@ function MFAEnrollment({ onEnrolled, title }) {
|
|
|
934
869
|
}
|
|
935
870
|
)
|
|
936
871
|
] }),
|
|
937
|
-
/* @__PURE__ */
|
|
938
|
-
/* @__PURE__ */
|
|
872
|
+
/* @__PURE__ */ jsx9(FormError, { children: error }),
|
|
873
|
+
/* @__PURE__ */ jsx9("button", { className: "ba-button", type: "submit", disabled: pending || !code, "aria-busy": pending || void 0, children: /* @__PURE__ */ jsx9(Busy, { busy: pending, label: t("common.verifying"), children: t("mfa.enroll.activateSubmit") }) })
|
|
939
874
|
]
|
|
940
875
|
}
|
|
941
876
|
)
|
|
@@ -943,13 +878,13 @@ function MFAEnrollment({ onEnrolled, title }) {
|
|
|
943
878
|
}
|
|
944
879
|
|
|
945
880
|
// src/components/mfa-enrollment-step.tsx
|
|
946
|
-
import { Fragment as Fragment2, jsx as
|
|
881
|
+
import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
947
882
|
function useConfirmedMfaPending(onUnknown = "pending") {
|
|
948
883
|
const client = useAuthClient();
|
|
949
884
|
const { needsMfaEnrollment } = useUser();
|
|
950
885
|
const { refetch } = useSession();
|
|
951
|
-
const [confirmed, setConfirmed] =
|
|
952
|
-
|
|
886
|
+
const [confirmed, setConfirmed] = React8.useState(null);
|
|
887
|
+
React8.useEffect(() => {
|
|
953
888
|
if (!needsMfaEnrollment) {
|
|
954
889
|
setConfirmed(null);
|
|
955
890
|
return;
|
|
@@ -974,22 +909,22 @@ function MfaEnrollmentStep({ title }) {
|
|
|
974
909
|
const t = useT();
|
|
975
910
|
const { refetch } = useSession();
|
|
976
911
|
return /* @__PURE__ */ jsxs10(Fragment2, { children: [
|
|
977
|
-
/* @__PURE__ */
|
|
978
|
-
/* @__PURE__ */
|
|
979
|
-
/* @__PURE__ */
|
|
912
|
+
/* @__PURE__ */ jsx10("h2", { className: "ba-title", children: title ?? t("mfaGate.title") }),
|
|
913
|
+
/* @__PURE__ */ jsx10("p", { className: "ba-muted", children: t("mfaGate.body") }),
|
|
914
|
+
/* @__PURE__ */ jsx10(MFAEnrollment, { onEnrolled: () => refetch({ query: { disableCookieCache: true } }) })
|
|
980
915
|
] });
|
|
981
916
|
}
|
|
982
917
|
|
|
983
918
|
// src/components/AuthOwlBadge.tsx
|
|
984
|
-
import { jsx as
|
|
919
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
985
920
|
function OwlMark() {
|
|
986
921
|
return /* @__PURE__ */ jsxs11("svg", { className: "ba-badge-mark", viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", children: [
|
|
987
|
-
/* @__PURE__ */
|
|
988
|
-
/* @__PURE__ */
|
|
989
|
-
/* @__PURE__ */
|
|
990
|
-
/* @__PURE__ */
|
|
991
|
-
/* @__PURE__ */
|
|
992
|
-
/* @__PURE__ */
|
|
922
|
+
/* @__PURE__ */ jsx11("circle", { cx: "12", cy: "12", r: "11", fill: "#F5B84C" }),
|
|
923
|
+
/* @__PURE__ */ jsx11("circle", { cx: "8.4", cy: "10", r: "3", fill: "#fff" }),
|
|
924
|
+
/* @__PURE__ */ jsx11("circle", { cx: "15.6", cy: "10", r: "3", fill: "#fff" }),
|
|
925
|
+
/* @__PURE__ */ jsx11("circle", { cx: "8.4", cy: "10", r: "1.4", fill: "#1f1300" }),
|
|
926
|
+
/* @__PURE__ */ jsx11("circle", { cx: "15.6", cy: "10", r: "1.4", fill: "#1f1300" }),
|
|
927
|
+
/* @__PURE__ */ jsx11("path", { d: "M12 13.1l1.5 2.1h-3z", fill: "#1f1300" })
|
|
993
928
|
] });
|
|
994
929
|
}
|
|
995
930
|
function AuthOwlBadge({ href = "https://authowl.dev", force } = {}) {
|
|
@@ -1005,9 +940,9 @@ function AuthOwlBadge({ href = "https://authowl.dev", force } = {}) {
|
|
|
1005
940
|
rel: "noopener noreferrer",
|
|
1006
941
|
"data-testid": "authowl-badge",
|
|
1007
942
|
children: [
|
|
1008
|
-
/* @__PURE__ */
|
|
1009
|
-
/* @__PURE__ */
|
|
1010
|
-
brand: /* @__PURE__ */
|
|
943
|
+
/* @__PURE__ */ jsx11(OwlMark, {}),
|
|
944
|
+
/* @__PURE__ */ jsx11("span", { children: richMessage(t("badge.securedBy"), {
|
|
945
|
+
brand: /* @__PURE__ */ jsx11("span", { className: "ba-badge-brand", children: "AuthOwl" })
|
|
1011
946
|
}) })
|
|
1012
947
|
]
|
|
1013
948
|
}
|
|
@@ -1022,19 +957,19 @@ import {
|
|
|
1022
957
|
} from "@authowl/core";
|
|
1023
958
|
|
|
1024
959
|
// src/components/ConsentDocLinks.tsx
|
|
1025
|
-
import { Fragment as Fragment3, jsx as
|
|
960
|
+
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1026
961
|
function ConsentDocLinks({ termsUrl, privacyUrl }) {
|
|
1027
962
|
const t = useT();
|
|
1028
963
|
if (!termsUrl && !privacyUrl) return null;
|
|
1029
964
|
return /* @__PURE__ */ jsxs12(Fragment3, { children: [
|
|
1030
|
-
termsUrl && /* @__PURE__ */
|
|
965
|
+
termsUrl && /* @__PURE__ */ jsx12("a", { href: termsUrl, target: "_blank", rel: "noopener noreferrer", children: t("consent.termsOfService") }),
|
|
1031
966
|
termsUrl && privacyUrl && t("consent.docJoiner"),
|
|
1032
|
-
privacyUrl && /* @__PURE__ */
|
|
967
|
+
privacyUrl && /* @__PURE__ */ jsx12("a", { href: privacyUrl, target: "_blank", rel: "noopener noreferrer", children: t("consent.privacyPolicy") })
|
|
1033
968
|
] });
|
|
1034
969
|
}
|
|
1035
970
|
|
|
1036
971
|
// src/components/LegalConsentCheckbox.tsx
|
|
1037
|
-
import { jsx as
|
|
972
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1038
973
|
function LegalConsentCheckbox({
|
|
1039
974
|
legal,
|
|
1040
975
|
accepted,
|
|
@@ -1045,7 +980,7 @@ function LegalConsentCheckbox({
|
|
|
1045
980
|
if (!legal.required) return null;
|
|
1046
981
|
return /* @__PURE__ */ jsxs13("label", { className: "ba-consent", "data-testid": testId, children: [
|
|
1047
982
|
/* @__PURE__ */ jsxs13("span", { className: "ba-checkbox-control", children: [
|
|
1048
|
-
/* @__PURE__ */
|
|
983
|
+
/* @__PURE__ */ jsx13(
|
|
1049
984
|
"input",
|
|
1050
985
|
{
|
|
1051
986
|
className: "ba-checkbox",
|
|
@@ -1054,14 +989,69 @@ function LegalConsentCheckbox({
|
|
|
1054
989
|
onChange: (event) => onAcceptedChange(event.target.checked)
|
|
1055
990
|
}
|
|
1056
991
|
),
|
|
1057
|
-
/* @__PURE__ */
|
|
992
|
+
/* @__PURE__ */ jsx13("span", { className: "ba-checkbox-visual", "aria-hidden": "true", children: /* @__PURE__ */ jsx13("span", { className: "ba-checkbox-check" }) })
|
|
1058
993
|
] }),
|
|
1059
|
-
/* @__PURE__ */
|
|
1060
|
-
links: /* @__PURE__ */
|
|
994
|
+
/* @__PURE__ */ jsx13("span", { children: richMessage(t("signUp.consentLabel"), {
|
|
995
|
+
links: /* @__PURE__ */ jsx13(ConsentDocLinks, { termsUrl: legal.termsUrl, privacyUrl: legal.privacyUrl })
|
|
1061
996
|
}) })
|
|
1062
997
|
] });
|
|
1063
998
|
}
|
|
1064
999
|
|
|
1000
|
+
// src/components/Turnstile.tsx
|
|
1001
|
+
import * as React9 from "react";
|
|
1002
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1003
|
+
var LOCAL_TURNSTILE_TEST_TOKEN = "XXXX.DUMMY.TOKEN.XXXX";
|
|
1004
|
+
async function loadTurnstile() {
|
|
1005
|
+
const [{ loadCaptcha }, { CAPTCHA_ADAPTERS }] = await Promise.all([
|
|
1006
|
+
import("./captcha-loader-VNULARCZ.js"),
|
|
1007
|
+
import("./captcha-providers-STYFL25P.js")
|
|
1008
|
+
]);
|
|
1009
|
+
const adapter = CAPTCHA_ADAPTERS.turnstile;
|
|
1010
|
+
return { api: await loadCaptcha(adapter), adapter };
|
|
1011
|
+
}
|
|
1012
|
+
function Turnstile({
|
|
1013
|
+
siteKey,
|
|
1014
|
+
theme,
|
|
1015
|
+
onToken,
|
|
1016
|
+
onUnavailable
|
|
1017
|
+
}) {
|
|
1018
|
+
const container = React9.useRef(null);
|
|
1019
|
+
const callbacks = React9.useRef({ onToken, onUnavailable });
|
|
1020
|
+
callbacks.current = { onToken, onUnavailable };
|
|
1021
|
+
React9.useEffect(() => {
|
|
1022
|
+
callbacks.current.onToken(null);
|
|
1023
|
+
if (!siteKey) {
|
|
1024
|
+
callbacks.current.onToken(LOCAL_TURNSTILE_TEST_TOKEN);
|
|
1025
|
+
return;
|
|
1026
|
+
}
|
|
1027
|
+
let active = true;
|
|
1028
|
+
let widget = null;
|
|
1029
|
+
void loadTurnstile().then(({ api, adapter }) => {
|
|
1030
|
+
if (!active || !container.current) return;
|
|
1031
|
+
const id = api.render(container.current, {
|
|
1032
|
+
sitekey: siteKey,
|
|
1033
|
+
theme: theme === "system" ? "auto" : theme,
|
|
1034
|
+
size: "flexible",
|
|
1035
|
+
callback: (token) => callbacks.current.onToken(token),
|
|
1036
|
+
"expired-callback": () => callbacks.current.onToken(null),
|
|
1037
|
+
"error-callback": () => {
|
|
1038
|
+
callbacks.current.onToken(null);
|
|
1039
|
+
callbacks.current.onUnavailable();
|
|
1040
|
+
}
|
|
1041
|
+
});
|
|
1042
|
+
widget = { api, adapter, id };
|
|
1043
|
+
}).catch(() => {
|
|
1044
|
+
if (active) callbacks.current.onUnavailable();
|
|
1045
|
+
});
|
|
1046
|
+
return () => {
|
|
1047
|
+
active = false;
|
|
1048
|
+
if (widget) widget.adapter.teardown(widget.api, widget.id);
|
|
1049
|
+
};
|
|
1050
|
+
}, [siteKey, theme]);
|
|
1051
|
+
if (!siteKey) return null;
|
|
1052
|
+
return /* @__PURE__ */ jsx14("div", { className: "ba-turnstile", ref: container, "data-testid": "phoneotp-turnstile" });
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1065
1055
|
// src/components/PhoneOTP.tsx
|
|
1066
1056
|
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1067
1057
|
function PhoneOTP({
|
|
@@ -3449,9 +3439,9 @@ function formatSessionTime(date, locale) {
|
|
|
3449
3439
|
|
|
3450
3440
|
// src/components/user-profile/use-account-resource.ts
|
|
3451
3441
|
import * as React32 from "react";
|
|
3452
|
-
function useAccountResource(
|
|
3453
|
-
const loaderRef = React32.useRef(
|
|
3454
|
-
loaderRef.current =
|
|
3442
|
+
function useAccountResource(loader, failure) {
|
|
3443
|
+
const loaderRef = React32.useRef(loader);
|
|
3444
|
+
loaderRef.current = loader;
|
|
3455
3445
|
const failureRef = React32.useRef(failure);
|
|
3456
3446
|
failureRef.current = failure;
|
|
3457
3447
|
const toServerError = useServerError();
|