@orangecheck/auth-client 2.5.0 → 2.6.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 +19 -3
- package/dist/index.d.ts +19 -3
- package/dist/index.js +903 -72
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +903 -73
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React3 = require('react');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var browser = require('@simplewebauthn/browser');
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@ function _interopNamespace(e) {
|
|
|
22
22
|
return Object.freeze(n);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
var
|
|
25
|
+
var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
|
|
26
26
|
|
|
27
27
|
// src/provider.tsx
|
|
28
28
|
|
|
@@ -43,7 +43,7 @@ function buildSignInUrl(cfg, returnTo) {
|
|
|
43
43
|
u.searchParams.set("return_to", returnTo);
|
|
44
44
|
return u.toString();
|
|
45
45
|
}
|
|
46
|
-
var SessionContext =
|
|
46
|
+
var SessionContext = React3__namespace.createContext(null);
|
|
47
47
|
function normalizeAccount(raw) {
|
|
48
48
|
if (!raw) return null;
|
|
49
49
|
const didOc = raw.did_oc ?? raw.didOc;
|
|
@@ -66,11 +66,11 @@ function OcSessionProvider({
|
|
|
66
66
|
config,
|
|
67
67
|
defaultReturnTo
|
|
68
68
|
}) {
|
|
69
|
-
const cfg =
|
|
70
|
-
const [account, setAccount] =
|
|
71
|
-
const [status, setStatus] =
|
|
72
|
-
const [error, setError] =
|
|
73
|
-
const refresh =
|
|
69
|
+
const cfg = React3__namespace.useMemo(() => resolveConfig(config), [config]);
|
|
70
|
+
const [account, setAccount] = React3__namespace.useState(null);
|
|
71
|
+
const [status, setStatus] = React3__namespace.useState("loading");
|
|
72
|
+
const [error, setError] = React3__namespace.useState(null);
|
|
73
|
+
const refresh = React3__namespace.useCallback(async () => {
|
|
74
74
|
if (typeof window === "undefined") return;
|
|
75
75
|
try {
|
|
76
76
|
const res = await fetch(cfg.mePath, {
|
|
@@ -99,10 +99,10 @@ function OcSessionProvider({
|
|
|
99
99
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
100
100
|
}
|
|
101
101
|
}, [cfg.mePath]);
|
|
102
|
-
|
|
102
|
+
React3__namespace.useEffect(() => {
|
|
103
103
|
void refresh();
|
|
104
104
|
}, [refresh]);
|
|
105
|
-
const signOut =
|
|
105
|
+
const signOut = React3__namespace.useCallback(async () => {
|
|
106
106
|
try {
|
|
107
107
|
await fetch(`${cfg.authOrigin}${cfg.logoutPath}`, {
|
|
108
108
|
method: "POST",
|
|
@@ -113,7 +113,7 @@ function OcSessionProvider({
|
|
|
113
113
|
setAccount(null);
|
|
114
114
|
setStatus("anonymous");
|
|
115
115
|
}, [cfg.authOrigin, cfg.logoutPath]);
|
|
116
|
-
const value =
|
|
116
|
+
const value = React3__namespace.useMemo(() => {
|
|
117
117
|
const returnTo = defaultReturnTo ?? (typeof window !== "undefined" ? window.location.href : void 0);
|
|
118
118
|
return {
|
|
119
119
|
status,
|
|
@@ -127,7 +127,7 @@ function OcSessionProvider({
|
|
|
127
127
|
return /* @__PURE__ */ jsxRuntime.jsx(SessionContext.Provider, { value, children });
|
|
128
128
|
}
|
|
129
129
|
function useOcSession() {
|
|
130
|
-
const ctx =
|
|
130
|
+
const ctx = React3__namespace.useContext(SessionContext);
|
|
131
131
|
if (!ctx) {
|
|
132
132
|
throw new Error(
|
|
133
133
|
"[@orangecheck/auth-client] useOcSession() must be called inside <OcSessionProvider>"
|
|
@@ -136,7 +136,7 @@ function useOcSession() {
|
|
|
136
136
|
return ctx;
|
|
137
137
|
}
|
|
138
138
|
function useOptionalOcSession() {
|
|
139
|
-
return
|
|
139
|
+
return React3__namespace.useContext(SessionContext);
|
|
140
140
|
}
|
|
141
141
|
function shortenAddress(addr) {
|
|
142
142
|
if (addr.length <= 12) return addr;
|
|
@@ -151,7 +151,7 @@ function isPrefixOf(value, target) {
|
|
|
151
151
|
}
|
|
152
152
|
var listboxIdCounter = 0;
|
|
153
153
|
function useUniqueId(prefix) {
|
|
154
|
-
const [id] =
|
|
154
|
+
const [id] = React3__namespace.useState(() => `${prefix}-${++listboxIdCounter}`);
|
|
155
155
|
return id;
|
|
156
156
|
}
|
|
157
157
|
function OcAccountChip({
|
|
@@ -165,9 +165,9 @@ function OcAccountChip({
|
|
|
165
165
|
}) {
|
|
166
166
|
const { status, account, signInUrl: sessionSignInUrl, signOut } = useOcSession();
|
|
167
167
|
const signInUrl = signInUrlOverride ?? sessionSignInUrl;
|
|
168
|
-
const [open, setOpen] =
|
|
169
|
-
const wrapRef =
|
|
170
|
-
|
|
168
|
+
const [open, setOpen] = React3__namespace.useState(false);
|
|
169
|
+
const wrapRef = React3__namespace.useRef(null);
|
|
170
|
+
React3__namespace.useEffect(() => {
|
|
171
171
|
if (!open) return;
|
|
172
172
|
function handleClickOutside(e) {
|
|
173
173
|
if (wrapRef.current && !wrapRef.current.contains(e.target)) {
|
|
@@ -490,9 +490,9 @@ function useOcAddressSuggestion(options) {
|
|
|
490
490
|
} = options;
|
|
491
491
|
const { status, account } = useOcSession();
|
|
492
492
|
const sessionAddress = status === "authenticated" ? account?.primaryBtc ?? null : null;
|
|
493
|
-
const [open, setOpen] =
|
|
494
|
-
const [highlighted, setHighlighted] =
|
|
495
|
-
const blurTimer =
|
|
493
|
+
const [open, setOpen] = React3__namespace.useState(false);
|
|
494
|
+
const [highlighted, setHighlighted] = React3__namespace.useState(false);
|
|
495
|
+
const blurTimer = React3__namespace.useRef(null);
|
|
496
496
|
const listboxId = useUniqueId("oc-addr-listbox");
|
|
497
497
|
const optionId = `${listboxId}-opt`;
|
|
498
498
|
const valueMatchesSession = sessionAddress != null && value.toLowerCase() === sessionAddress.toLowerCase();
|
|
@@ -504,7 +504,7 @@ function useOcAddressSuggestion(options) {
|
|
|
504
504
|
setOpen(false);
|
|
505
505
|
setHighlighted(false);
|
|
506
506
|
}
|
|
507
|
-
|
|
507
|
+
React3__namespace.useEffect(() => {
|
|
508
508
|
return () => {
|
|
509
509
|
if (blurTimer.current != null) window.clearTimeout(blurTimer.current);
|
|
510
510
|
};
|
|
@@ -607,7 +607,7 @@ function useOcAddressSuggestion(options) {
|
|
|
607
607
|
) : null;
|
|
608
608
|
return { inputProps, popover };
|
|
609
609
|
}
|
|
610
|
-
var OcAddressInput =
|
|
610
|
+
var OcAddressInput = React3__namespace.forwardRef(
|
|
611
611
|
function OcAddressInput2({
|
|
612
612
|
value,
|
|
613
613
|
onValueChange,
|
|
@@ -622,15 +622,15 @@ var OcAddressInput = React4__namespace.forwardRef(
|
|
|
622
622
|
}, forwardedRef) {
|
|
623
623
|
const { status, account } = useOcSession();
|
|
624
624
|
const sessionAddress = status === "authenticated" ? account?.primaryBtc ?? null : null;
|
|
625
|
-
const [open, setOpen] =
|
|
626
|
-
const [highlighted, setHighlighted] =
|
|
627
|
-
const innerRef =
|
|
625
|
+
const [open, setOpen] = React3__namespace.useState(false);
|
|
626
|
+
const [highlighted, setHighlighted] = React3__namespace.useState(false);
|
|
627
|
+
const innerRef = React3__namespace.useRef(null);
|
|
628
628
|
const setRef = (node) => {
|
|
629
629
|
innerRef.current = node;
|
|
630
630
|
if (typeof forwardedRef === "function") forwardedRef(node);
|
|
631
631
|
else if (forwardedRef) forwardedRef.current = node;
|
|
632
632
|
};
|
|
633
|
-
const blurTimer =
|
|
633
|
+
const blurTimer = React3__namespace.useRef(null);
|
|
634
634
|
const listboxId = useUniqueId("oc-addr-listbox");
|
|
635
635
|
const optionId = `${listboxId}-opt`;
|
|
636
636
|
const valueMatchesSession = sessionAddress != null && value.toLowerCase() === sessionAddress.toLowerCase();
|
|
@@ -677,7 +677,7 @@ var OcAddressInput = React4__namespace.forwardRef(
|
|
|
677
677
|
}
|
|
678
678
|
onKeyDown?.(e);
|
|
679
679
|
}
|
|
680
|
-
|
|
680
|
+
React3__namespace.useEffect(() => {
|
|
681
681
|
return () => {
|
|
682
682
|
if (blurTimer.current != null) window.clearTimeout(blurTimer.current);
|
|
683
683
|
};
|
|
@@ -770,6 +770,797 @@ var OcAddressInput = React4__namespace.forwardRef(
|
|
|
770
770
|
);
|
|
771
771
|
}
|
|
772
772
|
);
|
|
773
|
+
var DEFAULT_AUTH_ORIGIN = "https://ochk.io";
|
|
774
|
+
function OcLinkedIdentities({
|
|
775
|
+
authOrigin = DEFAULT_AUTH_ORIGIN,
|
|
776
|
+
className,
|
|
777
|
+
onChange
|
|
778
|
+
}) {
|
|
779
|
+
const [resp, setResp] = React3__namespace.useState(null);
|
|
780
|
+
const [error, setError] = React3__namespace.useState(null);
|
|
781
|
+
const [showEmailLink, setShowEmailLink] = React3__namespace.useState(false);
|
|
782
|
+
const [showBtcLink, setShowBtcLink] = React3__namespace.useState(false);
|
|
783
|
+
const refresh = React3__namespace.useCallback(async () => {
|
|
784
|
+
setError(null);
|
|
785
|
+
try {
|
|
786
|
+
const r = await fetch(`${authOrigin}/api/auth/identities`, {
|
|
787
|
+
credentials: "include"
|
|
788
|
+
});
|
|
789
|
+
if (!r.ok) {
|
|
790
|
+
if (r.status === 401) {
|
|
791
|
+
setError("not signed in");
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
throw new Error(`http_${r.status}`);
|
|
795
|
+
}
|
|
796
|
+
setResp(await r.json());
|
|
797
|
+
} catch (e) {
|
|
798
|
+
setError(e instanceof Error ? e.message : "load failed");
|
|
799
|
+
}
|
|
800
|
+
}, [authOrigin]);
|
|
801
|
+
React3__namespace.useEffect(() => {
|
|
802
|
+
void refresh();
|
|
803
|
+
}, [refresh]);
|
|
804
|
+
const afterChange = React3__namespace.useCallback(() => {
|
|
805
|
+
setShowEmailLink(false);
|
|
806
|
+
setShowBtcLink(false);
|
|
807
|
+
void refresh();
|
|
808
|
+
onChange?.();
|
|
809
|
+
}, [refresh, onChange]);
|
|
810
|
+
if (error) {
|
|
811
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-oc-li": "", style: panelStyle("warn"), role: "alert", children: [
|
|
812
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { tone: "warn", children: "\xA7 identities \xB7 load deferred" }),
|
|
813
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { style: bodyStyle, children: [
|
|
814
|
+
"Couldn't reach the auth host (",
|
|
815
|
+
error,
|
|
816
|
+
"). Linking is temporarily unavailable; your signed-in identity still works as normal."
|
|
817
|
+
] }),
|
|
818
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => void refresh(), style: ghostBtnStyle(false), children: "retry" })
|
|
819
|
+
] });
|
|
820
|
+
}
|
|
821
|
+
if (!resp) {
|
|
822
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-oc-li": "", style: panelStyle(), children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: hintStyle, children: [
|
|
823
|
+
"> ",
|
|
824
|
+
"loading\u2026"
|
|
825
|
+
] }) });
|
|
826
|
+
}
|
|
827
|
+
const linked = resp.linked ?? [];
|
|
828
|
+
const emailRows = linked.filter((i) => i.kind === "email");
|
|
829
|
+
const btcRows = linked.filter((i) => i.kind === "btc");
|
|
830
|
+
const hasEmail = emailRows.some((i) => i.value);
|
|
831
|
+
const hasBtc = btcRows.some((i) => i.value);
|
|
832
|
+
const mergedFrom = resp.merged_from ?? [];
|
|
833
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-oc-li": "", style: { display: "grid", gap: 16 }, children: [
|
|
834
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyle(), children: [
|
|
835
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "\xA7 what this is" }),
|
|
836
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { style: bodyStyle, children: [
|
|
837
|
+
"Your public identity is the opaque ",
|
|
838
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { style: codeStyle, children: "did:oc:" }),
|
|
839
|
+
" DID. Below it sit your private linked identities \u2014 your email and your Bitcoin address. They never appear in dashboard chrome and never reach an integrator unless you grant the matching scope. Linking a second identity is also your account-recovery path: if you lose one, the other still signs you in."
|
|
840
|
+
] })
|
|
841
|
+
] }),
|
|
842
|
+
mergedFrom.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ConsolidationPanel, { entries: mergedFrom }),
|
|
843
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyle("plain"), "data-oc-li-rows": "", children: [
|
|
844
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
845
|
+
IdentityGroup,
|
|
846
|
+
{
|
|
847
|
+
kind: "email",
|
|
848
|
+
title: "email",
|
|
849
|
+
rows: emailRows,
|
|
850
|
+
authOrigin,
|
|
851
|
+
onChange: afterChange,
|
|
852
|
+
addCta: hasEmail ? null : "link an email",
|
|
853
|
+
onAdd: () => {
|
|
854
|
+
setShowEmailLink((v) => !v);
|
|
855
|
+
setShowBtcLink(false);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
),
|
|
859
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { borderTop: `1px solid ${V.border}` } }),
|
|
860
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
861
|
+
IdentityGroup,
|
|
862
|
+
{
|
|
863
|
+
kind: "btc",
|
|
864
|
+
title: "bitcoin address",
|
|
865
|
+
rows: btcRows,
|
|
866
|
+
authOrigin,
|
|
867
|
+
onChange: afterChange,
|
|
868
|
+
addCta: hasBtc ? null : "link a Bitcoin address",
|
|
869
|
+
onAdd: () => {
|
|
870
|
+
setShowBtcLink((v) => !v);
|
|
871
|
+
setShowEmailLink(false);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
)
|
|
875
|
+
] }),
|
|
876
|
+
showEmailLink && /* @__PURE__ */ jsxRuntime.jsx(
|
|
877
|
+
EmailLinkForm,
|
|
878
|
+
{
|
|
879
|
+
authOrigin,
|
|
880
|
+
onDone: afterChange,
|
|
881
|
+
onCancel: () => setShowEmailLink(false)
|
|
882
|
+
}
|
|
883
|
+
),
|
|
884
|
+
showBtcLink && /* @__PURE__ */ jsxRuntime.jsx(
|
|
885
|
+
BtcLinkForm,
|
|
886
|
+
{
|
|
887
|
+
authOrigin,
|
|
888
|
+
didOc: resp.did_oc ?? null,
|
|
889
|
+
onDone: afterChange,
|
|
890
|
+
onCancel: () => setShowBtcLink(false)
|
|
891
|
+
}
|
|
892
|
+
)
|
|
893
|
+
] });
|
|
894
|
+
}
|
|
895
|
+
function IdentityGroup({
|
|
896
|
+
kind,
|
|
897
|
+
title,
|
|
898
|
+
rows,
|
|
899
|
+
authOrigin,
|
|
900
|
+
onChange,
|
|
901
|
+
addCta,
|
|
902
|
+
onAdd
|
|
903
|
+
}) {
|
|
904
|
+
if (rows.length === 0) {
|
|
905
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: rowStyle, children: [
|
|
906
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
907
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: rowLabelStyle, children: [
|
|
908
|
+
"\xA7 ",
|
|
909
|
+
title
|
|
910
|
+
] }),
|
|
911
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...bodyStyle, marginTop: 4 }, children: "none linked" })
|
|
912
|
+
] }),
|
|
913
|
+
addCta && /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", onClick: onAdd, style: primaryChipStyle, children: [
|
|
914
|
+
"+ ",
|
|
915
|
+
addCta
|
|
916
|
+
] })
|
|
917
|
+
] });
|
|
918
|
+
}
|
|
919
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: rows.map((r) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
920
|
+
IdentityRow,
|
|
921
|
+
{
|
|
922
|
+
row: r,
|
|
923
|
+
kind,
|
|
924
|
+
authOrigin,
|
|
925
|
+
onChange
|
|
926
|
+
},
|
|
927
|
+
r.id
|
|
928
|
+
)) });
|
|
929
|
+
}
|
|
930
|
+
function IdentityRow({
|
|
931
|
+
row,
|
|
932
|
+
kind,
|
|
933
|
+
authOrigin,
|
|
934
|
+
onChange
|
|
935
|
+
}) {
|
|
936
|
+
const [shown, setShown] = React3__namespace.useState(false);
|
|
937
|
+
const [confirming, setConfirming] = React3__namespace.useState(false);
|
|
938
|
+
const [busy, setBusy] = React3__namespace.useState(false);
|
|
939
|
+
const [err, setErr] = React3__namespace.useState(null);
|
|
940
|
+
const masked = row.value ? mask(row.value, kind) : "\u2014 pending recovery \u2014";
|
|
941
|
+
const display = shown && row.value ? row.value : masked;
|
|
942
|
+
async function unlink() {
|
|
943
|
+
if (row.is_primary) return;
|
|
944
|
+
setBusy(true);
|
|
945
|
+
setErr(null);
|
|
946
|
+
try {
|
|
947
|
+
const r = await fetch(
|
|
948
|
+
`${authOrigin}/api/auth/identities?id=${encodeURIComponent(row.id)}`,
|
|
949
|
+
{ method: "DELETE", credentials: "include" }
|
|
950
|
+
);
|
|
951
|
+
if (!r.ok) {
|
|
952
|
+
const j = await r.json().catch(() => ({}));
|
|
953
|
+
throw new Error(j.reason ?? `http_${r.status}`);
|
|
954
|
+
}
|
|
955
|
+
onChange();
|
|
956
|
+
} catch (e) {
|
|
957
|
+
setErr(e instanceof Error ? e.message : "unlink failed");
|
|
958
|
+
setBusy(false);
|
|
959
|
+
setConfirming(false);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: rowStyle, "data-oc-li-row": kind, children: [
|
|
963
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { minWidth: 0, flex: 1 }, children: [
|
|
964
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexWrap: "wrap", gap: "4px 12px" }, children: [
|
|
965
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: rowLabelStyle, children: [
|
|
966
|
+
"\xA7 ",
|
|
967
|
+
kind === "email" ? "email" : "bitcoin address"
|
|
968
|
+
] }),
|
|
969
|
+
row.is_primary && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...rowLabelStyle, color: V.primary }, children: "primary \xB7 signup-time" })
|
|
970
|
+
] }),
|
|
971
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
972
|
+
"div",
|
|
973
|
+
{
|
|
974
|
+
style: {
|
|
975
|
+
marginTop: 4,
|
|
976
|
+
color: V.foreground,
|
|
977
|
+
fontFamily: MONO,
|
|
978
|
+
fontSize: 12,
|
|
979
|
+
wordBreak: "break-all"
|
|
980
|
+
},
|
|
981
|
+
children: display
|
|
982
|
+
}
|
|
983
|
+
),
|
|
984
|
+
row.verified_at && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...hintStyle, marginTop: 4 }, children: [
|
|
985
|
+
"verified \xB7 ",
|
|
986
|
+
new Date(row.verified_at).toUTCString()
|
|
987
|
+
] }),
|
|
988
|
+
err && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine, { children: err })
|
|
989
|
+
] }),
|
|
990
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexShrink: 0, gap: 8, flexWrap: "wrap" }, children: [
|
|
991
|
+
row.value && /* @__PURE__ */ jsxRuntime.jsx(
|
|
992
|
+
"button",
|
|
993
|
+
{
|
|
994
|
+
type: "button",
|
|
995
|
+
onClick: () => setShown((s) => !s),
|
|
996
|
+
style: ghostBtnStyle(false),
|
|
997
|
+
children: shown ? "hide" : "show"
|
|
998
|
+
}
|
|
999
|
+
),
|
|
1000
|
+
!row.is_primary && !confirming && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1001
|
+
"button",
|
|
1002
|
+
{
|
|
1003
|
+
type: "button",
|
|
1004
|
+
onClick: () => setConfirming(true),
|
|
1005
|
+
style: dangerBtnStyle(false),
|
|
1006
|
+
children: "unlink"
|
|
1007
|
+
}
|
|
1008
|
+
),
|
|
1009
|
+
!row.is_primary && confirming && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1010
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1011
|
+
"button",
|
|
1012
|
+
{
|
|
1013
|
+
type: "button",
|
|
1014
|
+
onClick: () => void unlink(),
|
|
1015
|
+
disabled: busy,
|
|
1016
|
+
style: dangerBtnStyle(busy),
|
|
1017
|
+
children: busy ? "unlinking\u2026" : "confirm unlink"
|
|
1018
|
+
}
|
|
1019
|
+
),
|
|
1020
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1021
|
+
"button",
|
|
1022
|
+
{
|
|
1023
|
+
type: "button",
|
|
1024
|
+
onClick: () => setConfirming(false),
|
|
1025
|
+
disabled: busy,
|
|
1026
|
+
style: ghostBtnStyle(busy),
|
|
1027
|
+
children: "cancel"
|
|
1028
|
+
}
|
|
1029
|
+
)
|
|
1030
|
+
] })
|
|
1031
|
+
] })
|
|
1032
|
+
] });
|
|
1033
|
+
}
|
|
1034
|
+
function ConsolidationPanel({ entries }) {
|
|
1035
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyle("success"), "data-oc-li-consolidated": "", children: [
|
|
1036
|
+
/* @__PURE__ */ jsxRuntime.jsxs(SectionLabel, { tone: "success", children: [
|
|
1037
|
+
"\xA7 consolidated accounts \xB7 ",
|
|
1038
|
+
entries.length
|
|
1039
|
+
] }),
|
|
1040
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { style: bodyStyle, children: [
|
|
1041
|
+
entries.length === 1 ? "A previous OC account" : "Previous OC accounts",
|
|
1042
|
+
" you signed up with, folded into this one under dual proof of control. Historical activity is unioned into this account automatically;",
|
|
1043
|
+
" ",
|
|
1044
|
+
entries.length === 1 ? "it" : "they",
|
|
1045
|
+
" can no longer sign in."
|
|
1046
|
+
] }),
|
|
1047
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { style: { listStyle: "none", margin: "12px 0 0", padding: 0 }, children: entries.map((e) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1048
|
+
"li",
|
|
1049
|
+
{
|
|
1050
|
+
style: {
|
|
1051
|
+
display: "flex",
|
|
1052
|
+
flexWrap: "wrap",
|
|
1053
|
+
gap: 8,
|
|
1054
|
+
padding: "8px 0",
|
|
1055
|
+
borderTop: `1px solid ${V.border}`,
|
|
1056
|
+
fontFamily: MONO,
|
|
1057
|
+
fontSize: 11
|
|
1058
|
+
},
|
|
1059
|
+
children: [
|
|
1060
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { style: { color: V.foreground, wordBreak: "break-all" }, children: e.did_oc }),
|
|
1061
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { ...hintStyle, marginLeft: "auto" }, children: [
|
|
1062
|
+
"created ",
|
|
1063
|
+
new Date(e.created_at).toLocaleDateString()
|
|
1064
|
+
] })
|
|
1065
|
+
]
|
|
1066
|
+
},
|
|
1067
|
+
e.did_oc
|
|
1068
|
+
)) })
|
|
1069
|
+
] });
|
|
1070
|
+
}
|
|
1071
|
+
function EmailLinkForm({
|
|
1072
|
+
authOrigin,
|
|
1073
|
+
onDone,
|
|
1074
|
+
onCancel
|
|
1075
|
+
}) {
|
|
1076
|
+
const [step, setStep] = React3__namespace.useState("email");
|
|
1077
|
+
const [email, setEmail] = React3__namespace.useState("");
|
|
1078
|
+
const [code, setCode] = React3__namespace.useState("");
|
|
1079
|
+
const [token, setToken] = React3__namespace.useState("");
|
|
1080
|
+
const [busy, setBusy] = React3__namespace.useState(false);
|
|
1081
|
+
const [err, setErr] = React3__namespace.useState(null);
|
|
1082
|
+
const [transfer, setTransfer] = React3__namespace.useState(false);
|
|
1083
|
+
async function start() {
|
|
1084
|
+
setBusy(true);
|
|
1085
|
+
setErr(null);
|
|
1086
|
+
try {
|
|
1087
|
+
const r = await fetch(`${authOrigin}/api/auth/email-otp/start`, {
|
|
1088
|
+
method: "POST",
|
|
1089
|
+
credentials: "include",
|
|
1090
|
+
headers: { "Content-Type": "application/json" },
|
|
1091
|
+
body: JSON.stringify({ email: email.trim().toLowerCase() })
|
|
1092
|
+
});
|
|
1093
|
+
const j = await r.json();
|
|
1094
|
+
if (!r.ok || !j.token) throw new Error(j.reason ?? `http_${r.status}`);
|
|
1095
|
+
setToken(j.token);
|
|
1096
|
+
setStep("code");
|
|
1097
|
+
} catch (e) {
|
|
1098
|
+
setErr(e instanceof Error ? e.message : "could not send code");
|
|
1099
|
+
} finally {
|
|
1100
|
+
setBusy(false);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
async function verify(confirmTransfer) {
|
|
1104
|
+
setBusy(true);
|
|
1105
|
+
setErr(null);
|
|
1106
|
+
try {
|
|
1107
|
+
const r = await fetch(`${authOrigin}/api/auth/link/email`, {
|
|
1108
|
+
method: "POST",
|
|
1109
|
+
credentials: "include",
|
|
1110
|
+
headers: { "Content-Type": "application/json" },
|
|
1111
|
+
body: JSON.stringify({
|
|
1112
|
+
email: email.trim().toLowerCase(),
|
|
1113
|
+
code: code.trim(),
|
|
1114
|
+
token,
|
|
1115
|
+
...confirmTransfer ? { confirm_transfer: true } : {}
|
|
1116
|
+
})
|
|
1117
|
+
});
|
|
1118
|
+
const j = await r.json();
|
|
1119
|
+
if (r.status === 409 && j.reason === "email_linked_elsewhere") {
|
|
1120
|
+
setTransfer(true);
|
|
1121
|
+
setBusy(false);
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
if (!r.ok || !j.ok) throw new Error(j.reason ?? `http_${r.status}`);
|
|
1125
|
+
onDone();
|
|
1126
|
+
} catch (e) {
|
|
1127
|
+
setErr(e instanceof Error ? e.message : "link failed");
|
|
1128
|
+
setBusy(false);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyle("accent"), "data-oc-li-form": "email", children: [
|
|
1132
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "\xA7 link an email" }),
|
|
1133
|
+
step === "email" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1134
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1135
|
+
"input",
|
|
1136
|
+
{
|
|
1137
|
+
type: "email",
|
|
1138
|
+
autoComplete: "email",
|
|
1139
|
+
value: email,
|
|
1140
|
+
onChange: (e) => setEmail(e.target.value),
|
|
1141
|
+
placeholder: "you@example.com",
|
|
1142
|
+
style: inputStyle
|
|
1143
|
+
}
|
|
1144
|
+
),
|
|
1145
|
+
err && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine, { children: err }),
|
|
1146
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FormButtons, { children: [
|
|
1147
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1148
|
+
"button",
|
|
1149
|
+
{
|
|
1150
|
+
type: "button",
|
|
1151
|
+
onClick: () => void start(),
|
|
1152
|
+
disabled: busy || email.trim().length < 5,
|
|
1153
|
+
style: primaryBtnStyle(busy || email.trim().length < 5),
|
|
1154
|
+
children: busy ? "sending\u2026" : "send code"
|
|
1155
|
+
}
|
|
1156
|
+
),
|
|
1157
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onCancel, style: ghostBtnStyle(busy), children: "cancel" })
|
|
1158
|
+
] })
|
|
1159
|
+
] }) : transfer ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1160
|
+
TransferConfirm,
|
|
1161
|
+
{
|
|
1162
|
+
what: "email",
|
|
1163
|
+
busy,
|
|
1164
|
+
onConfirm: () => void verify(true),
|
|
1165
|
+
onCancel,
|
|
1166
|
+
err
|
|
1167
|
+
}
|
|
1168
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1169
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { style: bodyStyle, children: [
|
|
1170
|
+
"Enter the 6-digit code sent to ",
|
|
1171
|
+
email,
|
|
1172
|
+
"."
|
|
1173
|
+
] }),
|
|
1174
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1175
|
+
"input",
|
|
1176
|
+
{
|
|
1177
|
+
type: "text",
|
|
1178
|
+
inputMode: "numeric",
|
|
1179
|
+
autoComplete: "one-time-code",
|
|
1180
|
+
maxLength: 6,
|
|
1181
|
+
value: code,
|
|
1182
|
+
onChange: (e) => setCode(e.target.value.replace(/\D/g, "").slice(0, 6)),
|
|
1183
|
+
placeholder: "123456",
|
|
1184
|
+
style: { ...inputStyle, letterSpacing: "0.3em" }
|
|
1185
|
+
}
|
|
1186
|
+
),
|
|
1187
|
+
err && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine, { children: err }),
|
|
1188
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FormButtons, { children: [
|
|
1189
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1190
|
+
"button",
|
|
1191
|
+
{
|
|
1192
|
+
type: "button",
|
|
1193
|
+
onClick: () => void verify(false),
|
|
1194
|
+
disabled: busy || code.length !== 6,
|
|
1195
|
+
style: primaryBtnStyle(busy || code.length !== 6),
|
|
1196
|
+
children: busy ? "linking\u2026" : "verify + link"
|
|
1197
|
+
}
|
|
1198
|
+
),
|
|
1199
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1200
|
+
"button",
|
|
1201
|
+
{
|
|
1202
|
+
type: "button",
|
|
1203
|
+
onClick: () => setStep("email"),
|
|
1204
|
+
disabled: busy,
|
|
1205
|
+
style: ghostBtnStyle(busy),
|
|
1206
|
+
children: "back"
|
|
1207
|
+
}
|
|
1208
|
+
)
|
|
1209
|
+
] })
|
|
1210
|
+
] })
|
|
1211
|
+
] });
|
|
1212
|
+
}
|
|
1213
|
+
function BtcLinkForm({
|
|
1214
|
+
authOrigin,
|
|
1215
|
+
didOc,
|
|
1216
|
+
onDone,
|
|
1217
|
+
onCancel
|
|
1218
|
+
}) {
|
|
1219
|
+
const [step, setStep] = React3__namespace.useState("request");
|
|
1220
|
+
const [addr, setAddr] = React3__namespace.useState("");
|
|
1221
|
+
const [challenge, setChallenge] = React3__namespace.useState("");
|
|
1222
|
+
const [busy, setBusy] = React3__namespace.useState(false);
|
|
1223
|
+
const [err, setErr] = React3__namespace.useState(null);
|
|
1224
|
+
const [pendingSig, setPendingSig] = React3__namespace.useState(null);
|
|
1225
|
+
async function getChallenge() {
|
|
1226
|
+
if (!didOc) {
|
|
1227
|
+
setErr("session not loaded yet \xB7 refresh and retry");
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
setBusy(true);
|
|
1231
|
+
setErr(null);
|
|
1232
|
+
try {
|
|
1233
|
+
const r = await fetch(
|
|
1234
|
+
`${authOrigin}/api/challenge?addr=${encodeURIComponent(addr)}&purpose=link&audience=${encodeURIComponent(didOc)}`
|
|
1235
|
+
);
|
|
1236
|
+
const j = await r.json();
|
|
1237
|
+
if (!r.ok || !j.message) throw new Error(j.reason ?? `http_${r.status}`);
|
|
1238
|
+
setChallenge(j.message);
|
|
1239
|
+
setStep("sign");
|
|
1240
|
+
} catch (e) {
|
|
1241
|
+
setErr(e instanceof Error ? e.message : "challenge failed");
|
|
1242
|
+
} finally {
|
|
1243
|
+
setBusy(false);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
async function postLink(sig, confirmTransfer) {
|
|
1247
|
+
setBusy(true);
|
|
1248
|
+
setErr(null);
|
|
1249
|
+
try {
|
|
1250
|
+
const r = await fetch(`${authOrigin}/api/auth/link/btc`, {
|
|
1251
|
+
method: "POST",
|
|
1252
|
+
credentials: "include",
|
|
1253
|
+
headers: { "Content-Type": "application/json" },
|
|
1254
|
+
body: JSON.stringify({
|
|
1255
|
+
message: challenge,
|
|
1256
|
+
signature: sig,
|
|
1257
|
+
...confirmTransfer ? { confirm_transfer: true } : {}
|
|
1258
|
+
})
|
|
1259
|
+
});
|
|
1260
|
+
const j = await r.json();
|
|
1261
|
+
if (r.status === 409 && j.reason === "address_linked_elsewhere") {
|
|
1262
|
+
setPendingSig(sig);
|
|
1263
|
+
setBusy(false);
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
if (!r.ok || !j.ok) throw new Error(j.reason ?? `http_${r.status}`);
|
|
1267
|
+
onDone();
|
|
1268
|
+
} catch (e) {
|
|
1269
|
+
setErr(e instanceof Error ? e.message : "link failed");
|
|
1270
|
+
setBusy(false);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyle("accent"), "data-oc-li-form": "btc", children: [
|
|
1274
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "\xA7 link a Bitcoin address" }),
|
|
1275
|
+
step === "request" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1276
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: bodyStyle, children: "Enter a Bitcoin address you control. We generate a challenge and your wallet signs it (BIP-322)." }),
|
|
1277
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1278
|
+
"input",
|
|
1279
|
+
{
|
|
1280
|
+
type: "text",
|
|
1281
|
+
value: addr,
|
|
1282
|
+
onChange: (e) => setAddr(e.target.value.trim()),
|
|
1283
|
+
placeholder: "bc1q\u2026",
|
|
1284
|
+
autoCapitalize: "none",
|
|
1285
|
+
spellCheck: false,
|
|
1286
|
+
style: { ...inputStyle, fontFamily: MONO }
|
|
1287
|
+
}
|
|
1288
|
+
),
|
|
1289
|
+
err && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine, { children: err }),
|
|
1290
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FormButtons, { children: [
|
|
1291
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1292
|
+
"button",
|
|
1293
|
+
{
|
|
1294
|
+
type: "button",
|
|
1295
|
+
onClick: () => void getChallenge(),
|
|
1296
|
+
disabled: busy || addr.length < 14,
|
|
1297
|
+
style: primaryBtnStyle(busy || addr.length < 14),
|
|
1298
|
+
children: busy ? "requesting\u2026" : "get challenge"
|
|
1299
|
+
}
|
|
1300
|
+
),
|
|
1301
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onCancel, style: ghostBtnStyle(busy), children: "cancel" })
|
|
1302
|
+
] })
|
|
1303
|
+
] }) : pendingSig ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1304
|
+
TransferConfirm,
|
|
1305
|
+
{
|
|
1306
|
+
what: "bitcoin address",
|
|
1307
|
+
busy,
|
|
1308
|
+
onConfirm: () => void postLink(pendingSig, true),
|
|
1309
|
+
onCancel,
|
|
1310
|
+
err
|
|
1311
|
+
}
|
|
1312
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1313
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { style: bodyStyle, children: [
|
|
1314
|
+
"Sign the challenge with the wallet that controls",
|
|
1315
|
+
" ",
|
|
1316
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontFamily: MONO, wordBreak: "break-all" }, children: addr }),
|
|
1317
|
+
"."
|
|
1318
|
+
] }),
|
|
1319
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1320
|
+
LazyWalletButton,
|
|
1321
|
+
{
|
|
1322
|
+
address: addr,
|
|
1323
|
+
message: challenge,
|
|
1324
|
+
showManual: true,
|
|
1325
|
+
layout: "list",
|
|
1326
|
+
heading: null,
|
|
1327
|
+
onSigned: (sig) => void postLink(sig, false),
|
|
1328
|
+
onError: (e) => setErr(e?.message ?? "wallet rejected")
|
|
1329
|
+
}
|
|
1330
|
+
),
|
|
1331
|
+
err && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine, { children: err }),
|
|
1332
|
+
/* @__PURE__ */ jsxRuntime.jsx(FormButtons, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1333
|
+
"button",
|
|
1334
|
+
{
|
|
1335
|
+
type: "button",
|
|
1336
|
+
onClick: () => {
|
|
1337
|
+
setStep("request");
|
|
1338
|
+
setErr(null);
|
|
1339
|
+
},
|
|
1340
|
+
disabled: busy,
|
|
1341
|
+
style: ghostBtnStyle(busy),
|
|
1342
|
+
children: "back"
|
|
1343
|
+
}
|
|
1344
|
+
) })
|
|
1345
|
+
] })
|
|
1346
|
+
] });
|
|
1347
|
+
}
|
|
1348
|
+
function TransferConfirm({
|
|
1349
|
+
what,
|
|
1350
|
+
busy,
|
|
1351
|
+
onConfirm,
|
|
1352
|
+
onCancel,
|
|
1353
|
+
err
|
|
1354
|
+
}) {
|
|
1355
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1356
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { style: bodyStyle, children: [
|
|
1357
|
+
"This ",
|
|
1358
|
+
what,
|
|
1359
|
+
" is already linked to another OrangeCheck account. You've just proven control of it \u2014 you can transfer the link to this account under dual proof of control. The other account loses this sign-in path; its history stays verifiable. Continue?"
|
|
1360
|
+
] }),
|
|
1361
|
+
err && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine, { children: err }),
|
|
1362
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FormButtons, { children: [
|
|
1363
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1364
|
+
"button",
|
|
1365
|
+
{
|
|
1366
|
+
type: "button",
|
|
1367
|
+
onClick: onConfirm,
|
|
1368
|
+
disabled: busy,
|
|
1369
|
+
style: dangerBtnStyle(busy),
|
|
1370
|
+
children: busy ? "transferring\u2026" : "transfer link here"
|
|
1371
|
+
}
|
|
1372
|
+
),
|
|
1373
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onCancel, disabled: busy, style: ghostBtnStyle(busy), children: "cancel" })
|
|
1374
|
+
] })
|
|
1375
|
+
] });
|
|
1376
|
+
}
|
|
1377
|
+
function LazyWalletButton(props) {
|
|
1378
|
+
const [Comp, setComp] = React3__namespace.useState(null);
|
|
1379
|
+
const [failed, setFailed] = React3__namespace.useState(false);
|
|
1380
|
+
React3__namespace.useEffect(() => {
|
|
1381
|
+
let alive = true;
|
|
1382
|
+
import('@orangecheck/wallet-adapter/react').then((m) => {
|
|
1383
|
+
if (alive) {
|
|
1384
|
+
setComp(
|
|
1385
|
+
() => m.OcWalletButton
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
}).catch(() => {
|
|
1389
|
+
if (alive) setFailed(true);
|
|
1390
|
+
});
|
|
1391
|
+
return () => {
|
|
1392
|
+
alive = false;
|
|
1393
|
+
};
|
|
1394
|
+
}, []);
|
|
1395
|
+
if (failed) {
|
|
1396
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ErrorLine, { children: "@orangecheck/wallet-adapter not installed \xB7 add it to your site to link a wallet" });
|
|
1397
|
+
}
|
|
1398
|
+
if (!Comp) return /* @__PURE__ */ jsxRuntime.jsxs("span", { style: hintStyle, children: [
|
|
1399
|
+
"> ",
|
|
1400
|
+
"loading wallet options\u2026"
|
|
1401
|
+
] });
|
|
1402
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Comp, { ...props });
|
|
1403
|
+
}
|
|
1404
|
+
function mask(value, kind) {
|
|
1405
|
+
if (kind === "email") {
|
|
1406
|
+
const [user, host] = value.split("@");
|
|
1407
|
+
if (!user || !host) return "\u2022\u2022\u2022\u2022";
|
|
1408
|
+
const m = user.length <= 2 ? "\u2022".repeat(user.length) : user[0] + "\u2022".repeat(user.length - 2) + user.slice(-1);
|
|
1409
|
+
return `${m}@${host}`;
|
|
1410
|
+
}
|
|
1411
|
+
if (value.length <= 12) return "\u2022".repeat(value.length);
|
|
1412
|
+
return `${value.slice(0, 6)}\u2026${value.slice(-4)}`;
|
|
1413
|
+
}
|
|
1414
|
+
function SectionLabel({
|
|
1415
|
+
children,
|
|
1416
|
+
tone = "primary"
|
|
1417
|
+
}) {
|
|
1418
|
+
const color = tone === "success" ? V.success : tone === "warn" ? V.warn : V.primary;
|
|
1419
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1420
|
+
"div",
|
|
1421
|
+
{
|
|
1422
|
+
style: {
|
|
1423
|
+
color,
|
|
1424
|
+
fontFamily: MONO,
|
|
1425
|
+
fontSize: 10,
|
|
1426
|
+
letterSpacing: "0.18em",
|
|
1427
|
+
textTransform: "uppercase",
|
|
1428
|
+
marginBottom: 8
|
|
1429
|
+
},
|
|
1430
|
+
children
|
|
1431
|
+
}
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
function ErrorLine({ children }) {
|
|
1435
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1436
|
+
"p",
|
|
1437
|
+
{
|
|
1438
|
+
role: "alert",
|
|
1439
|
+
style: {
|
|
1440
|
+
margin: "8px 0 0",
|
|
1441
|
+
color: V.destructive,
|
|
1442
|
+
fontFamily: MONO,
|
|
1443
|
+
fontSize: 11
|
|
1444
|
+
},
|
|
1445
|
+
children
|
|
1446
|
+
}
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
function FormButtons({ children }) {
|
|
1450
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 8, marginTop: 12 }, children });
|
|
1451
|
+
}
|
|
1452
|
+
var MONO = "ui-monospace, SFMono-Regular, monospace";
|
|
1453
|
+
var V = {
|
|
1454
|
+
primary: "var(--primary, #f97316)",
|
|
1455
|
+
foreground: "var(--foreground, #fafafa)",
|
|
1456
|
+
muted: "var(--muted-foreground, #a1a1aa)",
|
|
1457
|
+
background: "var(--background, #0a0a0a)",
|
|
1458
|
+
card: "var(--card, #111113)",
|
|
1459
|
+
border: "var(--border, #27272a)",
|
|
1460
|
+
destructive: "var(--destructive, #ef4444)",
|
|
1461
|
+
success: "var(--success, #22c55e)",
|
|
1462
|
+
warn: "var(--warning, #eab308)"
|
|
1463
|
+
};
|
|
1464
|
+
function panelStyle(tone = "default") {
|
|
1465
|
+
const base = {
|
|
1466
|
+
background: V.card,
|
|
1467
|
+
border: `1px solid ${V.border}`,
|
|
1468
|
+
padding: "1.25rem"
|
|
1469
|
+
};
|
|
1470
|
+
if (tone === "plain") return { ...base, padding: 0 };
|
|
1471
|
+
if (tone === "accent") return { ...base, borderColor: V.primary, background: "var(--card, #111113)" };
|
|
1472
|
+
if (tone === "success") return { ...base, borderColor: V.success };
|
|
1473
|
+
if (tone === "warn") return { ...base, borderColor: V.warn };
|
|
1474
|
+
return base;
|
|
1475
|
+
}
|
|
1476
|
+
var bodyStyle = {
|
|
1477
|
+
color: V.muted,
|
|
1478
|
+
fontSize: 13,
|
|
1479
|
+
lineHeight: 1.55,
|
|
1480
|
+
margin: "0 0 12px"
|
|
1481
|
+
};
|
|
1482
|
+
var hintStyle = {
|
|
1483
|
+
color: V.muted,
|
|
1484
|
+
fontFamily: MONO,
|
|
1485
|
+
fontSize: 10.5,
|
|
1486
|
+
opacity: 0.8
|
|
1487
|
+
};
|
|
1488
|
+
var codeStyle = {
|
|
1489
|
+
fontFamily: MONO,
|
|
1490
|
+
color: V.foreground
|
|
1491
|
+
};
|
|
1492
|
+
var rowStyle = {
|
|
1493
|
+
display: "flex",
|
|
1494
|
+
flexWrap: "wrap",
|
|
1495
|
+
alignItems: "center",
|
|
1496
|
+
justifyContent: "space-between",
|
|
1497
|
+
gap: 12,
|
|
1498
|
+
padding: "1rem"
|
|
1499
|
+
};
|
|
1500
|
+
var rowLabelStyle = {
|
|
1501
|
+
color: V.foreground,
|
|
1502
|
+
fontFamily: MONO,
|
|
1503
|
+
fontSize: 10.5,
|
|
1504
|
+
letterSpacing: "0.12em",
|
|
1505
|
+
textTransform: "uppercase",
|
|
1506
|
+
opacity: 0.8
|
|
1507
|
+
};
|
|
1508
|
+
var inputStyle = {
|
|
1509
|
+
width: "100%",
|
|
1510
|
+
padding: "0.55rem 0.75rem",
|
|
1511
|
+
background: V.background,
|
|
1512
|
+
color: V.foreground,
|
|
1513
|
+
border: `1px solid ${V.border}`,
|
|
1514
|
+
borderRadius: 6,
|
|
1515
|
+
fontFamily: MONO,
|
|
1516
|
+
// 16px — never lower · suppresses iOS Safari focus auto-zoom.
|
|
1517
|
+
fontSize: 16,
|
|
1518
|
+
outline: "none",
|
|
1519
|
+
boxSizing: "border-box"
|
|
1520
|
+
};
|
|
1521
|
+
function btnBase(disabled) {
|
|
1522
|
+
return {
|
|
1523
|
+
padding: "0.5rem 0.875rem",
|
|
1524
|
+
borderRadius: 6,
|
|
1525
|
+
fontFamily: MONO,
|
|
1526
|
+
fontSize: 10.5,
|
|
1527
|
+
letterSpacing: "0.12em",
|
|
1528
|
+
textTransform: "uppercase",
|
|
1529
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
1530
|
+
opacity: disabled ? 0.5 : 1
|
|
1531
|
+
};
|
|
1532
|
+
}
|
|
1533
|
+
function primaryBtnStyle(disabled) {
|
|
1534
|
+
return {
|
|
1535
|
+
...btnBase(disabled),
|
|
1536
|
+
background: V.primary,
|
|
1537
|
+
color: "var(--primary-foreground, #0a0a0a)",
|
|
1538
|
+
border: `1px solid ${V.primary}`,
|
|
1539
|
+
fontWeight: 600
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1542
|
+
function ghostBtnStyle(disabled) {
|
|
1543
|
+
return {
|
|
1544
|
+
...btnBase(disabled),
|
|
1545
|
+
background: V.background,
|
|
1546
|
+
color: V.foreground,
|
|
1547
|
+
border: `1px solid ${V.border}`
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1550
|
+
function dangerBtnStyle(disabled) {
|
|
1551
|
+
return {
|
|
1552
|
+
...btnBase(disabled),
|
|
1553
|
+
background: "transparent",
|
|
1554
|
+
color: V.destructive,
|
|
1555
|
+
border: `1px solid ${V.destructive}`
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
var primaryChipStyle = {
|
|
1559
|
+
...btnBase(false),
|
|
1560
|
+
background: "transparent",
|
|
1561
|
+
color: V.primary,
|
|
1562
|
+
border: `1px solid ${V.primary}`
|
|
1563
|
+
};
|
|
773
1564
|
function safeReturnTo(input) {
|
|
774
1565
|
const candidate = input ?? "/";
|
|
775
1566
|
if (typeof candidate !== "string") return "/";
|
|
@@ -785,6 +1576,7 @@ function OcSignIn({
|
|
|
785
1576
|
returnTo,
|
|
786
1577
|
onSuccess,
|
|
787
1578
|
resolveReturnTo,
|
|
1579
|
+
linkPrompt,
|
|
788
1580
|
authOrigin = "https://ochk.io",
|
|
789
1581
|
initialPath = "wallet",
|
|
790
1582
|
paths,
|
|
@@ -793,24 +1585,34 @@ function OcSignIn({
|
|
|
793
1585
|
const walletEnabled = paths?.wallet ?? true;
|
|
794
1586
|
const emailEnabled = paths?.email ?? true;
|
|
795
1587
|
const safeReturn = safeReturnTo(returnTo);
|
|
796
|
-
const [path, setPath] =
|
|
797
|
-
const
|
|
1588
|
+
const [path, setPath] = React3__namespace.useState(initialPath);
|
|
1589
|
+
const [signedIn, setSignedIn] = React3__namespace.useState(null);
|
|
1590
|
+
const navigate = React3__namespace.useCallback(
|
|
798
1591
|
async (account) => {
|
|
799
|
-
if (onSuccess) {
|
|
800
|
-
onSuccess(account);
|
|
801
|
-
return;
|
|
802
|
-
}
|
|
803
1592
|
if (resolveReturnTo) {
|
|
804
1593
|
try {
|
|
805
|
-
|
|
806
|
-
hardNavigate(safeReturnTo(target));
|
|
1594
|
+
hardNavigate(safeReturnTo(await resolveReturnTo(account)));
|
|
807
1595
|
return;
|
|
808
1596
|
} catch {
|
|
809
1597
|
}
|
|
810
1598
|
}
|
|
811
1599
|
hardNavigate(safeReturn);
|
|
812
1600
|
},
|
|
813
|
-
[
|
|
1601
|
+
[resolveReturnTo, safeReturn]
|
|
1602
|
+
);
|
|
1603
|
+
const handleSuccess = React3__namespace.useCallback(
|
|
1604
|
+
async (account, token) => {
|
|
1605
|
+
if (onSuccess) {
|
|
1606
|
+
onSuccess(account, token);
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
if (linkPrompt) {
|
|
1610
|
+
setSignedIn(account);
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1613
|
+
await navigate(account);
|
|
1614
|
+
},
|
|
1615
|
+
[onSuccess, linkPrompt, navigate]
|
|
814
1616
|
);
|
|
815
1617
|
if (!walletEnabled && !emailEnabled) {
|
|
816
1618
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -837,6 +1639,15 @@ function OcSignIn({
|
|
|
837
1639
|
}
|
|
838
1640
|
);
|
|
839
1641
|
}
|
|
1642
|
+
if (signedIn) {
|
|
1643
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-oc-signin": "", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1644
|
+
LinkPromptStep,
|
|
1645
|
+
{
|
|
1646
|
+
authOrigin,
|
|
1647
|
+
onContinue: () => void navigate(signedIn)
|
|
1648
|
+
}
|
|
1649
|
+
) });
|
|
1650
|
+
}
|
|
840
1651
|
const showWallet = walletEnabled && (path === "wallet" || !emailEnabled);
|
|
841
1652
|
const showEmail = emailEnabled && (path === "email" || !walletEnabled);
|
|
842
1653
|
const bothEnabled = walletEnabled && emailEnabled;
|
|
@@ -879,6 +1690,25 @@ function OcSignIn({
|
|
|
879
1690
|
] })
|
|
880
1691
|
] });
|
|
881
1692
|
}
|
|
1693
|
+
function LinkPromptStep({
|
|
1694
|
+
authOrigin,
|
|
1695
|
+
onContinue
|
|
1696
|
+
}) {
|
|
1697
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-oc-signin-linkprompt": "", children: [
|
|
1698
|
+
/* @__PURE__ */ jsxRuntime.jsx(FlowHeader, { label: "\xA7 signed in \xB7 add a backup", children: "You're in. Linking a second way to sign in \u2014 your email or your Bitcoin wallet \u2014 is also your recovery path: lose one, the other still gets you in. Optional; skip with continue." }),
|
|
1699
|
+
/* @__PURE__ */ jsxRuntime.jsx(OcLinkedIdentities, { authOrigin }),
|
|
1700
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1701
|
+
"button",
|
|
1702
|
+
{
|
|
1703
|
+
type: "button",
|
|
1704
|
+
onClick: onContinue,
|
|
1705
|
+
style: submitStyle(false),
|
|
1706
|
+
"data-oc-signin-continue": "",
|
|
1707
|
+
children: "continue \u2192"
|
|
1708
|
+
}
|
|
1709
|
+
)
|
|
1710
|
+
] });
|
|
1711
|
+
}
|
|
882
1712
|
function SigninTab({
|
|
883
1713
|
active,
|
|
884
1714
|
onClick,
|
|
@@ -910,10 +1740,10 @@ function SigninTab({
|
|
|
910
1740
|
);
|
|
911
1741
|
}
|
|
912
1742
|
function WalletFlow({ authOrigin, audience, onSuccess }) {
|
|
913
|
-
const [address, setAddress] =
|
|
914
|
-
const [error, setError] =
|
|
915
|
-
const [submitting, setSubmitting] =
|
|
916
|
-
const [stage, setStage] =
|
|
1743
|
+
const [address, setAddress] = React3__namespace.useState("");
|
|
1744
|
+
const [error, setError] = React3__namespace.useState(null);
|
|
1745
|
+
const [submitting, setSubmitting] = React3__namespace.useState(false);
|
|
1746
|
+
const [stage, setStage] = React3__namespace.useState("enter");
|
|
917
1747
|
async function signIn(e) {
|
|
918
1748
|
e.preventDefault();
|
|
919
1749
|
const addr = address.trim();
|
|
@@ -966,7 +1796,7 @@ function WalletFlow({ authOrigin, audience, onSuccess }) {
|
|
|
966
1796
|
"reason" in json && json.reason || "error" in json && json.error || `verify_failed_${res.status}`
|
|
967
1797
|
);
|
|
968
1798
|
}
|
|
969
|
-
onSuccess(json.account);
|
|
1799
|
+
onSuccess(json.account, json.token);
|
|
970
1800
|
} catch (err) {
|
|
971
1801
|
const msg = err instanceof Error ? err.message : "sign-in failed";
|
|
972
1802
|
setError(msg);
|
|
@@ -992,10 +1822,10 @@ function WalletFlow({ authOrigin, audience, onSuccess }) {
|
|
|
992
1822
|
spellCheck: false,
|
|
993
1823
|
required: true,
|
|
994
1824
|
"aria-invalid": error ? true : void 0,
|
|
995
|
-
style:
|
|
1825
|
+
style: inputStyle2
|
|
996
1826
|
}
|
|
997
1827
|
),
|
|
998
|
-
error && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1828
|
+
error && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine2, { children: error }),
|
|
999
1829
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1000
1830
|
"button",
|
|
1001
1831
|
{
|
|
@@ -1009,13 +1839,13 @@ function WalletFlow({ authOrigin, audience, onSuccess }) {
|
|
|
1009
1839
|
] });
|
|
1010
1840
|
}
|
|
1011
1841
|
function EmailFlow({ authOrigin, onSuccess }) {
|
|
1012
|
-
const [stage, setStage] =
|
|
1013
|
-
const [email, setEmail] =
|
|
1014
|
-
const [emailError, setEmailError] =
|
|
1015
|
-
const [code, setCode] =
|
|
1016
|
-
const [codeError, setCodeError] =
|
|
1017
|
-
const [token, setToken] =
|
|
1018
|
-
const [submitting, setSubmitting] =
|
|
1842
|
+
const [stage, setStage] = React3__namespace.useState("enter");
|
|
1843
|
+
const [email, setEmail] = React3__namespace.useState("");
|
|
1844
|
+
const [emailError, setEmailError] = React3__namespace.useState(null);
|
|
1845
|
+
const [code, setCode] = React3__namespace.useState("");
|
|
1846
|
+
const [codeError, setCodeError] = React3__namespace.useState(null);
|
|
1847
|
+
const [token, setToken] = React3__namespace.useState(null);
|
|
1848
|
+
const [submitting, setSubmitting] = React3__namespace.useState(false);
|
|
1019
1849
|
async function start(e) {
|
|
1020
1850
|
e.preventDefault();
|
|
1021
1851
|
const trimmed = email.trim().toLowerCase();
|
|
@@ -1067,7 +1897,7 @@ function EmailFlow({ authOrigin, onSuccess }) {
|
|
|
1067
1897
|
"reason" in json && json.reason || "error" in json && json.error || `verify failed (${res.status})`
|
|
1068
1898
|
);
|
|
1069
1899
|
}
|
|
1070
|
-
onSuccess(json.account);
|
|
1900
|
+
onSuccess(json.account, json.token);
|
|
1071
1901
|
} catch (err) {
|
|
1072
1902
|
setCodeError(err instanceof Error ? err.message : "verify failed");
|
|
1073
1903
|
} finally {
|
|
@@ -1091,10 +1921,10 @@ function EmailFlow({ authOrigin, onSuccess }) {
|
|
|
1091
1921
|
placeholder: "you@example.com",
|
|
1092
1922
|
required: true,
|
|
1093
1923
|
"aria-invalid": emailError ? true : void 0,
|
|
1094
|
-
style:
|
|
1924
|
+
style: inputStyle2
|
|
1095
1925
|
}
|
|
1096
1926
|
),
|
|
1097
|
-
emailError && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1927
|
+
emailError && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine2, { children: emailError }),
|
|
1098
1928
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: submitting, style: submitStyle(submitting), children: submitting ? "sending\u2026" : "send one-time code \u2192" }),
|
|
1099
1929
|
/* @__PURE__ */ jsxRuntime.jsx(Hint, { children: "OTP delivered by the auth host. Codes expire in 10 minutes and are single-use. Rate-limited 5 starts/hour/IP." })
|
|
1100
1930
|
] });
|
|
@@ -1123,10 +1953,10 @@ function EmailFlow({ authOrigin, onSuccess }) {
|
|
|
1123
1953
|
required: true,
|
|
1124
1954
|
autoFocus: true,
|
|
1125
1955
|
"aria-invalid": codeError ? true : void 0,
|
|
1126
|
-
style: { ...
|
|
1956
|
+
style: { ...inputStyle2, letterSpacing: "0.4em", fontSize: 16 }
|
|
1127
1957
|
}
|
|
1128
1958
|
),
|
|
1129
|
-
codeError && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1959
|
+
codeError && /* @__PURE__ */ jsxRuntime.jsx(ErrorLine2, { children: codeError }),
|
|
1130
1960
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1131
1961
|
"button",
|
|
1132
1962
|
{
|
|
@@ -1213,7 +2043,7 @@ function Label({ children }) {
|
|
|
1213
2043
|
}
|
|
1214
2044
|
);
|
|
1215
2045
|
}
|
|
1216
|
-
var
|
|
2046
|
+
var inputStyle2 = {
|
|
1217
2047
|
width: "100%",
|
|
1218
2048
|
padding: "0.55rem 0.75rem",
|
|
1219
2049
|
background: "var(--background, #0a0a0a)",
|
|
@@ -1245,7 +2075,7 @@ function submitStyle(disabled) {
|
|
|
1245
2075
|
width: "100%"
|
|
1246
2076
|
};
|
|
1247
2077
|
}
|
|
1248
|
-
function
|
|
2078
|
+
function ErrorLine2({ children }) {
|
|
1249
2079
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1250
2080
|
"p",
|
|
1251
2081
|
{
|
|
@@ -1292,13 +2122,13 @@ function isAbortError(err) {
|
|
|
1292
2122
|
}
|
|
1293
2123
|
function useWebAuthnRegister(opts) {
|
|
1294
2124
|
const authOrigin = resolveAuthOrigin(opts);
|
|
1295
|
-
const [status, setStatus] =
|
|
1296
|
-
const [error, setError] =
|
|
1297
|
-
const reset =
|
|
2125
|
+
const [status, setStatus] = React3__namespace.useState("idle");
|
|
2126
|
+
const [error, setError] = React3__namespace.useState(null);
|
|
2127
|
+
const reset = React3__namespace.useCallback(() => {
|
|
1298
2128
|
setStatus("idle");
|
|
1299
2129
|
setError(null);
|
|
1300
2130
|
}, []);
|
|
1301
|
-
const register =
|
|
2131
|
+
const register = React3__namespace.useCallback(
|
|
1302
2132
|
async (args) => {
|
|
1303
2133
|
setError(null);
|
|
1304
2134
|
setStatus("requesting-options");
|
|
@@ -1360,10 +2190,10 @@ function useWebAuthnRegister(opts) {
|
|
|
1360
2190
|
function useWebAuthnList(opts) {
|
|
1361
2191
|
const authOrigin = resolveAuthOrigin(opts);
|
|
1362
2192
|
const { status: sessionStatus } = useOcSession();
|
|
1363
|
-
const [credentials, setCredentials] =
|
|
1364
|
-
const [status, setStatus] =
|
|
1365
|
-
const [error, setError] =
|
|
1366
|
-
const refetch =
|
|
2193
|
+
const [credentials, setCredentials] = React3__namespace.useState([]);
|
|
2194
|
+
const [status, setStatus] = React3__namespace.useState("loading");
|
|
2195
|
+
const [error, setError] = React3__namespace.useState(null);
|
|
2196
|
+
const refetch = React3__namespace.useCallback(async () => {
|
|
1367
2197
|
setError(null);
|
|
1368
2198
|
if (sessionStatus !== "authenticated") {
|
|
1369
2199
|
setCredentials([]);
|
|
@@ -1391,10 +2221,10 @@ function useWebAuthnList(opts) {
|
|
|
1391
2221
|
setStatus("error");
|
|
1392
2222
|
}
|
|
1393
2223
|
}, [authOrigin, sessionStatus]);
|
|
1394
|
-
|
|
2224
|
+
React3__namespace.useEffect(() => {
|
|
1395
2225
|
void refetch();
|
|
1396
2226
|
}, [refetch]);
|
|
1397
|
-
const rename =
|
|
2227
|
+
const rename = React3__namespace.useCallback(
|
|
1398
2228
|
async (id, label) => {
|
|
1399
2229
|
try {
|
|
1400
2230
|
const r = await fetch(`${authOrigin}/api/auth/webauthn/credentials/${id}`, {
|
|
@@ -1419,7 +2249,7 @@ function useWebAuthnList(opts) {
|
|
|
1419
2249
|
},
|
|
1420
2250
|
[authOrigin, refetch]
|
|
1421
2251
|
);
|
|
1422
|
-
const remove =
|
|
2252
|
+
const remove = React3__namespace.useCallback(
|
|
1423
2253
|
async (id) => {
|
|
1424
2254
|
try {
|
|
1425
2255
|
const r = await fetch(`${authOrigin}/api/auth/webauthn/credentials/${id}`, {
|
|
@@ -1447,13 +2277,13 @@ function useWebAuthnList(opts) {
|
|
|
1447
2277
|
function useStepUpAuth(opts) {
|
|
1448
2278
|
const authOrigin = resolveAuthOrigin(opts);
|
|
1449
2279
|
const { refresh } = useOcSession();
|
|
1450
|
-
const [status, setStatus] =
|
|
1451
|
-
const [error, setError] =
|
|
1452
|
-
const reset =
|
|
2280
|
+
const [status, setStatus] = React3__namespace.useState("idle");
|
|
2281
|
+
const [error, setError] = React3__namespace.useState(null);
|
|
2282
|
+
const reset = React3__namespace.useCallback(() => {
|
|
1453
2283
|
setStatus("idle");
|
|
1454
2284
|
setError(null);
|
|
1455
2285
|
}, []);
|
|
1456
|
-
const stepUp =
|
|
2286
|
+
const stepUp = React3__namespace.useCallback(
|
|
1457
2287
|
async (args) => {
|
|
1458
2288
|
setError(null);
|
|
1459
2289
|
setStatus("requesting-options");
|
|
@@ -1542,6 +2372,7 @@ exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
|
|
|
1542
2372
|
exports.OcAccountChip = OcAccountChip;
|
|
1543
2373
|
exports.OcAccountPill = OcAccountPill;
|
|
1544
2374
|
exports.OcAddressInput = OcAddressInput;
|
|
2375
|
+
exports.OcLinkedIdentities = OcLinkedIdentities;
|
|
1545
2376
|
exports.OcSessionProvider = OcSessionProvider;
|
|
1546
2377
|
exports.OcSignIn = OcSignIn;
|
|
1547
2378
|
exports.OcSignInButton = OcSignInButton;
|