@oxyhq/core 5.5.0 → 7.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 (196) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/HttpService.js +7 -4
  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 +54 -45
  12. package/dist/cjs/mixins/OxyServices.accounts.js +13 -26
  13. package/dist/cjs/mixins/OxyServices.auth.js +66 -201
  14. package/dist/cjs/mixins/OxyServices.deviceBoot.js +119 -0
  15. package/dist/cjs/mixins/index.js +8 -17
  16. package/dist/cjs/server/index.js +2 -2
  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/shared/utils/debugUtils.js +3 -3
  21. package/dist/cjs/utils/accountUtils.js +1 -55
  22. package/dist/cjs/utils/authWebUrl.js +10 -39
  23. package/dist/cjs/utils/coldBoot.js +10 -8
  24. package/dist/cjs/utils/platform.js +19 -0
  25. package/dist/cjs/utils/registrableApex.js +49 -0
  26. package/dist/cjs/utils/ssoBounce.js +15 -362
  27. package/dist/cjs/utils/validationUtils.js +57 -0
  28. package/dist/esm/.tsbuildinfo +1 -1
  29. package/dist/esm/HttpService.js +7 -4
  30. package/dist/esm/OxyServices.base.js +7 -102
  31. package/dist/esm/boot/coldBootV2.js +344 -0
  32. package/dist/esm/boot/deviceBootReturn.js +146 -0
  33. package/dist/esm/crypto/keyManager.js +95 -0
  34. package/dist/esm/i18n/locales/en-US.json +13 -1
  35. package/dist/esm/i18n/locales/es-ES.json +13 -1
  36. package/dist/esm/i18n/locales/locales/en-US.json +13 -1
  37. package/dist/esm/i18n/locales/locales/es-ES.json +13 -1
  38. package/dist/esm/index.js +34 -17
  39. package/dist/esm/mixins/OxyServices.accounts.js +13 -26
  40. package/dist/esm/mixins/OxyServices.auth.js +66 -201
  41. package/dist/esm/mixins/OxyServices.deviceBoot.js +116 -0
  42. package/dist/esm/mixins/index.js +8 -17
  43. package/dist/esm/server/index.js +1 -1
  44. package/dist/esm/session/SessionClient.js +40 -1
  45. package/dist/esm/session/authStateStore.js +278 -0
  46. package/dist/esm/session/refresh.js +257 -0
  47. package/dist/esm/shared/utils/debugUtils.js +3 -3
  48. package/dist/esm/utils/accountUtils.js +0 -53
  49. package/dist/esm/utils/authWebUrl.js +9 -37
  50. package/dist/esm/utils/coldBoot.js +10 -8
  51. package/dist/esm/utils/platform.js +18 -0
  52. package/dist/esm/utils/registrableApex.js +46 -0
  53. package/dist/esm/utils/ssoBounce.js +14 -345
  54. package/dist/esm/utils/validationUtils.js +56 -0
  55. package/dist/types/.tsbuildinfo +1 -1
  56. package/dist/types/HttpService.d.ts +14 -1
  57. package/dist/types/OxyServices.base.d.ts +0 -52
  58. package/dist/types/OxyServices.d.ts +0 -25
  59. package/dist/types/boot/coldBootV2.d.ts +76 -0
  60. package/dist/types/boot/deviceBootReturn.d.ts +83 -0
  61. package/dist/types/crypto/keyManager.d.ts +21 -0
  62. package/dist/types/index.d.ts +14 -21
  63. package/dist/types/mixins/OxyServices.accounts.d.ts +24 -29
  64. package/dist/types/mixins/OxyServices.analytics.d.ts +0 -2
  65. package/dist/types/mixins/OxyServices.appData.d.ts +0 -2
  66. package/dist/types/mixins/OxyServices.assets.d.ts +0 -2
  67. package/dist/types/mixins/OxyServices.auth.d.ts +35 -77
  68. package/dist/types/mixins/OxyServices.civic.d.ts +0 -2
  69. package/dist/types/mixins/OxyServices.connectedApps.d.ts +0 -2
  70. package/dist/types/mixins/OxyServices.contacts.d.ts +0 -2
  71. package/dist/types/mixins/OxyServices.deviceBoot.d.ts +110 -0
  72. package/dist/types/mixins/OxyServices.devices.d.ts +0 -2
  73. package/dist/types/mixins/OxyServices.features.d.ts +0 -2
  74. package/dist/types/mixins/OxyServices.identity.d.ts +0 -2
  75. package/dist/types/mixins/OxyServices.language.d.ts +0 -2
  76. package/dist/types/mixins/OxyServices.links.d.ts +0 -2
  77. package/dist/types/mixins/OxyServices.location.d.ts +0 -2
  78. package/dist/types/mixins/OxyServices.nodes.d.ts +0 -2
  79. package/dist/types/mixins/OxyServices.payment.d.ts +0 -2
  80. package/dist/types/mixins/OxyServices.privacy.d.ts +0 -2
  81. package/dist/types/mixins/OxyServices.reputation.d.ts +0 -2
  82. package/dist/types/mixins/OxyServices.security.d.ts +0 -2
  83. package/dist/types/mixins/OxyServices.topics.d.ts +0 -2
  84. package/dist/types/mixins/OxyServices.user.d.ts +0 -2
  85. package/dist/types/mixins/OxyServices.utility.d.ts +0 -2
  86. package/dist/types/mixins/index.d.ts +5 -9
  87. package/dist/types/models/interfaces.d.ts +0 -67
  88. package/dist/types/models/session.d.ts +4 -5
  89. package/dist/types/server/index.d.ts +1 -1
  90. package/dist/types/session/SessionClient.d.ts +26 -1
  91. package/dist/types/session/authStateStore.d.ts +119 -0
  92. package/dist/types/session/refresh.d.ts +93 -0
  93. package/dist/types/shared/utils/debugUtils.d.ts +3 -3
  94. package/dist/types/utils/accountUtils.d.ts +2 -17
  95. package/dist/types/utils/authWebUrl.d.ts +9 -35
  96. package/dist/types/utils/coldBoot.d.ts +17 -14
  97. package/dist/types/utils/platform.d.ts +14 -0
  98. package/dist/types/utils/registrableApex.d.ts +31 -0
  99. package/dist/types/utils/ssoBounce.d.ts +14 -280
  100. package/dist/types/utils/validationUtils.d.ts +15 -0
  101. package/package.json +2 -2
  102. package/src/HttpService.ts +20 -4
  103. package/src/OxyServices.base.ts +7 -112
  104. package/src/OxyServices.ts +0 -38
  105. package/src/boot/__tests__/coldBootV2.test.ts +317 -0
  106. package/src/boot/__tests__/deviceBootReturn.test.ts +158 -0
  107. package/src/boot/coldBootV2.ts +426 -0
  108. package/src/boot/deviceBootReturn.ts +195 -0
  109. package/src/crypto/__tests__/sharedDeviceToken.test.ts +24 -0
  110. package/src/crypto/keyManager.ts +101 -0
  111. package/src/i18n/locales/en-US.json +13 -1
  112. package/src/i18n/locales/es-ES.json +13 -1
  113. package/src/index.ts +75 -65
  114. package/src/mixins/OxyServices.accounts.ts +27 -39
  115. package/src/mixins/OxyServices.auth.ts +78 -253
  116. package/src/mixins/OxyServices.deviceBoot.ts +146 -0
  117. package/src/mixins/__tests__/OxyServices.deviceBoot.test.ts +107 -0
  118. package/src/mixins/__tests__/accounts.test.ts +17 -44
  119. package/src/mixins/__tests__/passwordSignIn.test.ts +91 -0
  120. package/src/mixins/index.ts +10 -23
  121. package/src/models/interfaces.ts +0 -79
  122. package/src/models/session.ts +4 -5
  123. package/src/server/index.ts +1 -1
  124. package/src/session/SessionClient.ts +53 -2
  125. package/src/session/__tests__/SessionClient.additive.test.ts +92 -0
  126. package/src/session/__tests__/SessionClient.rest.test.ts +25 -0
  127. package/src/session/__tests__/SessionClient.state.test.ts +18 -5
  128. package/src/session/__tests__/authStateStore.test.ts +209 -0
  129. package/src/session/__tests__/refresh.test.ts +256 -0
  130. package/src/session/authStateStore.ts +335 -0
  131. package/src/session/refresh.ts +334 -0
  132. package/src/shared/utils/debugUtils.ts +3 -3
  133. package/src/utils/__tests__/authWebUrl.test.ts +5 -40
  134. package/src/utils/__tests__/registrableApex.test.ts +62 -0
  135. package/src/utils/__tests__/validationUtils.test.ts +30 -0
  136. package/src/utils/accountUtils.ts +2 -65
  137. package/src/utils/authWebUrl.ts +9 -39
  138. package/src/utils/coldBoot.ts +17 -14
  139. package/src/utils/platform.ts +21 -0
  140. package/src/utils/registrableApex.ts +45 -0
  141. package/src/utils/ssoBounce.ts +14 -393
  142. package/src/utils/validationUtils.ts +62 -0
  143. package/dist/cjs/AuthManager.js +0 -1110
  144. package/dist/cjs/AuthManagerTypes.js +0 -13
  145. package/dist/cjs/CrossDomainAuth.js +0 -206
  146. package/dist/cjs/mixins/OxyServices.fedcm.js +0 -823
  147. package/dist/cjs/mixins/OxyServices.redirect.js +0 -95
  148. package/dist/cjs/mixins/OxyServices.silent.js +0 -204
  149. package/dist/cjs/mixins/OxyServices.sso.js +0 -208
  150. package/dist/cjs/utils/fapiAutoDetect.js +0 -99
  151. package/dist/cjs/utils/ssoEstablish.js +0 -110
  152. package/dist/cjs/utils/ssoReturn.js +0 -275
  153. package/dist/esm/AuthManager.js +0 -1105
  154. package/dist/esm/AuthManagerTypes.js +0 -12
  155. package/dist/esm/CrossDomainAuth.js +0 -201
  156. package/dist/esm/mixins/OxyServices.fedcm.js +0 -821
  157. package/dist/esm/mixins/OxyServices.redirect.js +0 -92
  158. package/dist/esm/mixins/OxyServices.silent.js +0 -202
  159. package/dist/esm/mixins/OxyServices.sso.js +0 -204
  160. package/dist/esm/utils/fapiAutoDetect.js +0 -95
  161. package/dist/esm/utils/ssoEstablish.js +0 -107
  162. package/dist/esm/utils/ssoReturn.js +0 -271
  163. package/dist/types/AuthManager.d.ts +0 -380
  164. package/dist/types/AuthManagerTypes.d.ts +0 -81
  165. package/dist/types/CrossDomainAuth.d.ts +0 -164
  166. package/dist/types/mixins/OxyServices.fedcm.d.ts +0 -331
  167. package/dist/types/mixins/OxyServices.redirect.d.ts +0 -92
  168. package/dist/types/mixins/OxyServices.silent.d.ts +0 -132
  169. package/dist/types/mixins/OxyServices.sso.d.ts +0 -138
  170. package/dist/types/utils/fapiAutoDetect.d.ts +0 -56
  171. package/dist/types/utils/ssoEstablish.d.ts +0 -85
  172. package/dist/types/utils/ssoReturn.d.ts +0 -156
  173. package/src/AuthManager.ts +0 -1269
  174. package/src/AuthManagerTypes.ts +0 -86
  175. package/src/CrossDomainAuth.ts +0 -243
  176. package/src/__tests__/authManager.cookiePath.test.ts +0 -390
  177. package/src/__tests__/authManager.security.test.ts +0 -377
  178. package/src/__tests__/crossDomainAuth.test.ts +0 -116
  179. package/src/__tests__/establishDeviceRefreshSlot.test.ts +0 -221
  180. package/src/mixins/OxyServices.fedcm.ts +0 -1026
  181. package/src/mixins/OxyServices.redirect.ts +0 -122
  182. package/src/mixins/OxyServices.silent.ts +0 -272
  183. package/src/mixins/OxyServices.sso.ts +0 -261
  184. package/src/mixins/__tests__/constructorAuthWebUrl.test.ts +0 -85
  185. package/src/mixins/__tests__/fedcm.test.ts +0 -667
  186. package/src/mixins/__tests__/sessionBaseUrl.test.ts +0 -61
  187. package/src/mixins/__tests__/silent.test.ts +0 -102
  188. package/src/mixins/__tests__/sso.test.ts +0 -228
  189. package/src/utils/__tests__/consumeSsoReturn.test.ts +0 -816
  190. package/src/utils/__tests__/fapiAutoDetect.test.ts +0 -183
  191. package/src/utils/__tests__/ssoBounce.test.ts +0 -219
  192. package/src/utils/__tests__/ssoEstablish.test.ts +0 -204
  193. package/src/utils/__tests__/ssoReturn.test.ts +0 -276
  194. package/src/utils/fapiAutoDetect.ts +0 -91
  195. package/src/utils/ssoEstablish.ts +0 -174
  196. package/src/utils/ssoReturn.ts +0 -389
@@ -1,380 +0,0 @@
1
- /**
2
- * AuthManager - Centralized Authentication Manager
3
- *
4
- * Provides a unified authentication interface for all platforms.
5
- * Handles token storage, session management, and auth state changes.
6
- *
7
- * @module core/AuthManager
8
- */
9
- import type { OxyServices } from './OxyServices';
10
- import type { SessionLoginResponse, MinimalUserData } from './models/session';
11
- import type { AuthManagerAccount, RestoreFromCookiesResult, RestoreFromCookiesOptions, SwitchAuthuserResult } from './AuthManagerTypes';
12
- /**
13
- * Storage adapter interface for platform-agnostic storage.
14
- */
15
- export interface StorageAdapter {
16
- getItem: (key: string) => Promise<string | null> | string | null;
17
- setItem: (key: string, value: string) => Promise<void> | void;
18
- removeItem: (key: string) => Promise<void> | void;
19
- }
20
- /**
21
- * Auth state change callback type.
22
- */
23
- export type AuthStateChangeCallback = (user: MinimalUserData | null) => void;
24
- /**
25
- * Auth method types.
26
- */
27
- export type AuthMethod = 'fedcm' | 'redirect' | 'credentials' | 'identity';
28
- /**
29
- * Auth manager configuration.
30
- */
31
- export interface AuthManagerConfig {
32
- /** Storage adapter (localStorage, AsyncStorage, etc.) */
33
- storage?: StorageAdapter;
34
- /** Whether to auto-refresh tokens */
35
- autoRefresh?: boolean;
36
- /** Token refresh interval in milliseconds (default: 5 minutes before expiry) */
37
- refreshBuffer?: number;
38
- /** Enable cross-tab coordination via BroadcastChannel (default: true in browsers) */
39
- crossTabSync?: boolean;
40
- }
41
- /**
42
- * AuthManager - Centralized authentication management.
43
- *
44
- * Provides a single point of control for:
45
- * - Token storage and retrieval
46
- * - Session management
47
- * - Auth state change notifications
48
- * - Multiple auth method support
49
- *
50
- * @example
51
- * ```typescript
52
- * const authManager = new AuthManager(oxyServices);
53
- *
54
- * // Listen for auth changes
55
- * authManager.onAuthStateChange((user) => {
56
- * console.log('Auth state changed:', user);
57
- * });
58
- *
59
- * // Handle successful auth
60
- * await authManager.handleAuthSuccess(session);
61
- *
62
- * // Sign out
63
- * await authManager.signOut();
64
- * ```
65
- */
66
- export declare class AuthManager {
67
- private oxyServices;
68
- private storage;
69
- private listeners;
70
- private currentUser;
71
- private currentAuthMethod;
72
- private refreshTimer;
73
- private refreshPromise;
74
- private config;
75
- /** Tracks the access token this instance last knew about, for cross-tab adoption. */
76
- private _lastKnownAccessToken;
77
- /** BroadcastChannel for coordinating token refreshes across browser tabs. */
78
- private _broadcastChannel;
79
- /**
80
- * Identifier for this AuthManager instance (≈ "this tab"). Random hex
81
- * generated at construction; advertised in every outgoing broadcast and
82
- * used as the lookup key in `_knownPeerNonces`.
83
- */
84
- private readonly _tabId;
85
- /**
86
- * Per-tab nonce, advertised in every outgoing broadcast. Receivers record
87
- * the first (tabId, nonce) pair they see from a given peer; subsequent
88
- * messages from the same tabId MUST carry the same nonce or they're
89
- * ignored.
90
- *
91
- * Threat model: a same-origin XSS payload can post to the channel but can
92
- * NOT read this instance's private `_broadcastNonce` field (it lives in
93
- * closure, not on `window`). Forged broadcasts from XSS therefore can't
94
- * impersonate this tab. A new attacker-controlled tabId trips the
95
- * "first message from a new peer" branch, which is by definition trusted
96
- * — so the gate raises the bar but is not a complete defence (a perfect
97
- * mitigation would require message signing with a server-issued key).
98
- */
99
- private readonly _broadcastNonce;
100
- /**
101
- * Bounded LRU of `(tabId → nonce)` pairs seen on inbound broadcasts. First
102
- * sighting of a new tabId records its nonce; later messages from that
103
- * tabId are rejected if the nonce doesn't match.
104
- */
105
- private readonly _knownPeerNonces;
106
- private static readonly _MAX_KNOWN_PEERS;
107
- /**
108
- * In-flight `switchAuthuser` promise. Deduplicates concurrent calls so two
109
- * near-simultaneous switches don't both fire refresh requests and rotate
110
- * the slot twice. Mirrors the `refreshPromise` pattern used by
111
- * `refreshToken`.
112
- */
113
- private _switchPromise;
114
- /**
115
- * Last `restoreFromCookies()` completion timestamp, keyed by the
116
- * AuthManager's active authuser at the time of completion. Used to gate
117
- * cross-tab cascade: a flurry of BroadcastChannel events from sibling
118
- * tabs can otherwise trigger N back-to-back snapshots and rotate every
119
- * slot's access token N times.
120
- */
121
- private readonly _lastRestoreAt;
122
- private static readonly _RESTORE_DEBOUNCE_MS;
123
- /**
124
- * In-memory registry of every device-local account the AuthManager knows
125
- * about, keyed by `authuser` slot index. Populated by:
126
- * - `restoreFromCookies()` (cold boot)
127
- * - `switchAuthuser()` (per-account rotation)
128
- * - `handleAuthSuccess()` (fresh login when the server response carries
129
- * an `authuser` field)
130
- * Access tokens live ONLY here in the cookie path — they are never
131
- * persisted to localStorage.
132
- */
133
- private accounts;
134
- /**
135
- * Currently-active `authuser` slot in the cookie path. `null` means either
136
- * the cookie path hasn't been initialised yet, or no slots are signed in.
137
- */
138
- private activeAuthuser;
139
- constructor(oxyServices: OxyServices, config?: AuthManagerConfig);
140
- /**
141
- * Initialize BroadcastChannel for cross-tab token refresh coordination.
142
- * Only called in browser environments where BroadcastChannel is available.
143
- */
144
- private _initBroadcastChannel;
145
- /**
146
- * Handle messages from other tabs about token refresh activity.
147
- */
148
- private _handleCrossTabMessage;
149
- /**
150
- * Broadcast a message to other tabs. Always stamps this tab's `tabId` and
151
- * `nonce` onto the message so receivers can run the cross-tab nonce gate.
152
- */
153
- private _broadcast;
154
- /**
155
- * Generate `bytes` bytes of cryptographic randomness encoded as lowercase
156
- * hex. Prefers Web Crypto's `getRandomValues` when available (browser /
157
- * modern Node); falls back to `Math.random` ONLY in environments without
158
- * Web Crypto (the resulting nonce is still unguessable to a same-origin
159
- * XSS payload — the goal is unforgeability across tabs, not cryptographic
160
- * secrecy across the network).
161
- */
162
- private static _randomHex;
163
- /**
164
- * Validate an inbound broadcast against the cross-tab nonce gate.
165
- *
166
- * Returns `true` when the message should be honoured, `false` when it
167
- * MUST be ignored:
168
- * - Message is missing `tabId` or `nonce` → ignore (forged or
169
- * mismatched-version sibling tab).
170
- * - First sighting of `tabId` → record the nonce and honour the message
171
- * (trust-on-first-use, the best we can do without a shared secret).
172
- * - Subsequent message from the same `tabId` with the SAME nonce →
173
- * honour.
174
- * - Subsequent message from the same `tabId` with a DIFFERENT nonce →
175
- * ignore (the canonical "forged broadcast" case — a same-origin XSS
176
- * payload can't read the real tab's `_broadcastNonce`).
177
- *
178
- * Echoes of this tab's own broadcasts (same `tabId`) are also dropped so
179
- * we don't react to our own messages.
180
- */
181
- private _acceptBroadcast;
182
- /**
183
- * Get default storage based on environment.
184
- */
185
- private getDefaultStorage;
186
- /**
187
- * Subscribe to auth state changes.
188
- *
189
- * @param callback - Function called when auth state changes
190
- * @returns Unsubscribe function
191
- */
192
- onAuthStateChange(callback: AuthStateChangeCallback): () => void;
193
- /**
194
- * Notify all listeners of auth state change.
195
- */
196
- private notifyListeners;
197
- /**
198
- * Handle successful authentication.
199
- *
200
- * @param session - Session response from auth
201
- * @param method - Auth method used
202
- */
203
- handleAuthSuccess(session: SessionLoginResponse, method?: AuthMethod): Promise<void>;
204
- /**
205
- * Refresh the access token. Deduplicates concurrent calls so only one
206
- * refresh request is in-flight at a time. The only refresh authority is the
207
- * active httpOnly refresh-cookie slot; this method never reads access tokens
208
- * from storage.
209
- */
210
- refreshToken(): Promise<boolean>;
211
- private _doRefreshToken;
212
- /**
213
- * Sign out and clear all auth data.
214
- */
215
- signOut(): Promise<void>;
216
- /**
217
- * Clear local cookie-path state. The only persisted AuthManager value is the
218
- * active numeric slot; tokens and user objects are intentionally memory-only.
219
- */
220
- private clearSession;
221
- /**
222
- * Get current user.
223
- */
224
- getCurrentUser(): MinimalUserData | null;
225
- /**
226
- * Check if user is authenticated.
227
- */
228
- isAuthenticated(): boolean;
229
- /**
230
- * Get a valid access token, refreshing automatically if expired or expiring
231
- * soon. The token is read from memory only.
232
- */
233
- getAccessToken(): Promise<string | null>;
234
- /**
235
- * Get the auth method used for current session.
236
- */
237
- getAuthMethod(): Promise<AuthMethod | null>;
238
- /**
239
- * Initialize auth state on app startup.
240
- *
241
- * Only the cookie path is authoritative. `restoreFromCookies()` refreshes
242
- * the httpOnly `oxy_rt_${authuser}` slots through `/auth/refresh-all`,
243
- * plants the active access token in memory, and returns the active user.
244
- * No access token, refresh token, or session JSON is read from localStorage.
245
- *
246
- * Returns the active user on success, or `null` when no cookie-backed
247
- * account was restored.
248
- */
249
- initialize(options?: RestoreFromCookiesOptions): Promise<MinimalUserData | null>;
250
- /**
251
- * Read the persisted active `authuser` slot index. Returns `null` when
252
- * none is persisted, the value is corrupt, or the storage adapter has no
253
- * record. Storage failures are non-fatal: the cookie path falls back to
254
- * "lowest authuser" deterministic selection.
255
- */
256
- private readActiveAuthuser;
257
- /**
258
- * Persist the active `authuser` slot index. No-ops on storage failure
259
- * (e.g. Safari private mode, native SecureStore unavailable) — this is
260
- * best-effort UX persistence, not authoritative state.
261
- */
262
- private writeActiveAuthuser;
263
- /**
264
- * Clear the persisted active `authuser` so the next cold boot starts from
265
- * a clean slate (used on full sign-out).
266
- */
267
- private clearActiveAuthuser;
268
- /**
269
- * Build a `MinimalUserData` from a `RefreshAllAccount`. Returns `null` when
270
- * the wire entry has no user shape; the AuthManager's caller is expected to
271
- * hydrate via `/users/me` in that case.
272
- */
273
- private static toMinimalUser;
274
- /**
275
- * Hydrate the user shape for a slot whose AuthManagerAccount currently has
276
- * `user: null` (for example, a switch onto a previously unknown slot). Calls
277
- * `/users/me` with the slot's freshly-planted access
278
- * token already on the HTTP client; merges the result back into the
279
- * registry entry. Network failures are non-fatal — the slot remains with
280
- * `user: null` and the UI is expected to render the public-key fallback
281
- * handle until a later restore picks the real user shape up.
282
- */
283
- private _hydrateUnknownUser;
284
- /**
285
- * Snapshot of the registered cookie-path accounts, sorted by `authuser`
286
- * ascending (canonical order). Mutating the returned array does not
287
- * affect AuthManager state.
288
- */
289
- getAccounts(): AuthManagerAccount[];
290
- /**
291
- * The slot index that is currently active in the cookie path, or `null`
292
- * if the cookie path hasn't been initialised or no slots are signed in.
293
- */
294
- getActiveAuthuser(): number | null;
295
- /**
296
- * Convenience: the AuthManagerAccount currently flagged active.
297
- */
298
- getActiveAccount(): AuthManagerAccount | null;
299
- /**
300
- * Restore every device-local account from the httpOnly refresh cookies.
301
- *
302
- * Calls `oxyServices.refreshAllSessions()` (`POST /auth/refresh-all` with
303
- * `credentials: 'include'`). The server rotates every presented
304
- * `oxy_rt_${authuser}` cookie in parallel and returns one entry per
305
- * valid slot.
306
- *
307
- * Plants the active account's access token on the shared HTTP client;
308
- * sibling slots' tokens stay in the in-memory registry so a later
309
- * `switchAuthuser()` can hot-swap them without a network round-trip.
310
- *
311
- * The persisted `oxy_active_authuser` slot wins when it matches a
312
- * returned account; otherwise the lowest returned `authuser` is chosen
313
- * deterministically.
314
- *
315
- * Returns `{ accounts: [], activeAuthuser: null }` on any failure or
316
- * empty snapshot — callers treat that as "no signed-in accounts" and
317
- * proceed unauthenticated. State is NOT cleared on failure; existing
318
- * accounts (if any) remain intact.
319
- */
320
- restoreFromCookies(options?: RestoreFromCookiesOptions): Promise<RestoreFromCookiesResult>;
321
- /**
322
- * Switch the active account to a different device-local slot.
323
- *
324
- * Calls `oxyServices.refreshTokenViaCookie({ authuser })` to mint a fresh
325
- * access token from the slot's httpOnly cookie, updates the in-memory
326
- * registry entry, plants the token on the HTTP client, persists the new
327
- * active slot, and broadcasts cross-tab.
328
- *
329
- * Throws when the slot's refresh cookie is missing / expired / reused
330
- * (the SDK returns `null` from `refreshTokenViaCookie` in that case, and
331
- * we surface it as an `Error` so callers can clean up the slot from
332
- * their UI).
333
- */
334
- switchAuthuser(authuser: number): Promise<SwitchAuthuserResult>;
335
- private _doSwitchAuthuser;
336
- /**
337
- * Sign out a single device-local slot.
338
- *
339
- * Calls `oxyServices.logoutSessionByAuthuser(authuser)`: server-side
340
- * revokes the slot's refresh-token family and clears the
341
- * `oxy_rt_${authuser}` cookie via `Set-Cookie`. The slot is removed from
342
- * the in-memory registry. If the slot was active, the next lowest
343
- * remaining authuser becomes active (or `null` when none remain).
344
- */
345
- signOutAuthuser(authuser: number): Promise<void>;
346
- /**
347
- * Sign out EVERY device-local account on this device.
348
- *
349
- * Calls `oxyServices.logoutAllSessionsViaCookie()`: server-side revokes
350
- * every presented family and `Set-Cookie`s an immediate expiry for every
351
- * recognised `oxy_rt_${n}` slot. The in-memory registry is wiped, the active
352
- * slot is cleared, and the persisted `oxy_active_authuser` is removed so the
353
- * next cold boot starts fresh.
354
- */
355
- signOutAllViaCookies(): Promise<void>;
356
- /**
357
- * Schedule an auto-refresh for the cookie path on the active slot. The
358
- * AuthManager has exactly one active slot at a time, so one timer suffices.
359
- */
360
- private setupCookieRefresh;
361
- /**
362
- * Decode the session id from an unverified JWT access token. Decode-only
363
- * (no signature verification) — the server already verified the
364
- * signature when minting the token. Returns `null` on malformed input.
365
- */
366
- private static decodeSessionIdFromAccessToken;
367
- private static decodeAuthuserFromAccessToken;
368
- /**
369
- * Destroy the auth manager and clean up resources.
370
- */
371
- destroy(): void;
372
- }
373
- /**
374
- * Create an AuthManager instance.
375
- *
376
- * @param oxyServices - OxyServices instance
377
- * @param config - Optional configuration
378
- * @returns AuthManager instance
379
- */
380
- export declare function createAuthManager(oxyServices: OxyServices, config?: AuthManagerConfig): AuthManager;
@@ -1,81 +0,0 @@
1
- /**
2
- * AuthManager — public types for the multi-account cookie path.
3
- *
4
- * Lives in its own module (rather than the 670-line `models/interfaces.ts`)
5
- * so consumers can `import type` exactly the multi-account surface without
6
- * pulling in the full interfaces graph, and so `AuthManager.ts` stays
7
- * decoupled from the wire shapes — these types re-state the wire as the
8
- * AuthManager's in-memory representation.
9
- *
10
- * @module core/AuthManagerTypes
11
- */
12
- import type { RefreshAllAccountUser } from './models/interfaces';
13
- /**
14
- * One device-local account known to `AuthManager` in the cookie path.
15
- *
16
- * Built from a `POST /auth/refresh-all` entry, OR from a single
17
- * `POST /auth/refresh?authuser=N` rotation after a switch, OR from a
18
- * `handleAuthSuccess` call after a fresh login. The `accessToken` is held in
19
- * memory only — the refresh token never enters JS (it lives in the httpOnly
20
- * `oxy_rt_${authuser}` cookie).
21
- */
22
- export interface AuthManagerAccount {
23
- /** Device-local cookie slot index (0..N-1). */
24
- authuser: number;
25
- /** Server-side session id this slot is bound to. */
26
- sessionId: string;
27
- /**
28
- * Projected user shape from the wire (username/avatar/color/email).
29
- *
30
- * `null` when a refresh-via-cookie planted a fresh access token for a slot
31
- * that the AuthManager has no prior in-memory user metadata for. Callers (or
32
- * the AuthManager itself) are expected to hydrate the user shape via
33
- * `getCurrentUser()` after the token is planted; the chooser UI must render
34
- * the public-key fallback handle until the hydration completes.
35
- */
36
- user: RefreshAllAccountUser | null;
37
- /** Currently-valid access token for this slot (in-memory only). */
38
- accessToken: string;
39
- /** ISO-8601 expiry of the access token. */
40
- expiresAt: string;
41
- }
42
- /**
43
- * Outcome of `AuthManager.restoreFromCookies()`.
44
- *
45
- * `accounts` is sorted by `authuser` ascending (matching the server's
46
- * canonical ordering). `activeAuthuser` is whichever slot the AuthManager
47
- * picked as active — usually the persisted `oxy_active_authuser` if it
48
- * matched a returned slot, otherwise the lowest returned `authuser`, or
49
- * `null` if no accounts were restored.
50
- */
51
- export interface RestoreFromCookiesResult {
52
- accounts: AuthManagerAccount[];
53
- activeAuthuser: number | null;
54
- }
55
- /**
56
- * Options for `AuthManager.restoreFromCookies()` / `AuthManager.initialize()`.
57
- */
58
- export interface RestoreFromCookiesOptions {
59
- /**
60
- * Abort the underlying `POST /auth/refresh-all` after this many milliseconds
61
- * and treat it as "no signed-in accounts" instead of hanging. Forwarded
62
- * verbatim to `OxyServices.refreshAllSessions({ timeout })`.
63
- *
64
- * Intended for the cold-boot cookie-restore step on a cross-domain RP, where
65
- * the `Domain=oxy.so` refresh cookie never reaches `api.<apex>` and the
66
- * request can stall with no useful answer. Omit (the default) to wait
67
- * indefinitely — the warm cross-tab cascade path passes nothing, preserving
68
- * its existing behaviour.
69
- */
70
- timeout?: number;
71
- }
72
- /**
73
- * Outcome of `AuthManager.switchAuthuser()`.
74
- *
75
- * Mirrors the wire `RefreshCookieResponse`.
76
- */
77
- export interface SwitchAuthuserResult {
78
- accessToken: string;
79
- expiresAt: string;
80
- authuser: number;
81
- }
@@ -1,164 +0,0 @@
1
- /**
2
- * Cross-Domain Authentication Helper
3
- *
4
- * Provides a simplified API for cross-domain SSO authentication. The
5
- * automatic sign-in path uses a full-page redirect through the central IdP
6
- * (`auth.oxy.so`) — a tokenless, universal mechanism that works in every
7
- * browser.
8
- *
9
- * FedCM (`signInWithFedCM`) is intentionally NOT part of the automatic
10
- * (`'auto'`) path: it is a Chrome-only browser API, and a misconfigured or
11
- * unreachable FedCM endpoint fails fast and silently, which — combined with a
12
- * caller's auth-guard effect re-invoking `signIn()` whenever the user is still
13
- * unauthenticated — produced a real production incident (an accelerating
14
- * `autoSignIn` → FedCM-fails → redirect retry loop). `signInWithFedCM` remains
15
- * available for callers that want to opt into it EXPLICITLY
16
- * (`signIn({ method: 'fedcm' })`).
17
- *
18
- * Usage:
19
- * ```typescript
20
- * import { CrossDomainAuth } from '@oxyhq/core';
21
- *
22
- * const auth = new CrossDomainAuth(oxyServices);
23
- *
24
- * // Automatic method selection (always redirect)
25
- * const session = await auth.signIn();
26
- *
27
- * // Or use a specific method
28
- * auth.signInWithRedirect();
29
- * ```
30
- */
31
- import type { OxyServices } from './OxyServices';
32
- import type { SessionLoginResponse } from './models/session';
33
- export interface CrossDomainAuthOptions {
34
- /**
35
- * Preferred authentication method
36
- * - 'auto': Automatically select best method (default)
37
- * - 'fedcm': Use FedCM (browser-native)
38
- * - 'redirect': Use full-page redirect
39
- */
40
- method?: 'auto' | 'fedcm' | 'redirect';
41
- /**
42
- * Custom redirect URI (for redirect method)
43
- */
44
- redirectUri?: string;
45
- /**
46
- * Whether to open signup page instead of login
47
- */
48
- isSignup?: boolean;
49
- /**
50
- * Callback when auth method is selected
51
- */
52
- onMethodSelected?: (method: 'fedcm' | 'redirect') => void;
53
- }
54
- export declare class CrossDomainAuth {
55
- private oxyServices;
56
- constructor(oxyServices: OxyServices);
57
- /**
58
- * Sign in with automatic method selection.
59
- *
60
- * Auto mode always uses the full-page redirect (see the class doc comment
61
- * for why FedCM was removed from this path). Pass `{ method: 'fedcm' }` to
62
- * opt into FedCM explicitly.
63
- *
64
- * @param options - Authentication options
65
- * @returns Session with user data and access token
66
- */
67
- signIn(options?: CrossDomainAuthOptions): Promise<SessionLoginResponse | null>;
68
- /**
69
- * Automatic sign-in.
70
- *
71
- * Goes straight to the full-page redirect — the sole automatic method.
72
- * FedCM is deliberately NOT attempted here (see the class doc comment):
73
- * it is Chrome-only, and its fast/silent failure mode combined with a
74
- * caller's auth-guard effect re-invoking `signIn()` produced a real
75
- * production sign-in loop. Use `signIn({ method: 'fedcm' })` to opt in
76
- * explicitly.
77
- *
78
- * @private
79
- */
80
- private autoSignIn;
81
- /**
82
- * Sign in using FedCM (Federated Credential Management)
83
- *
84
- * Best method - browser-native, Google-like experience
85
- */
86
- signInWithFedCM(options?: CrossDomainAuthOptions): Promise<SessionLoginResponse>;
87
- /**
88
- * Sign in using full-page redirect
89
- *
90
- * Fallback method - works everywhere but loses app state
91
- */
92
- signInWithRedirect(options?: CrossDomainAuthOptions): void;
93
- /**
94
- * Handle redirect callback
95
- *
96
- * Call this on app startup to check if we're returning from auth redirect
97
- */
98
- handleRedirectCallback(): SessionLoginResponse | null;
99
- /**
100
- * Silent sign-in (check for existing session)
101
- *
102
- * Tries to automatically sign in without user interaction, via the
103
- * iframe-based silent auth against the per-apex `/auth/silent` IdP host.
104
- * FedCM is deliberately NOT attempted here (see the class doc comment).
105
- *
106
- * @returns Session if user is already signed in, null otherwise
107
- */
108
- silentSignIn(): Promise<SessionLoginResponse | null>;
109
- /**
110
- * Restore session from storage.
111
- *
112
- * Access tokens are no longer persisted in browser storage; providers restore
113
- * through refresh cookies / SSO code exchange instead.
114
- */
115
- restoreSession(): boolean;
116
- /**
117
- * Check if FedCM is supported in current browser
118
- */
119
- isFedCMSupported(): boolean;
120
- /**
121
- * Get recommended authentication method for current environment
122
- *
123
- * Redirect is the sole recommended automatic method — it works in every
124
- * browser, unlike FedCM (Chrome-only). Callers that want FedCM must opt in
125
- * explicitly via `signIn({ method: 'fedcm' })`.
126
- *
127
- * @returns Recommended method name and reason
128
- */
129
- getRecommendedMethod(): {
130
- method: 'redirect';
131
- reason: string;
132
- };
133
- /**
134
- * Initialize cross-domain auth on app startup
135
- *
136
- * This handles:
137
- * 1. Redirect callback (if returning from auth.oxy.so)
138
- * 2. Silent sign-in (check for existing SSO session)
139
- *
140
- * @returns Session if user is authenticated, null otherwise
141
- */
142
- initialize(): Promise<SessionLoginResponse | null>;
143
- }
144
- /**
145
- * Helper function to create CrossDomainAuth instance
146
- *
147
- * @example
148
- * ```typescript
149
- * import { createCrossDomainAuth } from '@oxyhq/core';
150
- *
151
- * const oxyServices = new OxyServices({ baseURL: 'https://api.oxy.so' });
152
- * const auth = createCrossDomainAuth(oxyServices);
153
- *
154
- * // On app startup
155
- * const session = await auth.initialize();
156
- * if (session) {
157
- * console.log('User is signed in:', session.user);
158
- * }
159
- *
160
- * // Sign in button click
161
- * const session = await auth.signIn();
162
- * ```
163
- */
164
- export declare function createCrossDomainAuth(oxyServices: OxyServices): CrossDomainAuth;