@orangecheck/auth-client 2.16.0 → 2.17.1
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 +18 -3
- package/dist/index.d.ts +18 -3
- package/dist/index.js +155 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +155 -20
- 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);
|
|
@@ -1785,6 +1872,41 @@ function OcSignIn({
|
|
|
1785
1872
|
children: "That sign-in didn't complete. Please try again."
|
|
1786
1873
|
}
|
|
1787
1874
|
),
|
|
1875
|
+
addMode && /* @__PURE__ */ jsxs(
|
|
1876
|
+
"div",
|
|
1877
|
+
{
|
|
1878
|
+
"data-oc-signin-add-mode": "",
|
|
1879
|
+
style: {
|
|
1880
|
+
marginBottom: 14,
|
|
1881
|
+
padding: "0.6rem 0.75rem",
|
|
1882
|
+
border: "1px solid var(--primary, #f97316)",
|
|
1883
|
+
borderLeftWidth: 3,
|
|
1884
|
+
borderRadius: 4,
|
|
1885
|
+
background: "color-mix(in srgb, var(--primary, #f97316) 8%, transparent)",
|
|
1886
|
+
color: "var(--foreground, #fafafa)",
|
|
1887
|
+
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
1888
|
+
fontSize: 11,
|
|
1889
|
+
lineHeight: 1.6
|
|
1890
|
+
},
|
|
1891
|
+
children: [
|
|
1892
|
+
/* @__PURE__ */ jsx(
|
|
1893
|
+
"strong",
|
|
1894
|
+
{
|
|
1895
|
+
style: {
|
|
1896
|
+
color: "var(--primary, #f97316)",
|
|
1897
|
+
letterSpacing: "0.12em",
|
|
1898
|
+
textTransform: "uppercase",
|
|
1899
|
+
fontSize: 10,
|
|
1900
|
+
display: "block",
|
|
1901
|
+
marginBottom: 3
|
|
1902
|
+
},
|
|
1903
|
+
children: "\xA7 adding another account"
|
|
1904
|
+
}
|
|
1905
|
+
),
|
|
1906
|
+
"Your current OrangeCheck account stays signed in. The new account joins your browser's roster; you can switch between them anytime from the account menu."
|
|
1907
|
+
]
|
|
1908
|
+
}
|
|
1909
|
+
),
|
|
1788
1910
|
bothEnabled && /* @__PURE__ */ jsxs(
|
|
1789
1911
|
"div",
|
|
1790
1912
|
{
|
|
@@ -1816,6 +1938,7 @@ function OcSignIn({
|
|
|
1816
1938
|
{
|
|
1817
1939
|
authOrigin,
|
|
1818
1940
|
audience,
|
|
1941
|
+
add: addMode,
|
|
1819
1942
|
onSuccess: (a, t) => void handleSuccess(a, t, "wallet")
|
|
1820
1943
|
}
|
|
1821
1944
|
),
|
|
@@ -1823,6 +1946,7 @@ function OcSignIn({
|
|
|
1823
1946
|
EmailFlow,
|
|
1824
1947
|
{
|
|
1825
1948
|
authOrigin,
|
|
1949
|
+
add: addMode,
|
|
1826
1950
|
onSuccess: (a, t) => void handleSuccess(a, t, "email")
|
|
1827
1951
|
}
|
|
1828
1952
|
)
|
|
@@ -1970,7 +2094,7 @@ function ProviderSignIn({
|
|
|
1970
2094
|
))
|
|
1971
2095
|
] });
|
|
1972
2096
|
}
|
|
1973
|
-
function WalletFlow({ authOrigin, audience, onSuccess }) {
|
|
2097
|
+
function WalletFlow({ authOrigin, audience, add, onSuccess }) {
|
|
1974
2098
|
const [address, setAddress] = React3.useState("");
|
|
1975
2099
|
const [error, setError] = React3.useState(null);
|
|
1976
2100
|
const [submitting, setSubmitting] = React3.useState(false);
|
|
@@ -2018,7 +2142,12 @@ function WalletFlow({ authOrigin, audience, onSuccess }) {
|
|
|
2018
2142
|
scheme: "bip322",
|
|
2019
2143
|
expectedNonce: challenge.nonce,
|
|
2020
2144
|
expectedAudience: audience,
|
|
2021
|
-
expectedPurpose: "login"
|
|
2145
|
+
expectedPurpose: "login",
|
|
2146
|
+
// Multi-account add-mode · the auth host preserves
|
|
2147
|
+
// the current roster_id when set, instead of minting
|
|
2148
|
+
// a fresh one. Hosts that haven't deployed the
|
|
2149
|
+
// multi-account migration silently ignore the field.
|
|
2150
|
+
...add ? { add: true } : {}
|
|
2022
2151
|
})
|
|
2023
2152
|
});
|
|
2024
2153
|
const json = await res.json();
|
|
@@ -2069,7 +2198,7 @@ function WalletFlow({ authOrigin, audience, onSuccess }) {
|
|
|
2069
2198
|
/* @__PURE__ */ jsx(Hint, { children: "Detection picks the first installed BIP-322-capable extension. Address is the one your wallet will sign for." })
|
|
2070
2199
|
] });
|
|
2071
2200
|
}
|
|
2072
|
-
function EmailFlow({ authOrigin, onSuccess }) {
|
|
2201
|
+
function EmailFlow({ authOrigin, add, onSuccess }) {
|
|
2073
2202
|
const [stage, setStage] = React3.useState("enter");
|
|
2074
2203
|
const [email, setEmail] = React3.useState("");
|
|
2075
2204
|
const [emailError, setEmailError] = React3.useState(null);
|
|
@@ -2120,7 +2249,13 @@ function EmailFlow({ authOrigin, onSuccess }) {
|
|
|
2120
2249
|
method: "POST",
|
|
2121
2250
|
credentials: "include",
|
|
2122
2251
|
headers: { "Content-Type": "application/json" },
|
|
2123
|
-
body: JSON.stringify({
|
|
2252
|
+
body: JSON.stringify({
|
|
2253
|
+
email,
|
|
2254
|
+
code,
|
|
2255
|
+
token,
|
|
2256
|
+
// Multi-account add-mode · see WalletFlow.
|
|
2257
|
+
...add ? { add: true } : {}
|
|
2258
|
+
})
|
|
2124
2259
|
});
|
|
2125
2260
|
const json = await res.json();
|
|
2126
2261
|
if (!res.ok || !("ok" in json) || !json.ok || !json.account) {
|
|
@@ -2612,6 +2747,6 @@ function handleSudoRequired(body, args = {}) {
|
|
|
2612
2747
|
return false;
|
|
2613
2748
|
}
|
|
2614
2749
|
|
|
2615
|
-
export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, OcAccountChip, OcAccountPill, OcAddressInput, OcLinkedIdentities, OcSessionProvider, OcSignIn, OcSignInButton, buildSignInUrl, fetchOcLinkedIdentities, handleSudoRequired, redirectToSudo, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister };
|
|
2750
|
+
export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, OcAccountChip, OcAccountPill, OcAddressInput, OcLinkedIdentities, OcSessionProvider, OcSignIn, OcSignInButton, buildAddAccountUrl, buildSignInUrl, fetchOcLinkedIdentities, handleSudoRequired, redirectToSudo, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister };
|
|
2616
2751
|
//# sourceMappingURL=index.mjs.map
|
|
2617
2752
|
//# sourceMappingURL=index.mjs.map
|