@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 CHANGED
@@ -12,6 +12,13 @@ sign-in button.
12
12
 
13
13
  Pairs with [`@orangecheck/auth-core`](../auth-core) on the server side.
14
14
 
15
+ > **Which integration pathway is this?** This package is for letting
16
+ > OrangeCheck *be* your sign-in. If you already run your own login
17
+ > (Google, Auth0, Clerk, NextAuth, …) and just want to add a `did:oc`
18
+ > to your users, you don't need this package — see
19
+ > [OrangeCheck Connect](https://docs.ochk.io/connect). Both pathways are
20
+ > compared at [docs.ochk.io/integration](https://docs.ochk.io/integration).
21
+
15
22
  ## Install
16
23
 
17
24
  ```bash
package/dist/index.d.mts CHANGED
@@ -19,12 +19,25 @@ interface OcAccount {
19
19
  displayIdentity: DisplayIdentity;
20
20
  }
21
21
  type OcSessionStatus = 'loading' | 'authenticated' | 'anonymous' | 'error';
22
+ interface OcAccountSummary {
23
+ didOc: string;
24
+ displayName: string | null;
25
+ primaryBtc: string | null;
26
+ displayIdentity: DisplayIdentity;
27
+ lastSeenAt: string | null;
28
+ }
29
+ type OcSignOutScope = 'all' | 'current';
22
30
  interface OcSessionState {
23
31
  status: OcSessionStatus;
24
32
  account: OcAccount | null;
33
+ roster: OcAccountSummary[];
25
34
  error: Error | null;
26
35
  refresh: () => Promise<void>;
27
- signOut: () => Promise<void>;
36
+ signOut: (opts?: {
37
+ scope?: OcSignOutScope;
38
+ }) => Promise<void>;
39
+ switchAccount: (didOc: string) => Promise<void>;
40
+ addAccountUrl: (returnTo?: string) => string;
28
41
  setDisplayIdentity: (kind: DisplayIdentityKind) => Promise<void>;
29
42
  signInUrl: string;
30
43
  }
@@ -36,6 +49,7 @@ interface OcAuthConfig {
36
49
  }
37
50
  declare const DEFAULT_CONFIG: Required<OcAuthConfig>;
38
51
  declare function buildSignInUrl(cfg: Required<OcAuthConfig>, returnTo?: string): string;
52
+ declare function buildAddAccountUrl(cfg: Required<OcAuthConfig>, returnTo?: string): string;
39
53
 
40
54
  interface OcSessionProviderProps {
41
55
  children: React.ReactNode;
@@ -115,9 +129,10 @@ interface OcSignInProps {
115
129
  email?: boolean;
116
130
  };
117
131
  linkPrompt?: boolean;
132
+ add?: boolean;
118
133
  className?: string;
119
134
  }
120
- declare function OcSignIn({ audience, returnTo, onSuccess, resolveReturnTo, linkPrompt, authOrigin, initialPath, paths, className, }: OcSignInProps): React.ReactElement;
135
+ declare function OcSignIn({ audience, returnTo, onSuccess, resolveReturnTo, linkPrompt, add: addProp, authOrigin, initialPath, paths, className, }: OcSignInProps): React.ReactElement;
121
136
 
122
137
  interface OcLinkedIdentity {
123
138
  id: string;
@@ -219,4 +234,4 @@ declare function handleSudoRequired(body: {
219
234
  returnTo?: string;
220
235
  }): boolean;
221
236
 
222
- export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, type DisplayIdentity, type DisplayIdentityKind, type OcAccount, OcAccountChip, type OcAccountChipProps, OcAccountPill, type OcAccountPillProps, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcLinkedIdentities, type OcLinkedIdentitiesProps, type OcLinkedIdentity, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignIn, OcSignInButton, type OcSignInButtonProps, type OcSignInProps, type RedirectToSudoArgs, type UseOcAddressSuggestionOptions, type UseOcAddressSuggestionReturn, type UseStepUpAuthReturn, type UseWebAuthnListReturn, type UseWebAuthnRegisterReturn, type WebAuthnAssertionStatus, type WebAuthnCredentialPublic, type WebAuthnListStatus, type WebAuthnRegisterResult, type WebAuthnRegisterStatus, type WebAuthnRemoveResult, type WebAuthnRenameResult, type WebAuthnStepUpResult, buildSignInUrl, fetchOcLinkedIdentities, handleSudoRequired, redirectToSudo, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister };
237
+ export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, type DisplayIdentity, type DisplayIdentityKind, type OcAccount, OcAccountChip, type OcAccountChipProps, OcAccountPill, type OcAccountPillProps, type OcAccountSummary, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcLinkedIdentities, type OcLinkedIdentitiesProps, type OcLinkedIdentity, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignIn, OcSignInButton, type OcSignInButtonProps, type OcSignInProps, type OcSignOutScope, type RedirectToSudoArgs, type UseOcAddressSuggestionOptions, type UseOcAddressSuggestionReturn, type UseStepUpAuthReturn, type UseWebAuthnListReturn, type UseWebAuthnRegisterReturn, type WebAuthnAssertionStatus, type WebAuthnCredentialPublic, type WebAuthnListStatus, type WebAuthnRegisterResult, type WebAuthnRegisterStatus, type WebAuthnRemoveResult, type WebAuthnRenameResult, type WebAuthnStepUpResult, buildAddAccountUrl, buildSignInUrl, fetchOcLinkedIdentities, handleSudoRequired, redirectToSudo, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister };
package/dist/index.d.ts CHANGED
@@ -19,12 +19,25 @@ interface OcAccount {
19
19
  displayIdentity: DisplayIdentity;
20
20
  }
21
21
  type OcSessionStatus = 'loading' | 'authenticated' | 'anonymous' | 'error';
22
+ interface OcAccountSummary {
23
+ didOc: string;
24
+ displayName: string | null;
25
+ primaryBtc: string | null;
26
+ displayIdentity: DisplayIdentity;
27
+ lastSeenAt: string | null;
28
+ }
29
+ type OcSignOutScope = 'all' | 'current';
22
30
  interface OcSessionState {
23
31
  status: OcSessionStatus;
24
32
  account: OcAccount | null;
33
+ roster: OcAccountSummary[];
25
34
  error: Error | null;
26
35
  refresh: () => Promise<void>;
27
- signOut: () => Promise<void>;
36
+ signOut: (opts?: {
37
+ scope?: OcSignOutScope;
38
+ }) => Promise<void>;
39
+ switchAccount: (didOc: string) => Promise<void>;
40
+ addAccountUrl: (returnTo?: string) => string;
28
41
  setDisplayIdentity: (kind: DisplayIdentityKind) => Promise<void>;
29
42
  signInUrl: string;
30
43
  }
@@ -36,6 +49,7 @@ interface OcAuthConfig {
36
49
  }
37
50
  declare const DEFAULT_CONFIG: Required<OcAuthConfig>;
38
51
  declare function buildSignInUrl(cfg: Required<OcAuthConfig>, returnTo?: string): string;
52
+ declare function buildAddAccountUrl(cfg: Required<OcAuthConfig>, returnTo?: string): string;
39
53
 
40
54
  interface OcSessionProviderProps {
41
55
  children: React.ReactNode;
@@ -115,9 +129,10 @@ interface OcSignInProps {
115
129
  email?: boolean;
116
130
  };
117
131
  linkPrompt?: boolean;
132
+ add?: boolean;
118
133
  className?: string;
119
134
  }
120
- declare function OcSignIn({ audience, returnTo, onSuccess, resolveReturnTo, linkPrompt, authOrigin, initialPath, paths, className, }: OcSignInProps): React.ReactElement;
135
+ declare function OcSignIn({ audience, returnTo, onSuccess, resolveReturnTo, linkPrompt, add: addProp, authOrigin, initialPath, paths, className, }: OcSignInProps): React.ReactElement;
121
136
 
122
137
  interface OcLinkedIdentity {
123
138
  id: string;
@@ -219,4 +234,4 @@ declare function handleSudoRequired(body: {
219
234
  returnTo?: string;
220
235
  }): boolean;
221
236
 
222
- export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, type DisplayIdentity, type DisplayIdentityKind, type OcAccount, OcAccountChip, type OcAccountChipProps, OcAccountPill, type OcAccountPillProps, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcLinkedIdentities, type OcLinkedIdentitiesProps, type OcLinkedIdentity, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignIn, OcSignInButton, type OcSignInButtonProps, type OcSignInProps, type RedirectToSudoArgs, type UseOcAddressSuggestionOptions, type UseOcAddressSuggestionReturn, type UseStepUpAuthReturn, type UseWebAuthnListReturn, type UseWebAuthnRegisterReturn, type WebAuthnAssertionStatus, type WebAuthnCredentialPublic, type WebAuthnListStatus, type WebAuthnRegisterResult, type WebAuthnRegisterStatus, type WebAuthnRemoveResult, type WebAuthnRenameResult, type WebAuthnStepUpResult, buildSignInUrl, fetchOcLinkedIdentities, handleSudoRequired, redirectToSudo, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister };
237
+ export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, type DisplayIdentity, type DisplayIdentityKind, type OcAccount, OcAccountChip, type OcAccountChipProps, OcAccountPill, type OcAccountPillProps, type OcAccountSummary, OcAddressInput, type OcAddressInputProps, type OcAuthConfig, OcLinkedIdentities, type OcLinkedIdentitiesProps, type OcLinkedIdentity, OcSessionProvider, type OcSessionState, type OcSessionStatus, OcSignIn, OcSignInButton, type OcSignInButtonProps, type OcSignInProps, type OcSignOutScope, type RedirectToSudoArgs, type UseOcAddressSuggestionOptions, type UseOcAddressSuggestionReturn, type UseStepUpAuthReturn, type UseWebAuthnListReturn, type UseWebAuthnRegisterReturn, type WebAuthnAssertionStatus, type WebAuthnCredentialPublic, type WebAuthnListStatus, type WebAuthnRegisterResult, type WebAuthnRegisterStatus, type WebAuthnRemoveResult, type WebAuthnRenameResult, type WebAuthnStepUpResult, buildAddAccountUrl, buildSignInUrl, fetchOcLinkedIdentities, handleSudoRequired, redirectToSudo, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister };
package/dist/index.js CHANGED
@@ -44,6 +44,11 @@ function buildSignInUrl(cfg, returnTo) {
44
44
  u.searchParams.set("return_to", returnTo);
45
45
  return u.toString();
46
46
  }
47
+ function buildAddAccountUrl(cfg, returnTo) {
48
+ const u = new URL(buildSignInUrl(cfg, returnTo));
49
+ u.searchParams.set("add", "1");
50
+ return u.toString();
51
+ }
47
52
  var SessionContext = React3__namespace.createContext(null);
48
53
  function normalizeDisplayIdentity(raw, didOc) {
49
54
  const di = raw.display_identity ?? raw.displayIdentity;
@@ -52,6 +57,19 @@ function normalizeDisplayIdentity(raw, didOc) {
52
57
  }
53
58
  return { kind: "did", value: didOc };
54
59
  }
60
+ function normalizeRosterEntry(raw) {
61
+ const didOc = raw.did_oc ?? raw.didOc;
62
+ if (!didOc) return null;
63
+ const di = raw.display_identity ?? raw.displayIdentity;
64
+ 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 };
65
+ return {
66
+ didOc,
67
+ displayName: raw.display_name ?? raw.displayName ?? null,
68
+ primaryBtc: raw.primary_btc ?? raw.primaryBtc ?? null,
69
+ displayIdentity,
70
+ lastSeenAt: raw.last_seen_at ?? raw.lastSeenAt ?? null
71
+ };
72
+ }
55
73
  function normalizeAccount(raw) {
56
74
  if (!raw) return null;
57
75
  const didOc = raw.did_oc ?? raw.didOc;
@@ -77,6 +95,7 @@ function OcSessionProvider({
77
95
  }) {
78
96
  const cfg = React3__namespace.useMemo(() => resolveConfig(config), [config]);
79
97
  const [account, setAccount] = React3__namespace.useState(null);
98
+ const [roster, setRoster] = React3__namespace.useState([]);
80
99
  const [status, setStatus] = React3__namespace.useState("loading");
81
100
  const [error, setError] = React3__namespace.useState(null);
82
101
  const refresh = React3__namespace.useCallback(async () => {
@@ -89,6 +108,7 @@ function OcSessionProvider({
89
108
  });
90
109
  if (res.status === 401) {
91
110
  setAccount(null);
111
+ setRoster([]);
92
112
  setStatus("anonymous");
93
113
  setError(null);
94
114
  return;
@@ -100,7 +120,9 @@ function OcSessionProvider({
100
120
  }
101
121
  const body = await res.json();
102
122
  const acct = normalizeAccount(body.account);
123
+ const rosterEntries = Array.isArray(body.roster) ? body.roster.map(normalizeRosterEntry).filter((r) => r !== null) : [];
103
124
  setAccount(acct);
125
+ setRoster(rosterEntries);
104
126
  setStatus(acct ? "authenticated" : "anonymous");
105
127
  setError(null);
106
128
  } catch (err) {
@@ -111,23 +133,63 @@ function OcSessionProvider({
111
133
  React3__namespace.useEffect(() => {
112
134
  void refresh();
113
135
  }, [refresh]);
114
- const signOut = React3__namespace.useCallback(async () => {
115
- try {
116
- await fetch(`${cfg.authOrigin}${cfg.logoutPath}`, {
136
+ const signOut = React3__namespace.useCallback(
137
+ async (opts) => {
138
+ const scope = opts?.scope ?? "all";
139
+ try {
140
+ const url = new URL(`${cfg.authOrigin}${cfg.logoutPath}`);
141
+ if (scope === "current") url.searchParams.set("scope", "current");
142
+ const res = await fetch(url.toString(), {
143
+ method: "POST",
144
+ credentials: "include",
145
+ // `keepalive` lets the logout round-trip complete even if
146
+ // the caller hard-navigates away in the same tick (e.g.
147
+ // `<OcAccountMenu>` redirects home immediately on sign-out).
148
+ // Without it the in-flight request is cancelled on unload
149
+ // and the `.ochk.io` cookie may never get cleared.
150
+ keepalive: true
151
+ });
152
+ if (scope === "current" && res.ok) {
153
+ await refresh();
154
+ return;
155
+ }
156
+ } catch {
157
+ }
158
+ setAccount(null);
159
+ setRoster([]);
160
+ setStatus("anonymous");
161
+ },
162
+ [cfg.authOrigin, cfg.logoutPath, refresh]
163
+ );
164
+ const switchAccount = React3__namespace.useCallback(
165
+ async (didOc) => {
166
+ if (typeof window === "undefined") return;
167
+ const res = await fetch(`${cfg.authOrigin}/api/auth/switch`, {
117
168
  method: "POST",
118
169
  credentials: "include",
119
- // `keepalive` lets the logout round-trip complete even if
120
- // the caller hard-navigates away in the same tick (e.g.
121
- // `<OcAccountMenu>` redirects home immediately on sign-out).
122
- // Without it the in-flight request is cancelled on unload
123
- // and the `.ochk.io` cookie may never get cleared.
124
- keepalive: true
170
+ headers: { "Content-Type": "application/json" },
171
+ body: JSON.stringify({ did_oc: didOc })
125
172
  });
126
- } catch {
127
- }
128
- setAccount(null);
129
- setStatus("anonymous");
130
- }, [cfg.authOrigin, cfg.logoutPath]);
173
+ if (!res.ok) {
174
+ let reason = `http_${res.status}`;
175
+ try {
176
+ const body = await res.json();
177
+ if (body.reason) reason = body.reason;
178
+ } catch {
179
+ }
180
+ throw new Error(`[@orangecheck/auth-client] switchAccount failed: ${reason}`);
181
+ }
182
+ await refresh();
183
+ },
184
+ [cfg.authOrigin, refresh]
185
+ );
186
+ const addAccountUrl = React3__namespace.useCallback(
187
+ (returnTo) => {
188
+ const rt = returnTo ?? (typeof window !== "undefined" ? window.location.href : void 0);
189
+ return buildAddAccountUrl(cfg, rt);
190
+ },
191
+ [cfg]
192
+ );
131
193
  const setDisplayIdentity = React3__namespace.useCallback(
132
194
  async (kind) => {
133
195
  if (typeof window === "undefined") return;
@@ -155,13 +217,28 @@ function OcSessionProvider({
155
217
  return {
156
218
  status,
157
219
  account,
220
+ roster,
158
221
  error,
159
222
  refresh,
160
223
  signOut,
224
+ switchAccount,
225
+ addAccountUrl,
161
226
  setDisplayIdentity,
162
227
  signInUrl: buildSignInUrl(cfg, returnTo)
163
228
  };
164
- }, [status, account, error, refresh, signOut, setDisplayIdentity, cfg, defaultReturnTo]);
229
+ }, [
230
+ status,
231
+ account,
232
+ roster,
233
+ error,
234
+ refresh,
235
+ signOut,
236
+ switchAccount,
237
+ addAccountUrl,
238
+ setDisplayIdentity,
239
+ cfg,
240
+ defaultReturnTo
241
+ ]);
165
242
  return /* @__PURE__ */ jsxRuntime.jsx(SessionContext.Provider, { value, children });
166
243
  }
167
244
  function useOcSession() {
@@ -1688,6 +1765,7 @@ function OcSignIn({
1688
1765
  onSuccess,
1689
1766
  resolveReturnTo,
1690
1767
  linkPrompt = true,
1768
+ add: addProp,
1691
1769
  authOrigin = "https://ochk.io",
1692
1770
  initialPath = "wallet",
1693
1771
  paths,
@@ -1696,6 +1774,15 @@ function OcSignIn({
1696
1774
  const walletEnabled = paths?.wallet ?? true;
1697
1775
  const emailEnabled = paths?.email ?? true;
1698
1776
  const safeReturn = safeReturnTo(returnTo);
1777
+ const [addMode, setAddMode] = React3__namespace.useState(Boolean(addProp));
1778
+ React3__namespace.useEffect(() => {
1779
+ if (typeof window === "undefined") return;
1780
+ if (addProp !== void 0) {
1781
+ setAddMode(Boolean(addProp));
1782
+ return;
1783
+ }
1784
+ setAddMode(new URLSearchParams(window.location.search).get("add") === "1");
1785
+ }, [addProp]);
1699
1786
  const [path, setPath] = React3__namespace.useState(initialPath);
1700
1787
  const [signedIn, setSignedIn] = React3__namespace.useState(null);
1701
1788
  const [linkAlso, setLinkAlso] = React3__namespace.useState(false);
@@ -1838,6 +1925,7 @@ function OcSignIn({
1838
1925
  {
1839
1926
  authOrigin,
1840
1927
  audience,
1928
+ add: addMode,
1841
1929
  onSuccess: (a, t) => void handleSuccess(a, t, "wallet")
1842
1930
  }
1843
1931
  ),
@@ -1845,6 +1933,7 @@ function OcSignIn({
1845
1933
  EmailFlow,
1846
1934
  {
1847
1935
  authOrigin,
1936
+ add: addMode,
1848
1937
  onSuccess: (a, t) => void handleSuccess(a, t, "email")
1849
1938
  }
1850
1939
  )
@@ -1900,6 +1989,23 @@ function SigninTab({
1900
1989
  }
1901
1990
  );
1902
1991
  }
1992
+ function ProviderIcon({ id }) {
1993
+ const common = {
1994
+ width: 14,
1995
+ height: 14,
1996
+ viewBox: "0 0 24 24",
1997
+ fill: "currentColor",
1998
+ "aria-hidden": true,
1999
+ style: { flex: "0 0 auto" }
2000
+ };
2001
+ if (id === "google") {
2002
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { ...common, children: /* @__PURE__ */ jsxRuntime.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" }) });
2003
+ }
2004
+ if (id === "github") {
2005
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { ...common, children: /* @__PURE__ */ jsxRuntime.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" }) });
2006
+ }
2007
+ return null;
2008
+ }
1903
2009
  function ProviderSignIn({
1904
2010
  authOrigin,
1905
2011
  returnTo
@@ -1942,7 +2048,7 @@ function ProviderSignIn({
1942
2048
  ]
1943
2049
  }
1944
2050
  ),
1945
- providers.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx(
2051
+ providers.map((p, i) => /* @__PURE__ */ jsxRuntime.jsxs(
1946
2052
  "a",
1947
2053
  {
1948
2054
  href: `${authOrigin}/api/auth/${p.id}/start?return_to=${encodeURIComponent(
@@ -1950,12 +2056,14 @@ function ProviderSignIn({
1950
2056
  )}`,
1951
2057
  "data-oc-signin-provider": p.id,
1952
2058
  style: {
1953
- display: "block",
2059
+ display: "flex",
2060
+ alignItems: "center",
2061
+ justifyContent: "center",
2062
+ gap: 10,
1954
2063
  boxSizing: "border-box",
1955
2064
  width: "100%",
1956
2065
  marginTop: i === 0 ? 0 : 8,
1957
2066
  padding: "0.6rem 0.875rem",
1958
- textAlign: "center",
1959
2067
  border: "1px solid var(--border, #27272a)",
1960
2068
  borderRadius: 6,
1961
2069
  background: "transparent",
@@ -1964,13 +2072,16 @@ function ProviderSignIn({
1964
2072
  fontSize: 12,
1965
2073
  textDecoration: "none"
1966
2074
  },
1967
- children: p.label
2075
+ children: [
2076
+ /* @__PURE__ */ jsxRuntime.jsx(ProviderIcon, { id: p.id }),
2077
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: p.label })
2078
+ ]
1968
2079
  },
1969
2080
  p.id
1970
2081
  ))
1971
2082
  ] });
1972
2083
  }
1973
- function WalletFlow({ authOrigin, audience, onSuccess }) {
2084
+ function WalletFlow({ authOrigin, audience, add, onSuccess }) {
1974
2085
  const [address, setAddress] = React3__namespace.useState("");
1975
2086
  const [error, setError] = React3__namespace.useState(null);
1976
2087
  const [submitting, setSubmitting] = React3__namespace.useState(false);
@@ -2018,7 +2129,12 @@ function WalletFlow({ authOrigin, audience, onSuccess }) {
2018
2129
  scheme: "bip322",
2019
2130
  expectedNonce: challenge.nonce,
2020
2131
  expectedAudience: audience,
2021
- expectedPurpose: "login"
2132
+ expectedPurpose: "login",
2133
+ // Multi-account add-mode · the auth host preserves
2134
+ // the current roster_id when set, instead of minting
2135
+ // a fresh one. Hosts that haven't deployed the
2136
+ // multi-account migration silently ignore the field.
2137
+ ...add ? { add: true } : {}
2022
2138
  })
2023
2139
  });
2024
2140
  const json = await res.json();
@@ -2069,7 +2185,7 @@ function WalletFlow({ authOrigin, audience, onSuccess }) {
2069
2185
  /* @__PURE__ */ jsxRuntime.jsx(Hint, { children: "Detection picks the first installed BIP-322-capable extension. Address is the one your wallet will sign for." })
2070
2186
  ] });
2071
2187
  }
2072
- function EmailFlow({ authOrigin, onSuccess }) {
2188
+ function EmailFlow({ authOrigin, add, onSuccess }) {
2073
2189
  const [stage, setStage] = React3__namespace.useState("enter");
2074
2190
  const [email, setEmail] = React3__namespace.useState("");
2075
2191
  const [emailError, setEmailError] = React3__namespace.useState(null);
@@ -2120,7 +2236,13 @@ function EmailFlow({ authOrigin, onSuccess }) {
2120
2236
  method: "POST",
2121
2237
  credentials: "include",
2122
2238
  headers: { "Content-Type": "application/json" },
2123
- body: JSON.stringify({ email, code, token })
2239
+ body: JSON.stringify({
2240
+ email,
2241
+ code,
2242
+ token,
2243
+ // Multi-account add-mode · see WalletFlow.
2244
+ ...add ? { add: true } : {}
2245
+ })
2124
2246
  });
2125
2247
  const json = await res.json();
2126
2248
  if (!res.ok || !("ok" in json) || !json.ok || !json.account) {
@@ -2621,6 +2743,7 @@ exports.OcLinkedIdentities = OcLinkedIdentities;
2621
2743
  exports.OcSessionProvider = OcSessionProvider;
2622
2744
  exports.OcSignIn = OcSignIn;
2623
2745
  exports.OcSignInButton = OcSignInButton;
2746
+ exports.buildAddAccountUrl = buildAddAccountUrl;
2624
2747
  exports.buildSignInUrl = buildSignInUrl;
2625
2748
  exports.fetchOcLinkedIdentities = fetchOcLinkedIdentities;
2626
2749
  exports.handleSudoRequired = handleSudoRequired;