@orangecheck/auth-client 2.17.2 → 2.18.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 CHANGED
@@ -31,6 +31,7 @@ interface OcSessionState {
31
31
  status: OcSessionStatus;
32
32
  account: OcAccount | null;
33
33
  roster: OcAccountSummary[];
34
+ tabPinned: boolean;
34
35
  error: Error | null;
35
36
  refresh: () => Promise<void>;
36
37
  signOut: (opts?: {
@@ -152,6 +153,20 @@ interface OcLinkedIdentitiesProps {
152
153
  }
153
154
  declare function OcLinkedIdentities({ authOrigin, className, onChange, }: OcLinkedIdentitiesProps): React.ReactElement;
154
155
 
156
+ declare const TAB_SESSION_HEADER = "x-oc-tab-session";
157
+ declare const TAB_SESSION_STORAGE_KEY = "oc_tab_session";
158
+ declare const TAB_ADOPT_HASH = "#oc-adopt";
159
+ interface OcTabSession {
160
+ token: string;
161
+ didOc: string;
162
+ }
163
+ declare function readTabSession(): OcTabSession | null;
164
+ declare function writeTabSession(session: OcTabSession): void;
165
+ declare function clearTabSession(): void;
166
+ declare function tabSessionHeader(): Record<string, string>;
167
+ declare function installTabFetchInterceptor(authOrigin: string): () => void;
168
+ declare function consumeTabAdoptMarker(): boolean;
169
+
155
170
  interface WebAuthnCredentialPublic {
156
171
  id: string;
157
172
  label: string;
@@ -234,4 +249,4 @@ declare function handleSudoRequired(body: {
234
249
  returnTo?: string;
235
250
  }): boolean;
236
251
 
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 };
252
+ 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 OcTabSession, type RedirectToSudoArgs, TAB_ADOPT_HASH, TAB_SESSION_HEADER, TAB_SESSION_STORAGE_KEY, 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, clearTabSession, consumeTabAdoptMarker, fetchOcLinkedIdentities, handleSudoRequired, installTabFetchInterceptor, readTabSession, redirectToSudo, tabSessionHeader, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister, writeTabSession };
package/dist/index.d.ts CHANGED
@@ -31,6 +31,7 @@ interface OcSessionState {
31
31
  status: OcSessionStatus;
32
32
  account: OcAccount | null;
33
33
  roster: OcAccountSummary[];
34
+ tabPinned: boolean;
34
35
  error: Error | null;
35
36
  refresh: () => Promise<void>;
36
37
  signOut: (opts?: {
@@ -152,6 +153,20 @@ interface OcLinkedIdentitiesProps {
152
153
  }
153
154
  declare function OcLinkedIdentities({ authOrigin, className, onChange, }: OcLinkedIdentitiesProps): React.ReactElement;
154
155
 
156
+ declare const TAB_SESSION_HEADER = "x-oc-tab-session";
157
+ declare const TAB_SESSION_STORAGE_KEY = "oc_tab_session";
158
+ declare const TAB_ADOPT_HASH = "#oc-adopt";
159
+ interface OcTabSession {
160
+ token: string;
161
+ didOc: string;
162
+ }
163
+ declare function readTabSession(): OcTabSession | null;
164
+ declare function writeTabSession(session: OcTabSession): void;
165
+ declare function clearTabSession(): void;
166
+ declare function tabSessionHeader(): Record<string, string>;
167
+ declare function installTabFetchInterceptor(authOrigin: string): () => void;
168
+ declare function consumeTabAdoptMarker(): boolean;
169
+
155
170
  interface WebAuthnCredentialPublic {
156
171
  id: string;
157
172
  label: string;
@@ -234,4 +249,4 @@ declare function handleSudoRequired(body: {
234
249
  returnTo?: string;
235
250
  }): boolean;
236
251
 
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 };
252
+ 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 OcTabSession, type RedirectToSudoArgs, TAB_ADOPT_HASH, TAB_SESSION_HEADER, TAB_SESSION_STORAGE_KEY, 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, clearTabSession, consumeTabAdoptMarker, fetchOcLinkedIdentities, handleSudoRequired, installTabFetchInterceptor, readTabSession, redirectToSudo, tabSessionHeader, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister, writeTabSession };
package/dist/index.js CHANGED
@@ -49,6 +49,91 @@ function buildAddAccountUrl(cfg, returnTo) {
49
49
  u.searchParams.set("add", "1");
50
50
  return u.toString();
51
51
  }
52
+
53
+ // src/tab-session.ts
54
+ var TAB_SESSION_HEADER = "x-oc-tab-session";
55
+ var TAB_SESSION_STORAGE_KEY = "oc_tab_session";
56
+ var TAB_ADOPT_HASH = "#oc-adopt";
57
+ function readTabSession() {
58
+ if (typeof window === "undefined") return null;
59
+ try {
60
+ const raw = window.sessionStorage.getItem(TAB_SESSION_STORAGE_KEY);
61
+ if (!raw) return null;
62
+ const parsed = JSON.parse(raw);
63
+ if (typeof parsed.token !== "string" || parsed.token.length === 0) return null;
64
+ if (typeof parsed.didOc !== "string" || parsed.didOc.length === 0) return null;
65
+ return { token: parsed.token, didOc: parsed.didOc };
66
+ } catch {
67
+ return null;
68
+ }
69
+ }
70
+ function writeTabSession(session) {
71
+ if (typeof window === "undefined") return;
72
+ try {
73
+ window.sessionStorage.setItem(TAB_SESSION_STORAGE_KEY, JSON.stringify(session));
74
+ } catch {
75
+ }
76
+ }
77
+ function clearTabSession() {
78
+ if (typeof window === "undefined") return;
79
+ try {
80
+ window.sessionStorage.removeItem(TAB_SESSION_STORAGE_KEY);
81
+ } catch {
82
+ }
83
+ }
84
+ function tabSessionHeader() {
85
+ const pin = readTabSession();
86
+ return pin ? { [TAB_SESSION_HEADER]: pin.token } : {};
87
+ }
88
+ function isPinnableUrl(url, authOrigin) {
89
+ if (typeof window === "undefined") return false;
90
+ try {
91
+ const u = new URL(url, window.location.href);
92
+ return u.origin === window.location.origin || u.origin === authOrigin;
93
+ } catch {
94
+ return false;
95
+ }
96
+ }
97
+ function installTabFetchInterceptor(authOrigin) {
98
+ if (typeof window === "undefined") return () => {
99
+ };
100
+ const original = window.fetch;
101
+ const wrapped = (input, init) => {
102
+ try {
103
+ const pin = readTabSession();
104
+ if (pin) {
105
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
106
+ if (isPinnableUrl(url, authOrigin)) {
107
+ const headers = new Headers(
108
+ init?.headers ?? (input instanceof Request ? input.headers : void 0)
109
+ );
110
+ if (!headers.has("authorization") && !headers.has(TAB_SESSION_HEADER)) {
111
+ headers.set(TAB_SESSION_HEADER, pin.token);
112
+ init = { ...init, headers };
113
+ }
114
+ }
115
+ }
116
+ } catch {
117
+ }
118
+ return original.call(window, input, init);
119
+ };
120
+ window.fetch = wrapped;
121
+ return () => {
122
+ if (window.fetch === wrapped) window.fetch = original;
123
+ };
124
+ }
125
+ function consumeTabAdoptMarker() {
126
+ if (typeof window === "undefined") return false;
127
+ if (!window.location.hash.includes(TAB_ADOPT_HASH.slice(1))) return false;
128
+ clearTabSession();
129
+ try {
130
+ const url = new URL(window.location.href);
131
+ url.hash = "";
132
+ window.history.replaceState(window.history.state, "", url.toString());
133
+ } catch {
134
+ }
135
+ return true;
136
+ }
52
137
  var SessionContext = React3__namespace.createContext(null);
53
138
  function normalizeDisplayIdentity(raw, didOc) {
54
139
  const di = raw.display_identity ?? raw.displayIdentity;
@@ -75,7 +160,7 @@ async function fetchHostRoster(cfg) {
75
160
  const res = await fetch(`${cfg.authOrigin}${cfg.mePath}`, {
76
161
  method: "GET",
77
162
  credentials: "include",
78
- headers: { Accept: "application/json" }
163
+ headers: { Accept: "application/json", ...tabSessionHeader() }
79
164
  });
80
165
  if (!res.ok) return [];
81
166
  const body = await res.json();
@@ -112,14 +197,50 @@ function OcSessionProvider({
112
197
  const [roster, setRoster] = React3__namespace.useState([]);
113
198
  const [status, setStatus] = React3__namespace.useState("loading");
114
199
  const [error, setError] = React3__namespace.useState(null);
200
+ const [tabPinned, setTabPinned] = React3__namespace.useState(false);
201
+ const pinInFlightRef = React3__namespace.useRef(false);
202
+ const pinThisTab = React3__namespace.useCallback(
203
+ async (didOc) => {
204
+ if (pinInFlightRef.current || readTabSession()) return;
205
+ pinInFlightRef.current = true;
206
+ try {
207
+ const res = await fetch(`${cfg.authOrigin}/api/auth/tab`, {
208
+ method: "POST",
209
+ credentials: "include",
210
+ headers: { Accept: "application/json" }
211
+ });
212
+ if (!res.ok) return;
213
+ const body = await res.json();
214
+ if (body.ok && typeof body.token === "string" && body.account?.did_oc === didOc) {
215
+ writeTabSession({ token: body.token, didOc });
216
+ setTabPinned(true);
217
+ }
218
+ } catch {
219
+ } finally {
220
+ pinInFlightRef.current = false;
221
+ }
222
+ },
223
+ [cfg.authOrigin]
224
+ );
115
225
  const refresh = React3__namespace.useCallback(async () => {
116
226
  if (typeof window === "undefined") return;
117
227
  try {
118
- const res = await fetch(cfg.mePath, {
228
+ let pin = readTabSession();
229
+ let res = await fetch(cfg.mePath, {
119
230
  method: "GET",
120
231
  credentials: "include",
121
- headers: { Accept: "application/json" }
232
+ headers: { Accept: "application/json", ...tabSessionHeader() }
122
233
  });
234
+ if (res.status === 401 && pin) {
235
+ clearTabSession();
236
+ pin = null;
237
+ setTabPinned(false);
238
+ res = await fetch(cfg.mePath, {
239
+ method: "GET",
240
+ credentials: "include",
241
+ headers: { Accept: "application/json" }
242
+ });
243
+ }
123
244
  if (res.status === 401) {
124
245
  setAccount(null);
125
246
  setRoster([]);
@@ -134,11 +255,17 @@ function OcSessionProvider({
134
255
  }
135
256
  const body = await res.json();
136
257
  const acct = normalizeAccount(body.account);
258
+ if (acct && pin && acct.didOc !== pin.didOc) {
259
+ clearTabSession();
260
+ pin = null;
261
+ }
262
+ setTabPinned(pin !== null);
137
263
  const rosterEntries = Array.isArray(body.roster) ? body.roster.map(normalizeRosterEntry).filter((r) => r !== null) : [];
138
264
  setAccount(acct);
139
265
  setRoster(rosterEntries);
140
266
  setStatus(acct ? "authenticated" : "anonymous");
141
267
  setError(null);
268
+ if (acct && !pin) void pinThisTab(acct.didOc);
142
269
  const currentOrigin = typeof window !== "undefined" ? window.location.origin : null;
143
270
  if (acct && rosterEntries.length === 0 && currentOrigin !== null && !cfg.authOrigin.startsWith(currentOrigin)) {
144
271
  const peers = await fetchHostRoster(cfg);
@@ -148,10 +275,12 @@ function OcSessionProvider({
148
275
  setStatus("error");
149
276
  setError(err instanceof Error ? err : new Error(String(err)));
150
277
  }
151
- }, [cfg]);
278
+ }, [cfg, pinThisTab]);
152
279
  React3__namespace.useEffect(() => {
280
+ consumeTabAdoptMarker();
153
281
  void refresh();
154
282
  }, [refresh]);
283
+ React3__namespace.useEffect(() => installTabFetchInterceptor(cfg.authOrigin), [cfg.authOrigin]);
155
284
  const signOut = React3__namespace.useCallback(
156
285
  async (opts) => {
157
286
  const scope = opts?.scope ?? "all";
@@ -161,6 +290,10 @@ function OcSessionProvider({
161
290
  const res = await fetch(url.toString(), {
162
291
  method: "POST",
163
292
  credentials: "include",
293
+ // Per-tab · carry the pin so scope='current' signs out
294
+ // the account THIS tab is operating as, not whichever
295
+ // account the shared cookie happens to point at.
296
+ headers: { ...tabSessionHeader() },
164
297
  // `keepalive` lets the logout round-trip complete even if
165
298
  // the caller hard-navigates away in the same tick (e.g.
166
299
  // `<OcAccountMenu>` redirects home immediately on sign-out).
@@ -168,11 +301,15 @@ function OcSessionProvider({
168
301
  // and the `.ochk.io` cookie may never get cleared.
169
302
  keepalive: true
170
303
  });
304
+ clearTabSession();
305
+ setTabPinned(false);
171
306
  if (scope === "current" && res.ok) {
172
307
  await refresh();
173
308
  return;
174
309
  }
175
310
  } catch {
311
+ clearTabSession();
312
+ setTabPinned(false);
176
313
  }
177
314
  setAccount(null);
178
315
  setRoster([]);
@@ -186,7 +323,7 @@ function OcSessionProvider({
186
323
  const res = await fetch(`${cfg.authOrigin}/api/auth/switch`, {
187
324
  method: "POST",
188
325
  credentials: "include",
189
- headers: { "Content-Type": "application/json" },
326
+ headers: { "Content-Type": "application/json", ...tabSessionHeader() },
190
327
  body: JSON.stringify({ did_oc: didOc })
191
328
  });
192
329
  if (!res.ok) {
@@ -198,6 +335,14 @@ function OcSessionProvider({
198
335
  }
199
336
  throw new Error(`[@orangecheck/auth-client] switchAccount failed: ${reason}`);
200
337
  }
338
+ try {
339
+ const body = await res.json();
340
+ if (typeof body.token === "string" && body.account?.did_oc) {
341
+ writeTabSession({ token: body.token, didOc: body.account.did_oc });
342
+ setTabPinned(true);
343
+ }
344
+ } catch {
345
+ }
201
346
  await refresh();
202
347
  },
203
348
  [cfg.authOrigin, refresh]
@@ -215,7 +360,7 @@ function OcSessionProvider({
215
360
  const res = await fetch(`${cfg.authOrigin}/api/auth/account`, {
216
361
  method: "PATCH",
217
362
  credentials: "include",
218
- headers: { "Content-Type": "application/json" },
363
+ headers: { "Content-Type": "application/json", ...tabSessionHeader() },
219
364
  body: JSON.stringify({ display_identity: kind })
220
365
  });
221
366
  if (!res.ok) {
@@ -227,6 +372,14 @@ function OcSessionProvider({
227
372
  }
228
373
  throw new Error(`[@orangecheck/auth-client] setDisplayIdentity failed: ${reason}`);
229
374
  }
375
+ try {
376
+ const body = await res.json();
377
+ const pin = readTabSession();
378
+ if (pin && typeof body.token === "string" && body.account?.did_oc === pin.didOc) {
379
+ writeTabSession({ token: body.token, didOc: pin.didOc });
380
+ }
381
+ } catch {
382
+ }
230
383
  await refresh();
231
384
  },
232
385
  [cfg.authOrigin, refresh]
@@ -237,6 +390,7 @@ function OcSessionProvider({
237
390
  status,
238
391
  account,
239
392
  roster,
393
+ tabPinned,
240
394
  error,
241
395
  refresh,
242
396
  signOut,
@@ -249,6 +403,7 @@ function OcSessionProvider({
249
403
  status,
250
404
  account,
251
405
  roster,
406
+ tabPinned,
252
407
  error,
253
408
  refresh,
254
409
  signOut,
@@ -1774,6 +1929,18 @@ function safeReturnTo(input) {
1774
1929
  if (!candidate.startsWith("/") || candidate.startsWith("//")) return "/";
1775
1930
  return candidate;
1776
1931
  }
1932
+ function familyReturnTarget(input) {
1933
+ if (typeof input !== "string" || input.length === 0) return void 0;
1934
+ if (input.startsWith("/") && !input.startsWith("//")) return input;
1935
+ try {
1936
+ const u = new URL(input);
1937
+ if (u.protocol !== "https:") return void 0;
1938
+ const host = u.hostname.toLowerCase();
1939
+ if (host === "ochk.io" || host.endsWith(".ochk.io")) return u.toString();
1940
+ } catch {
1941
+ }
1942
+ return void 0;
1943
+ }
1777
1944
  function hardNavigate(target) {
1778
1945
  if (typeof window === "undefined") return;
1779
1946
  window.location.assign(target);
@@ -1792,7 +1959,20 @@ function OcSignIn({
1792
1959
  }) {
1793
1960
  const walletEnabled = paths?.wallet ?? true;
1794
1961
  const emailEnabled = paths?.email ?? true;
1795
- const safeReturn = safeReturnTo(returnTo);
1962
+ const [resolvedReturn, setResolvedReturn] = React3__namespace.useState(
1963
+ () => familyReturnTarget(returnTo) ?? safeReturnTo(returnTo)
1964
+ );
1965
+ React3__namespace.useEffect(() => {
1966
+ const fromProp = familyReturnTarget(returnTo);
1967
+ if (fromProp) {
1968
+ setResolvedReturn(fromProp);
1969
+ return;
1970
+ }
1971
+ if (typeof window === "undefined") return;
1972
+ const q = new URLSearchParams(window.location.search);
1973
+ const fromQuery = familyReturnTarget(q.get("return_to")) ?? familyReturnTarget(q.get("next"));
1974
+ setResolvedReturn(fromQuery ?? "/");
1975
+ }, [returnTo]);
1796
1976
  const [addMode, setAddMode] = React3__namespace.useState(Boolean(addProp));
1797
1977
  React3__namespace.useEffect(() => {
1798
1978
  if (typeof window === "undefined") return;
@@ -1816,18 +1996,20 @@ function OcSignIn({
1816
1996
  async (account) => {
1817
1997
  if (resolveReturnTo) {
1818
1998
  try {
1819
- hardNavigate(safeReturnTo(await resolveReturnTo(account)));
1999
+ const resolved = familyReturnTarget(await resolveReturnTo(account));
2000
+ hardNavigate(resolved ?? resolvedReturn);
1820
2001
  return;
1821
2002
  } catch {
1822
2003
  }
1823
2004
  }
1824
- hardNavigate(safeReturn);
2005
+ hardNavigate(resolvedReturn);
1825
2006
  },
1826
- [resolveReturnTo, safeReturn]
2007
+ [resolveReturnTo, resolvedReturn]
1827
2008
  );
1828
2009
  const handleSuccess = React3__namespace.useCallback(
1829
2010
  async (account, token, via) => {
1830
2011
  const proceed = () => {
2012
+ clearTabSession();
1831
2013
  if (onSuccess) onSuccess(account, token);
1832
2014
  else void navigate(account);
1833
2015
  };
@@ -1992,7 +2174,7 @@ function OcSignIn({
1992
2174
  }
1993
2175
  )
1994
2176
  ] }),
1995
- /* @__PURE__ */ jsxRuntime.jsx(ProviderSignIn, { authOrigin, returnTo: safeReturn }),
2177
+ /* @__PURE__ */ jsxRuntime.jsx(ProviderSignIn, { authOrigin, returnTo: resolvedReturn, add: addMode }),
1996
2178
  linkPrompt && /* @__PURE__ */ jsxRuntime.jsxs("label", { "data-oc-signin-linkalso": "", style: linkAlsoStyle, children: [
1997
2179
  /* @__PURE__ */ jsxRuntime.jsx(
1998
2180
  "input",
@@ -2062,7 +2244,8 @@ function ProviderIcon({ id }) {
2062
2244
  }
2063
2245
  function ProviderSignIn({
2064
2246
  authOrigin,
2065
- returnTo
2247
+ returnTo,
2248
+ add
2066
2249
  }) {
2067
2250
  const [providers, setProviders] = React3__namespace.useState([]);
2068
2251
  const [origin, setOrigin] = React3__namespace.useState("");
@@ -2078,7 +2261,7 @@ function ProviderSignIn({
2078
2261
  };
2079
2262
  }, [authOrigin]);
2080
2263
  if (providers.length === 0) return null;
2081
- const providerReturnTo = origin ? `${origin}${returnTo}` : returnTo;
2264
+ const providerReturnTo = returnTo.startsWith("/") ? origin ? `${origin}${returnTo}` : returnTo : returnTo;
2082
2265
  const line = { flex: 1, height: 1, background: "var(--border, #27272a)" };
2083
2266
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-oc-signin-providers": "", style: { marginTop: 20 }, children: [
2084
2267
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2107,7 +2290,7 @@ function ProviderSignIn({
2107
2290
  {
2108
2291
  href: `${authOrigin}/api/auth/${p.id}/start?return_to=${encodeURIComponent(
2109
2292
  providerReturnTo
2110
- )}`,
2293
+ )}${add ? "&add=1" : ""}`,
2111
2294
  "data-oc-signin-provider": p.id,
2112
2295
  style: {
2113
2296
  display: "flex",
@@ -2797,16 +2980,25 @@ exports.OcLinkedIdentities = OcLinkedIdentities;
2797
2980
  exports.OcSessionProvider = OcSessionProvider;
2798
2981
  exports.OcSignIn = OcSignIn;
2799
2982
  exports.OcSignInButton = OcSignInButton;
2983
+ exports.TAB_ADOPT_HASH = TAB_ADOPT_HASH;
2984
+ exports.TAB_SESSION_HEADER = TAB_SESSION_HEADER;
2985
+ exports.TAB_SESSION_STORAGE_KEY = TAB_SESSION_STORAGE_KEY;
2800
2986
  exports.buildAddAccountUrl = buildAddAccountUrl;
2801
2987
  exports.buildSignInUrl = buildSignInUrl;
2988
+ exports.clearTabSession = clearTabSession;
2989
+ exports.consumeTabAdoptMarker = consumeTabAdoptMarker;
2802
2990
  exports.fetchOcLinkedIdentities = fetchOcLinkedIdentities;
2803
2991
  exports.handleSudoRequired = handleSudoRequired;
2992
+ exports.installTabFetchInterceptor = installTabFetchInterceptor;
2993
+ exports.readTabSession = readTabSession;
2804
2994
  exports.redirectToSudo = redirectToSudo;
2995
+ exports.tabSessionHeader = tabSessionHeader;
2805
2996
  exports.useOcAddressSuggestion = useOcAddressSuggestion;
2806
2997
  exports.useOcSession = useOcSession;
2807
2998
  exports.useOptionalOcSession = useOptionalOcSession;
2808
2999
  exports.useStepUpAuth = useStepUpAuth;
2809
3000
  exports.useWebAuthnList = useWebAuthnList;
2810
3001
  exports.useWebAuthnRegister = useWebAuthnRegister;
3002
+ exports.writeTabSession = writeTabSession;
2811
3003
  //# sourceMappingURL=index.js.map
2812
3004
  //# sourceMappingURL=index.js.map