@oxyhq/services 12.0.0 → 12.1.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.
Files changed (26) hide show
  1. package/lib/commonjs/ui/context/OxyContext.js +45 -18
  2. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  3. package/lib/commonjs/ui/context/inSessionTokenRefresh.js +262 -0
  4. package/lib/commonjs/ui/context/inSessionTokenRefresh.js.map +1 -0
  5. package/lib/commonjs/ui/context/silentSessionRestore.js +65 -0
  6. package/lib/commonjs/ui/context/silentSessionRestore.js.map +1 -0
  7. package/lib/module/ui/context/OxyContext.js +46 -19
  8. package/lib/module/ui/context/OxyContext.js.map +1 -1
  9. package/lib/module/ui/context/inSessionTokenRefresh.js +257 -0
  10. package/lib/module/ui/context/inSessionTokenRefresh.js.map +1 -0
  11. package/lib/module/ui/context/silentSessionRestore.js +61 -0
  12. package/lib/module/ui/context/silentSessionRestore.js.map +1 -0
  13. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  14. package/lib/typescript/commonjs/ui/context/inSessionTokenRefresh.d.ts +101 -0
  15. package/lib/typescript/commonjs/ui/context/inSessionTokenRefresh.d.ts.map +1 -0
  16. package/lib/typescript/commonjs/ui/context/silentSessionRestore.d.ts +42 -0
  17. package/lib/typescript/commonjs/ui/context/silentSessionRestore.d.ts.map +1 -0
  18. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  19. package/lib/typescript/module/ui/context/inSessionTokenRefresh.d.ts +101 -0
  20. package/lib/typescript/module/ui/context/inSessionTokenRefresh.d.ts.map +1 -0
  21. package/lib/typescript/module/ui/context/silentSessionRestore.d.ts +42 -0
  22. package/lib/typescript/module/ui/context/silentSessionRestore.d.ts.map +1 -0
  23. package/package.json +3 -3
  24. package/src/ui/context/OxyContext.tsx +45 -21
  25. package/src/ui/context/inSessionTokenRefresh.ts +283 -0
  26. package/src/ui/context/silentSessionRestore.ts +67 -0
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * In-session access-token refresh for the React Native / Expo SDK.
5
+ *
6
+ * THE GAP THIS CLOSES: the services `OxyContext` owns the session but never
7
+ * installed an `authRefreshHandler` on the owner `HttpService`, so
8
+ * `HttpService.refreshAccessToken` short-circuited to `null` — there was NO
9
+ * in-session token refresh on the RN path at all. A 15-minute access token
10
+ * expired with the tab/app open and nothing re-minted one; cross-apex RP feeds
11
+ * (mention.earth, …) then 401'd in a loop while `isAuthenticated` stayed `true`
12
+ * (a zombie logged-in state), because the `Domain=oxy.so` refresh cookie can't
13
+ * reach `api.<apex>`. (`AuthManager`, which installs a refresh handler on the
14
+ * web path, is only ever constructed by `WebOxyProvider` in `@oxyhq/auth`.)
15
+ *
16
+ * THE FIX, two cooperating pieces both wired from `OxyContext`:
17
+ *
18
+ * 1. {@link createInSessionRefreshHandler} — an `AuthRefreshHandler` installed
19
+ * on the owner client. It re-mints a fresh access token WITHOUT a page
20
+ * reload by composing the SAME silent-restore primitives cold boot uses
21
+ * ({@link mintSessionViaPerApexIframe}, {@link selectActiveRefreshAccount}) —
22
+ * not a copy. The linked client (`createLinkedClient`) inherits the fix for
23
+ * free: its refresh delegates back to the owner's `refreshAccessToken`.
24
+ *
25
+ * 2. {@link startTokenRefreshScheduler} — a proactive scheduler that refreshes
26
+ * ~{@link TOKEN_REFRESH_LEAD_MS} before expiry (and on web tab-focus / native
27
+ * app-foreground), so the common case never even reaches the reactive
28
+ * 401-then-recover flash.
29
+ *
30
+ * Concurrency/cooldown/dedup are owned by `HttpService.refreshAccessToken`
31
+ * (single in-flight `tokenRefreshPromise` + cooldown) — this module does not
32
+ * reimplement them, so the timer / foreground / per-request triggers collapse to
33
+ * one network attempt (no refresh storm).
34
+ */
35
+
36
+ import { logger as loggerUtil } from '@oxyhq/core';
37
+ import { AppState } from 'react-native';
38
+ import { isWebBrowser } from "../hooks/useWebSSO.js";
39
+ import { readActiveAuthuser } from "../utils/activeAuthuser.js";
40
+ import { mintSessionViaPerApexIframe, selectActiveRefreshAccount } from "./silentSessionRestore.js";
41
+
42
+ /**
43
+ * Per-arm fail-fast budget (ms) for the web first-party `/auth/silent` iframe
44
+ * arm. Slightly more generous than the cold-boot iframe budget (2.5s) because an
45
+ * in-session refresh is NOT in the first-paint critical path — a couple hundred
46
+ * ms of extra headroom for the same-origin handshake is worth a higher success
47
+ * rate. `silentSignIn` still fail-fasts on `iframe.onerror`, so a hard failure
48
+ * returns well before this.
49
+ */
50
+ const SILENT_IFRAME_REFRESH_TIMEOUT = 4000;
51
+
52
+ /**
53
+ * Per-arm fail-fast budget (ms) for the same-apex refresh-cookie arm
54
+ * (`refreshAllSessions`). On a cross-apex RP the `Domain=oxy.so` cookie never
55
+ * reaches `api.<apex>`, so this returns `{accounts:[]}` quickly; the bound only
56
+ * matters if that endpoint stalls.
57
+ */
58
+ const COOKIE_REFRESH_TIMEOUT = 4000;
59
+
60
+ /**
61
+ * Lead time (ms) before access-token expiry at which the proactive scheduler
62
+ * refreshes. Mirrors `HttpService`'s per-request `TOKEN_REFRESH_LEAD_SECONDS`
63
+ * (60s) so the scheduled refresh and the request-time preflight refresh use the
64
+ * same window — the scheduler simply fires it during idle/background instead of
65
+ * waiting for the next request.
66
+ */
67
+ export const TOKEN_REFRESH_LEAD_MS = 60_000;
68
+
69
+ /**
70
+ * A single refresh arm: attempts one silent-restore mechanism and resolves to
71
+ * the freshly planted access token, or `null` to fall through to the next arm.
72
+ */
73
+
74
+ /**
75
+ * Build the in-session `AuthRefreshHandler` for the owner client.
76
+ *
77
+ * Arms run in an explicit order; the first to plant a token wins. Each arm
78
+ * resolves to the planted token (read back via `getAccessToken()` — the
79
+ * underlying SDK call plants it internally) or `null`. A throw in one arm is
80
+ * logged and treated as `null` so the chain continues.
81
+ *
82
+ * NATIVE (Expo): shared cross-app identity key re-mint
83
+ * (`signInWithSharedIdentity` → challenge→sign→verify plants the tokens).
84
+ * The ONLY silent native arm (mirrors cold boot's `shared-key-signin`); the
85
+ * `/auth/silent` web iframe is NEVER attempted on native. Resolves to `null`
86
+ * when the device holds no shared identity (e.g. a password-only native
87
+ * sign-in) so a genuinely dead session reconciles to logged-out rather than
88
+ * staying a zombie.
89
+ *
90
+ * WEB, in order:
91
+ * 1. Per-apex `/auth/silent` iframe — {@link mintSessionViaPerApexIframe}
92
+ * (shared verbatim with cold boot). The durable cross-apex path; also
93
+ * covers `*.oxy.so` (the per-apex host IS the central host there).
94
+ * 2. FedCM silent re-auth (Chrome) — `silentSignInWithFedCM`.
95
+ * 3. Same-apex refresh cookie — `refreshAllSessions` + the shared
96
+ * {@link selectActiveRefreshAccount}; plant the active account's rotated
97
+ * token. On a cross-apex RP it returns `{accounts:[]}` (clean no-op).
98
+ * Unlike the cold-boot cookie restore this does NOT rebuild multi-session
99
+ * state — an in-session refresh only needs a fresh bearer.
100
+ *
101
+ * NO RECURSION: no arm issues a request through the authed client's
102
+ * `refreshAccessToken` path. The iframe/FedCM transports are postMessage /
103
+ * credential APIs; the follow-up `/session/user` fetch inside `silentSignIn`
104
+ * runs against the just-planted FULL-TTL token (≫ the preflight lead), so it
105
+ * never re-enters the refresh path; `refreshAllSessions` uses a raw `fetch`.
106
+ */
107
+ export function createInSessionRefreshHandler(oxyServices) {
108
+ const runArm = async (label, reason, arm) => {
109
+ try {
110
+ return await arm();
111
+ } catch (error) {
112
+ if (__DEV__) {
113
+ loggerUtil.debug(`In-session refresh arm "${label}" failed (falling through)`, {
114
+ component: 'inSessionTokenRefresh',
115
+ method: 'authRefreshHandler',
116
+ reason
117
+ }, error);
118
+ }
119
+ return null;
120
+ }
121
+ };
122
+ const webArms = [['silent-iframe', async () => (await mintSessionViaPerApexIframe(oxyServices, SILENT_IFRAME_REFRESH_TIMEOUT)) ? oxyServices.getAccessToken() : null], ['fedcm-silent', async () => {
123
+ if (oxyServices.isFedCMSupported?.() !== true) {
124
+ return null;
125
+ }
126
+ return (await oxyServices.silentSignInWithFedCM?.()) ? oxyServices.getAccessToken() : null;
127
+ }], ['refresh-cookie', async () => {
128
+ const snapshot = await oxyServices.refreshAllSessions({
129
+ timeout: COOKIE_REFRESH_TIMEOUT
130
+ });
131
+ if (snapshot.accounts.length === 0) {
132
+ return null;
133
+ }
134
+ const active = selectActiveRefreshAccount(snapshot.accounts, readActiveAuthuser());
135
+ oxyServices.httpService.setTokens(active.accessToken);
136
+ return oxyServices.getAccessToken();
137
+ }]];
138
+ return async reason => {
139
+ if (!isWebBrowser()) {
140
+ return runArm('native-shared-key', reason, async () => (await oxyServices.signInWithSharedIdentity?.()) ? oxyServices.getAccessToken() : null);
141
+ }
142
+ for (const [label, arm] of webArms) {
143
+ const token = await runArm(label, reason, arm);
144
+ if (token) {
145
+ return token;
146
+ }
147
+ }
148
+ return null;
149
+ };
150
+ }
151
+
152
+ /**
153
+ * Handle returned by {@link startTokenRefreshScheduler}; call `dispose()` to tear
154
+ * down the timer and the foreground listener.
155
+ */
156
+
157
+ /**
158
+ * Start the proactive in-session refresh scheduler against `oxyServices`.
159
+ *
160
+ * Schedules a single timer to fire {@link TOKEN_REFRESH_LEAD_MS} before the
161
+ * current access token's `exp`, calling `httpService.refreshAccessToken`
162
+ * ('preflight') — which runs the installed handler and is deduped + cooldown-
163
+ * guarded. After every attempt it reschedules from the (possibly rotated) token.
164
+ * It also reschedules whenever the token changes (`onTokensChanged` — so a
165
+ * sign-out that clears the token cancels the timer) and, on web tab-focus /
166
+ * native app-foreground, refreshes immediately if already inside the lead window
167
+ * (a long-hidden tab throttles timers, so the token can be expired on return).
168
+ *
169
+ * The `exp` is derived directly from the JWT via `getAccessTokenExpiry()`. No-ops
170
+ * cleanly when there is no token, an opaque/no-`exp` token, or the host lacks
171
+ * `getAccessTokenExpiry` (older stubs) — the reactive 401 path stays the only
172
+ * refresh trigger in those cases.
173
+ */
174
+ export function startTokenRefreshScheduler(oxyServices) {
175
+ let disposed = false;
176
+ let timer = null;
177
+ const clearTimer = () => {
178
+ if (timer !== null) {
179
+ clearTimeout(timer);
180
+ timer = null;
181
+ }
182
+ };
183
+ const runRefresh = () => {
184
+ // `refreshAccessToken` is deduped + cooldown-guarded internally, so this is
185
+ // safe to call from the timer, the foreground listener, and request-time
186
+ // preflight concurrently — they collapse to one network attempt.
187
+ const refresh = oxyServices.httpService.refreshAccessToken?.('preflight');
188
+ if (!refresh) {
189
+ return;
190
+ }
191
+ void refresh.catch(() => null).finally(() => {
192
+ if (!disposed) {
193
+ schedule();
194
+ }
195
+ });
196
+ };
197
+ const schedule = () => {
198
+ clearTimer();
199
+ if (disposed || !oxyServices.getAccessToken()) {
200
+ return;
201
+ }
202
+ const expSeconds = oxyServices.getAccessTokenExpiry?.() ?? null;
203
+ if (expSeconds === null) {
204
+ return;
205
+ }
206
+ const fireInMs = expSeconds * 1000 - Date.now() - TOKEN_REFRESH_LEAD_MS;
207
+ timer = setTimeout(runRefresh, Math.max(fireInMs, 0));
208
+ };
209
+ const onForeground = () => {
210
+ if (disposed || !oxyServices.getAccessToken()) {
211
+ return;
212
+ }
213
+ const expSeconds = oxyServices.getAccessTokenExpiry?.() ?? null;
214
+ if (expSeconds === null) {
215
+ return;
216
+ }
217
+ const remainingMs = expSeconds * 1000 - Date.now();
218
+ if (remainingMs <= TOKEN_REFRESH_LEAD_MS) {
219
+ runRefresh();
220
+ } else {
221
+ schedule();
222
+ }
223
+ };
224
+ const unsubscribeTokens = oxyServices.onTokensChanged(() => {
225
+ if (!disposed) {
226
+ schedule();
227
+ }
228
+ });
229
+ let removeForeground = null;
230
+ if (isWebBrowser() && typeof document !== 'undefined') {
231
+ const handler = () => {
232
+ if (document.visibilityState === 'visible') {
233
+ onForeground();
234
+ }
235
+ };
236
+ document.addEventListener('visibilitychange', handler);
237
+ removeForeground = () => document.removeEventListener('visibilitychange', handler);
238
+ } else if (!isWebBrowser() && AppState && typeof AppState.addEventListener === 'function') {
239
+ const subscription = AppState.addEventListener('change', state => {
240
+ if (state === 'active') {
241
+ onForeground();
242
+ }
243
+ });
244
+ removeForeground = () => subscription.remove();
245
+ }
246
+ schedule();
247
+ return {
248
+ dispose() {
249
+ disposed = true;
250
+ clearTimer();
251
+ unsubscribeTokens();
252
+ removeForeground?.();
253
+ removeForeground = null;
254
+ }
255
+ };
256
+ }
257
+ //# sourceMappingURL=inSessionTokenRefresh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["logger","loggerUtil","AppState","isWebBrowser","readActiveAuthuser","mintSessionViaPerApexIframe","selectActiveRefreshAccount","SILENT_IFRAME_REFRESH_TIMEOUT","COOKIE_REFRESH_TIMEOUT","TOKEN_REFRESH_LEAD_MS","createInSessionRefreshHandler","oxyServices","runArm","label","reason","arm","error","__DEV__","debug","component","method","webArms","getAccessToken","isFedCMSupported","silentSignInWithFedCM","snapshot","refreshAllSessions","timeout","accounts","length","active","httpService","setTokens","accessToken","signInWithSharedIdentity","token","startTokenRefreshScheduler","disposed","timer","clearTimer","clearTimeout","runRefresh","refresh","refreshAccessToken","catch","finally","schedule","expSeconds","getAccessTokenExpiry","fireInMs","Date","now","setTimeout","Math","max","onForeground","remainingMs","unsubscribeTokens","onTokensChanged","removeForeground","document","handler","visibilityState","addEventListener","removeEventListener","subscription","state","remove","dispose"],"sourceRoot":"../../../../src","sources":["ui/context/inSessionTokenRefresh.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Silent, no-reload session-restore PRIMITIVES — the single shared
5
+ * implementation used by BOTH cold boot (`OxyContext.restoreSessionsFromStorage`)
6
+ * and in-session token refresh (`createInSessionRefreshHandler`). Neither caller
7
+ * re-implements these; they compose them. Keeping one home avoids the two paths
8
+ * drifting on "how do we mint a first-party token without a page reload".
9
+ *
10
+ * Each function is platform-agnostic at the type level and returns plain data;
11
+ * the callers own the side effects that differ between them (cold boot COMMITS
12
+ * the recovered session into provider state; refresh only reads the freshly
13
+ * planted bearer).
14
+ */
15
+
16
+ import { autoDetectAuthWebUrl } from '@oxyhq/core';
17
+
18
+ /**
19
+ * Mint a fresh first-party session via the PER-APEX `/auth/silent` iframe — the
20
+ * durable cross-domain restore path that works WITHOUT a top-level navigation
21
+ * (so it succeeds under Safari ITP / Firefox TCP and in a backgrounded tab).
22
+ *
23
+ * The instance is configured with the CENTRAL auth URL, so we explicitly point
24
+ * the iframe at the per-apex host (`auth.<rp-apex>`) via `autoDetectAuthWebUrl()`
25
+ * + `silentSignIn`'s `authWebUrlOverride`. On a `*.oxy.so` app the per-apex host
26
+ * IS the central host, so this also covers same-apex. When auto-detection bails
27
+ * (localhost / IP / single-label / off-browser) there is no per-apex IdP and we
28
+ * return `null`. `silentSignIn` plants the access token internally on success.
29
+ *
30
+ * @returns the recovered session (token already planted) when complete, else
31
+ * `null` (no per-apex IdP, no session, or an incomplete iframe response).
32
+ */
33
+ export async function mintSessionViaPerApexIframe(oxyServices, timeoutMs) {
34
+ const perApexAuthUrl = autoDetectAuthWebUrl();
35
+ if (!perApexAuthUrl) {
36
+ return null;
37
+ }
38
+ const session = await oxyServices.silentSignIn?.({
39
+ authWebUrlOverride: perApexAuthUrl,
40
+ timeout: timeoutMs
41
+ });
42
+ if (!session?.user || !session.sessionId) {
43
+ return null;
44
+ }
45
+ return session;
46
+ }
47
+
48
+ /**
49
+ * Pick the active account from a `refreshAllSessions` snapshot: the persisted
50
+ * `authuser` slot when it still matches a returned account, otherwise the lowest
51
+ * `authuser` (the server sorts ascending, so `[0]`). Callers guarantee a
52
+ * non-empty list, so the result is always defined.
53
+ *
54
+ * Shared by cold-boot cookie restore and the in-session refresh cookie arm so
55
+ * the active-slot selection can never diverge between them.
56
+ */
57
+ export function selectActiveRefreshAccount(accounts, persistedAuthuser) {
58
+ const matched = persistedAuthuser !== null ? accounts.find(account => account.authuser === persistedAuthuser) : undefined;
59
+ return matched ?? accounts[0];
60
+ }
61
+ //# sourceMappingURL=silentSessionRestore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["autoDetectAuthWebUrl","mintSessionViaPerApexIframe","oxyServices","timeoutMs","perApexAuthUrl","session","silentSignIn","authWebUrlOverride","timeout","user","sessionId","selectActiveRefreshAccount","accounts","persistedAuthuser","matched","find","account","authuser","undefined"],"sourceRoot":"../../../../src","sources":["ui/context/silentSessionRestore.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASA,oBAAoB,QAAQ,aAAa;;AAElD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeC,2BAA2BA,CAC/CC,WAAwB,EACxBC,SAAiB,EACqB;EACtC,MAAMC,cAAc,GAAGJ,oBAAoB,CAAC,CAAC;EAC7C,IAAI,CAACI,cAAc,EAAE;IACnB,OAAO,IAAI;EACb;EACA,MAAMC,OAAO,GAAG,MAAMH,WAAW,CAACI,YAAY,GAAG;IAC/CC,kBAAkB,EAAEH,cAAc;IAClCI,OAAO,EAAEL;EACX,CAAC,CAAC;EACF,IAAI,CAACE,OAAO,EAAEI,IAAI,IAAI,CAACJ,OAAO,CAACK,SAAS,EAAE;IACxC,OAAO,IAAI;EACb;EACA,OAAOL,OAAO;AAChB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASM,0BAA0BA,CACxCC,QAAa,EACbC,iBAAgC,EAC7B;EACH,MAAMC,OAAO,GACXD,iBAAiB,KAAK,IAAI,GACtBD,QAAQ,CAACG,IAAI,CAAEC,OAAO,IAAKA,OAAO,CAACC,QAAQ,KAAKJ,iBAAiB,CAAC,GAClEK,SAAS;EACf,OAAOJ,OAAO,IAAIF,QAAQ,CAAC,CAAC,CAAC;AAC/B","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"OxyContext.d.ts","sourceRoot":"","sources":["../../../../../src/ui/context/OxyContext.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OxyContext.d.ts","sourceRoot":"","sources":["../../../../../src/ui/context/OxyContext.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * In-session access-token refresh for the React Native / Expo SDK.
3
+ *
4
+ * THE GAP THIS CLOSES: the services `OxyContext` owns the session but never
5
+ * installed an `authRefreshHandler` on the owner `HttpService`, so
6
+ * `HttpService.refreshAccessToken` short-circuited to `null` — there was NO
7
+ * in-session token refresh on the RN path at all. A 15-minute access token
8
+ * expired with the tab/app open and nothing re-minted one; cross-apex RP feeds
9
+ * (mention.earth, …) then 401'd in a loop while `isAuthenticated` stayed `true`
10
+ * (a zombie logged-in state), because the `Domain=oxy.so` refresh cookie can't
11
+ * reach `api.<apex>`. (`AuthManager`, which installs a refresh handler on the
12
+ * web path, is only ever constructed by `WebOxyProvider` in `@oxyhq/auth`.)
13
+ *
14
+ * THE FIX, two cooperating pieces both wired from `OxyContext`:
15
+ *
16
+ * 1. {@link createInSessionRefreshHandler} — an `AuthRefreshHandler` installed
17
+ * on the owner client. It re-mints a fresh access token WITHOUT a page
18
+ * reload by composing the SAME silent-restore primitives cold boot uses
19
+ * ({@link mintSessionViaPerApexIframe}, {@link selectActiveRefreshAccount}) —
20
+ * not a copy. The linked client (`createLinkedClient`) inherits the fix for
21
+ * free: its refresh delegates back to the owner's `refreshAccessToken`.
22
+ *
23
+ * 2. {@link startTokenRefreshScheduler} — a proactive scheduler that refreshes
24
+ * ~{@link TOKEN_REFRESH_LEAD_MS} before expiry (and on web tab-focus / native
25
+ * app-foreground), so the common case never even reaches the reactive
26
+ * 401-then-recover flash.
27
+ *
28
+ * Concurrency/cooldown/dedup are owned by `HttpService.refreshAccessToken`
29
+ * (single in-flight `tokenRefreshPromise` + cooldown) — this module does not
30
+ * reimplement them, so the timer / foreground / per-request triggers collapse to
31
+ * one network attempt (no refresh storm).
32
+ */
33
+ import type { OxyServices, AuthRefreshHandler } from '@oxyhq/core';
34
+ /**
35
+ * Lead time (ms) before access-token expiry at which the proactive scheduler
36
+ * refreshes. Mirrors `HttpService`'s per-request `TOKEN_REFRESH_LEAD_SECONDS`
37
+ * (60s) so the scheduled refresh and the request-time preflight refresh use the
38
+ * same window — the scheduler simply fires it during idle/background instead of
39
+ * waiting for the next request.
40
+ */
41
+ export declare const TOKEN_REFRESH_LEAD_MS = 60000;
42
+ /**
43
+ * Build the in-session `AuthRefreshHandler` for the owner client.
44
+ *
45
+ * Arms run in an explicit order; the first to plant a token wins. Each arm
46
+ * resolves to the planted token (read back via `getAccessToken()` — the
47
+ * underlying SDK call plants it internally) or `null`. A throw in one arm is
48
+ * logged and treated as `null` so the chain continues.
49
+ *
50
+ * NATIVE (Expo): shared cross-app identity key re-mint
51
+ * (`signInWithSharedIdentity` → challenge→sign→verify plants the tokens).
52
+ * The ONLY silent native arm (mirrors cold boot's `shared-key-signin`); the
53
+ * `/auth/silent` web iframe is NEVER attempted on native. Resolves to `null`
54
+ * when the device holds no shared identity (e.g. a password-only native
55
+ * sign-in) so a genuinely dead session reconciles to logged-out rather than
56
+ * staying a zombie.
57
+ *
58
+ * WEB, in order:
59
+ * 1. Per-apex `/auth/silent` iframe — {@link mintSessionViaPerApexIframe}
60
+ * (shared verbatim with cold boot). The durable cross-apex path; also
61
+ * covers `*.oxy.so` (the per-apex host IS the central host there).
62
+ * 2. FedCM silent re-auth (Chrome) — `silentSignInWithFedCM`.
63
+ * 3. Same-apex refresh cookie — `refreshAllSessions` + the shared
64
+ * {@link selectActiveRefreshAccount}; plant the active account's rotated
65
+ * token. On a cross-apex RP it returns `{accounts:[]}` (clean no-op).
66
+ * Unlike the cold-boot cookie restore this does NOT rebuild multi-session
67
+ * state — an in-session refresh only needs a fresh bearer.
68
+ *
69
+ * NO RECURSION: no arm issues a request through the authed client's
70
+ * `refreshAccessToken` path. The iframe/FedCM transports are postMessage /
71
+ * credential APIs; the follow-up `/session/user` fetch inside `silentSignIn`
72
+ * runs against the just-planted FULL-TTL token (≫ the preflight lead), so it
73
+ * never re-enters the refresh path; `refreshAllSessions` uses a raw `fetch`.
74
+ */
75
+ export declare function createInSessionRefreshHandler(oxyServices: OxyServices): AuthRefreshHandler;
76
+ /**
77
+ * Handle returned by {@link startTokenRefreshScheduler}; call `dispose()` to tear
78
+ * down the timer and the foreground listener.
79
+ */
80
+ export interface TokenRefreshSchedulerHandle {
81
+ dispose(): void;
82
+ }
83
+ /**
84
+ * Start the proactive in-session refresh scheduler against `oxyServices`.
85
+ *
86
+ * Schedules a single timer to fire {@link TOKEN_REFRESH_LEAD_MS} before the
87
+ * current access token's `exp`, calling `httpService.refreshAccessToken`
88
+ * ('preflight') — which runs the installed handler and is deduped + cooldown-
89
+ * guarded. After every attempt it reschedules from the (possibly rotated) token.
90
+ * It also reschedules whenever the token changes (`onTokensChanged` — so a
91
+ * sign-out that clears the token cancels the timer) and, on web tab-focus /
92
+ * native app-foreground, refreshes immediately if already inside the lead window
93
+ * (a long-hidden tab throttles timers, so the token can be expired on return).
94
+ *
95
+ * The `exp` is derived directly from the JWT via `getAccessTokenExpiry()`. No-ops
96
+ * cleanly when there is no token, an opaque/no-`exp` token, or the host lacks
97
+ * `getAccessTokenExpiry` (older stubs) — the reactive 401 path stays the only
98
+ * refresh trigger in those cases.
99
+ */
100
+ export declare function startTokenRefreshScheduler(oxyServices: OxyServices): TokenRefreshSchedulerHandle;
101
+ //# sourceMappingURL=inSessionTokenRefresh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inSessionTokenRefresh.d.ts","sourceRoot":"","sources":["../../../../../src/ui/context/inSessionTokenRefresh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAEnB,MAAM,aAAa,CAAC;AAyBrB;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAQ5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,WAAW,GAAG,kBAAkB,CAsD1F;AAED;;;GAGG;AACH,MAAM,WAAW,2BAA2B;IAC1C,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,WAAW,GAAG,2BAA2B,CA4FhG"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Silent, no-reload session-restore PRIMITIVES — the single shared
3
+ * implementation used by BOTH cold boot (`OxyContext.restoreSessionsFromStorage`)
4
+ * and in-session token refresh (`createInSessionRefreshHandler`). Neither caller
5
+ * re-implements these; they compose them. Keeping one home avoids the two paths
6
+ * drifting on "how do we mint a first-party token without a page reload".
7
+ *
8
+ * Each function is platform-agnostic at the type level and returns plain data;
9
+ * the callers own the side effects that differ between them (cold boot COMMITS
10
+ * the recovered session into provider state; refresh only reads the freshly
11
+ * planted bearer).
12
+ */
13
+ import type { OxyServices, SessionLoginResponse } from '@oxyhq/core';
14
+ /**
15
+ * Mint a fresh first-party session via the PER-APEX `/auth/silent` iframe — the
16
+ * durable cross-domain restore path that works WITHOUT a top-level navigation
17
+ * (so it succeeds under Safari ITP / Firefox TCP and in a backgrounded tab).
18
+ *
19
+ * The instance is configured with the CENTRAL auth URL, so we explicitly point
20
+ * the iframe at the per-apex host (`auth.<rp-apex>`) via `autoDetectAuthWebUrl()`
21
+ * + `silentSignIn`'s `authWebUrlOverride`. On a `*.oxy.so` app the per-apex host
22
+ * IS the central host, so this also covers same-apex. When auto-detection bails
23
+ * (localhost / IP / single-label / off-browser) there is no per-apex IdP and we
24
+ * return `null`. `silentSignIn` plants the access token internally on success.
25
+ *
26
+ * @returns the recovered session (token already planted) when complete, else
27
+ * `null` (no per-apex IdP, no session, or an incomplete iframe response).
28
+ */
29
+ export declare function mintSessionViaPerApexIframe(oxyServices: OxyServices, timeoutMs: number): Promise<SessionLoginResponse | null>;
30
+ /**
31
+ * Pick the active account from a `refreshAllSessions` snapshot: the persisted
32
+ * `authuser` slot when it still matches a returned account, otherwise the lowest
33
+ * `authuser` (the server sorts ascending, so `[0]`). Callers guarantee a
34
+ * non-empty list, so the result is always defined.
35
+ *
36
+ * Shared by cold-boot cookie restore and the in-session refresh cookie arm so
37
+ * the active-slot selection can never diverge between them.
38
+ */
39
+ export declare function selectActiveRefreshAccount<T extends {
40
+ authuser: number;
41
+ }>(accounts: T[], persistedAuthuser: number | null): T;
42
+ //# sourceMappingURL=silentSessionRestore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"silentSessionRestore.d.ts","sourceRoot":"","sources":["../../../../../src/ui/context/silentSessionRestore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGrE;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,2BAA2B,CAC/C,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAatC;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,EACvE,QAAQ,EAAE,CAAC,EAAE,EACb,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAC/B,CAAC,CAMH"}
@@ -1 +1 @@
1
- {"version":3,"file":"OxyContext.d.ts","sourceRoot":"","sources":["../../../../../src/ui/context/OxyContext.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OxyContext.d.ts","sourceRoot":"","sources":["../../../../../src/ui/context/OxyContext.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * In-session access-token refresh for the React Native / Expo SDK.
3
+ *
4
+ * THE GAP THIS CLOSES: the services `OxyContext` owns the session but never
5
+ * installed an `authRefreshHandler` on the owner `HttpService`, so
6
+ * `HttpService.refreshAccessToken` short-circuited to `null` — there was NO
7
+ * in-session token refresh on the RN path at all. A 15-minute access token
8
+ * expired with the tab/app open and nothing re-minted one; cross-apex RP feeds
9
+ * (mention.earth, …) then 401'd in a loop while `isAuthenticated` stayed `true`
10
+ * (a zombie logged-in state), because the `Domain=oxy.so` refresh cookie can't
11
+ * reach `api.<apex>`. (`AuthManager`, which installs a refresh handler on the
12
+ * web path, is only ever constructed by `WebOxyProvider` in `@oxyhq/auth`.)
13
+ *
14
+ * THE FIX, two cooperating pieces both wired from `OxyContext`:
15
+ *
16
+ * 1. {@link createInSessionRefreshHandler} — an `AuthRefreshHandler` installed
17
+ * on the owner client. It re-mints a fresh access token WITHOUT a page
18
+ * reload by composing the SAME silent-restore primitives cold boot uses
19
+ * ({@link mintSessionViaPerApexIframe}, {@link selectActiveRefreshAccount}) —
20
+ * not a copy. The linked client (`createLinkedClient`) inherits the fix for
21
+ * free: its refresh delegates back to the owner's `refreshAccessToken`.
22
+ *
23
+ * 2. {@link startTokenRefreshScheduler} — a proactive scheduler that refreshes
24
+ * ~{@link TOKEN_REFRESH_LEAD_MS} before expiry (and on web tab-focus / native
25
+ * app-foreground), so the common case never even reaches the reactive
26
+ * 401-then-recover flash.
27
+ *
28
+ * Concurrency/cooldown/dedup are owned by `HttpService.refreshAccessToken`
29
+ * (single in-flight `tokenRefreshPromise` + cooldown) — this module does not
30
+ * reimplement them, so the timer / foreground / per-request triggers collapse to
31
+ * one network attempt (no refresh storm).
32
+ */
33
+ import type { OxyServices, AuthRefreshHandler } from '@oxyhq/core';
34
+ /**
35
+ * Lead time (ms) before access-token expiry at which the proactive scheduler
36
+ * refreshes. Mirrors `HttpService`'s per-request `TOKEN_REFRESH_LEAD_SECONDS`
37
+ * (60s) so the scheduled refresh and the request-time preflight refresh use the
38
+ * same window — the scheduler simply fires it during idle/background instead of
39
+ * waiting for the next request.
40
+ */
41
+ export declare const TOKEN_REFRESH_LEAD_MS = 60000;
42
+ /**
43
+ * Build the in-session `AuthRefreshHandler` for the owner client.
44
+ *
45
+ * Arms run in an explicit order; the first to plant a token wins. Each arm
46
+ * resolves to the planted token (read back via `getAccessToken()` — the
47
+ * underlying SDK call plants it internally) or `null`. A throw in one arm is
48
+ * logged and treated as `null` so the chain continues.
49
+ *
50
+ * NATIVE (Expo): shared cross-app identity key re-mint
51
+ * (`signInWithSharedIdentity` → challenge→sign→verify plants the tokens).
52
+ * The ONLY silent native arm (mirrors cold boot's `shared-key-signin`); the
53
+ * `/auth/silent` web iframe is NEVER attempted on native. Resolves to `null`
54
+ * when the device holds no shared identity (e.g. a password-only native
55
+ * sign-in) so a genuinely dead session reconciles to logged-out rather than
56
+ * staying a zombie.
57
+ *
58
+ * WEB, in order:
59
+ * 1. Per-apex `/auth/silent` iframe — {@link mintSessionViaPerApexIframe}
60
+ * (shared verbatim with cold boot). The durable cross-apex path; also
61
+ * covers `*.oxy.so` (the per-apex host IS the central host there).
62
+ * 2. FedCM silent re-auth (Chrome) — `silentSignInWithFedCM`.
63
+ * 3. Same-apex refresh cookie — `refreshAllSessions` + the shared
64
+ * {@link selectActiveRefreshAccount}; plant the active account's rotated
65
+ * token. On a cross-apex RP it returns `{accounts:[]}` (clean no-op).
66
+ * Unlike the cold-boot cookie restore this does NOT rebuild multi-session
67
+ * state — an in-session refresh only needs a fresh bearer.
68
+ *
69
+ * NO RECURSION: no arm issues a request through the authed client's
70
+ * `refreshAccessToken` path. The iframe/FedCM transports are postMessage /
71
+ * credential APIs; the follow-up `/session/user` fetch inside `silentSignIn`
72
+ * runs against the just-planted FULL-TTL token (≫ the preflight lead), so it
73
+ * never re-enters the refresh path; `refreshAllSessions` uses a raw `fetch`.
74
+ */
75
+ export declare function createInSessionRefreshHandler(oxyServices: OxyServices): AuthRefreshHandler;
76
+ /**
77
+ * Handle returned by {@link startTokenRefreshScheduler}; call `dispose()` to tear
78
+ * down the timer and the foreground listener.
79
+ */
80
+ export interface TokenRefreshSchedulerHandle {
81
+ dispose(): void;
82
+ }
83
+ /**
84
+ * Start the proactive in-session refresh scheduler against `oxyServices`.
85
+ *
86
+ * Schedules a single timer to fire {@link TOKEN_REFRESH_LEAD_MS} before the
87
+ * current access token's `exp`, calling `httpService.refreshAccessToken`
88
+ * ('preflight') — which runs the installed handler and is deduped + cooldown-
89
+ * guarded. After every attempt it reschedules from the (possibly rotated) token.
90
+ * It also reschedules whenever the token changes (`onTokensChanged` — so a
91
+ * sign-out that clears the token cancels the timer) and, on web tab-focus /
92
+ * native app-foreground, refreshes immediately if already inside the lead window
93
+ * (a long-hidden tab throttles timers, so the token can be expired on return).
94
+ *
95
+ * The `exp` is derived directly from the JWT via `getAccessTokenExpiry()`. No-ops
96
+ * cleanly when there is no token, an opaque/no-`exp` token, or the host lacks
97
+ * `getAccessTokenExpiry` (older stubs) — the reactive 401 path stays the only
98
+ * refresh trigger in those cases.
99
+ */
100
+ export declare function startTokenRefreshScheduler(oxyServices: OxyServices): TokenRefreshSchedulerHandle;
101
+ //# sourceMappingURL=inSessionTokenRefresh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inSessionTokenRefresh.d.ts","sourceRoot":"","sources":["../../../../../src/ui/context/inSessionTokenRefresh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAEnB,MAAM,aAAa,CAAC;AAyBrB;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAQ5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,WAAW,GAAG,kBAAkB,CAsD1F;AAED;;;GAGG;AACH,MAAM,WAAW,2BAA2B;IAC1C,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,WAAW,GAAG,2BAA2B,CA4FhG"}