@oxyhq/services 8.4.3 → 8.6.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/lib/commonjs/ui/context/OxyContext.js +158 -29
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/useAuth.js +2 -0
- package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +158 -29
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/useAuth.js +2 -0
- package/lib/module/ui/hooks/useAuth.js.map +1 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +15 -0
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts +11 -0
- package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts +15 -0
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useAuth.d.ts +11 -0
- package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/ui/context/OxyContext.tsx +167 -22
- package/src/ui/hooks/useAuth.ts +14 -0
|
@@ -14,6 +14,21 @@ export interface OxyContextState {
|
|
|
14
14
|
isAuthenticated: boolean;
|
|
15
15
|
isLoading: boolean;
|
|
16
16
|
isTokenReady: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Whether the initial auth determination has concluded.
|
|
19
|
+
*
|
|
20
|
+
* `false` from mount until the FIRST cold-boot session restore finishes —
|
|
21
|
+
* during that window `isAuthenticated: false` is UNDETERMINED, not a
|
|
22
|
+
* definitive "logged out". Flips to `true` exactly once the restore concludes
|
|
23
|
+
* (a session was committed OR none exists) and never reverts. Consumers should
|
|
24
|
+
* defer their first auth-dependent fetch until this is `true` so a cold-boot
|
|
25
|
+
* web reload with an existing session does not fetch anonymous data.
|
|
26
|
+
*
|
|
27
|
+
* On native, cold boot runs only the `stored-session` step, so this resolves
|
|
28
|
+
* promptly. It is set in the restore `finally`, so the success, no-session,
|
|
29
|
+
* and error paths all reach `true` — it can never get stuck `false`.
|
|
30
|
+
*/
|
|
31
|
+
isAuthResolved: boolean;
|
|
17
32
|
isStorageReady: boolean;
|
|
18
33
|
error: string | null;
|
|
19
34
|
currentLanguage: string;
|
|
@@ -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":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,WAAW,EAAa,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAqBjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAOvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAStD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;;;;;;;;;OAaG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,uBAAuB,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,UAAU,CAAC,CAAC;IAC9E,mBAAmB,EAAE,MAAM,CAAC;IAC5B,yBAAyB,EAAE,MAAM,CAAC;IAGlC,WAAW,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAG3C,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAElE;;;OAGG;IACH,kBAAkB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAGrE,MAAM,EAAE,CAAC,eAAe,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,iBAAiB,EAAE,MAAM,OAAO,CAC9B,KAAK,CAAC;QACJ,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CACH,CAAC;IACF,uBAAuB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,mBAAmB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,eAAe,CAAC,EAAE,CAAC,cAAc,EAAE,SAAS,GAAG;QAAE,MAAM,EAAE,SAAS,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/G,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAG7B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,sBAAsB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,oBAAoB,EAAE,CAAC,IAAI,EAAE,yBAAyB,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;CACpF;AAED,QAAA,MAAM,UAAU,uCAA8C,CAAC;AAM/D,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,SAAS,CAAC;IACpB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;CACrC;AA4HD,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA42CzD,CAAC;AAEF,eAAO,MAAM,kBAAkB,mCAAc,CAAC;AA2D9C,eAAO,MAAM,MAAM,QAAO,eAMzB,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -33,6 +33,17 @@ export interface AuthState {
|
|
|
33
33
|
isLoading: boolean;
|
|
34
34
|
/** Whether the auth token is ready for API calls */
|
|
35
35
|
isReady: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Whether the initial auth determination has concluded.
|
|
38
|
+
*
|
|
39
|
+
* `false` from mount until the first cold-boot session restore finishes;
|
|
40
|
+
* while `false`, `isAuthenticated: false` is UNDETERMINED (not a definitive
|
|
41
|
+
* "logged out"). Flips to `true` once — when a session is committed or none
|
|
42
|
+
* is found — and never reverts. Defer the first auth-dependent fetch until
|
|
43
|
+
* this is `true` so a cold-boot reload with an existing session does not load
|
|
44
|
+
* anonymous data.
|
|
45
|
+
*/
|
|
46
|
+
isAuthResolved: boolean;
|
|
36
47
|
/** Current error message, if any */
|
|
37
48
|
error: string | null;
|
|
38
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useAuth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGxC,MAAM,WAAW,SAAS;IACxB,4DAA4D;IAC5D,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAElB,oCAAoC;IACpC,eAAe,EAAE,OAAO,CAAC;IAEzB,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAC;IAEnB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IAEjB,oCAAoC;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;;OAUG;IACH,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9E;;OAEG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;;OAEG;IACH,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC;;OAEG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,aAAc,SAAQ,SAAS,EAAE,WAAW;IAC3D,6DAA6D;IAC7D,WAAW,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC;IACtD,0EAA0E;IAC1E,eAAe,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC9D,0CAA0C;IAC1C,gBAAgB,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC;CACjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,IAAI,aAAa,
|
|
1
|
+
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../../../../src/ui/hooks/useAuth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGxC,MAAM,WAAW,SAAS;IACxB,4DAA4D;IAC5D,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAElB,oCAAoC;IACpC,eAAe,EAAE,OAAO,CAAC;IAEzB,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAC;IAEnB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IAEjB;;;;;;;;;OASG;IACH,cAAc,EAAE,OAAO,CAAC;IAExB,oCAAoC;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;;OAUG;IACH,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9E;;OAEG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;;OAEG;IACH,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC;;OAEG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,aAAc,SAAQ,SAAS,EAAE,WAAW;IAC3D,6DAA6D;IAC7D,WAAW,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC;IACtD,0EAA0E;IAC1E,eAAe,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC9D,0CAA0C;IAC1C,gBAAgB,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC;CACjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,IAAI,aAAa,CA6IvC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxyhq/services",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.6.0",
|
|
4
4
|
"description": "OxyHQ Expo/React Native SDK — UI components, screens, and native features",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -160,7 +160,7 @@
|
|
|
160
160
|
"peerDependencies": {
|
|
161
161
|
"@expo/vector-icons": "^15.0.3",
|
|
162
162
|
"@oxyhq/bloom": ">=0.5.0",
|
|
163
|
-
"@oxyhq/core": "^2.
|
|
163
|
+
"@oxyhq/core": "^2.4.0",
|
|
164
164
|
"@react-native-community/netinfo": "^11.4.1",
|
|
165
165
|
"@tanstack/query-async-storage-persister": "^5.100",
|
|
166
166
|
"@tanstack/query-sync-storage-persister": "^5.100",
|
|
@@ -58,6 +58,21 @@ export interface OxyContextState {
|
|
|
58
58
|
isAuthenticated: boolean;
|
|
59
59
|
isLoading: boolean;
|
|
60
60
|
isTokenReady: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Whether the initial auth determination has concluded.
|
|
63
|
+
*
|
|
64
|
+
* `false` from mount until the FIRST cold-boot session restore finishes —
|
|
65
|
+
* during that window `isAuthenticated: false` is UNDETERMINED, not a
|
|
66
|
+
* definitive "logged out". Flips to `true` exactly once the restore concludes
|
|
67
|
+
* (a session was committed OR none exists) and never reverts. Consumers should
|
|
68
|
+
* defer their first auth-dependent fetch until this is `true` so a cold-boot
|
|
69
|
+
* web reload with an existing session does not fetch anonymous data.
|
|
70
|
+
*
|
|
71
|
+
* On native, cold boot runs only the `stored-session` step, so this resolves
|
|
72
|
+
* promptly. It is set in the restore `finally`, so the success, no-session,
|
|
73
|
+
* and error paths all reach `true` — it can never get stuck `false`.
|
|
74
|
+
*/
|
|
75
|
+
isAuthResolved: boolean;
|
|
61
76
|
isStorageReady: boolean;
|
|
62
77
|
error: string | null;
|
|
63
78
|
currentLanguage: string;
|
|
@@ -163,6 +178,32 @@ function silentColdBootKey(oxyServices: OxyServices): string {
|
|
|
163
178
|
return `${origin}|${baseURL}`;
|
|
164
179
|
}
|
|
165
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Per-step fail-fast budget for the cold-boot silent iframe (`silentSignIn`
|
|
183
|
+
* against the per-apex `/auth/silent` host).
|
|
184
|
+
*
|
|
185
|
+
* This step ONLY succeeds when a durable per-apex `fedcm_session` cookie exists
|
|
186
|
+
* (established by a prior `/sso` bounce). On the common reload of a logged-out
|
|
187
|
+
* tab — or a tab that restores via the now-earlier stored-session step — the
|
|
188
|
+
* iframe never posts a message, so the full wait would be dead latency in front
|
|
189
|
+
* of the terminal `/sso` bounce. `silentSignIn` already fails fast on a load
|
|
190
|
+
* error via `iframe.onerror`; this caps the no-message case. 2.5s is well above
|
|
191
|
+
* a same-origin iframe handshake yet a fraction of the legacy 5s default.
|
|
192
|
+
*/
|
|
193
|
+
const SILENT_IFRAME_TIMEOUT = 2500;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Per-step fail-fast budget for the cold-boot refresh-cookie restore
|
|
197
|
+
* (`refreshAllSessions`).
|
|
198
|
+
*
|
|
199
|
+
* On a cross-domain RP the `Domain=oxy.so` refresh cookie never reaches
|
|
200
|
+
* `api.<apex>`, so this request returns no accounts (or stalls behind a slow
|
|
201
|
+
* endpoint) with no useful answer. As one cold-boot step it must not block the
|
|
202
|
+
* fall-through to the terminal `/sso` bounce. 3s bounds the wait while leaving
|
|
203
|
+
* ample headroom for a genuine first-party `*.oxy.so` rotation round-trip.
|
|
204
|
+
*/
|
|
205
|
+
const COOKIE_RESTORE_TIMEOUT = 3000;
|
|
206
|
+
|
|
166
207
|
/**
|
|
167
208
|
* Whether `idpOrigin` is a same-site, first-party host of the current page —
|
|
168
209
|
* i.e. it shares the page's registrable apex (last two labels), so a "no
|
|
@@ -284,6 +325,15 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
284
325
|
);
|
|
285
326
|
|
|
286
327
|
const [tokenReady, setTokenReady] = useState(true);
|
|
328
|
+
// Whether the FIRST cold-boot auth restore has concluded. Starts `false`
|
|
329
|
+
// (auth undetermined) and flips to `true` exactly once — monotonic, never
|
|
330
|
+
// reverts. It now flips the MOMENT a session commits (the common reload case
|
|
331
|
+
// unblocks immediately, without waiting for the rest of the cold-boot chain),
|
|
332
|
+
// with the restore `finally` as the no-session/error backstop. The ref makes
|
|
333
|
+
// the flip idempotent across both sites so the setters fire at most once. See
|
|
334
|
+
// `isAuthResolved` on the context type for the consumer contract.
|
|
335
|
+
const [authResolved, setAuthResolved] = useState(false);
|
|
336
|
+
const authResolvedRef = useRef(false);
|
|
287
337
|
const [initialized, setInitialized] = useState(false);
|
|
288
338
|
const setAuthState = useAuthStore.setState;
|
|
289
339
|
|
|
@@ -545,6 +595,26 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
545
595
|
const onAuthStateChangeRef = useRef(onAuthStateChange);
|
|
546
596
|
onAuthStateChangeRef.current = onAuthStateChange;
|
|
547
597
|
|
|
598
|
+
// Flip the auth-resolution gate (`authResolved` + `tokenReady`) the MOMENT a
|
|
599
|
+
// session commits, instead of waiting for the whole cold-boot chain to finish.
|
|
600
|
+
// Idempotent and monotonic via `authResolvedRef`: the first call wins and the
|
|
601
|
+
// setters fire at most once, so the restore `finally` backstop becomes a no-op
|
|
602
|
+
// once a commit site has already marked resolution. Called from EVERY place a
|
|
603
|
+
// user is actually committed (the FedCM/iframe/redirect/SSO path
|
|
604
|
+
// `handleWebSSOSession`, the cookie-restore path, and the stored-session path)
|
|
605
|
+
// so the common reload case unblocks the loading gate without sitting behind
|
|
606
|
+
// the remaining (now-skipped) cold-boot steps.
|
|
607
|
+
const markAuthResolved = useCallback(() => {
|
|
608
|
+
if (authResolvedRef.current) {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
authResolvedRef.current = true;
|
|
612
|
+
setTokenReady(true);
|
|
613
|
+
setAuthResolved(true);
|
|
614
|
+
}, []);
|
|
615
|
+
const markAuthResolvedRef = useRef(markAuthResolved);
|
|
616
|
+
markAuthResolvedRef.current = markAuthResolved;
|
|
617
|
+
|
|
548
618
|
// `handleWebSSOSession` is declared further down (it depends on values that
|
|
549
619
|
// are only available there). The FedCM/iframe cold-boot steps need to commit
|
|
550
620
|
// a recovered session through it, so we route the call through a ref that is
|
|
@@ -578,7 +648,9 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
578
648
|
|
|
579
649
|
let snapshot;
|
|
580
650
|
try {
|
|
581
|
-
|
|
651
|
+
// Bound the refresh so a cross-domain/stalled call cannot hang the cold
|
|
652
|
+
// boot in front of the terminal `/sso` bounce (see COOKIE_RESTORE_TIMEOUT).
|
|
653
|
+
snapshot = await oxyServices.refreshAllSessions({ timeout: COOKIE_RESTORE_TIMEOUT });
|
|
582
654
|
} catch (fetchError) {
|
|
583
655
|
// Offline / network error — fall through to the cached/stored-session flow.
|
|
584
656
|
if (__DEV__) {
|
|
@@ -642,6 +714,9 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
642
714
|
await persistSessionDurably(activeAccount.sessionId);
|
|
643
715
|
|
|
644
716
|
loginSuccessRef.current(fullUser);
|
|
717
|
+
// A session is now committed — unblock the auth-resolution gate immediately
|
|
718
|
+
// rather than waiting for `runColdBoot` to return (idempotent).
|
|
719
|
+
markAuthResolvedRef.current();
|
|
645
720
|
onAuthStateChangeRef.current?.(fullUser);
|
|
646
721
|
return true;
|
|
647
722
|
}, [oxyServices, persistSessionDurably]);
|
|
@@ -719,6 +794,11 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
719
794
|
if (storedActiveSessionId) {
|
|
720
795
|
try {
|
|
721
796
|
await switchSessionRef.current(storedActiveSessionId);
|
|
797
|
+
// The stored session is committed (this is native's ONLY restore path
|
|
798
|
+
// and the common web reload winner). Unblock the auth-resolution gate
|
|
799
|
+
// immediately so the loading screen clears without waiting for the
|
|
800
|
+
// remaining cold-boot steps to be evaluated/short-circuited (idempotent).
|
|
801
|
+
markAuthResolvedRef.current();
|
|
722
802
|
return true;
|
|
723
803
|
} catch (switchError) {
|
|
724
804
|
// Silently handle expected errors (invalid sessions, timeouts, network issues)
|
|
@@ -821,11 +901,21 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
821
901
|
// web-only step is gated by `isWebBrowser()`, so on native ONLY
|
|
822
902
|
// `stored-session` runs.
|
|
823
903
|
//
|
|
824
|
-
// Order (web): redirect callback → SSO return → FedCM silent
|
|
825
|
-
// silent iframe (per-apex, the durable reload path) → cookie
|
|
826
|
-
//
|
|
827
|
-
//
|
|
828
|
-
//
|
|
904
|
+
// Order (web): redirect callback → SSO return → stored session → FedCM silent
|
|
905
|
+
// (central) → silent iframe (per-apex, the durable reload path) → cookie
|
|
906
|
+
// restore → SSO bounce (terminal).
|
|
907
|
+
//
|
|
908
|
+
// LATENCY (FIX A): `stored-session` runs BEFORE the slow no-redirect probes
|
|
909
|
+
// (`fedcm-silent`, `silent-iframe`, `cookie-restore`). On a normal reload the
|
|
910
|
+
// local bearer validates in one round-trip and wins, so `runColdBoot`
|
|
911
|
+
// short-circuits and never sits through those probes' timeouts (the prior
|
|
912
|
+
// serial sum was a ~20-30s stall). `redirect` and `sso-return` MUST stay
|
|
913
|
+
// first — they consume the URL fragment before anything can strip it. On a
|
|
914
|
+
// first visit with no local session, `stored-session` skips and the
|
|
915
|
+
// cross-domain fallback chain (fedcm → iframe → cookie → sso-bounce) runs
|
|
916
|
+
// exactly as before; the per-apex silent iframe still restores a durable
|
|
917
|
+
// cross-domain session on reload WITHOUT a top-level bounce, so when it wins
|
|
918
|
+
// `sso-bounce` never fires (no flash, no loop).
|
|
829
919
|
// Order (native): stored session only (every web-only step is disabled
|
|
830
920
|
// off-browser).
|
|
831
921
|
const restoreSessionsFromStorage = useCallback(async (): Promise<void> => {
|
|
@@ -839,6 +929,16 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
839
929
|
const silentKey = silentColdBootKey(oxyServices);
|
|
840
930
|
const fedcmSupported = isWebBrowser() && oxyServices.isFedCMSupported?.() === true;
|
|
841
931
|
|
|
932
|
+
// FIX-B precondition flag: set true the instant the (now-earlier)
|
|
933
|
+
// `stored-session` step recovers a local bearer session. The slow web-only
|
|
934
|
+
// probes (`fedcm-silent`, `silent-iframe`) AND `enabled` on `!storedSessionRestored`
|
|
935
|
+
// so they are explicitly skipped once a local session won. `runColdBoot`
|
|
936
|
+
// already short-circuits on the first `{kind:'session'}`, so on a winning
|
|
937
|
+
// reload those `enabled` bodies are never even reached — this flag makes the
|
|
938
|
+
// intent explicit and is redundant-safe. On a first-visit-no-local-session,
|
|
939
|
+
// `stored-session` skips, this stays false, and the probes run as before.
|
|
940
|
+
let storedSessionRestored = false;
|
|
941
|
+
|
|
842
942
|
try {
|
|
843
943
|
const outcome = await runColdBoot<true>({
|
|
844
944
|
steps: [
|
|
@@ -875,14 +975,47 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
875
975
|
},
|
|
876
976
|
},
|
|
877
977
|
{
|
|
878
|
-
// 2)
|
|
978
|
+
// 2) Stored-session bearer restore. NO `enabled` gate — runs on ALL
|
|
979
|
+
// platforms. This is native's ONLY restore path (every web-only step
|
|
980
|
+
// is disabled off-browser, so native reaches exactly this) AND the
|
|
981
|
+
// common WEB reload winner.
|
|
982
|
+
//
|
|
983
|
+
// ORDERING (FIX A): this step now runs BEFORE the slow web-only
|
|
984
|
+
// probes (`fedcm-silent`, `silent-iframe`, `cookie-restore`). On a
|
|
985
|
+
// normal reload the local bearer validates in one round-trip and
|
|
986
|
+
// wins; `runColdBoot` then short-circuits and never even evaluates
|
|
987
|
+
// the slow no-redirect probes that would otherwise time out (the
|
|
988
|
+
// ~20-30s serial stall). The `redirect` and `sso-return` steps stay
|
|
989
|
+
// AHEAD of this one — they must consume the URL fragment before any
|
|
990
|
+
// later step (or anything else) strips it. On a first visit with no
|
|
991
|
+
// local session this step skips and the cross-domain fallback chain
|
|
992
|
+
// (fedcm → iframe → cookie → sso-bounce) runs exactly as before.
|
|
993
|
+
id: 'stored-session',
|
|
994
|
+
run: async () => {
|
|
995
|
+
const restored = await restoreStoredSession();
|
|
996
|
+
if (restored) {
|
|
997
|
+
// FIX-B: record the win so the slow probes below explicitly skip
|
|
998
|
+
// (belt-and-suspenders; `runColdBoot` already short-circuits).
|
|
999
|
+
storedSessionRestored = true;
|
|
1000
|
+
return { kind: 'session', session: true };
|
|
1001
|
+
}
|
|
1002
|
+
return { kind: 'skip' };
|
|
1003
|
+
},
|
|
1004
|
+
},
|
|
1005
|
+
{
|
|
1006
|
+
// 3) FedCM silent reauthn (Chrome) against the CENTRAL IdP
|
|
879
1007
|
// (auth.oxy.so). `silentSignInWithFedCM` plants the access token
|
|
880
1008
|
// internally; we commit the returned session via
|
|
881
1009
|
// `handleWebSSOSession`. Guarded so it fires at most once per page
|
|
882
1010
|
// load across remounts. This is an enhancement layered above the
|
|
883
1011
|
// opaque-code bounce: when it succeeds the bounce never fires.
|
|
1012
|
+
//
|
|
1013
|
+
// FIX-B: additionally skipped when the earlier `stored-session` step
|
|
1014
|
+
// already recovered a local session — the probe cannot improve on a
|
|
1015
|
+
// valid local bearer, and skipping it avoids the silent round-trip.
|
|
884
1016
|
id: 'fedcm-silent',
|
|
885
|
-
enabled: () =>
|
|
1017
|
+
enabled: () =>
|
|
1018
|
+
!storedSessionRestored && fedcmSupported && !servicesSilentAttempted.has(silentKey),
|
|
886
1019
|
run: async () => {
|
|
887
1020
|
servicesSilentAttempted.add(silentKey);
|
|
888
1021
|
const session = await oxyServices.silentSignInWithFedCM?.();
|
|
@@ -894,7 +1027,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
894
1027
|
},
|
|
895
1028
|
},
|
|
896
1029
|
{
|
|
897
|
-
//
|
|
1030
|
+
// 4) First-party silent iframe at the PER-APEX IdP — the DURABLE
|
|
898
1031
|
// cross-domain reload-restore path. The durable session lives as a
|
|
899
1032
|
// first-party `fedcm_session` cookie on `auth.<rp-apex>` (e.g.
|
|
900
1033
|
// `auth.mention.earth`), established during the `/sso` bounce's
|
|
@@ -913,8 +1046,12 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
913
1046
|
// equivalent. When auto-detection bails (localhost/IP/single-label)
|
|
914
1047
|
// there is no per-apex IdP and the step skips. Web only; on native
|
|
915
1048
|
// `isWebBrowser()` gates it off, so native never runs an iframe.
|
|
1049
|
+
//
|
|
1050
|
+
// FIX-B: additionally skipped when `stored-session` already won.
|
|
1051
|
+
// FIX-D: bounded by `SILENT_IFRAME_TIMEOUT` (plus `iframe.onerror`
|
|
1052
|
+
// fail-fast in core) so a no-message iframe cannot stall cold boot.
|
|
916
1053
|
id: 'silent-iframe',
|
|
917
|
-
enabled: () => isWebBrowser(),
|
|
1054
|
+
enabled: () => !storedSessionRestored && isWebBrowser(),
|
|
918
1055
|
run: async () => {
|
|
919
1056
|
const perApexAuthUrl = autoDetectAuthWebUrl();
|
|
920
1057
|
if (!perApexAuthUrl || !commitWebSession) {
|
|
@@ -922,6 +1059,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
922
1059
|
}
|
|
923
1060
|
const session = await oxyServices.silentSignIn?.({
|
|
924
1061
|
authWebUrlOverride: perApexAuthUrl,
|
|
1062
|
+
timeout: SILENT_IFRAME_TIMEOUT,
|
|
925
1063
|
});
|
|
926
1064
|
if (!session?.user || !session?.sessionId) {
|
|
927
1065
|
return { kind: 'skip' };
|
|
@@ -931,12 +1069,14 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
931
1069
|
},
|
|
932
1070
|
},
|
|
933
1071
|
{
|
|
934
|
-
//
|
|
1072
|
+
// 5) Refresh-cookie restore (first-party only). On `*.oxy.so` the
|
|
935
1073
|
// httpOnly `oxy_rt_${n}` cookies ride along and resurrect every
|
|
936
1074
|
// device-local slot. On a cross-domain RP (mention.earth, …) the
|
|
937
1075
|
// cookie is `Domain=oxy.so` so it never reaches `api.<apex>` —
|
|
938
1076
|
// `refreshAllSessions` returns `{accounts:[]}` and this skips. That
|
|
939
1077
|
// is correct; cross-domain restore is handled by the SSO bounce.
|
|
1078
|
+
// FIX-D: `restoreViaRefreshCookie` bounds the request with
|
|
1079
|
+
// `COOKIE_RESTORE_TIMEOUT` so a cross-domain stall cannot hang here.
|
|
940
1080
|
id: 'cookie-restore',
|
|
941
1081
|
enabled: () => isWebBrowser(),
|
|
942
1082
|
run: async () => {
|
|
@@ -944,16 +1084,6 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
944
1084
|
return restored ? { kind: 'session', session: true } : { kind: 'skip' };
|
|
945
1085
|
},
|
|
946
1086
|
},
|
|
947
|
-
{
|
|
948
|
-
// 5) Stored-session bearer restore. NO `enabled` gate — runs on ALL
|
|
949
|
-
// platforms. This is native's ONLY restore path (every web-only step
|
|
950
|
-
// is disabled off-browser, so native reaches exactly this).
|
|
951
|
-
id: 'stored-session',
|
|
952
|
-
run: async () => {
|
|
953
|
-
const restored = await restoreStoredSession();
|
|
954
|
-
return restored ? { kind: 'session', session: true } : { kind: 'skip' };
|
|
955
|
-
},
|
|
956
|
-
},
|
|
957
1087
|
{
|
|
958
1088
|
// 6) SSO bounce (TERMINAL, web only, at most once). No local session
|
|
959
1089
|
// was found by any step above. Top-level navigate to the central
|
|
@@ -1028,7 +1158,14 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
1028
1158
|
}
|
|
1029
1159
|
await clearSessionStateRef.current();
|
|
1030
1160
|
} finally {
|
|
1031
|
-
|
|
1161
|
+
// Backstop: mark auth resolved on EVERY exit path — success, no-session,
|
|
1162
|
+
// AND error→catch→finally — and on native (which only runs the
|
|
1163
|
+
// `stored-session` step), so the gate can never hang `false`. Idempotent
|
|
1164
|
+
// via `markAuthResolved`'s ref: when a commit site already flipped it
|
|
1165
|
+
// mid-chain (the common reload case), this is a no-op. When no session was
|
|
1166
|
+
// recovered (the unauthenticated/error path), this is where `tokenReady` +
|
|
1167
|
+
// `authResolved` finally flip. Monotonic — never reverts on later restores.
|
|
1168
|
+
markAuthResolved();
|
|
1032
1169
|
}
|
|
1033
1170
|
}, [
|
|
1034
1171
|
oxyServices,
|
|
@@ -1036,6 +1173,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
1036
1173
|
restoreViaRefreshCookie,
|
|
1037
1174
|
restoreStoredSession,
|
|
1038
1175
|
runSsoReturn,
|
|
1176
|
+
markAuthResolved,
|
|
1039
1177
|
]);
|
|
1040
1178
|
|
|
1041
1179
|
useEffect(() => {
|
|
@@ -1189,6 +1327,10 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
1189
1327
|
fullUser = session.user as unknown as User;
|
|
1190
1328
|
}
|
|
1191
1329
|
loginSuccess(fullUser);
|
|
1330
|
+
// A session is now committed (FedCM silent / per-apex iframe / redirect /
|
|
1331
|
+
// SSO-return / popup all funnel through here) — unblock the auth-resolution
|
|
1332
|
+
// gate immediately, ahead of the cold-boot chain returning (idempotent).
|
|
1333
|
+
markAuthResolvedRef.current();
|
|
1192
1334
|
onAuthStateChange?.(fullUser);
|
|
1193
1335
|
}, [oxyServices, updateSessions, setActiveSessionId, loginSuccess, onAuthStateChange, persistSessionDurably]);
|
|
1194
1336
|
|
|
@@ -1436,6 +1578,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
1436
1578
|
isAuthenticated,
|
|
1437
1579
|
isLoading,
|
|
1438
1580
|
isTokenReady: tokenReady,
|
|
1581
|
+
isAuthResolved: authResolved,
|
|
1439
1582
|
isStorageReady: storage !== null,
|
|
1440
1583
|
error,
|
|
1441
1584
|
currentLanguage,
|
|
@@ -1492,6 +1635,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
1492
1635
|
storage,
|
|
1493
1636
|
switchSessionForContext,
|
|
1494
1637
|
tokenReady,
|
|
1638
|
+
authResolved,
|
|
1495
1639
|
updateDeviceName,
|
|
1496
1640
|
clearAllAccountData,
|
|
1497
1641
|
useFollowHook,
|
|
@@ -1539,6 +1683,7 @@ const LOADING_STATE: OxyContextState = {
|
|
|
1539
1683
|
isAuthenticated: false,
|
|
1540
1684
|
isLoading: true,
|
|
1541
1685
|
isTokenReady: false,
|
|
1686
|
+
isAuthResolved: false,
|
|
1542
1687
|
isStorageReady: false,
|
|
1543
1688
|
error: null,
|
|
1544
1689
|
currentLanguage: 'en',
|
package/src/ui/hooks/useAuth.ts
CHANGED
|
@@ -41,6 +41,18 @@ export interface AuthState {
|
|
|
41
41
|
/** Whether the auth token is ready for API calls */
|
|
42
42
|
isReady: boolean;
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Whether the initial auth determination has concluded.
|
|
46
|
+
*
|
|
47
|
+
* `false` from mount until the first cold-boot session restore finishes;
|
|
48
|
+
* while `false`, `isAuthenticated: false` is UNDETERMINED (not a definitive
|
|
49
|
+
* "logged out"). Flips to `true` once — when a session is committed or none
|
|
50
|
+
* is found — and never reverts. Defer the first auth-dependent fetch until
|
|
51
|
+
* this is `true` so a cold-boot reload with an existing session does not load
|
|
52
|
+
* anonymous data.
|
|
53
|
+
*/
|
|
54
|
+
isAuthResolved: boolean;
|
|
55
|
+
|
|
44
56
|
/** Current error message, if any */
|
|
45
57
|
error: string | null;
|
|
46
58
|
}
|
|
@@ -99,6 +111,7 @@ export function useAuth(): UseAuthReturn {
|
|
|
99
111
|
isAuthenticated,
|
|
100
112
|
isLoading,
|
|
101
113
|
isTokenReady,
|
|
114
|
+
isAuthResolved,
|
|
102
115
|
error,
|
|
103
116
|
signIn: oxySignIn,
|
|
104
117
|
handlePopupSession,
|
|
@@ -219,6 +232,7 @@ export function useAuth(): UseAuthReturn {
|
|
|
219
232
|
isAuthenticated,
|
|
220
233
|
isLoading,
|
|
221
234
|
isReady: isTokenReady,
|
|
235
|
+
isAuthResolved,
|
|
222
236
|
error,
|
|
223
237
|
|
|
224
238
|
// Actions
|