@orangecheck/auth-client 0.6.0 → 1.1.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.d.mts +22 -5
- package/dist/index.d.ts +22 -5
- package/dist/index.js +523 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +523 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -21,22 +21,20 @@ function buildSignInUrl(cfg, returnTo) {
|
|
|
21
21
|
return u.toString();
|
|
22
22
|
}
|
|
23
23
|
var SessionContext = React2.createContext(null);
|
|
24
|
-
function defaultSigningMethodFor(address) {
|
|
25
|
-
return address.startsWith("did:email:") ? "fedimint_threshold" : "bip322";
|
|
26
|
-
}
|
|
27
24
|
function normalizeAccount(raw) {
|
|
28
25
|
if (!raw) return null;
|
|
29
|
-
const
|
|
26
|
+
const didOc = raw.did_oc ?? raw.didOc;
|
|
30
27
|
const accountId = raw.id ?? raw.account_id ?? raw.accountId;
|
|
31
|
-
if (!
|
|
28
|
+
if (!didOc || !accountId) return null;
|
|
32
29
|
return {
|
|
33
30
|
accountId,
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
didOc,
|
|
32
|
+
primaryBtc: raw.primary_btc ?? raw.primaryBtc ?? null,
|
|
33
|
+
hasEmail: raw.has_email ?? raw.hasEmail ?? false,
|
|
36
34
|
displayName: raw.display_name ?? raw.displayName ?? null,
|
|
37
35
|
nostrNpub: raw.nostr_npub ?? raw.nostrNpub ?? null,
|
|
38
36
|
homeFederation: raw.home_federation_slug ?? raw.homeFederation ?? null,
|
|
39
|
-
signingMethod: raw.signing_method ?? raw.signingMethod ??
|
|
37
|
+
signingMethod: raw.signing_method ?? raw.signingMethod ?? null
|
|
40
38
|
};
|
|
41
39
|
}
|
|
42
40
|
function OcSessionProvider({
|
|
@@ -134,13 +132,15 @@ function useUniqueId(prefix) {
|
|
|
134
132
|
}
|
|
135
133
|
function OcAccountChip({
|
|
136
134
|
dashboardUrl = "https://ochk.io/dashboard",
|
|
135
|
+
signInUrl: signInUrlOverride,
|
|
137
136
|
signInLabel = "sign in",
|
|
138
137
|
className,
|
|
139
138
|
triggerClassName,
|
|
140
139
|
popoverClassName,
|
|
141
140
|
menuItemClassName
|
|
142
141
|
}) {
|
|
143
|
-
const { status, account, signInUrl, signOut } = useOcSession();
|
|
142
|
+
const { status, account, signInUrl: sessionSignInUrl, signOut } = useOcSession();
|
|
143
|
+
const signInUrl = signInUrlOverride ?? sessionSignInUrl;
|
|
144
144
|
const [open, setOpen] = React2.useState(false);
|
|
145
145
|
const wrapRef = React2.useRef(null);
|
|
146
146
|
React2.useEffect(() => {
|
|
@@ -187,7 +187,7 @@ function OcAccountChip({
|
|
|
187
187
|
onClick: () => setOpen((v) => !v),
|
|
188
188
|
"aria-haspopup": "menu",
|
|
189
189
|
"aria-expanded": open,
|
|
190
|
-
"aria-label": `Signed in as ${account.
|
|
190
|
+
"aria-label": `Signed in as ${account.didOc}. Open account menu.`,
|
|
191
191
|
className: triggerClassName,
|
|
192
192
|
"data-oc-account-chip-trigger": "",
|
|
193
193
|
style: triggerClassName ? void 0 : {
|
|
@@ -205,7 +205,7 @@ function OcAccountChip({
|
|
|
205
205
|
},
|
|
206
206
|
children: [
|
|
207
207
|
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { color: "#22c55e", fontSize: 8 }, children: "\u25CF" }),
|
|
208
|
-
/* @__PURE__ */ jsx("span", { children: account.displayName ?? shortenAddress(account.
|
|
208
|
+
/* @__PURE__ */ jsx("span", { children: account.displayName ?? shortenAddress(account.didOc) }),
|
|
209
209
|
/* @__PURE__ */ jsx(
|
|
210
210
|
"svg",
|
|
211
211
|
{
|
|
@@ -286,7 +286,7 @@ function OcAccountChip({
|
|
|
286
286
|
wordBreak: "break-all",
|
|
287
287
|
lineHeight: 1.35
|
|
288
288
|
},
|
|
289
|
-
children: account.
|
|
289
|
+
children: account.didOc
|
|
290
290
|
}
|
|
291
291
|
),
|
|
292
292
|
account.displayName ? /* @__PURE__ */ jsx(
|
|
@@ -397,16 +397,18 @@ function OcSignInButton({
|
|
|
397
397
|
label = "sign in with bitcoin",
|
|
398
398
|
eager = false,
|
|
399
399
|
className,
|
|
400
|
+
signInUrl: signInUrlOverride,
|
|
400
401
|
...rest
|
|
401
402
|
}) {
|
|
402
|
-
const { status, signInUrl } = useOcSession();
|
|
403
|
+
const { status, signInUrl: sessionSignInUrl } = useOcSession();
|
|
404
|
+
const href = signInUrlOverride ?? sessionSignInUrl;
|
|
403
405
|
if (status === "authenticated") return null;
|
|
404
406
|
if (!eager && status === "loading") return null;
|
|
405
407
|
return /* @__PURE__ */ jsx(
|
|
406
408
|
"a",
|
|
407
409
|
{
|
|
408
410
|
...rest,
|
|
409
|
-
href
|
|
411
|
+
href,
|
|
410
412
|
className,
|
|
411
413
|
"data-oc-sign-in-button": "",
|
|
412
414
|
children: label
|
|
@@ -421,7 +423,7 @@ function OcAccountPill({
|
|
|
421
423
|
}) {
|
|
422
424
|
const { status, account, signOut } = useOcSession();
|
|
423
425
|
if (status !== "authenticated" || !account) return null;
|
|
424
|
-
const label = render ? render({ address: account.
|
|
426
|
+
const label = render ? render({ address: account.didOc, displayName: account.displayName }) : account.displayName ?? shortenAddress(account.didOc);
|
|
425
427
|
return /* @__PURE__ */ jsxs(
|
|
426
428
|
"div",
|
|
427
429
|
{
|
|
@@ -463,7 +465,7 @@ function useOcAddressSuggestion(options) {
|
|
|
463
465
|
suggestionClassName
|
|
464
466
|
} = options;
|
|
465
467
|
const { status, account } = useOcSession();
|
|
466
|
-
const sessionAddress = status === "authenticated" ? account?.
|
|
468
|
+
const sessionAddress = status === "authenticated" ? account?.primaryBtc ?? null : null;
|
|
467
469
|
const [open, setOpen] = React2.useState(false);
|
|
468
470
|
const [highlighted, setHighlighted] = React2.useState(false);
|
|
469
471
|
const blurTimer = React2.useRef(null);
|
|
@@ -595,7 +597,7 @@ var OcAddressInput = React2.forwardRef(
|
|
|
595
597
|
...rest
|
|
596
598
|
}, forwardedRef) {
|
|
597
599
|
const { status, account } = useOcSession();
|
|
598
|
-
const sessionAddress = status === "authenticated" ? account?.
|
|
600
|
+
const sessionAddress = status === "authenticated" ? account?.primaryBtc ?? null : null;
|
|
599
601
|
const [open, setOpen] = React2.useState(false);
|
|
600
602
|
const [highlighted, setHighlighted] = React2.useState(false);
|
|
601
603
|
const innerRef = React2.useRef(null);
|
|
@@ -744,7 +746,510 @@ var OcAddressInput = React2.forwardRef(
|
|
|
744
746
|
);
|
|
745
747
|
}
|
|
746
748
|
);
|
|
749
|
+
function safeReturnTo(input) {
|
|
750
|
+
const candidate = input ?? "/";
|
|
751
|
+
if (typeof candidate !== "string") return "/";
|
|
752
|
+
if (!candidate.startsWith("/") || candidate.startsWith("//")) return "/";
|
|
753
|
+
return candidate;
|
|
754
|
+
}
|
|
755
|
+
function hardNavigate(target) {
|
|
756
|
+
if (typeof window === "undefined") return;
|
|
757
|
+
window.location.assign(target);
|
|
758
|
+
}
|
|
759
|
+
function OcSignIn({
|
|
760
|
+
audience,
|
|
761
|
+
returnTo,
|
|
762
|
+
onSuccess,
|
|
763
|
+
authOrigin = "https://ochk.io",
|
|
764
|
+
initialPath = "wallet",
|
|
765
|
+
paths,
|
|
766
|
+
className
|
|
767
|
+
}) {
|
|
768
|
+
const walletEnabled = paths?.wallet ?? true;
|
|
769
|
+
const emailEnabled = paths?.email ?? true;
|
|
770
|
+
const safeReturn = safeReturnTo(returnTo);
|
|
771
|
+
const [path, setPath] = React2.useState(initialPath);
|
|
772
|
+
const handleSuccess = React2.useCallback(
|
|
773
|
+
(account) => {
|
|
774
|
+
if (onSuccess) {
|
|
775
|
+
onSuccess(account);
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
hardNavigate(safeReturn);
|
|
779
|
+
},
|
|
780
|
+
[onSuccess, safeReturn]
|
|
781
|
+
);
|
|
782
|
+
if (!walletEnabled && !emailEnabled) {
|
|
783
|
+
return /* @__PURE__ */ jsxs(
|
|
784
|
+
"div",
|
|
785
|
+
{
|
|
786
|
+
className,
|
|
787
|
+
"data-oc-signin": "",
|
|
788
|
+
style: {
|
|
789
|
+
padding: "1rem",
|
|
790
|
+
border: "1px solid var(--border, #27272a)",
|
|
791
|
+
color: "var(--foreground, #fafafa)",
|
|
792
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
793
|
+
fontSize: 12
|
|
794
|
+
},
|
|
795
|
+
children: [
|
|
796
|
+
"no signin paths enabled \u2014 set ",
|
|
797
|
+
/* @__PURE__ */ jsx("code", { children: "paths.wallet" }),
|
|
798
|
+
" or",
|
|
799
|
+
" ",
|
|
800
|
+
/* @__PURE__ */ jsx("code", { children: "paths.email" }),
|
|
801
|
+
" to ",
|
|
802
|
+
/* @__PURE__ */ jsx("code", { children: "true" })
|
|
803
|
+
]
|
|
804
|
+
}
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
const showWallet = walletEnabled && (path === "wallet" || !emailEnabled);
|
|
808
|
+
const showEmail = emailEnabled && (path === "email" || !walletEnabled);
|
|
809
|
+
const bothEnabled = walletEnabled && emailEnabled;
|
|
810
|
+
return /* @__PURE__ */ jsxs("div", { className, "data-oc-signin": "", children: [
|
|
811
|
+
bothEnabled && /* @__PURE__ */ jsxs(
|
|
812
|
+
"div",
|
|
813
|
+
{
|
|
814
|
+
role: "tablist",
|
|
815
|
+
"aria-label": "signin method",
|
|
816
|
+
"data-oc-signin-tabs": "",
|
|
817
|
+
style: {
|
|
818
|
+
display: "flex",
|
|
819
|
+
gap: 8,
|
|
820
|
+
marginBottom: 16,
|
|
821
|
+
borderBottom: "1px solid var(--border, #27272a)"
|
|
822
|
+
},
|
|
823
|
+
children: [
|
|
824
|
+
/* @__PURE__ */ jsx(
|
|
825
|
+
SigninTab,
|
|
826
|
+
{
|
|
827
|
+
active: path === "wallet",
|
|
828
|
+
onClick: () => setPath("wallet"),
|
|
829
|
+
children: "bitcoin wallet"
|
|
830
|
+
}
|
|
831
|
+
),
|
|
832
|
+
/* @__PURE__ */ jsx(SigninTab, { active: path === "email", onClick: () => setPath("email"), children: "email + otp" })
|
|
833
|
+
]
|
|
834
|
+
}
|
|
835
|
+
),
|
|
836
|
+
/* @__PURE__ */ jsxs("div", { "data-oc-signin-panel": "", role: "tabpanel", children: [
|
|
837
|
+
showWallet && /* @__PURE__ */ jsx(
|
|
838
|
+
WalletFlow,
|
|
839
|
+
{
|
|
840
|
+
authOrigin,
|
|
841
|
+
audience,
|
|
842
|
+
onSuccess: handleSuccess
|
|
843
|
+
}
|
|
844
|
+
),
|
|
845
|
+
showEmail && /* @__PURE__ */ jsx(EmailFlow, { authOrigin, onSuccess: handleSuccess })
|
|
846
|
+
] })
|
|
847
|
+
] });
|
|
848
|
+
}
|
|
849
|
+
function SigninTab({
|
|
850
|
+
active,
|
|
851
|
+
onClick,
|
|
852
|
+
children
|
|
853
|
+
}) {
|
|
854
|
+
return /* @__PURE__ */ jsx(
|
|
855
|
+
"button",
|
|
856
|
+
{
|
|
857
|
+
type: "button",
|
|
858
|
+
role: "tab",
|
|
859
|
+
"aria-selected": active,
|
|
860
|
+
onClick,
|
|
861
|
+
"data-oc-signin-tab": active ? "active" : "inactive",
|
|
862
|
+
style: {
|
|
863
|
+
padding: "0.6rem 0.875rem",
|
|
864
|
+
background: "transparent",
|
|
865
|
+
border: "none",
|
|
866
|
+
borderBottom: active ? "2px solid var(--primary, #f97316)" : "2px solid transparent",
|
|
867
|
+
color: active ? "var(--foreground, #fafafa)" : "var(--muted-foreground, #a1a1aa)",
|
|
868
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
869
|
+
fontSize: 11,
|
|
870
|
+
letterSpacing: "0.12em",
|
|
871
|
+
textTransform: "uppercase",
|
|
872
|
+
cursor: "pointer",
|
|
873
|
+
marginBottom: -1
|
|
874
|
+
},
|
|
875
|
+
children
|
|
876
|
+
}
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
function WalletFlow({ authOrigin, audience, onSuccess }) {
|
|
880
|
+
const [address, setAddress] = React2.useState("");
|
|
881
|
+
const [error, setError] = React2.useState(null);
|
|
882
|
+
const [submitting, setSubmitting] = React2.useState(false);
|
|
883
|
+
const [stage, setStage] = React2.useState("enter");
|
|
884
|
+
async function signIn(e) {
|
|
885
|
+
e.preventDefault();
|
|
886
|
+
const addr = address.trim();
|
|
887
|
+
if (!addr) {
|
|
888
|
+
setError("paste a Bitcoin address");
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
setError(null);
|
|
892
|
+
setSubmitting(true);
|
|
893
|
+
setStage("signing");
|
|
894
|
+
try {
|
|
895
|
+
const challengeRes = await fetch(
|
|
896
|
+
`${authOrigin}/api/challenge?addr=${encodeURIComponent(addr)}&audience=${encodeURIComponent(audience)}&purpose=login`
|
|
897
|
+
);
|
|
898
|
+
const challenge = await challengeRes.json();
|
|
899
|
+
if (!challengeRes.ok || !challenge.message || !challenge.nonce) {
|
|
900
|
+
throw new Error(challenge.error ?? "challenge_failed");
|
|
901
|
+
}
|
|
902
|
+
let adapter;
|
|
903
|
+
try {
|
|
904
|
+
const moduleId = "@orangecheck/wallet-adapter";
|
|
905
|
+
adapter = await Function("m", "return import(m)")(
|
|
906
|
+
moduleId
|
|
907
|
+
);
|
|
908
|
+
} catch {
|
|
909
|
+
throw new Error(
|
|
910
|
+
"@orangecheck/wallet-adapter not installed \xB7 add it to your consumer site"
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
const wallets = adapter.detectWallets().filter((w) => w.detected && w.id !== "manual");
|
|
914
|
+
if (wallets.length === 0) {
|
|
915
|
+
throw new Error("no BIP-322 wallet extension detected \xB7 install one and refresh");
|
|
916
|
+
}
|
|
917
|
+
const wallet = wallets[0];
|
|
918
|
+
const signer = adapter.getSigner(wallet.id, { address: addr });
|
|
919
|
+
const signature = await signer(challenge.message);
|
|
920
|
+
const res = await fetch(`${authOrigin}/api/auth/signin`, {
|
|
921
|
+
method: "POST",
|
|
922
|
+
credentials: "include",
|
|
923
|
+
headers: { "Content-Type": "application/json" },
|
|
924
|
+
body: JSON.stringify({
|
|
925
|
+
message: challenge.message,
|
|
926
|
+
signature,
|
|
927
|
+
scheme: "bip322",
|
|
928
|
+
expectedNonce: challenge.nonce,
|
|
929
|
+
expectedAudience: audience,
|
|
930
|
+
expectedPurpose: "login"
|
|
931
|
+
})
|
|
932
|
+
});
|
|
933
|
+
const json = await res.json();
|
|
934
|
+
if (!res.ok || !("ok" in json) || !json.ok || !json.account) {
|
|
935
|
+
throw new Error(
|
|
936
|
+
"reason" in json && json.reason || "error" in json && json.error || `verify_failed_${res.status}`
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
onSuccess(json.account);
|
|
940
|
+
} catch (err) {
|
|
941
|
+
const msg = err instanceof Error ? err.message : "sign-in failed";
|
|
942
|
+
setError(msg);
|
|
943
|
+
setSubmitting(false);
|
|
944
|
+
setStage("enter");
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
return /* @__PURE__ */ jsxs("form", { onSubmit: signIn, "data-oc-signin-wallet": "", children: [
|
|
948
|
+
/* @__PURE__ */ jsx(FlowHeader, { label: "\xA7 bitcoin wallet", children: "Sign in with any BIP-322-capable Bitcoin wallet (Sparrow, Xverse, Leather, UniSat, Alby, OKX, Phantom). Paste your address, click sign \u2014 your wallet extension prompts for a one-time signature on a short challenge. The address becomes your OC identity. Private key material never leaves your wallet." }),
|
|
949
|
+
/* @__PURE__ */ jsx(Label, { children: "bitcoin address" }),
|
|
950
|
+
/* @__PURE__ */ jsx(
|
|
951
|
+
"input",
|
|
952
|
+
{
|
|
953
|
+
type: "text",
|
|
954
|
+
value: address,
|
|
955
|
+
onChange: (e) => {
|
|
956
|
+
setAddress(e.target.value);
|
|
957
|
+
if (error) setError(null);
|
|
958
|
+
},
|
|
959
|
+
placeholder: "bc1q\u2026 \xB7 3\u2026 \xB7 1\u2026",
|
|
960
|
+
autoComplete: "off",
|
|
961
|
+
autoCapitalize: "none",
|
|
962
|
+
spellCheck: false,
|
|
963
|
+
required: true,
|
|
964
|
+
"aria-invalid": error ? true : void 0,
|
|
965
|
+
style: inputStyle
|
|
966
|
+
}
|
|
967
|
+
),
|
|
968
|
+
error && /* @__PURE__ */ jsx(ErrorLine, { children: error }),
|
|
969
|
+
/* @__PURE__ */ jsx(
|
|
970
|
+
"button",
|
|
971
|
+
{
|
|
972
|
+
type: "submit",
|
|
973
|
+
disabled: submitting || !address.trim(),
|
|
974
|
+
style: submitStyle(submitting || !address.trim()),
|
|
975
|
+
children: stage === "signing" && submitting ? "waiting for wallet\u2026" : "sign challenge \xB7 sign me in \u2192"
|
|
976
|
+
}
|
|
977
|
+
),
|
|
978
|
+
/* @__PURE__ */ jsx(Hint, { children: "Detection picks the first installed BIP-322-capable extension. Address is the one your wallet will sign for." })
|
|
979
|
+
] });
|
|
980
|
+
}
|
|
981
|
+
function EmailFlow({ authOrigin, onSuccess }) {
|
|
982
|
+
const [stage, setStage] = React2.useState("enter");
|
|
983
|
+
const [email, setEmail] = React2.useState("");
|
|
984
|
+
const [emailError, setEmailError] = React2.useState(null);
|
|
985
|
+
const [code, setCode] = React2.useState("");
|
|
986
|
+
const [codeError, setCodeError] = React2.useState(null);
|
|
987
|
+
const [token, setToken] = React2.useState(null);
|
|
988
|
+
const [submitting, setSubmitting] = React2.useState(false);
|
|
989
|
+
async function start(e) {
|
|
990
|
+
e.preventDefault();
|
|
991
|
+
const trimmed = email.trim().toLowerCase();
|
|
992
|
+
if (!trimmed || !/.+@.+\..+/.test(trimmed)) {
|
|
993
|
+
setEmailError("enter a valid email");
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
setEmailError(null);
|
|
997
|
+
setSubmitting(true);
|
|
998
|
+
try {
|
|
999
|
+
const res = await fetch(`${authOrigin}/api/auth/email-otp/start`, {
|
|
1000
|
+
method: "POST",
|
|
1001
|
+
credentials: "include",
|
|
1002
|
+
headers: { "Content-Type": "application/json" },
|
|
1003
|
+
body: JSON.stringify({ email: trimmed })
|
|
1004
|
+
});
|
|
1005
|
+
const json = await res.json();
|
|
1006
|
+
if (!res.ok || !json.token) {
|
|
1007
|
+
throw new Error(json.reason ?? `start failed (${res.status})`);
|
|
1008
|
+
}
|
|
1009
|
+
setToken(json.token);
|
|
1010
|
+
setEmail(trimmed);
|
|
1011
|
+
setStage("code");
|
|
1012
|
+
} catch (err) {
|
|
1013
|
+
setEmailError(err instanceof Error ? err.message : "failed to send code");
|
|
1014
|
+
} finally {
|
|
1015
|
+
setSubmitting(false);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
async function verify(e) {
|
|
1019
|
+
e.preventDefault();
|
|
1020
|
+
if (!token) return;
|
|
1021
|
+
if (code.length !== 6) {
|
|
1022
|
+
setCodeError("6 digits");
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
setCodeError(null);
|
|
1026
|
+
setSubmitting(true);
|
|
1027
|
+
try {
|
|
1028
|
+
const res = await fetch(`${authOrigin}/api/auth/email-otp/verify`, {
|
|
1029
|
+
method: "POST",
|
|
1030
|
+
credentials: "include",
|
|
1031
|
+
headers: { "Content-Type": "application/json" },
|
|
1032
|
+
body: JSON.stringify({ email, code, token })
|
|
1033
|
+
});
|
|
1034
|
+
const json = await res.json();
|
|
1035
|
+
if (!res.ok || !("ok" in json) || !json.ok || !json.account) {
|
|
1036
|
+
throw new Error(
|
|
1037
|
+
"reason" in json && json.reason || "error" in json && json.error || `verify failed (${res.status})`
|
|
1038
|
+
);
|
|
1039
|
+
}
|
|
1040
|
+
onSuccess(json.account);
|
|
1041
|
+
} catch (err) {
|
|
1042
|
+
setCodeError(err instanceof Error ? err.message : "verify failed");
|
|
1043
|
+
} finally {
|
|
1044
|
+
setSubmitting(false);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
if (stage === "enter") {
|
|
1048
|
+
return /* @__PURE__ */ jsxs("form", { onSubmit: start, "data-oc-signin-email": "", children: [
|
|
1049
|
+
/* @__PURE__ */ jsx(FlowHeader, { label: "\xA7 email + otp", children: "We email you a 6-digit code. No password. The federation provisions a custodial wallet for you in your browser. Best path if you don't have a Bitcoin wallet yet \u2014 graduate to self-custody anytime by adding your BTC address from your account dashboard." }),
|
|
1050
|
+
/* @__PURE__ */ jsx(Label, { children: "email" }),
|
|
1051
|
+
/* @__PURE__ */ jsx(
|
|
1052
|
+
"input",
|
|
1053
|
+
{
|
|
1054
|
+
type: "email",
|
|
1055
|
+
autoComplete: "email",
|
|
1056
|
+
value: email,
|
|
1057
|
+
onChange: (e) => {
|
|
1058
|
+
setEmail(e.target.value);
|
|
1059
|
+
if (emailError) setEmailError(null);
|
|
1060
|
+
},
|
|
1061
|
+
placeholder: "you@example.com",
|
|
1062
|
+
required: true,
|
|
1063
|
+
"aria-invalid": emailError ? true : void 0,
|
|
1064
|
+
style: inputStyle
|
|
1065
|
+
}
|
|
1066
|
+
),
|
|
1067
|
+
emailError && /* @__PURE__ */ jsx(ErrorLine, { children: emailError }),
|
|
1068
|
+
/* @__PURE__ */ jsx("button", { type: "submit", disabled: submitting, style: submitStyle(submitting), children: submitting ? "sending\u2026" : "send one-time code \u2192" }),
|
|
1069
|
+
/* @__PURE__ */ jsx(Hint, { children: "OTP delivered by the auth host. Codes expire in 10 minutes and are single-use. Rate-limited 5 starts/hour/IP." })
|
|
1070
|
+
] });
|
|
1071
|
+
}
|
|
1072
|
+
return /* @__PURE__ */ jsxs("form", { onSubmit: verify, "data-oc-signin-email-verify": "", children: [
|
|
1073
|
+
/* @__PURE__ */ jsxs(FlowHeader, { label: "\xA7 enter the code", children: [
|
|
1074
|
+
"Sent a 6-digit code to ",
|
|
1075
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--foreground, #fafafa)" }, children: email }),
|
|
1076
|
+
". Code expires in 10 minutes."
|
|
1077
|
+
] }),
|
|
1078
|
+
/* @__PURE__ */ jsx(Label, { children: "one-time code" }),
|
|
1079
|
+
/* @__PURE__ */ jsx(
|
|
1080
|
+
"input",
|
|
1081
|
+
{
|
|
1082
|
+
type: "text",
|
|
1083
|
+
inputMode: "numeric",
|
|
1084
|
+
pattern: "\\d{6}",
|
|
1085
|
+
maxLength: 6,
|
|
1086
|
+
autoComplete: "one-time-code",
|
|
1087
|
+
value: code,
|
|
1088
|
+
onChange: (e) => {
|
|
1089
|
+
setCode(e.target.value.replace(/\D/g, "").slice(0, 6));
|
|
1090
|
+
if (codeError) setCodeError(null);
|
|
1091
|
+
},
|
|
1092
|
+
placeholder: "6 digits",
|
|
1093
|
+
required: true,
|
|
1094
|
+
autoFocus: true,
|
|
1095
|
+
"aria-invalid": codeError ? true : void 0,
|
|
1096
|
+
style: { ...inputStyle, letterSpacing: "0.4em", fontSize: 16 }
|
|
1097
|
+
}
|
|
1098
|
+
),
|
|
1099
|
+
codeError && /* @__PURE__ */ jsx(ErrorLine, { children: codeError }),
|
|
1100
|
+
/* @__PURE__ */ jsx(
|
|
1101
|
+
"button",
|
|
1102
|
+
{
|
|
1103
|
+
type: "submit",
|
|
1104
|
+
disabled: submitting || code.length !== 6,
|
|
1105
|
+
style: submitStyle(submitting || code.length !== 6),
|
|
1106
|
+
children: submitting ? "verifying\u2026" : "verify \xB7 sign me in \u2192"
|
|
1107
|
+
}
|
|
1108
|
+
),
|
|
1109
|
+
/* @__PURE__ */ jsx(
|
|
1110
|
+
"button",
|
|
1111
|
+
{
|
|
1112
|
+
type: "button",
|
|
1113
|
+
onClick: () => {
|
|
1114
|
+
setStage("enter");
|
|
1115
|
+
setCode("");
|
|
1116
|
+
setToken(null);
|
|
1117
|
+
},
|
|
1118
|
+
style: {
|
|
1119
|
+
marginTop: 12,
|
|
1120
|
+
background: "transparent",
|
|
1121
|
+
border: "none",
|
|
1122
|
+
color: "var(--muted-foreground, #a1a1aa)",
|
|
1123
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
1124
|
+
fontSize: 11,
|
|
1125
|
+
letterSpacing: "0.12em",
|
|
1126
|
+
textTransform: "uppercase",
|
|
1127
|
+
cursor: "pointer",
|
|
1128
|
+
padding: 0
|
|
1129
|
+
},
|
|
1130
|
+
children: "use a different email"
|
|
1131
|
+
}
|
|
1132
|
+
),
|
|
1133
|
+
/* @__PURE__ */ jsx(Hint, { children: "On verify, oc_session is set on Domain=.ochk.io family-wide." })
|
|
1134
|
+
] });
|
|
1135
|
+
}
|
|
1136
|
+
function FlowHeader({
|
|
1137
|
+
label,
|
|
1138
|
+
children
|
|
1139
|
+
}) {
|
|
1140
|
+
return /* @__PURE__ */ jsxs("div", { style: { marginBottom: 16 }, children: [
|
|
1141
|
+
/* @__PURE__ */ jsx(
|
|
1142
|
+
"div",
|
|
1143
|
+
{
|
|
1144
|
+
style: {
|
|
1145
|
+
color: "var(--primary, #f97316)",
|
|
1146
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
1147
|
+
fontSize: 10,
|
|
1148
|
+
letterSpacing: "0.18em",
|
|
1149
|
+
textTransform: "uppercase",
|
|
1150
|
+
marginBottom: 6
|
|
1151
|
+
},
|
|
1152
|
+
children: label
|
|
1153
|
+
}
|
|
1154
|
+
),
|
|
1155
|
+
/* @__PURE__ */ jsx(
|
|
1156
|
+
"p",
|
|
1157
|
+
{
|
|
1158
|
+
style: {
|
|
1159
|
+
color: "var(--muted-foreground, #a1a1aa)",
|
|
1160
|
+
fontSize: 13,
|
|
1161
|
+
lineHeight: 1.55,
|
|
1162
|
+
margin: 0
|
|
1163
|
+
},
|
|
1164
|
+
children
|
|
1165
|
+
}
|
|
1166
|
+
)
|
|
1167
|
+
] });
|
|
1168
|
+
}
|
|
1169
|
+
function Label({ children }) {
|
|
1170
|
+
return /* @__PURE__ */ jsx(
|
|
1171
|
+
"label",
|
|
1172
|
+
{
|
|
1173
|
+
style: {
|
|
1174
|
+
display: "block",
|
|
1175
|
+
color: "var(--foreground, #fafafa)",
|
|
1176
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
1177
|
+
fontSize: 11,
|
|
1178
|
+
letterSpacing: "0.12em",
|
|
1179
|
+
textTransform: "uppercase",
|
|
1180
|
+
marginBottom: 6
|
|
1181
|
+
},
|
|
1182
|
+
children
|
|
1183
|
+
}
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
var inputStyle = {
|
|
1187
|
+
width: "100%",
|
|
1188
|
+
padding: "0.55rem 0.75rem",
|
|
1189
|
+
background: "var(--background, #0a0a0a)",
|
|
1190
|
+
color: "var(--foreground, #fafafa)",
|
|
1191
|
+
border: "1px solid var(--input, #27272a)",
|
|
1192
|
+
borderRadius: 6,
|
|
1193
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
1194
|
+
fontSize: 13,
|
|
1195
|
+
outline: "none"
|
|
1196
|
+
};
|
|
1197
|
+
function submitStyle(disabled) {
|
|
1198
|
+
return {
|
|
1199
|
+
marginTop: 12,
|
|
1200
|
+
padding: "0.6rem 1rem",
|
|
1201
|
+
background: "var(--primary, #f97316)",
|
|
1202
|
+
color: "var(--primary-foreground, #0a0a0a)",
|
|
1203
|
+
border: "none",
|
|
1204
|
+
borderRadius: 6,
|
|
1205
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
1206
|
+
fontSize: 11,
|
|
1207
|
+
letterSpacing: "0.14em",
|
|
1208
|
+
textTransform: "uppercase",
|
|
1209
|
+
fontWeight: 600,
|
|
1210
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
1211
|
+
opacity: disabled ? 0.5 : 1,
|
|
1212
|
+
width: "100%"
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
function ErrorLine({ children }) {
|
|
1216
|
+
return /* @__PURE__ */ jsx(
|
|
1217
|
+
"p",
|
|
1218
|
+
{
|
|
1219
|
+
role: "alert",
|
|
1220
|
+
style: {
|
|
1221
|
+
marginTop: 6,
|
|
1222
|
+
marginBottom: 0,
|
|
1223
|
+
color: "var(--destructive, #ef4444)",
|
|
1224
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
1225
|
+
fontSize: 11,
|
|
1226
|
+
letterSpacing: "0.04em"
|
|
1227
|
+
},
|
|
1228
|
+
children
|
|
1229
|
+
}
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
function Hint({ children }) {
|
|
1233
|
+
return /* @__PURE__ */ jsxs(
|
|
1234
|
+
"p",
|
|
1235
|
+
{
|
|
1236
|
+
style: {
|
|
1237
|
+
marginTop: 12,
|
|
1238
|
+
marginBottom: 0,
|
|
1239
|
+
color: "var(--muted-foreground, #a1a1aa)",
|
|
1240
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
1241
|
+
fontSize: 10.5,
|
|
1242
|
+
lineHeight: 1.55,
|
|
1243
|
+
opacity: 0.7
|
|
1244
|
+
},
|
|
1245
|
+
children: [
|
|
1246
|
+
"> ",
|
|
1247
|
+
children
|
|
1248
|
+
]
|
|
1249
|
+
}
|
|
1250
|
+
);
|
|
1251
|
+
}
|
|
747
1252
|
|
|
748
|
-
export { DEFAULT_CONFIG, OcAccountChip, OcAccountPill, OcAddressInput, OcSessionProvider, OcSignInButton, buildSignInUrl, useOcAddressSuggestion, useOcSession, useOptionalOcSession };
|
|
1253
|
+
export { DEFAULT_CONFIG, OcAccountChip, OcAccountPill, OcAddressInput, OcSessionProvider, OcSignIn, OcSignInButton, buildSignInUrl, useOcAddressSuggestion, useOcSession, useOptionalOcSession };
|
|
749
1254
|
//# sourceMappingURL=index.mjs.map
|
|
750
1255
|
//# sourceMappingURL=index.mjs.map
|