@oxyhq/core 5.5.0 → 6.0.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 (181) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/HttpService.js +6 -3
  3. package/dist/cjs/OxyServices.base.js +7 -102
  4. package/dist/cjs/boot/coldBootV2.js +350 -0
  5. package/dist/cjs/boot/deviceBootReturn.js +152 -0
  6. package/dist/cjs/crypto/keyManager.js +95 -0
  7. package/dist/cjs/i18n/locales/en-US.json +13 -1
  8. package/dist/cjs/i18n/locales/es-ES.json +13 -1
  9. package/dist/cjs/i18n/locales/locales/en-US.json +13 -1
  10. package/dist/cjs/i18n/locales/locales/es-ES.json +13 -1
  11. package/dist/cjs/index.js +47 -44
  12. package/dist/cjs/mixins/OxyServices.accounts.js +6 -13
  13. package/dist/cjs/mixins/OxyServices.auth.js +66 -201
  14. package/dist/cjs/mixins/OxyServices.authorizedApps.js +38 -0
  15. package/dist/cjs/mixins/OxyServices.deviceBoot.js +119 -0
  16. package/dist/cjs/mixins/index.js +13 -17
  17. package/dist/cjs/session/SessionClient.js +40 -1
  18. package/dist/cjs/session/authStateStore.js +284 -0
  19. package/dist/cjs/session/refresh.js +264 -0
  20. package/dist/cjs/utils/accountUtils.js +1 -55
  21. package/dist/cjs/utils/authWebUrl.js +6 -15
  22. package/dist/cjs/utils/fapiAutoDetect.js +16 -64
  23. package/dist/cjs/utils/platform.js +19 -0
  24. package/dist/cjs/utils/ssoBounce.js +15 -362
  25. package/dist/cjs/utils/validationUtils.js +57 -0
  26. package/dist/esm/.tsbuildinfo +1 -1
  27. package/dist/esm/HttpService.js +6 -3
  28. package/dist/esm/OxyServices.base.js +7 -102
  29. package/dist/esm/boot/coldBootV2.js +344 -0
  30. package/dist/esm/boot/deviceBootReturn.js +146 -0
  31. package/dist/esm/crypto/keyManager.js +95 -0
  32. package/dist/esm/i18n/locales/en-US.json +13 -1
  33. package/dist/esm/i18n/locales/es-ES.json +13 -1
  34. package/dist/esm/i18n/locales/locales/en-US.json +13 -1
  35. package/dist/esm/i18n/locales/locales/es-ES.json +13 -1
  36. package/dist/esm/index.js +28 -18
  37. package/dist/esm/mixins/OxyServices.accounts.js +6 -13
  38. package/dist/esm/mixins/OxyServices.auth.js +66 -201
  39. package/dist/esm/mixins/OxyServices.authorizedApps.js +35 -0
  40. package/dist/esm/mixins/OxyServices.deviceBoot.js +116 -0
  41. package/dist/esm/mixins/index.js +13 -17
  42. package/dist/esm/session/SessionClient.js +40 -1
  43. package/dist/esm/session/authStateStore.js +278 -0
  44. package/dist/esm/session/refresh.js +257 -0
  45. package/dist/esm/utils/accountUtils.js +0 -53
  46. package/dist/esm/utils/authWebUrl.js +6 -14
  47. package/dist/esm/utils/fapiAutoDetect.js +16 -63
  48. package/dist/esm/utils/platform.js +18 -0
  49. package/dist/esm/utils/ssoBounce.js +14 -345
  50. package/dist/esm/utils/validationUtils.js +56 -0
  51. package/dist/types/.tsbuildinfo +1 -1
  52. package/dist/types/HttpService.d.ts +13 -0
  53. package/dist/types/OxyServices.base.d.ts +0 -52
  54. package/dist/types/OxyServices.d.ts +0 -25
  55. package/dist/types/boot/coldBootV2.d.ts +76 -0
  56. package/dist/types/boot/deviceBootReturn.d.ts +83 -0
  57. package/dist/types/crypto/keyManager.d.ts +21 -0
  58. package/dist/types/index.d.ts +15 -21
  59. package/dist/types/mixins/OxyServices.accounts.d.ts +0 -2
  60. package/dist/types/mixins/OxyServices.analytics.d.ts +0 -2
  61. package/dist/types/mixins/OxyServices.appData.d.ts +0 -2
  62. package/dist/types/mixins/OxyServices.assets.d.ts +0 -2
  63. package/dist/types/mixins/OxyServices.auth.d.ts +35 -77
  64. package/dist/types/mixins/{OxyServices.redirect.d.ts → OxyServices.authorizedApps.d.ts} +35 -33
  65. package/dist/types/mixins/OxyServices.civic.d.ts +0 -2
  66. package/dist/types/mixins/OxyServices.connectedApps.d.ts +0 -2
  67. package/dist/types/mixins/OxyServices.contacts.d.ts +0 -2
  68. package/dist/types/mixins/OxyServices.deviceBoot.d.ts +110 -0
  69. package/dist/types/mixins/OxyServices.devices.d.ts +0 -2
  70. package/dist/types/mixins/OxyServices.features.d.ts +0 -2
  71. package/dist/types/mixins/OxyServices.identity.d.ts +0 -2
  72. package/dist/types/mixins/OxyServices.language.d.ts +0 -2
  73. package/dist/types/mixins/OxyServices.links.d.ts +0 -2
  74. package/dist/types/mixins/OxyServices.location.d.ts +0 -2
  75. package/dist/types/mixins/OxyServices.nodes.d.ts +0 -2
  76. package/dist/types/mixins/OxyServices.payment.d.ts +0 -2
  77. package/dist/types/mixins/OxyServices.privacy.d.ts +0 -2
  78. package/dist/types/mixins/OxyServices.reputation.d.ts +0 -2
  79. package/dist/types/mixins/OxyServices.security.d.ts +0 -2
  80. package/dist/types/mixins/OxyServices.topics.d.ts +0 -2
  81. package/dist/types/mixins/OxyServices.user.d.ts +0 -2
  82. package/dist/types/mixins/OxyServices.utility.d.ts +0 -2
  83. package/dist/types/mixins/index.d.ts +6 -9
  84. package/dist/types/models/interfaces.d.ts +0 -67
  85. package/dist/types/session/SessionClient.d.ts +25 -0
  86. package/dist/types/session/authStateStore.d.ts +119 -0
  87. package/dist/types/session/refresh.d.ts +93 -0
  88. package/dist/types/utils/accountUtils.d.ts +0 -14
  89. package/dist/types/utils/authWebUrl.d.ts +6 -12
  90. package/dist/types/utils/fapiAutoDetect.d.ts +15 -38
  91. package/dist/types/utils/platform.d.ts +14 -0
  92. package/dist/types/utils/ssoBounce.d.ts +14 -280
  93. package/dist/types/utils/validationUtils.d.ts +15 -0
  94. package/package.json +2 -2
  95. package/src/HttpService.ts +19 -3
  96. package/src/OxyServices.base.ts +7 -112
  97. package/src/OxyServices.ts +0 -38
  98. package/src/boot/__tests__/coldBootV2.test.ts +317 -0
  99. package/src/boot/__tests__/deviceBootReturn.test.ts +158 -0
  100. package/src/boot/coldBootV2.ts +426 -0
  101. package/src/boot/deviceBootReturn.ts +195 -0
  102. package/src/crypto/__tests__/sharedDeviceToken.test.ts +24 -0
  103. package/src/crypto/keyManager.ts +101 -0
  104. package/src/i18n/locales/en-US.json +13 -1
  105. package/src/i18n/locales/es-ES.json +13 -1
  106. package/src/index.ts +74 -65
  107. package/src/mixins/OxyServices.accounts.ts +6 -13
  108. package/src/mixins/OxyServices.auth.ts +78 -253
  109. package/src/mixins/OxyServices.authorizedApps.ts +75 -0
  110. package/src/mixins/OxyServices.deviceBoot.ts +146 -0
  111. package/src/mixins/__tests__/OxyServices.deviceBoot.test.ts +107 -0
  112. package/src/mixins/__tests__/accounts.test.ts +17 -44
  113. package/src/mixins/__tests__/authorizedApps.test.ts +63 -0
  114. package/src/mixins/__tests__/passwordSignIn.test.ts +91 -0
  115. package/src/mixins/index.ts +16 -22
  116. package/src/models/interfaces.ts +0 -79
  117. package/src/session/SessionClient.ts +52 -1
  118. package/src/session/__tests__/SessionClient.additive.test.ts +92 -0
  119. package/src/session/__tests__/SessionClient.rest.test.ts +25 -0
  120. package/src/session/__tests__/SessionClient.state.test.ts +18 -5
  121. package/src/session/__tests__/authStateStore.test.ts +209 -0
  122. package/src/session/__tests__/refresh.test.ts +256 -0
  123. package/src/session/authStateStore.ts +335 -0
  124. package/src/session/refresh.ts +334 -0
  125. package/src/utils/__tests__/authWebUrl.test.ts +5 -29
  126. package/src/utils/__tests__/fapiAutoDetect.test.ts +5 -126
  127. package/src/utils/__tests__/validationUtils.test.ts +30 -0
  128. package/src/utils/accountUtils.ts +0 -62
  129. package/src/utils/authWebUrl.ts +6 -15
  130. package/src/utils/fapiAutoDetect.ts +16 -60
  131. package/src/utils/platform.ts +21 -0
  132. package/src/utils/ssoBounce.ts +14 -393
  133. package/src/utils/validationUtils.ts +62 -0
  134. package/dist/cjs/AuthManager.js +0 -1110
  135. package/dist/cjs/AuthManagerTypes.js +0 -13
  136. package/dist/cjs/CrossDomainAuth.js +0 -206
  137. package/dist/cjs/mixins/OxyServices.fedcm.js +0 -823
  138. package/dist/cjs/mixins/OxyServices.redirect.js +0 -95
  139. package/dist/cjs/mixins/OxyServices.silent.js +0 -204
  140. package/dist/cjs/mixins/OxyServices.sso.js +0 -208
  141. package/dist/cjs/utils/ssoEstablish.js +0 -110
  142. package/dist/cjs/utils/ssoReturn.js +0 -275
  143. package/dist/esm/AuthManager.js +0 -1105
  144. package/dist/esm/AuthManagerTypes.js +0 -12
  145. package/dist/esm/CrossDomainAuth.js +0 -201
  146. package/dist/esm/mixins/OxyServices.fedcm.js +0 -821
  147. package/dist/esm/mixins/OxyServices.redirect.js +0 -92
  148. package/dist/esm/mixins/OxyServices.silent.js +0 -202
  149. package/dist/esm/mixins/OxyServices.sso.js +0 -204
  150. package/dist/esm/utils/ssoEstablish.js +0 -107
  151. package/dist/esm/utils/ssoReturn.js +0 -271
  152. package/dist/types/AuthManager.d.ts +0 -380
  153. package/dist/types/AuthManagerTypes.d.ts +0 -81
  154. package/dist/types/CrossDomainAuth.d.ts +0 -164
  155. package/dist/types/mixins/OxyServices.fedcm.d.ts +0 -331
  156. package/dist/types/mixins/OxyServices.silent.d.ts +0 -132
  157. package/dist/types/mixins/OxyServices.sso.d.ts +0 -138
  158. package/dist/types/utils/ssoEstablish.d.ts +0 -85
  159. package/dist/types/utils/ssoReturn.d.ts +0 -156
  160. package/src/AuthManager.ts +0 -1269
  161. package/src/AuthManagerTypes.ts +0 -86
  162. package/src/CrossDomainAuth.ts +0 -243
  163. package/src/__tests__/authManager.cookiePath.test.ts +0 -390
  164. package/src/__tests__/authManager.security.test.ts +0 -377
  165. package/src/__tests__/crossDomainAuth.test.ts +0 -116
  166. package/src/__tests__/establishDeviceRefreshSlot.test.ts +0 -221
  167. package/src/mixins/OxyServices.fedcm.ts +0 -1026
  168. package/src/mixins/OxyServices.redirect.ts +0 -122
  169. package/src/mixins/OxyServices.silent.ts +0 -272
  170. package/src/mixins/OxyServices.sso.ts +0 -261
  171. package/src/mixins/__tests__/constructorAuthWebUrl.test.ts +0 -85
  172. package/src/mixins/__tests__/fedcm.test.ts +0 -667
  173. package/src/mixins/__tests__/sessionBaseUrl.test.ts +0 -61
  174. package/src/mixins/__tests__/silent.test.ts +0 -102
  175. package/src/mixins/__tests__/sso.test.ts +0 -228
  176. package/src/utils/__tests__/consumeSsoReturn.test.ts +0 -816
  177. package/src/utils/__tests__/ssoBounce.test.ts +0 -219
  178. package/src/utils/__tests__/ssoEstablish.test.ts +0 -204
  179. package/src/utils/__tests__/ssoReturn.test.ts +0 -276
  180. package/src/utils/ssoEstablish.ts +0 -174
  181. package/src/utils/ssoReturn.ts +0 -389
@@ -16,6 +16,16 @@ export interface SessionClientHost {
16
16
  }
17
17
  export interface SessionClientOptions {
18
18
  transport?: TokenTransport;
19
+ /**
20
+ * Invoked when an APPLIED state has zero accounts — i.e. a device
21
+ * signout-all removed the last account from this device set. Providers use
22
+ * this to clear the persisted {@link AuthStateStore} so a reload does not
23
+ * try to restore a session that no longer exists on the device.
24
+ *
25
+ * Only fires when a state is actually applied (revision advanced), never on
26
+ * a stale/rejected push. Exceptions thrown by the callback are isolated.
27
+ */
28
+ onUnauthenticated?: () => void;
19
29
  /**
20
30
  * Statically-injected `socket.io-client` factory (its `io` export).
21
31
  * `@oxyhq/services` and `@oxyhq/auth` list `socket.io-client` as a real
@@ -60,6 +70,21 @@ export declare class SessionClient {
60
70
  all: true;
61
71
  }): Promise<void>;
62
72
  addCurrentAccount(): Promise<void>;
73
+ /**
74
+ * Register the just-signed-in account into the device set AND make it the
75
+ * ACTIVE account — the explicit user-intent activation a sign-in UI performs.
76
+ *
77
+ * `addCurrentAccount` alone honors the server's `activate:'if-empty'` policy
78
+ * (a new account does NOT steal focus from an already-active one), which is
79
+ * correct for a background/silent add but wrong right after a deliberate
80
+ * sign-in. This adds, then switches to the target so the UI lands on the
81
+ * account the user just authenticated.
82
+ *
83
+ * @param accountId - The signed-in account id (e.g. `session.user.id`). When
84
+ * omitted, falls back to the host's current-account ref. If neither
85
+ * resolves, the add still applies and no switch is performed.
86
+ */
87
+ registerAndActivate(accountId?: string): Promise<void>;
63
88
  start(): Promise<void>;
64
89
  stop(): void;
65
90
  private connectSocket;
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Persisted auth state — ONE shape, web + native.
3
+ *
4
+ * The device-first session model (auth-centralization wave 1) persists the
5
+ * rotating refresh-token family head per ORIGIN so a reload restores the
6
+ * session locally without a redirect. This module is the storage seam: a tiny
7
+ * `load / save / clear` interface plus platform factories, so the cold boot
8
+ * (`coldBootV2`) and the unified refresh handler (`refresh.ts`) never touch a
9
+ * platform storage API directly.
10
+ *
11
+ * Platform-agnostic — the native factory takes an INJECTED key/value store
12
+ * (`@oxyhq/services` passes a SecureStore-backed adapter) so `@oxyhq/core`
13
+ * never imports `expo-secure-store`. The web factory is self-contained
14
+ * (`localStorage`) and degrades to in-memory when storage is unavailable
15
+ * (sandboxed iframe `SecurityError`, private-mode quota, SSR).
16
+ *
17
+ * ESM-safe (no `require()`).
18
+ */
19
+ /**
20
+ * The persisted session credential set for a single origin.
21
+ *
22
+ * `refreshToken` is the rotating single-use family head; `sessionId` + `userId`
23
+ * identify the owning device session and account. `deviceToken` is the opaque,
24
+ * add-only device attribution token (mirrored to the shared keychain on native
25
+ * so every Oxy app on one phone shares one DeviceSession).
26
+ *
27
+ * `accessToken` + `expiresAt` are OPTIONAL warm-boot fields. Persisting them
28
+ * lets the cold boot plant a still-valid access token on the very first paint
29
+ * WITHOUT a blocking `/auth/refresh-token` round-trip — the proactive scheduler
30
+ * then rotates it in the background. They are a strict optimization: the store
31
+ * is fully functional (via `refreshToken`) when they are absent or stale, and
32
+ * the access token is short-lived, so persisting it adds no exposure the
33
+ * already-persisted refresh token does not (see the plan's XSS risk note — the
34
+ * refresh token is the dominant secret either way).
35
+ */
36
+ export interface PersistedAuthState {
37
+ sessionId: string;
38
+ refreshToken: string;
39
+ userId: string;
40
+ deviceToken?: string;
41
+ /** Optional warm-boot access token (short-lived; see interface docs). */
42
+ accessToken?: string;
43
+ /** Optional warm-boot access-token expiry, ISO-8601. */
44
+ expiresAt?: string;
45
+ }
46
+ /**
47
+ * The storage seam consumed by the cold boot and the refresh handler. Async
48
+ * throughout so one interface fits both synchronous web `localStorage` and
49
+ * asynchronous native SecureStore/AsyncStorage.
50
+ *
51
+ * Two lifetimes:
52
+ * - The SESSION credential blob (`load`/`save`/`clear`) is per-sign-in and is
53
+ * wiped on `clear()` (sign-out).
54
+ * - The DEVICE token (`loadDeviceToken`/`saveDeviceToken`/`clearDeviceToken`)
55
+ * is long-lived device attribution that SURVIVES `clear()`: a signed-out
56
+ * browser is still the same device, and a later in-app (cross-apex,
57
+ * cookie-less) login sends this token so the new session joins the SAME
58
+ * server-side DeviceSession. Only an explicit device signout-all
59
+ * (`clearDeviceToken`) removes it.
60
+ */
61
+ export interface AuthStateStore {
62
+ load(): Promise<PersistedAuthState | null>;
63
+ save(state: PersistedAuthState): Promise<void>;
64
+ clear(): Promise<void>;
65
+ loadDeviceToken(): Promise<string | null>;
66
+ saveDeviceToken(token: string): Promise<void>;
67
+ clearDeviceToken(): Promise<void>;
68
+ }
69
+ /**
70
+ * The minimal async key/value surface a native store must provide. Matches
71
+ * both `expo-secure-store` (wrapped) and `@react-native-async-storage`.
72
+ */
73
+ export interface NativeKeyValueStorage {
74
+ getItem(key: string): Promise<string | null>;
75
+ setItem(key: string, value: string): Promise<void>;
76
+ removeItem(key: string): Promise<void>;
77
+ }
78
+ /**
79
+ * Versioned storage key. The `.v1` suffix lets a future shape change ship a
80
+ * `.v2` key without reading a stale/incompatible `.v1` blob. Distinct from the
81
+ * `oxy_shared_*` keychain keys in `KeyManager`, so it never collides.
82
+ */
83
+ export declare const AUTH_STATE_STORAGE_KEY = "oxy.auth.v1";
84
+ /**
85
+ * Storage key for the long-lived device-attribution token. Separate from
86
+ * {@link AUTH_STATE_STORAGE_KEY} because it must OUTLIVE a session `clear()`
87
+ * (sign-out) — the device is unchanged across sign-ins.
88
+ */
89
+ export declare const DEVICE_TOKEN_STORAGE_KEY = "oxy.device.v1";
90
+ /**
91
+ * A process-lifetime, in-memory {@link AuthStateStore}. Used directly for
92
+ * tests/SSR and as the degraded fallback of the web store when `localStorage`
93
+ * is unreachable. Not durable across reloads — that is acceptable for the
94
+ * fallback because the alternative (throwing) would break cold boot entirely.
95
+ */
96
+ export declare function createMemoryAuthStateStore(): AuthStateStore;
97
+ /**
98
+ * A `localStorage`-backed {@link AuthStateStore} under the versioned
99
+ * {@link AUTH_STATE_STORAGE_KEY}.
100
+ *
101
+ * Resilience:
102
+ * - If `localStorage` is unreachable (sandboxed-iframe `SecurityError`, SSR),
103
+ * the whole store degrades to an in-memory {@link createMemoryAuthStateStore}
104
+ * for this page's lifetime — never throws on construction.
105
+ * - Individual `getItem`/`setItem`/`removeItem` are each wrapped: a read that
106
+ * throws yields `null`; a write that throws (quota, private mode) is
107
+ * swallowed. The persisted-refresh lane treats a failed persist as "no
108
+ * durable state" (falls back to the bootstrap hop) rather than crashing.
109
+ */
110
+ export declare function createWebAuthStateStore(): AuthStateStore;
111
+ /**
112
+ * A native {@link AuthStateStore} over an injected async key/value store.
113
+ *
114
+ * `@oxyhq/core` never imports `expo-secure-store`; `@oxyhq/services` constructs
115
+ * the SecureStore-backed adapter and passes it here. Every operation is wrapped
116
+ * so a storage exception degrades gracefully (read → `null`, write → swallowed)
117
+ * exactly like the web store.
118
+ */
119
+ export declare function createNativeAuthStateStore(storage: NativeKeyValueStorage): AuthStateStore;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Unified token refresh — THE single refresh implementation for web + native.
3
+ *
4
+ * Before device-first, refresh was duplicated: `@oxyhq/auth`'s
5
+ * `session/tokenRefresh.ts` (per-apex `/auth/silent` iframe) and
6
+ * `@oxyhq/services`'s `inSessionTokenRefresh.ts` (native shared-key). This
7
+ * module replaces both with ONE persisted-refresh-token rotation shared by
8
+ * every consumer:
9
+ *
10
+ * - `refreshPersistedSession` — arm 1 rotates the stored refresh-token family
11
+ * (`POST /auth/refresh-token`), planting + persisting the rotated pair; arm 2
12
+ * (native only) re-mints via the shared-keychain identity when there is no
13
+ * live refresh token. It is used BOTH reactively (wrapped as the
14
+ * `AuthRefreshHandler` installed on `HttpService`) AND proactively (the
15
+ * cold-boot `stored-tokens` step calls it directly).
16
+ * - `createAuthRefreshHandler` / `installAuthRefreshHandler` wire arm 1+2 into
17
+ * `HttpService.setAuthRefreshHandler`, keeping that layer's single-flight
18
+ * dedup + cooldown (this module does NOT reimplement them).
19
+ * - `startTokenRefreshScheduler` — a proactive scheduler (lifted from the
20
+ * better of the two prior duplicates, `@oxyhq/auth`'s `tokenRefresh.ts`),
21
+ * decoupled from any React / auth-sdk type: refreshes ~60s before `exp`,
22
+ * re-arms on token change + web tab-focus, `.unref?.()`s its timer in Node.
23
+ *
24
+ * Framework-free; no module-level mutable state.
25
+ */
26
+ import type { OxyServices } from '../OxyServices';
27
+ import type { AuthRefreshHandler } from '../HttpService';
28
+ import type { AuthStateStore } from './authStateStore';
29
+ /**
30
+ * Lead time (ms) before access-token expiry at which the proactive scheduler
31
+ * refreshes. Mirrors `HttpService`'s per-request `TOKEN_REFRESH_LEAD_SECONDS`
32
+ * (60s) so the scheduled refresh and the request-time preflight refresh use
33
+ * the same window — the scheduler just fires it during idle/background.
34
+ */
35
+ export declare const TOKEN_REFRESH_LEAD_MS = 60000;
36
+ export interface RefreshDeps {
37
+ oxy: OxyServices;
38
+ store: AuthStateStore;
39
+ /**
40
+ * Whether to fall back to the native shared-keychain re-mint (arm 2) when
41
+ * there is no live refresh token / arm 1 is revoked. Defaults to `isNative()`
42
+ * — web has no shared keychain. Exposed for tests.
43
+ */
44
+ allowSharedKeyFallback?: boolean;
45
+ }
46
+ /**
47
+ * Rotate the persisted session and return the fresh access token, or `null`
48
+ * when no arm could produce one.
49
+ *
50
+ * Arm 1 (`POST /auth/refresh-token`): if the store holds a refresh token, rotate
51
+ * it — on success plant + persist the rotated pair; on a REVOKED error clear the
52
+ * store; on a transient error leave the store and return `null`.
53
+ *
54
+ * Arm 2 (native shared-keychain): when there is no refresh token or arm 1 was
55
+ * revoked, re-mint via `signInWithSharedIdentity` (which plants tokens). The
56
+ * shared keychain — not the per-origin store — is the durable native credential,
57
+ * so this arm does not write the store.
58
+ */
59
+ export declare function refreshPersistedSession(deps: RefreshDeps): Promise<string | null>;
60
+ /**
61
+ * Build the reactive `AuthRefreshHandler` (arm 1 + arm 2). Install it via
62
+ * {@link installAuthRefreshHandler} or directly on
63
+ * `oxy.httpService.setAuthRefreshHandler`. `HttpService` owns single-flight
64
+ * dedup + cooldown, so the timer, the request-time preflight, and a 401 all
65
+ * collapse to one network attempt.
66
+ */
67
+ export declare function createAuthRefreshHandler(deps: RefreshDeps): AuthRefreshHandler;
68
+ /**
69
+ * Install the unified refresh handler on the owner client's `HttpService`.
70
+ * Returns a disposer that removes it.
71
+ */
72
+ export declare function installAuthRefreshHandler(deps: RefreshDeps): () => void;
73
+ /** Handle returned by {@link startTokenRefreshScheduler}; `dispose()` tears it down. */
74
+ export interface TokenRefreshSchedulerHandle {
75
+ dispose(): void;
76
+ }
77
+ /**
78
+ * Start the proactive refresh scheduler against `oxy`.
79
+ *
80
+ * Schedules a single timer to fire {@link TOKEN_REFRESH_LEAD_MS} before the
81
+ * current access token's `exp`, calling
82
+ * `oxy.httpService.refreshAccessToken('preflight')` (which runs the installed
83
+ * handler; deduped + cooldown-guarded). After every attempt it reschedules
84
+ * from the possibly-rotated token. It also reschedules whenever the token
85
+ * changes (a sign-out that clears the token cancels the timer) and, on web
86
+ * tab-focus, refreshes immediately if already inside the lead window (a
87
+ * long-hidden tab throttles timers, so the token can be expired on return).
88
+ *
89
+ * No-ops cleanly when there is no token or an opaque/no-`exp` token — the
90
+ * reactive 401 path stays the only refresh trigger in that case. The timer is
91
+ * `.unref?.()`-ed so it never keeps a Node/Jest event loop alive.
92
+ */
93
+ export declare function startTokenRefreshScheduler(oxy: OxyServices): TokenRefreshSchedulerHandle;
@@ -2,7 +2,6 @@
2
2
  * Shared account types and pure helper functions.
3
3
  * Used by both @oxyhq/services (React Native) and @oxyhq/auth (Web) account stores.
4
4
  */
5
- import type { RefreshAllAccount } from '../models/interfaces';
6
5
  export interface QuickAccount {
7
6
  sessionId: string;
8
7
  userId?: string;
@@ -94,19 +93,6 @@ export declare const createQuickAccount: (sessionId: string, userData: {
94
93
  } | string;
95
94
  avatar?: string | null;
96
95
  }, existingAccount?: QuickAccount, getFileDownloadUrl?: (fileId: string, variant: string) => string) => QuickAccount;
97
- /**
98
- * Merge a fresh `/auth/refresh-all` snapshot into an existing QuickAccount
99
- * list, preserving any cached fields (`avatarUrl`) for slots that didn't
100
- * change. The fresh response is canonical: the resulting list contains EXACTLY
101
- * the slots present in `fresh`, sorted by `authuser` ascending. Stale stored
102
- * accounts that no longer appear in `fresh` are dropped (the server already
103
- * authoritatively cleared the corresponding cookie).
104
- *
105
- * @param stored Previously persisted QuickAccount list (any order).
106
- * @param fresh Server's authoritative refresh-all response.
107
- * @returns Canonical merged list, sorted by `authuser` asc.
108
- */
109
- export declare const mergeAccountsFromRefreshAll: (stored: QuickAccount[] | undefined, fresh: RefreshAllAccount[]) => QuickAccount[];
110
96
  /**
111
97
  * Return the account's preferred Bloom color preset, or `null` if it has no
112
98
  * preference. Centralises the `color ?? null` normalisation so consumers can
@@ -12,9 +12,11 @@
12
12
  * `window`/`location`, and has no side effects. It is the single source of
13
13
  * truth for the central IdP origin so call sites never hardcode the literal.
14
14
  *
15
- * Note: this is distinct from `autoDetectAuthWebUrl` (per-apex `auth.<rp-apex>`
16
- * derivation). The central-SSO path deliberately does NOT auto-detect per-apex
17
- * IdPs it is central only. An explicitly-configured `authWebUrl` still wins.
15
+ * LEGACY(old-sdk): the client resolver (`resolveCentralAuthUrl`) was removed in
16
+ * the device-first cutover; `CENTRAL_IDP_APEX` / `CENTRAL_AUTH_URL` survive ONLY
17
+ * because the lista-B IdP worker imports them to brand assertions. Deletable
18
+ * once Homiio/Allo/Alia/Syra are bumped off the old SDK AND CloudWatch
19
+ * `/oxy/ecs` shows the `/sso*` + `/fedcm/*` routes quiet — F-final sweep.
18
20
  */
19
21
  /**
20
22
  * The registrable apex (eTLD+1) of the Oxy ecosystem's central Identity
@@ -29,14 +31,6 @@ export declare const CENTRAL_IDP_APEX = "oxy.so";
29
31
  /**
30
32
  * The canonical central Identity Provider origin for the Oxy ecosystem.
31
33
  * No trailing slash. Derived from {@link CENTRAL_IDP_APEX} so the apex and the
32
- * full origin never drift apart.
34
+ * full origin never drift apart. The IdP worker imports it to brand assertions.
33
35
  */
34
36
  export declare const CENTRAL_AUTH_URL = "https://auth.oxy.so";
35
- /**
36
- * Resolve the central IdP origin, honouring an explicit override.
37
- *
38
- * @param explicit - A caller-supplied auth web URL, or `undefined`/empty to use
39
- * the central default. An explicit non-empty value always wins.
40
- * @returns The explicit value when provided, otherwise {@link CENTRAL_AUTH_URL}.
41
- */
42
- export declare function resolveCentralAuthUrl(explicit?: string): string;
@@ -1,46 +1,24 @@
1
1
  /**
2
- * Auto-detect the FAPI (IdP) URL from the current browser hostname.
3
- *
4
- * This is the canonical cross-domain IdP-resolution primitive for the Oxy
5
- * ecosystem. Both candidate cross-domain SSO designs derive `auth.<rp-apex>`
6
- * through this helper; do not fork it.
7
- *
8
- * Clerk-style multi-domain SSO depends on the IdP being reachable on a
9
- * subdomain of the RP's own apex (e.g. `auth.mention.earth` CNAMEd to the
10
- * central Oxy IdP). That way every FedCM endpoint, the session cookie,
11
- * and any redirect target are same-site with the RP the only way
12
- * to get first-party cookies in Safari ITP and Firefox Total Cookie
13
- * Protection.
14
- *
15
- * This helper computes `https://auth.<rp-apex>` from
16
- * `window.location.hostname` so a consuming app doesn't have to pass
17
- * `authWebUrl` explicitly. Returns `undefined` for environments where
18
- * auto-detection would be wrong:
19
- *
20
- * - SSR / non-browser (no `window`).
21
- * - `localhost`, `127.0.0.1`, IPv4/IPv6 literals.
22
- * - Hostnames with fewer than two labels.
23
- * - Hostnames where a registrable domain cannot be determined from the
24
- * Public Suffix List, including private hosted suffixes such as
25
- * `github.io`, `pages.dev`, and `netlify.app`.
26
- *
27
- * When the page is already loaded ON the IdP itself (`auth.<anything>`),
28
- * the helper returns the current origin so the SDK keeps everything
29
- * same-origin instead of hopping to a different IdP host.
30
- *
31
- * The IdP backend independently derives `iss`, `provider_urls`, and the
32
- * `fedcm.json` icon URLs from the request host
33
- * (`packages/auth/server/index.ts`), so an honest CNAME pair is all that
34
- * is required for end-to-end FedCM correctness — no per-RP config.
2
+ * Registrable-apex (eTLD+1) host kernel.
3
+ *
4
+ * The client FAPI auto-detection helper (`autoDetectAuthWebUrl`) was removed in
5
+ * the device-first cutover the SDK no longer derives a per-apex `auth.<rp>`
6
+ * IdP host. What survives is the pure registrable-domain kernel, still used by
7
+ * the api SSO surface, `fedcm.service`, `deviceAuth` (same-apex trust checks),
8
+ * and the IdP worker (all lista B / server-side). `@oxyhq/core/server`
9
+ * re-exports it for the api.
10
+ *
11
+ * LEGACY(old-sdk): `registrableApex` survives ONLY for the lista-B server/IdP
12
+ * SSO surface. Deletable once Homiio/Allo/Alia/Syra are bumped off the old SDK
13
+ * AND CloudWatch `/oxy/ecs` shows the `/sso*` + `/fedcm/*` routes quiet — the
14
+ * F-final sweep should remove this file then.
35
15
  */
36
16
  /**
37
17
  * Compute the bare registrable apex (eTLD+1) of a hostname using the Public
38
18
  * Suffix List, including private hosted suffixes.
39
19
  *
40
- * This is the pure host-handling kernel shared by {@link autoDetectAuthWebUrl}
41
- * and the IdP worker it performs NO protocol handling, NO `auth.` prefixing,
42
- * and builds NO URL. It only answers "what is the registrable domain of this
43
- * host, or is that undefinable?".
20
+ * Performs NO protocol handling and builds NO URL — it only answers "what is
21
+ * the registrable domain of this host, or is that undefinable?".
44
22
  *
45
23
  * Returns `null` (apex undefinable) for:
46
24
  * - empty input;
@@ -53,4 +31,3 @@
53
31
  * @returns The eTLD+1 (`mention.earth`), or `null` when undefinable.
54
32
  */
55
33
  export declare function registrableApex(hostname: string): string | null;
56
- export declare function autoDetectAuthWebUrl(location?: Pick<Location, 'hostname' | 'protocol'> | undefined): string | undefined;
@@ -33,3 +33,17 @@ export declare function isAndroid(): boolean;
33
33
  * This allows lazy detection in environments where react-native is available
34
34
  */
35
35
  export declare function setPlatformOS(os: PlatformOS): void;
36
+ /**
37
+ * True only in a real web browser (a DOM is present), false on React Native
38
+ * and Node/SSR.
39
+ *
40
+ * Native defines a global `window` but no `document`, so the DOM probe — not a
41
+ * bare `window` check — is the reliable discriminator. This is the single
42
+ * source of truth consumed by `@oxyhq/services` and `@oxyhq/auth` (both dropped
43
+ * their local copies), so every consumer shares the exact same predicate.
44
+ *
45
+ * NOTE: this is a live runtime probe (not the cached `getPlatformOS()` verdict)
46
+ * because it must reflect the actual DOM availability at call time in the
47
+ * consumer's bundle.
48
+ */
49
+ export declare function isWebBrowser(): boolean;