@oxyhq/services 11.1.1 → 12.1.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.
Files changed (73) hide show
  1. package/lib/commonjs/index.js +2 -0
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/ui/components/OxyProvider.js +0 -2
  4. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  5. package/lib/commonjs/ui/context/OxyContext.js +117 -20
  6. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  7. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +24 -3
  8. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  9. package/lib/commonjs/ui/context/inSessionTokenRefresh.js +286 -0
  10. package/lib/commonjs/ui/context/inSessionTokenRefresh.js.map +1 -0
  11. package/lib/commonjs/ui/context/silentSessionRestore.js +65 -0
  12. package/lib/commonjs/ui/context/silentSessionRestore.js.map +1 -0
  13. package/lib/commonjs/ui/index.js.map +1 -1
  14. package/lib/commonjs/ui/utils/storageHelpers.js +2 -1
  15. package/lib/commonjs/ui/utils/storageHelpers.js.map +1 -1
  16. package/lib/module/index.js +2 -0
  17. package/lib/module/index.js.map +1 -1
  18. package/lib/module/ui/components/OxyProvider.js +0 -2
  19. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  20. package/lib/module/ui/context/OxyContext.js +118 -21
  21. package/lib/module/ui/context/OxyContext.js.map +1 -1
  22. package/lib/module/ui/context/hooks/useAuthOperations.js +24 -3
  23. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  24. package/lib/module/ui/context/inSessionTokenRefresh.js +281 -0
  25. package/lib/module/ui/context/inSessionTokenRefresh.js.map +1 -0
  26. package/lib/module/ui/context/silentSessionRestore.js +61 -0
  27. package/lib/module/ui/context/silentSessionRestore.js.map +1 -0
  28. package/lib/module/ui/index.js +2 -0
  29. package/lib/module/ui/index.js.map +1 -1
  30. package/lib/module/ui/utils/storageHelpers.js +2 -1
  31. package/lib/module/ui/utils/storageHelpers.js.map +1 -1
  32. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  33. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  34. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +0 -10
  35. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  36. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts +9 -1
  37. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  38. package/lib/typescript/commonjs/ui/context/inSessionTokenRefresh.d.ts +105 -0
  39. package/lib/typescript/commonjs/ui/context/inSessionTokenRefresh.d.ts.map +1 -0
  40. package/lib/typescript/commonjs/ui/context/silentSessionRestore.d.ts +42 -0
  41. package/lib/typescript/commonjs/ui/context/silentSessionRestore.d.ts.map +1 -0
  42. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  43. package/lib/typescript/commonjs/ui/types/navigation.d.ts +0 -17
  44. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  45. package/lib/typescript/commonjs/ui/utils/storageHelpers.d.ts +11 -0
  46. package/lib/typescript/commonjs/ui/utils/storageHelpers.d.ts.map +1 -1
  47. package/lib/typescript/module/index.d.ts.map +1 -1
  48. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  49. package/lib/typescript/module/ui/context/OxyContext.d.ts +0 -10
  50. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  51. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +9 -1
  52. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  53. package/lib/typescript/module/ui/context/inSessionTokenRefresh.d.ts +105 -0
  54. package/lib/typescript/module/ui/context/inSessionTokenRefresh.d.ts.map +1 -0
  55. package/lib/typescript/module/ui/context/silentSessionRestore.d.ts +42 -0
  56. package/lib/typescript/module/ui/context/silentSessionRestore.d.ts.map +1 -0
  57. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  58. package/lib/typescript/module/ui/types/navigation.d.ts +0 -17
  59. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  60. package/lib/typescript/module/ui/utils/storageHelpers.d.ts +11 -0
  61. package/lib/typescript/module/ui/utils/storageHelpers.d.ts.map +1 -1
  62. package/lib/typescript/types/react-native-classname.d.ts +39 -0
  63. package/package.json +3 -3
  64. package/src/index.ts +2 -0
  65. package/src/types/react-native-classname.d.ts +39 -0
  66. package/src/ui/components/OxyProvider.tsx +0 -2
  67. package/src/ui/context/OxyContext.tsx +119 -32
  68. package/src/ui/context/hooks/useAuthOperations.ts +35 -2
  69. package/src/ui/context/inSessionTokenRefresh.ts +298 -0
  70. package/src/ui/context/silentSessionRestore.ts +67 -0
  71. package/src/ui/index.ts +2 -0
  72. package/src/ui/types/navigation.ts +0 -17
  73. package/src/ui/utils/storageHelpers.ts +12 -0
@@ -0,0 +1,67 @@
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
+ import { autoDetectAuthWebUrl } from '@oxyhq/core';
15
+
16
+ /**
17
+ * Mint a fresh first-party session via the PER-APEX `/auth/silent` iframe — the
18
+ * durable cross-domain restore path that works WITHOUT a top-level navigation
19
+ * (so it succeeds under Safari ITP / Firefox TCP and in a backgrounded tab).
20
+ *
21
+ * The instance is configured with the CENTRAL auth URL, so we explicitly point
22
+ * the iframe at the per-apex host (`auth.<rp-apex>`) via `autoDetectAuthWebUrl()`
23
+ * + `silentSignIn`'s `authWebUrlOverride`. On a `*.oxy.so` app the per-apex host
24
+ * IS the central host, so this also covers same-apex. When auto-detection bails
25
+ * (localhost / IP / single-label / off-browser) there is no per-apex IdP and we
26
+ * return `null`. `silentSignIn` plants the access token internally on success.
27
+ *
28
+ * @returns the recovered session (token already planted) when complete, else
29
+ * `null` (no per-apex IdP, no session, or an incomplete iframe response).
30
+ */
31
+ export async function mintSessionViaPerApexIframe(
32
+ oxyServices: OxyServices,
33
+ timeoutMs: number,
34
+ ): Promise<SessionLoginResponse | null> {
35
+ const perApexAuthUrl = autoDetectAuthWebUrl();
36
+ if (!perApexAuthUrl) {
37
+ return null;
38
+ }
39
+ const session = await oxyServices.silentSignIn?.({
40
+ authWebUrlOverride: perApexAuthUrl,
41
+ timeout: timeoutMs,
42
+ });
43
+ if (!session?.user || !session.sessionId) {
44
+ return null;
45
+ }
46
+ return session;
47
+ }
48
+
49
+ /**
50
+ * Pick the active account from a `refreshAllSessions` snapshot: the persisted
51
+ * `authuser` slot when it still matches a returned account, otherwise the lowest
52
+ * `authuser` (the server sorts ascending, so `[0]`). Callers guarantee a
53
+ * non-empty list, so the result is always defined.
54
+ *
55
+ * Shared by cold-boot cookie restore and the in-session refresh cookie arm so
56
+ * the active-slot selection can never diverge between them.
57
+ */
58
+ export function selectActiveRefreshAccount<T extends { authuser: number }>(
59
+ accounts: T[],
60
+ persistedAuthuser: number | null,
61
+ ): T {
62
+ const matched =
63
+ persistedAuthuser !== null
64
+ ? accounts.find((account) => account.authuser === persistedAuthuser)
65
+ : undefined;
66
+ return matched ?? accounts[0];
67
+ }
package/src/ui/index.ts CHANGED
@@ -12,6 +12,8 @@
12
12
  * cannot contain `require()` per CLAUDE.md) and (b) defeated tree-shaking.
13
13
  */
14
14
 
15
+ /// <reference path="../types/react-native-classname.d.ts" />
16
+
15
17
  // Components
16
18
  export { default as OxyProvider } from './components/OxyProvider';
17
19
  export { default as OxySignInButton } from './components/OxySignInButton';
@@ -63,21 +63,4 @@ export interface OxyProviderProps {
63
63
  authWebUrl?: string;
64
64
  authRedirectUri?: string;
65
65
  queryClient?: QueryClient;
66
- /**
67
- * When `true`, skips ONLY the terminal SSO bounce in the web cold-boot
68
- * chain — the force-redirect to `auth.<apex>/sso?prompt=none` that fires
69
- * for a visitor with no recoverable local session. This lets a truly
70
- * anonymous user keep browsing instead of being bounced to the central
71
- * IdP (e.g. a marketplace that allows anonymous browsing like eBay /
72
- * Shop.app).
73
- *
74
- * Session restore still runs in full: the callback consume, FedCM silent,
75
- * first-party `/auth/silent` iframe, stored-session bearer, and
76
- * cookie-restore steps all execute — so a returning signed-in user is
77
- * still silently restored. Only the force-bounce for a genuinely
78
- * anonymous visitor is suppressed.
79
- *
80
- * Default `false` (current behavior: the bounce fires).
81
- */
82
- disableAutoSso?: boolean;
83
66
  }
@@ -9,6 +9,17 @@ export interface SessionStorageKeys {
9
9
  activeSessionId: string;
10
10
  sessionIds: string;
11
11
  language: string;
12
+ /**
13
+ * DURABLE "this device/app has had a signed-in Oxy session before" hint.
14
+ *
15
+ * Lives in the SAME `storageKeyPrefix`-scoped durable store as the stored
16
+ * session ids, so it survives a session expiring (cleared only on explicit
17
+ * full sign-out). Read at cold boot to drive the smart `sso-bounce` gate:
18
+ * a returning visitor still gets ONE establish bounce so a central-only
19
+ * cross-domain session recovers, while a first-time anonymous visitor is
20
+ * never force-redirected. See `allowSsoBounce` in `@oxyhq/core`.
21
+ */
22
+ priorSession: string;
12
23
  }
13
24
 
14
25
  /**
@@ -125,6 +136,7 @@ export const getStorageKeys = (prefix: string = STORAGE_KEY_PREFIX): SessionStor
125
136
  activeSessionId: `${prefix}_active_session_id`,
126
137
  sessionIds: `${prefix}_session_ids`,
127
138
  language: `${prefix}_language`,
139
+ priorSession: `${prefix}_prior_session`,
128
140
  });
129
141
 
130
142