@orangecheck/auth-client 2.15.0 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/index.d.mts +18 -3
- package/dist/index.d.ts +18 -3
- package/dist/index.js +146 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +146 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -22,6 +22,11 @@ function buildSignInUrl(cfg, returnTo) {
|
|
|
22
22
|
u.searchParams.set("return_to", returnTo);
|
|
23
23
|
return u.toString();
|
|
24
24
|
}
|
|
25
|
+
function buildAddAccountUrl(cfg, returnTo) {
|
|
26
|
+
const u = new URL(buildSignInUrl(cfg, returnTo));
|
|
27
|
+
u.searchParams.set("add", "1");
|
|
28
|
+
return u.toString();
|
|
29
|
+
}
|
|
25
30
|
var SessionContext = React3.createContext(null);
|
|
26
31
|
function normalizeDisplayIdentity(raw, didOc) {
|
|
27
32
|
const di = raw.display_identity ?? raw.displayIdentity;
|
|
@@ -30,6 +35,19 @@ function normalizeDisplayIdentity(raw, didOc) {
|
|
|
30
35
|
}
|
|
31
36
|
return { kind: "did", value: didOc };
|
|
32
37
|
}
|
|
38
|
+
function normalizeRosterEntry(raw) {
|
|
39
|
+
const didOc = raw.did_oc ?? raw.didOc;
|
|
40
|
+
if (!didOc) return null;
|
|
41
|
+
const di = raw.display_identity ?? raw.displayIdentity;
|
|
42
|
+
const displayIdentity = di && typeof di === "object" && typeof di.value === "string" && di.value.length > 0 && typeof di.kind === "string" && DISPLAY_IDENTITY_KINDS.includes(di.kind) ? { kind: di.kind, value: di.value } : { kind: "did", value: didOc };
|
|
43
|
+
return {
|
|
44
|
+
didOc,
|
|
45
|
+
displayName: raw.display_name ?? raw.displayName ?? null,
|
|
46
|
+
primaryBtc: raw.primary_btc ?? raw.primaryBtc ?? null,
|
|
47
|
+
displayIdentity,
|
|
48
|
+
lastSeenAt: raw.last_seen_at ?? raw.lastSeenAt ?? null
|
|
49
|
+
};
|
|
50
|
+
}
|
|
33
51
|
function normalizeAccount(raw) {
|
|
34
52
|
if (!raw) return null;
|
|
35
53
|
const didOc = raw.did_oc ?? raw.didOc;
|
|
@@ -55,6 +73,7 @@ function OcSessionProvider({
|
|
|
55
73
|
}) {
|
|
56
74
|
const cfg = React3.useMemo(() => resolveConfig(config), [config]);
|
|
57
75
|
const [account, setAccount] = React3.useState(null);
|
|
76
|
+
const [roster, setRoster] = React3.useState([]);
|
|
58
77
|
const [status, setStatus] = React3.useState("loading");
|
|
59
78
|
const [error, setError] = React3.useState(null);
|
|
60
79
|
const refresh = React3.useCallback(async () => {
|
|
@@ -67,6 +86,7 @@ function OcSessionProvider({
|
|
|
67
86
|
});
|
|
68
87
|
if (res.status === 401) {
|
|
69
88
|
setAccount(null);
|
|
89
|
+
setRoster([]);
|
|
70
90
|
setStatus("anonymous");
|
|
71
91
|
setError(null);
|
|
72
92
|
return;
|
|
@@ -78,7 +98,9 @@ function OcSessionProvider({
|
|
|
78
98
|
}
|
|
79
99
|
const body = await res.json();
|
|
80
100
|
const acct = normalizeAccount(body.account);
|
|
101
|
+
const rosterEntries = Array.isArray(body.roster) ? body.roster.map(normalizeRosterEntry).filter((r) => r !== null) : [];
|
|
81
102
|
setAccount(acct);
|
|
103
|
+
setRoster(rosterEntries);
|
|
82
104
|
setStatus(acct ? "authenticated" : "anonymous");
|
|
83
105
|
setError(null);
|
|
84
106
|
} catch (err) {
|
|
@@ -89,23 +111,63 @@ function OcSessionProvider({
|
|
|
89
111
|
React3.useEffect(() => {
|
|
90
112
|
void refresh();
|
|
91
113
|
}, [refresh]);
|
|
92
|
-
const signOut = React3.useCallback(
|
|
93
|
-
|
|
94
|
-
|
|
114
|
+
const signOut = React3.useCallback(
|
|
115
|
+
async (opts) => {
|
|
116
|
+
const scope = opts?.scope ?? "all";
|
|
117
|
+
try {
|
|
118
|
+
const url = new URL(`${cfg.authOrigin}${cfg.logoutPath}`);
|
|
119
|
+
if (scope === "current") url.searchParams.set("scope", "current");
|
|
120
|
+
const res = await fetch(url.toString(), {
|
|
121
|
+
method: "POST",
|
|
122
|
+
credentials: "include",
|
|
123
|
+
// `keepalive` lets the logout round-trip complete even if
|
|
124
|
+
// the caller hard-navigates away in the same tick (e.g.
|
|
125
|
+
// `<OcAccountMenu>` redirects home immediately on sign-out).
|
|
126
|
+
// Without it the in-flight request is cancelled on unload
|
|
127
|
+
// and the `.ochk.io` cookie may never get cleared.
|
|
128
|
+
keepalive: true
|
|
129
|
+
});
|
|
130
|
+
if (scope === "current" && res.ok) {
|
|
131
|
+
await refresh();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
} catch {
|
|
135
|
+
}
|
|
136
|
+
setAccount(null);
|
|
137
|
+
setRoster([]);
|
|
138
|
+
setStatus("anonymous");
|
|
139
|
+
},
|
|
140
|
+
[cfg.authOrigin, cfg.logoutPath, refresh]
|
|
141
|
+
);
|
|
142
|
+
const switchAccount = React3.useCallback(
|
|
143
|
+
async (didOc) => {
|
|
144
|
+
if (typeof window === "undefined") return;
|
|
145
|
+
const res = await fetch(`${cfg.authOrigin}/api/auth/switch`, {
|
|
95
146
|
method: "POST",
|
|
96
147
|
credentials: "include",
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// `<OcAccountMenu>` redirects home immediately on sign-out).
|
|
100
|
-
// Without it the in-flight request is cancelled on unload
|
|
101
|
-
// and the `.ochk.io` cookie may never get cleared.
|
|
102
|
-
keepalive: true
|
|
148
|
+
headers: { "Content-Type": "application/json" },
|
|
149
|
+
body: JSON.stringify({ did_oc: didOc })
|
|
103
150
|
});
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
151
|
+
if (!res.ok) {
|
|
152
|
+
let reason = `http_${res.status}`;
|
|
153
|
+
try {
|
|
154
|
+
const body = await res.json();
|
|
155
|
+
if (body.reason) reason = body.reason;
|
|
156
|
+
} catch {
|
|
157
|
+
}
|
|
158
|
+
throw new Error(`[@orangecheck/auth-client] switchAccount failed: ${reason}`);
|
|
159
|
+
}
|
|
160
|
+
await refresh();
|
|
161
|
+
},
|
|
162
|
+
[cfg.authOrigin, refresh]
|
|
163
|
+
);
|
|
164
|
+
const addAccountUrl = React3.useCallback(
|
|
165
|
+
(returnTo) => {
|
|
166
|
+
const rt = returnTo ?? (typeof window !== "undefined" ? window.location.href : void 0);
|
|
167
|
+
return buildAddAccountUrl(cfg, rt);
|
|
168
|
+
},
|
|
169
|
+
[cfg]
|
|
170
|
+
);
|
|
109
171
|
const setDisplayIdentity = React3.useCallback(
|
|
110
172
|
async (kind) => {
|
|
111
173
|
if (typeof window === "undefined") return;
|
|
@@ -133,13 +195,28 @@ function OcSessionProvider({
|
|
|
133
195
|
return {
|
|
134
196
|
status,
|
|
135
197
|
account,
|
|
198
|
+
roster,
|
|
136
199
|
error,
|
|
137
200
|
refresh,
|
|
138
201
|
signOut,
|
|
202
|
+
switchAccount,
|
|
203
|
+
addAccountUrl,
|
|
139
204
|
setDisplayIdentity,
|
|
140
205
|
signInUrl: buildSignInUrl(cfg, returnTo)
|
|
141
206
|
};
|
|
142
|
-
}, [
|
|
207
|
+
}, [
|
|
208
|
+
status,
|
|
209
|
+
account,
|
|
210
|
+
roster,
|
|
211
|
+
error,
|
|
212
|
+
refresh,
|
|
213
|
+
signOut,
|
|
214
|
+
switchAccount,
|
|
215
|
+
addAccountUrl,
|
|
216
|
+
setDisplayIdentity,
|
|
217
|
+
cfg,
|
|
218
|
+
defaultReturnTo
|
|
219
|
+
]);
|
|
143
220
|
return /* @__PURE__ */ jsx(SessionContext.Provider, { value, children });
|
|
144
221
|
}
|
|
145
222
|
function useOcSession() {
|
|
@@ -1666,6 +1743,7 @@ function OcSignIn({
|
|
|
1666
1743
|
onSuccess,
|
|
1667
1744
|
resolveReturnTo,
|
|
1668
1745
|
linkPrompt = true,
|
|
1746
|
+
add: addProp,
|
|
1669
1747
|
authOrigin = "https://ochk.io",
|
|
1670
1748
|
initialPath = "wallet",
|
|
1671
1749
|
paths,
|
|
@@ -1674,6 +1752,15 @@ function OcSignIn({
|
|
|
1674
1752
|
const walletEnabled = paths?.wallet ?? true;
|
|
1675
1753
|
const emailEnabled = paths?.email ?? true;
|
|
1676
1754
|
const safeReturn = safeReturnTo(returnTo);
|
|
1755
|
+
const [addMode, setAddMode] = React3.useState(Boolean(addProp));
|
|
1756
|
+
React3.useEffect(() => {
|
|
1757
|
+
if (typeof window === "undefined") return;
|
|
1758
|
+
if (addProp !== void 0) {
|
|
1759
|
+
setAddMode(Boolean(addProp));
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1762
|
+
setAddMode(new URLSearchParams(window.location.search).get("add") === "1");
|
|
1763
|
+
}, [addProp]);
|
|
1677
1764
|
const [path, setPath] = React3.useState(initialPath);
|
|
1678
1765
|
const [signedIn, setSignedIn] = React3.useState(null);
|
|
1679
1766
|
const [linkAlso, setLinkAlso] = React3.useState(false);
|
|
@@ -1816,6 +1903,7 @@ function OcSignIn({
|
|
|
1816
1903
|
{
|
|
1817
1904
|
authOrigin,
|
|
1818
1905
|
audience,
|
|
1906
|
+
add: addMode,
|
|
1819
1907
|
onSuccess: (a, t) => void handleSuccess(a, t, "wallet")
|
|
1820
1908
|
}
|
|
1821
1909
|
),
|
|
@@ -1823,6 +1911,7 @@ function OcSignIn({
|
|
|
1823
1911
|
EmailFlow,
|
|
1824
1912
|
{
|
|
1825
1913
|
authOrigin,
|
|
1914
|
+
add: addMode,
|
|
1826
1915
|
onSuccess: (a, t) => void handleSuccess(a, t, "email")
|
|
1827
1916
|
}
|
|
1828
1917
|
)
|
|
@@ -1878,6 +1967,23 @@ function SigninTab({
|
|
|
1878
1967
|
}
|
|
1879
1968
|
);
|
|
1880
1969
|
}
|
|
1970
|
+
function ProviderIcon({ id }) {
|
|
1971
|
+
const common = {
|
|
1972
|
+
width: 14,
|
|
1973
|
+
height: 14,
|
|
1974
|
+
viewBox: "0 0 24 24",
|
|
1975
|
+
fill: "currentColor",
|
|
1976
|
+
"aria-hidden": true,
|
|
1977
|
+
style: { flex: "0 0 auto" }
|
|
1978
|
+
};
|
|
1979
|
+
if (id === "google") {
|
|
1980
|
+
return /* @__PURE__ */ jsx("svg", { ...common, children: /* @__PURE__ */ jsx("path", { d: "M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z" }) });
|
|
1981
|
+
}
|
|
1982
|
+
if (id === "github") {
|
|
1983
|
+
return /* @__PURE__ */ jsx("svg", { ...common, children: /* @__PURE__ */ jsx("path", { d: "M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" }) });
|
|
1984
|
+
}
|
|
1985
|
+
return null;
|
|
1986
|
+
}
|
|
1881
1987
|
function ProviderSignIn({
|
|
1882
1988
|
authOrigin,
|
|
1883
1989
|
returnTo
|
|
@@ -1920,7 +2026,7 @@ function ProviderSignIn({
|
|
|
1920
2026
|
]
|
|
1921
2027
|
}
|
|
1922
2028
|
),
|
|
1923
|
-
providers.map((p, i) => /* @__PURE__ */
|
|
2029
|
+
providers.map((p, i) => /* @__PURE__ */ jsxs(
|
|
1924
2030
|
"a",
|
|
1925
2031
|
{
|
|
1926
2032
|
href: `${authOrigin}/api/auth/${p.id}/start?return_to=${encodeURIComponent(
|
|
@@ -1928,12 +2034,14 @@ function ProviderSignIn({
|
|
|
1928
2034
|
)}`,
|
|
1929
2035
|
"data-oc-signin-provider": p.id,
|
|
1930
2036
|
style: {
|
|
1931
|
-
display: "
|
|
2037
|
+
display: "flex",
|
|
2038
|
+
alignItems: "center",
|
|
2039
|
+
justifyContent: "center",
|
|
2040
|
+
gap: 10,
|
|
1932
2041
|
boxSizing: "border-box",
|
|
1933
2042
|
width: "100%",
|
|
1934
2043
|
marginTop: i === 0 ? 0 : 8,
|
|
1935
2044
|
padding: "0.6rem 0.875rem",
|
|
1936
|
-
textAlign: "center",
|
|
1937
2045
|
border: "1px solid var(--border, #27272a)",
|
|
1938
2046
|
borderRadius: 6,
|
|
1939
2047
|
background: "transparent",
|
|
@@ -1942,13 +2050,16 @@ function ProviderSignIn({
|
|
|
1942
2050
|
fontSize: 12,
|
|
1943
2051
|
textDecoration: "none"
|
|
1944
2052
|
},
|
|
1945
|
-
children:
|
|
2053
|
+
children: [
|
|
2054
|
+
/* @__PURE__ */ jsx(ProviderIcon, { id: p.id }),
|
|
2055
|
+
/* @__PURE__ */ jsx("span", { children: p.label })
|
|
2056
|
+
]
|
|
1946
2057
|
},
|
|
1947
2058
|
p.id
|
|
1948
2059
|
))
|
|
1949
2060
|
] });
|
|
1950
2061
|
}
|
|
1951
|
-
function WalletFlow({ authOrigin, audience, onSuccess }) {
|
|
2062
|
+
function WalletFlow({ authOrigin, audience, add, onSuccess }) {
|
|
1952
2063
|
const [address, setAddress] = React3.useState("");
|
|
1953
2064
|
const [error, setError] = React3.useState(null);
|
|
1954
2065
|
const [submitting, setSubmitting] = React3.useState(false);
|
|
@@ -1996,7 +2107,12 @@ function WalletFlow({ authOrigin, audience, onSuccess }) {
|
|
|
1996
2107
|
scheme: "bip322",
|
|
1997
2108
|
expectedNonce: challenge.nonce,
|
|
1998
2109
|
expectedAudience: audience,
|
|
1999
|
-
expectedPurpose: "login"
|
|
2110
|
+
expectedPurpose: "login",
|
|
2111
|
+
// Multi-account add-mode · the auth host preserves
|
|
2112
|
+
// the current roster_id when set, instead of minting
|
|
2113
|
+
// a fresh one. Hosts that haven't deployed the
|
|
2114
|
+
// multi-account migration silently ignore the field.
|
|
2115
|
+
...add ? { add: true } : {}
|
|
2000
2116
|
})
|
|
2001
2117
|
});
|
|
2002
2118
|
const json = await res.json();
|
|
@@ -2047,7 +2163,7 @@ function WalletFlow({ authOrigin, audience, onSuccess }) {
|
|
|
2047
2163
|
/* @__PURE__ */ jsx(Hint, { children: "Detection picks the first installed BIP-322-capable extension. Address is the one your wallet will sign for." })
|
|
2048
2164
|
] });
|
|
2049
2165
|
}
|
|
2050
|
-
function EmailFlow({ authOrigin, onSuccess }) {
|
|
2166
|
+
function EmailFlow({ authOrigin, add, onSuccess }) {
|
|
2051
2167
|
const [stage, setStage] = React3.useState("enter");
|
|
2052
2168
|
const [email, setEmail] = React3.useState("");
|
|
2053
2169
|
const [emailError, setEmailError] = React3.useState(null);
|
|
@@ -2098,7 +2214,13 @@ function EmailFlow({ authOrigin, onSuccess }) {
|
|
|
2098
2214
|
method: "POST",
|
|
2099
2215
|
credentials: "include",
|
|
2100
2216
|
headers: { "Content-Type": "application/json" },
|
|
2101
|
-
body: JSON.stringify({
|
|
2217
|
+
body: JSON.stringify({
|
|
2218
|
+
email,
|
|
2219
|
+
code,
|
|
2220
|
+
token,
|
|
2221
|
+
// Multi-account add-mode · see WalletFlow.
|
|
2222
|
+
...add ? { add: true } : {}
|
|
2223
|
+
})
|
|
2102
2224
|
});
|
|
2103
2225
|
const json = await res.json();
|
|
2104
2226
|
if (!res.ok || !("ok" in json) || !json.ok || !json.account) {
|
|
@@ -2590,6 +2712,6 @@ function handleSudoRequired(body, args = {}) {
|
|
|
2590
2712
|
return false;
|
|
2591
2713
|
}
|
|
2592
2714
|
|
|
2593
|
-
export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, OcAccountChip, OcAccountPill, OcAddressInput, OcLinkedIdentities, OcSessionProvider, OcSignIn, OcSignInButton, buildSignInUrl, fetchOcLinkedIdentities, handleSudoRequired, redirectToSudo, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister };
|
|
2715
|
+
export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, OcAccountChip, OcAccountPill, OcAddressInput, OcLinkedIdentities, OcSessionProvider, OcSignIn, OcSignInButton, buildAddAccountUrl, buildSignInUrl, fetchOcLinkedIdentities, handleSudoRequired, redirectToSudo, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister };
|
|
2594
2716
|
//# sourceMappingURL=index.mjs.map
|
|
2595
2717
|
//# sourceMappingURL=index.mjs.map
|