@orangecheck/auth-client 2.20.0 → 2.22.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.mjs CHANGED
@@ -31,6 +31,7 @@ function buildAddAccountUrl(cfg, returnTo) {
31
31
  // src/tab-session.ts
32
32
  var TAB_SESSION_HEADER = "x-oc-tab-session";
33
33
  var TAB_SESSION_STORAGE_KEY = "oc_tab_session";
34
+ var TAB_ACCOUNT_HINT_KEY = "oc-as";
34
35
  var TAB_ADOPT_HASH = "#oc-adopt";
35
36
  function readTabSession() {
36
37
  if (typeof window === "undefined") return null;
@@ -112,6 +113,92 @@ function consumeTabAdoptMarker() {
112
113
  }
113
114
  return true;
114
115
  }
116
+ var OC_AS_HINT_RE = /^oc-as=(did:oc:[0-9a-f]{32})$/;
117
+ function familyApex(authOrigin) {
118
+ try {
119
+ return new URL(authOrigin).hostname.toLowerCase();
120
+ } catch {
121
+ return null;
122
+ }
123
+ }
124
+ function isFamilyUrl(u, authOrigin) {
125
+ if (u.protocol !== "http:" && u.protocol !== "https:") return false;
126
+ if (typeof window !== "undefined" && u.origin === window.location.origin) return true;
127
+ const apex = familyApex(authOrigin);
128
+ if (!apex) return false;
129
+ const host = u.hostname.toLowerCase();
130
+ return host === apex || host.endsWith(`.${apex}`);
131
+ }
132
+ function opensWithoutTabPin(e, anchor, dest) {
133
+ if (typeof window !== "undefined" && dest.origin !== window.location.origin) return true;
134
+ const target = (anchor.getAttribute("target") ?? "").toLowerCase();
135
+ return e.button === 1 || // middle-click
136
+ e.metaKey || e.ctrlKey || e.shiftKey || target === "_blank";
137
+ }
138
+ function installTabLinkDecorator(authOrigin) {
139
+ if (typeof window === "undefined" || typeof document === "undefined") return () => {
140
+ };
141
+ const onActivate = (e) => {
142
+ try {
143
+ const pin = readTabSession();
144
+ if (!pin) return;
145
+ const target = e.target;
146
+ if (!(target instanceof Element)) return;
147
+ const anchor = target.closest("a[href]");
148
+ if (!anchor || anchor.hasAttribute("download")) return;
149
+ const raw = anchor.getAttribute("href");
150
+ if (!raw || raw.includes(`${TAB_ACCOUNT_HINT_KEY}=`)) return;
151
+ let dest;
152
+ try {
153
+ dest = new URL(anchor.href);
154
+ } catch {
155
+ return;
156
+ }
157
+ if (dest.hash) return;
158
+ if (!isFamilyUrl(dest, authOrigin)) return;
159
+ if (!opensWithoutTabPin(e, anchor, dest)) return;
160
+ anchor.setAttribute("href", `${raw}#${TAB_ACCOUNT_HINT_KEY}=${pin.didOc}`);
161
+ } catch {
162
+ }
163
+ };
164
+ window.addEventListener("click", onActivate, true);
165
+ window.addEventListener("auxclick", onActivate, true);
166
+ return () => {
167
+ window.removeEventListener("click", onActivate, true);
168
+ window.removeEventListener("auxclick", onActivate, true);
169
+ };
170
+ }
171
+ async function consumeTabAccountHint(authOrigin) {
172
+ if (typeof window === "undefined") return null;
173
+ const frag = window.location.hash.replace(/^#/, "");
174
+ const m = OC_AS_HINT_RE.exec(frag);
175
+ if (!m) return null;
176
+ const did = m[1];
177
+ try {
178
+ const url = new URL(window.location.href);
179
+ url.hash = "";
180
+ window.history.replaceState(window.history.state, "", url.toString());
181
+ } catch {
182
+ }
183
+ const existing = readTabSession();
184
+ if (existing && existing.didOc === did) return did;
185
+ try {
186
+ const res = await fetch(`${authOrigin}/api/auth/tab`, {
187
+ method: "POST",
188
+ credentials: "include",
189
+ headers: { Accept: "application/json", "Content-Type": "application/json" },
190
+ body: JSON.stringify({ did_oc: did })
191
+ });
192
+ if (!res.ok) return null;
193
+ const body = await res.json();
194
+ if (body.ok && typeof body.token === "string" && body.account?.did_oc === did) {
195
+ writeTabSession({ token: body.token, didOc: did });
196
+ return did;
197
+ }
198
+ } catch {
199
+ }
200
+ return null;
201
+ }
115
202
  var SessionContext = React3.createContext(null);
116
203
  function normalizeDisplayIdentity(raw, didOc) {
117
204
  const di = raw.display_identity ?? raw.displayIdentity;
@@ -255,10 +342,18 @@ function OcSessionProvider({
255
342
  }
256
343
  }, [cfg, pinThisTab]);
257
344
  React3.useEffect(() => {
345
+ let cancelled = false;
258
346
  consumeTabAdoptMarker();
259
- void refresh();
260
- }, [refresh]);
347
+ void (async () => {
348
+ await consumeTabAccountHint(cfg.authOrigin);
349
+ if (!cancelled) void refresh();
350
+ })();
351
+ return () => {
352
+ cancelled = true;
353
+ };
354
+ }, [refresh, cfg.authOrigin]);
261
355
  React3.useEffect(() => installTabFetchInterceptor(cfg.authOrigin), [cfg.authOrigin]);
356
+ React3.useEffect(() => installTabLinkDecorator(cfg.authOrigin), [cfg.authOrigin]);
262
357
  const signOut = React3.useCallback(
263
358
  async (opts) => {
264
359
  const scope = opts?.scope ?? "all";
@@ -1041,7 +1136,8 @@ var DEFAULT_AUTH_ORIGIN = "https://ochk.io";
1041
1136
  async function fetchOcLinkedIdentities(opts) {
1042
1137
  const authOrigin = opts?.authOrigin ?? DEFAULT_AUTH_ORIGIN;
1043
1138
  const r = await fetch(`${authOrigin}/api/auth/identities`, {
1044
- credentials: "include"
1139
+ credentials: "include",
1140
+ headers: { ...tabSessionHeader() }
1045
1141
  });
1046
1142
  if (r.status === 401) return [];
1047
1143
  if (!r.ok) throw new Error(`identities fetch failed: http_${r.status}`);
@@ -1061,7 +1157,8 @@ function OcLinkedIdentities({
1061
1157
  setError(null);
1062
1158
  try {
1063
1159
  const r = await fetch(`${authOrigin}/api/auth/identities`, {
1064
- credentials: "include"
1160
+ credentials: "include",
1161
+ headers: { ...tabSessionHeader() }
1065
1162
  });
1066
1163
  if (!r.ok) {
1067
1164
  if (r.status === 401) {
@@ -2991,6 +3088,6 @@ function handleSudoRequired(body, args = {}) {
2991
3088
  return false;
2992
3089
  }
2993
3090
 
2994
- export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, OcAccountChip, OcAccountPill, OcAddressInput, OcLinkedIdentities, OcSessionProvider, OcSignIn, OcSignInButton, TAB_ADOPT_HASH, TAB_SESSION_HEADER, TAB_SESSION_STORAGE_KEY, buildAddAccountUrl, buildSignInUrl, clearTabSession, consumeTabAdoptMarker, fetchOcLinkedIdentities, handleSudoRequired, installTabFetchInterceptor, readTabSession, redirectToSudo, tabSessionHeader, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister, writeTabSession };
3091
+ export { DEFAULT_CONFIG, DISPLAY_IDENTITY_KINDS, OcAccountChip, OcAccountPill, OcAddressInput, OcLinkedIdentities, OcSessionProvider, OcSignIn, OcSignInButton, TAB_ACCOUNT_HINT_KEY, TAB_ADOPT_HASH, TAB_SESSION_HEADER, TAB_SESSION_STORAGE_KEY, buildAddAccountUrl, buildSignInUrl, clearTabSession, consumeTabAccountHint, consumeTabAdoptMarker, fetchOcLinkedIdentities, handleSudoRequired, installTabFetchInterceptor, installTabLinkDecorator, readTabSession, redirectToSudo, tabSessionHeader, useOcAddressSuggestion, useOcSession, useOptionalOcSession, useStepUpAuth, useWebAuthnList, useWebAuthnRegister, writeTabSession };
2995
3092
  //# sourceMappingURL=index.mjs.map
2996
3093
  //# sourceMappingURL=index.mjs.map