@oxyhq/core 1.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 (277) hide show
  1. package/README.md +50 -0
  2. package/dist/cjs/AuthManager.js +361 -0
  3. package/dist/cjs/CrossDomainAuth.js +258 -0
  4. package/dist/cjs/HttpService.js +618 -0
  5. package/dist/cjs/OxyServices.base.js +263 -0
  6. package/dist/cjs/OxyServices.errors.js +22 -0
  7. package/dist/cjs/OxyServices.js +63 -0
  8. package/dist/cjs/constants/version.js +16 -0
  9. package/dist/cjs/crypto/index.js +20 -0
  10. package/dist/cjs/crypto/keyManager.js +887 -0
  11. package/dist/cjs/crypto/polyfill.js +64 -0
  12. package/dist/cjs/crypto/recoveryPhrase.js +169 -0
  13. package/dist/cjs/crypto/signatureService.js +296 -0
  14. package/dist/cjs/i18n/index.js +73 -0
  15. package/dist/cjs/i18n/locales/ar-SA.json +120 -0
  16. package/dist/cjs/i18n/locales/ca-ES.json +120 -0
  17. package/dist/cjs/i18n/locales/de-DE.json +120 -0
  18. package/dist/cjs/i18n/locales/en-US.json +956 -0
  19. package/dist/cjs/i18n/locales/es-ES.json +944 -0
  20. package/dist/cjs/i18n/locales/fr-FR.json +120 -0
  21. package/dist/cjs/i18n/locales/it-IT.json +120 -0
  22. package/dist/cjs/i18n/locales/ja-JP.json +119 -0
  23. package/dist/cjs/i18n/locales/ko-KR.json +120 -0
  24. package/dist/cjs/i18n/locales/locales/ar-SA.json +120 -0
  25. package/dist/cjs/i18n/locales/locales/ca-ES.json +120 -0
  26. package/dist/cjs/i18n/locales/locales/de-DE.json +120 -0
  27. package/dist/cjs/i18n/locales/locales/en-US.json +956 -0
  28. package/dist/cjs/i18n/locales/locales/es-ES.json +944 -0
  29. package/dist/cjs/i18n/locales/locales/fr-FR.json +120 -0
  30. package/dist/cjs/i18n/locales/locales/it-IT.json +120 -0
  31. package/dist/cjs/i18n/locales/locales/ja-JP.json +119 -0
  32. package/dist/cjs/i18n/locales/locales/ko-KR.json +120 -0
  33. package/dist/cjs/i18n/locales/locales/pt-PT.json +120 -0
  34. package/dist/cjs/i18n/locales/locales/zh-CN.json +120 -0
  35. package/dist/cjs/i18n/locales/pt-PT.json +120 -0
  36. package/dist/cjs/i18n/locales/zh-CN.json +120 -0
  37. package/dist/cjs/index.js +153 -0
  38. package/dist/cjs/mixins/OxyServices.analytics.js +49 -0
  39. package/dist/cjs/mixins/OxyServices.assets.js +380 -0
  40. package/dist/cjs/mixins/OxyServices.auth.js +259 -0
  41. package/dist/cjs/mixins/OxyServices.developer.js +97 -0
  42. package/dist/cjs/mixins/OxyServices.devices.js +116 -0
  43. package/dist/cjs/mixins/OxyServices.features.js +309 -0
  44. package/dist/cjs/mixins/OxyServices.fedcm.js +435 -0
  45. package/dist/cjs/mixins/OxyServices.karma.js +108 -0
  46. package/dist/cjs/mixins/OxyServices.language.js +154 -0
  47. package/dist/cjs/mixins/OxyServices.location.js +43 -0
  48. package/dist/cjs/mixins/OxyServices.payment.js +158 -0
  49. package/dist/cjs/mixins/OxyServices.popup.js +371 -0
  50. package/dist/cjs/mixins/OxyServices.privacy.js +162 -0
  51. package/dist/cjs/mixins/OxyServices.redirect.js +345 -0
  52. package/dist/cjs/mixins/OxyServices.security.js +81 -0
  53. package/dist/cjs/mixins/OxyServices.user.js +355 -0
  54. package/dist/cjs/mixins/OxyServices.utility.js +156 -0
  55. package/dist/cjs/mixins/index.js +79 -0
  56. package/dist/cjs/mixins/mixinHelpers.js +53 -0
  57. package/dist/cjs/models/interfaces.js +20 -0
  58. package/dist/cjs/models/session.js +2 -0
  59. package/dist/cjs/shared/index.js +70 -0
  60. package/dist/cjs/shared/utils/colorUtils.js +153 -0
  61. package/dist/cjs/shared/utils/debugUtils.js +73 -0
  62. package/dist/cjs/shared/utils/errorUtils.js +183 -0
  63. package/dist/cjs/shared/utils/index.js +49 -0
  64. package/dist/cjs/shared/utils/networkUtils.js +183 -0
  65. package/dist/cjs/shared/utils/themeUtils.js +106 -0
  66. package/dist/cjs/utils/apiUtils.js +61 -0
  67. package/dist/cjs/utils/asyncUtils.js +194 -0
  68. package/dist/cjs/utils/cache.js +226 -0
  69. package/dist/cjs/utils/deviceManager.js +205 -0
  70. package/dist/cjs/utils/errorUtils.js +154 -0
  71. package/dist/cjs/utils/index.js +26 -0
  72. package/dist/cjs/utils/languageUtils.js +165 -0
  73. package/dist/cjs/utils/loggerUtils.js +126 -0
  74. package/dist/cjs/utils/platform.js +144 -0
  75. package/dist/cjs/utils/requestUtils.js +209 -0
  76. package/dist/cjs/utils/sessionUtils.js +181 -0
  77. package/dist/cjs/utils/validationUtils.js +173 -0
  78. package/dist/esm/AuthManager.js +356 -0
  79. package/dist/esm/CrossDomainAuth.js +253 -0
  80. package/dist/esm/HttpService.js +614 -0
  81. package/dist/esm/OxyServices.base.js +259 -0
  82. package/dist/esm/OxyServices.errors.js +17 -0
  83. package/dist/esm/OxyServices.js +59 -0
  84. package/dist/esm/constants/version.js +13 -0
  85. package/dist/esm/crypto/index.js +13 -0
  86. package/dist/esm/crypto/keyManager.js +850 -0
  87. package/dist/esm/crypto/polyfill.js +61 -0
  88. package/dist/esm/crypto/recoveryPhrase.js +132 -0
  89. package/dist/esm/crypto/signatureService.js +259 -0
  90. package/dist/esm/i18n/index.js +69 -0
  91. package/dist/esm/i18n/locales/ar-SA.json +120 -0
  92. package/dist/esm/i18n/locales/ca-ES.json +120 -0
  93. package/dist/esm/i18n/locales/de-DE.json +120 -0
  94. package/dist/esm/i18n/locales/en-US.json +956 -0
  95. package/dist/esm/i18n/locales/es-ES.json +944 -0
  96. package/dist/esm/i18n/locales/fr-FR.json +120 -0
  97. package/dist/esm/i18n/locales/it-IT.json +120 -0
  98. package/dist/esm/i18n/locales/ja-JP.json +119 -0
  99. package/dist/esm/i18n/locales/ko-KR.json +120 -0
  100. package/dist/esm/i18n/locales/locales/ar-SA.json +120 -0
  101. package/dist/esm/i18n/locales/locales/ca-ES.json +120 -0
  102. package/dist/esm/i18n/locales/locales/de-DE.json +120 -0
  103. package/dist/esm/i18n/locales/locales/en-US.json +956 -0
  104. package/dist/esm/i18n/locales/locales/es-ES.json +944 -0
  105. package/dist/esm/i18n/locales/locales/fr-FR.json +120 -0
  106. package/dist/esm/i18n/locales/locales/it-IT.json +120 -0
  107. package/dist/esm/i18n/locales/locales/ja-JP.json +119 -0
  108. package/dist/esm/i18n/locales/locales/ko-KR.json +120 -0
  109. package/dist/esm/i18n/locales/locales/pt-PT.json +120 -0
  110. package/dist/esm/i18n/locales/locales/zh-CN.json +120 -0
  111. package/dist/esm/i18n/locales/pt-PT.json +120 -0
  112. package/dist/esm/i18n/locales/zh-CN.json +120 -0
  113. package/dist/esm/index.js +55 -0
  114. package/dist/esm/mixins/OxyServices.analytics.js +46 -0
  115. package/dist/esm/mixins/OxyServices.assets.js +377 -0
  116. package/dist/esm/mixins/OxyServices.auth.js +256 -0
  117. package/dist/esm/mixins/OxyServices.developer.js +94 -0
  118. package/dist/esm/mixins/OxyServices.devices.js +113 -0
  119. package/dist/esm/mixins/OxyServices.features.js +306 -0
  120. package/dist/esm/mixins/OxyServices.fedcm.js +433 -0
  121. package/dist/esm/mixins/OxyServices.karma.js +105 -0
  122. package/dist/esm/mixins/OxyServices.language.js +118 -0
  123. package/dist/esm/mixins/OxyServices.location.js +40 -0
  124. package/dist/esm/mixins/OxyServices.payment.js +155 -0
  125. package/dist/esm/mixins/OxyServices.popup.js +369 -0
  126. package/dist/esm/mixins/OxyServices.privacy.js +159 -0
  127. package/dist/esm/mixins/OxyServices.redirect.js +343 -0
  128. package/dist/esm/mixins/OxyServices.security.js +78 -0
  129. package/dist/esm/mixins/OxyServices.user.js +352 -0
  130. package/dist/esm/mixins/OxyServices.utility.js +153 -0
  131. package/dist/esm/mixins/index.js +76 -0
  132. package/dist/esm/mixins/mixinHelpers.js +48 -0
  133. package/dist/esm/models/interfaces.js +17 -0
  134. package/dist/esm/models/session.js +1 -0
  135. package/dist/esm/shared/index.js +31 -0
  136. package/dist/esm/shared/utils/colorUtils.js +143 -0
  137. package/dist/esm/shared/utils/debugUtils.js +65 -0
  138. package/dist/esm/shared/utils/errorUtils.js +170 -0
  139. package/dist/esm/shared/utils/index.js +15 -0
  140. package/dist/esm/shared/utils/networkUtils.js +173 -0
  141. package/dist/esm/shared/utils/themeUtils.js +98 -0
  142. package/dist/esm/utils/apiUtils.js +55 -0
  143. package/dist/esm/utils/asyncUtils.js +179 -0
  144. package/dist/esm/utils/cache.js +218 -0
  145. package/dist/esm/utils/deviceManager.js +168 -0
  146. package/dist/esm/utils/errorUtils.js +146 -0
  147. package/dist/esm/utils/index.js +7 -0
  148. package/dist/esm/utils/languageUtils.js +158 -0
  149. package/dist/esm/utils/loggerUtils.js +115 -0
  150. package/dist/esm/utils/platform.js +102 -0
  151. package/dist/esm/utils/requestUtils.js +203 -0
  152. package/dist/esm/utils/sessionUtils.js +171 -0
  153. package/dist/esm/utils/validationUtils.js +153 -0
  154. package/dist/types/AuthManager.d.ts +143 -0
  155. package/dist/types/CrossDomainAuth.d.ts +160 -0
  156. package/dist/types/HttpService.d.ts +163 -0
  157. package/dist/types/OxyServices.base.d.ts +126 -0
  158. package/dist/types/OxyServices.d.ts +81 -0
  159. package/dist/types/OxyServices.errors.d.ts +11 -0
  160. package/dist/types/constants/version.d.ts +13 -0
  161. package/dist/types/crypto/index.d.ts +11 -0
  162. package/dist/types/crypto/keyManager.d.ts +189 -0
  163. package/dist/types/crypto/polyfill.d.ts +11 -0
  164. package/dist/types/crypto/recoveryPhrase.d.ts +58 -0
  165. package/dist/types/crypto/signatureService.d.ts +86 -0
  166. package/dist/types/i18n/index.d.ts +3 -0
  167. package/dist/types/index.d.ts +50 -0
  168. package/dist/types/mixins/OxyServices.analytics.d.ts +66 -0
  169. package/dist/types/mixins/OxyServices.assets.d.ts +135 -0
  170. package/dist/types/mixins/OxyServices.auth.d.ts +186 -0
  171. package/dist/types/mixins/OxyServices.developer.d.ts +99 -0
  172. package/dist/types/mixins/OxyServices.devices.d.ts +96 -0
  173. package/dist/types/mixins/OxyServices.features.d.ts +228 -0
  174. package/dist/types/mixins/OxyServices.fedcm.d.ts +200 -0
  175. package/dist/types/mixins/OxyServices.karma.d.ts +85 -0
  176. package/dist/types/mixins/OxyServices.language.d.ts +81 -0
  177. package/dist/types/mixins/OxyServices.location.d.ts +64 -0
  178. package/dist/types/mixins/OxyServices.payment.d.ts +111 -0
  179. package/dist/types/mixins/OxyServices.popup.d.ts +205 -0
  180. package/dist/types/mixins/OxyServices.privacy.d.ts +122 -0
  181. package/dist/types/mixins/OxyServices.redirect.d.ts +245 -0
  182. package/dist/types/mixins/OxyServices.security.d.ts +78 -0
  183. package/dist/types/mixins/OxyServices.user.d.ts +182 -0
  184. package/dist/types/mixins/OxyServices.utility.d.ts +93 -0
  185. package/dist/types/mixins/index.d.ts +30 -0
  186. package/dist/types/mixins/mixinHelpers.d.ts +31 -0
  187. package/dist/types/models/interfaces.d.ts +415 -0
  188. package/dist/types/models/session.d.ts +27 -0
  189. package/dist/types/shared/index.d.ts +28 -0
  190. package/dist/types/shared/utils/colorUtils.d.ts +104 -0
  191. package/dist/types/shared/utils/debugUtils.d.ts +48 -0
  192. package/dist/types/shared/utils/errorUtils.d.ts +97 -0
  193. package/dist/types/shared/utils/index.d.ts +13 -0
  194. package/dist/types/shared/utils/networkUtils.d.ts +139 -0
  195. package/dist/types/shared/utils/themeUtils.d.ts +90 -0
  196. package/dist/types/utils/apiUtils.d.ts +53 -0
  197. package/dist/types/utils/asyncUtils.d.ts +58 -0
  198. package/dist/types/utils/cache.d.ts +127 -0
  199. package/dist/types/utils/deviceManager.d.ts +65 -0
  200. package/dist/types/utils/errorUtils.d.ts +46 -0
  201. package/dist/types/utils/index.d.ts +6 -0
  202. package/dist/types/utils/languageUtils.d.ts +37 -0
  203. package/dist/types/utils/loggerUtils.d.ts +48 -0
  204. package/dist/types/utils/platform.d.ts +40 -0
  205. package/dist/types/utils/requestUtils.d.ts +123 -0
  206. package/dist/types/utils/sessionUtils.d.ts +54 -0
  207. package/dist/types/utils/validationUtils.d.ts +85 -0
  208. package/package.json +84 -0
  209. package/src/AuthManager.ts +436 -0
  210. package/src/CrossDomainAuth.ts +307 -0
  211. package/src/HttpService.ts +752 -0
  212. package/src/OxyServices.base.ts +334 -0
  213. package/src/OxyServices.errors.ts +26 -0
  214. package/src/OxyServices.ts +129 -0
  215. package/src/constants/version.ts +15 -0
  216. package/src/crypto/index.ts +25 -0
  217. package/src/crypto/keyManager.ts +962 -0
  218. package/src/crypto/polyfill.ts +70 -0
  219. package/src/crypto/recoveryPhrase.ts +166 -0
  220. package/src/crypto/signatureService.ts +323 -0
  221. package/src/i18n/index.ts +75 -0
  222. package/src/i18n/locales/ar-SA.json +120 -0
  223. package/src/i18n/locales/ca-ES.json +120 -0
  224. package/src/i18n/locales/de-DE.json +120 -0
  225. package/src/i18n/locales/en-US.json +956 -0
  226. package/src/i18n/locales/es-ES.json +944 -0
  227. package/src/i18n/locales/fr-FR.json +120 -0
  228. package/src/i18n/locales/it-IT.json +120 -0
  229. package/src/i18n/locales/ja-JP.json +119 -0
  230. package/src/i18n/locales/ko-KR.json +120 -0
  231. package/src/i18n/locales/pt-PT.json +120 -0
  232. package/src/i18n/locales/zh-CN.json +120 -0
  233. package/src/index.ts +153 -0
  234. package/src/mixins/OxyServices.analytics.ts +53 -0
  235. package/src/mixins/OxyServices.assets.ts +412 -0
  236. package/src/mixins/OxyServices.auth.ts +358 -0
  237. package/src/mixins/OxyServices.developer.ts +114 -0
  238. package/src/mixins/OxyServices.devices.ts +119 -0
  239. package/src/mixins/OxyServices.features.ts +428 -0
  240. package/src/mixins/OxyServices.fedcm.ts +494 -0
  241. package/src/mixins/OxyServices.karma.ts +111 -0
  242. package/src/mixins/OxyServices.language.ts +127 -0
  243. package/src/mixins/OxyServices.location.ts +46 -0
  244. package/src/mixins/OxyServices.payment.ts +163 -0
  245. package/src/mixins/OxyServices.popup.ts +443 -0
  246. package/src/mixins/OxyServices.privacy.ts +182 -0
  247. package/src/mixins/OxyServices.redirect.ts +397 -0
  248. package/src/mixins/OxyServices.security.ts +103 -0
  249. package/src/mixins/OxyServices.user.ts +392 -0
  250. package/src/mixins/OxyServices.utility.ts +191 -0
  251. package/src/mixins/index.ts +91 -0
  252. package/src/mixins/mixinHelpers.ts +69 -0
  253. package/src/models/interfaces.ts +511 -0
  254. package/src/models/session.ts +30 -0
  255. package/src/shared/index.ts +82 -0
  256. package/src/shared/utils/colorUtils.ts +155 -0
  257. package/src/shared/utils/debugUtils.ts +73 -0
  258. package/src/shared/utils/errorUtils.ts +181 -0
  259. package/src/shared/utils/index.ts +59 -0
  260. package/src/shared/utils/networkUtils.ts +248 -0
  261. package/src/shared/utils/themeUtils.ts +115 -0
  262. package/src/types/bip39.d.ts +32 -0
  263. package/src/types/buffer.d.ts +97 -0
  264. package/src/types/color.d.ts +20 -0
  265. package/src/types/elliptic.d.ts +62 -0
  266. package/src/utils/apiUtils.ts +88 -0
  267. package/src/utils/asyncUtils.ts +252 -0
  268. package/src/utils/cache.ts +264 -0
  269. package/src/utils/deviceManager.ts +198 -0
  270. package/src/utils/errorUtils.ts +216 -0
  271. package/src/utils/index.ts +21 -0
  272. package/src/utils/languageUtils.ts +174 -0
  273. package/src/utils/loggerUtils.ts +153 -0
  274. package/src/utils/platform.ts +117 -0
  275. package/src/utils/requestUtils.ts +237 -0
  276. package/src/utils/sessionUtils.ts +206 -0
  277. package/src/utils/validationUtils.ts +174 -0
@@ -0,0 +1,436 @@
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
+
10
+ import type { OxyServices } from './OxyServices';
11
+ import type { HttpService } from './HttpService';
12
+ import type { SessionLoginResponse, MinimalUserData } from './models/session';
13
+
14
+ /**
15
+ * OxyServices with optional FedCM methods (provided by FedCM mixin).
16
+ */
17
+ interface OxyServicesWithFedCM extends OxyServices {
18
+ revokeFedCMCredential?: () => Promise<void>;
19
+ }
20
+
21
+ /**
22
+ * Storage adapter interface for platform-agnostic storage.
23
+ */
24
+ export interface StorageAdapter {
25
+ getItem: (key: string) => Promise<string | null> | string | null;
26
+ setItem: (key: string, value: string) => Promise<void> | void;
27
+ removeItem: (key: string) => Promise<void> | void;
28
+ }
29
+
30
+ /**
31
+ * Auth state change callback type.
32
+ */
33
+ export type AuthStateChangeCallback = (user: MinimalUserData | null) => void;
34
+
35
+ /**
36
+ * Auth method types.
37
+ */
38
+ export type AuthMethod = 'fedcm' | 'popup' | 'redirect' | 'credentials' | 'identity';
39
+
40
+ /**
41
+ * Auth manager configuration.
42
+ */
43
+ export interface AuthManagerConfig {
44
+ /** Storage adapter (localStorage, AsyncStorage, etc.) */
45
+ storage?: StorageAdapter;
46
+ /** Whether to auto-refresh tokens */
47
+ autoRefresh?: boolean;
48
+ /** Token refresh interval in milliseconds (default: 5 minutes before expiry) */
49
+ refreshBuffer?: number;
50
+ }
51
+
52
+ /**
53
+ * Storage keys used by AuthManager.
54
+ */
55
+ const STORAGE_KEYS = {
56
+ ACCESS_TOKEN: 'oxy_access_token',
57
+ REFRESH_TOKEN: 'oxy_refresh_token',
58
+ SESSION: 'oxy_session',
59
+ USER: 'oxy_user',
60
+ AUTH_METHOD: 'oxy_auth_method',
61
+ } as const;
62
+
63
+ /**
64
+ * Default in-memory storage for non-browser environments.
65
+ */
66
+ class MemoryStorage implements StorageAdapter {
67
+ private store = new Map<string, string>();
68
+
69
+ getItem(key: string): string | null {
70
+ return this.store.get(key) ?? null;
71
+ }
72
+
73
+ setItem(key: string, value: string): void {
74
+ this.store.set(key, value);
75
+ }
76
+
77
+ removeItem(key: string): void {
78
+ this.store.delete(key);
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Browser localStorage adapter.
84
+ */
85
+ class LocalStorageAdapter implements StorageAdapter {
86
+ getItem(key: string): string | null {
87
+ if (typeof window === 'undefined') return null;
88
+ try {
89
+ return localStorage.getItem(key);
90
+ } catch {
91
+ return null;
92
+ }
93
+ }
94
+
95
+ setItem(key: string, value: string): void {
96
+ if (typeof window === 'undefined') return;
97
+ try {
98
+ localStorage.setItem(key, value);
99
+ } catch {
100
+ // Storage full or blocked
101
+ }
102
+ }
103
+
104
+ removeItem(key: string): void {
105
+ if (typeof window === 'undefined') return;
106
+ try {
107
+ localStorage.removeItem(key);
108
+ } catch {
109
+ // Ignore errors
110
+ }
111
+ }
112
+ }
113
+
114
+ /**
115
+ * AuthManager - Centralized authentication management.
116
+ *
117
+ * Provides a single point of control for:
118
+ * - Token storage and retrieval
119
+ * - Session management
120
+ * - Auth state change notifications
121
+ * - Multiple auth method support
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * const authManager = new AuthManager(oxyServices);
126
+ *
127
+ * // Listen for auth changes
128
+ * authManager.onAuthStateChange((user) => {
129
+ * console.log('Auth state changed:', user);
130
+ * });
131
+ *
132
+ * // Handle successful auth
133
+ * await authManager.handleAuthSuccess(session);
134
+ *
135
+ * // Sign out
136
+ * await authManager.signOut();
137
+ * ```
138
+ */
139
+ export class AuthManager {
140
+ private oxyServices: OxyServices;
141
+ private storage: StorageAdapter;
142
+ private listeners: Set<AuthStateChangeCallback> = new Set();
143
+ private currentUser: MinimalUserData | null = null;
144
+ private refreshTimer: ReturnType<typeof setTimeout> | null = null;
145
+ private config: Required<AuthManagerConfig>;
146
+
147
+ constructor(oxyServices: OxyServices, config: AuthManagerConfig = {}) {
148
+ this.oxyServices = oxyServices;
149
+ this.config = {
150
+ storage: config.storage ?? this.getDefaultStorage(),
151
+ autoRefresh: config.autoRefresh ?? true,
152
+ refreshBuffer: config.refreshBuffer ?? 5 * 60 * 1000, // 5 minutes
153
+ };
154
+ this.storage = this.config.storage;
155
+ }
156
+
157
+ /**
158
+ * Get default storage based on environment.
159
+ */
160
+ private getDefaultStorage(): StorageAdapter {
161
+ if (typeof window !== 'undefined' && window.localStorage) {
162
+ return new LocalStorageAdapter();
163
+ }
164
+ return new MemoryStorage();
165
+ }
166
+
167
+ /**
168
+ * Subscribe to auth state changes.
169
+ *
170
+ * @param callback - Function called when auth state changes
171
+ * @returns Unsubscribe function
172
+ */
173
+ onAuthStateChange(callback: AuthStateChangeCallback): () => void {
174
+ this.listeners.add(callback);
175
+ // Call immediately with current state
176
+ callback(this.currentUser);
177
+ return () => {
178
+ this.listeners.delete(callback);
179
+ };
180
+ }
181
+
182
+ /**
183
+ * Notify all listeners of auth state change.
184
+ */
185
+ private notifyListeners(): void {
186
+ for (const listener of this.listeners) {
187
+ try {
188
+ listener(this.currentUser);
189
+ } catch {
190
+ // Ignore listener errors
191
+ }
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Handle successful authentication.
197
+ *
198
+ * @param session - Session response from auth
199
+ * @param method - Auth method used
200
+ */
201
+ async handleAuthSuccess(
202
+ session: SessionLoginResponse,
203
+ method: AuthMethod = 'credentials'
204
+ ): Promise<void> {
205
+ // Store tokens
206
+ if (session.accessToken) {
207
+ await this.storage.setItem(STORAGE_KEYS.ACCESS_TOKEN, session.accessToken);
208
+ this.oxyServices.httpService.setTokens(session.accessToken);
209
+ }
210
+
211
+ // Store refresh token if available
212
+ if (session.refreshToken) {
213
+ await this.storage.setItem(STORAGE_KEYS.REFRESH_TOKEN, session.refreshToken);
214
+ }
215
+
216
+ // Store session info
217
+ await this.storage.setItem(STORAGE_KEYS.SESSION, JSON.stringify({
218
+ sessionId: session.sessionId,
219
+ deviceId: session.deviceId,
220
+ expiresAt: session.expiresAt,
221
+ }));
222
+
223
+ // Store user only if it has valid required fields (not an empty placeholder)
224
+ if (session.user && typeof (session.user as any).id === 'string' && (session.user as any).id.length > 0) {
225
+ await this.storage.setItem(STORAGE_KEYS.USER, JSON.stringify(session.user));
226
+ this.currentUser = session.user;
227
+ }
228
+
229
+ // Store auth method
230
+ await this.storage.setItem(STORAGE_KEYS.AUTH_METHOD, method);
231
+
232
+ // Setup auto-refresh if enabled
233
+ if (this.config.autoRefresh && session.expiresAt) {
234
+ this.setupTokenRefresh(session.expiresAt);
235
+ }
236
+
237
+ // Notify listeners
238
+ this.notifyListeners();
239
+ }
240
+
241
+ /**
242
+ * Setup automatic token refresh.
243
+ */
244
+ private setupTokenRefresh(expiresAt: string): void {
245
+ if (this.refreshTimer) {
246
+ clearTimeout(this.refreshTimer);
247
+ }
248
+
249
+ const expiresAtMs = new Date(expiresAt).getTime();
250
+ const now = Date.now();
251
+ const refreshAt = expiresAtMs - this.config.refreshBuffer;
252
+ const delay = Math.max(0, refreshAt - now);
253
+
254
+ if (delay > 0) {
255
+ this.refreshTimer = setTimeout(() => {
256
+ this.refreshToken().catch(() => {
257
+ // Refresh failed, user will need to re-auth
258
+ });
259
+ }, delay);
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Refresh the access token.
265
+ */
266
+ async refreshToken(): Promise<boolean> {
267
+ const refreshToken = await this.storage.getItem(STORAGE_KEYS.REFRESH_TOKEN);
268
+ if (!refreshToken) {
269
+ return false;
270
+ }
271
+
272
+ try {
273
+ // Cast httpService to proper type (needed due to mixin composition)
274
+ const httpService = this.oxyServices.httpService as HttpService;
275
+ const response = await httpService.request<SessionLoginResponse>({
276
+ method: 'POST',
277
+ url: '/api/auth/refresh',
278
+ data: { refreshToken },
279
+ cache: false,
280
+ });
281
+
282
+ await this.handleAuthSuccess(response, 'credentials');
283
+ return true;
284
+ } catch {
285
+ // Refresh failed, clear session and update state
286
+ await this.clearSession();
287
+ this.currentUser = null;
288
+ this.notifyListeners();
289
+ return false;
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Sign out and clear all auth data.
295
+ */
296
+ async signOut(): Promise<void> {
297
+ // Clear refresh timer
298
+ if (this.refreshTimer) {
299
+ clearTimeout(this.refreshTimer);
300
+ this.refreshTimer = null;
301
+ }
302
+
303
+ // Revoke FedCM credential if supported
304
+ try {
305
+ const services = this.oxyServices as OxyServicesWithFedCM;
306
+ if (services.revokeFedCMCredential) {
307
+ await services.revokeFedCMCredential();
308
+ }
309
+ } catch {
310
+ // Ignore FedCM errors
311
+ }
312
+
313
+ // Clear HTTP client tokens
314
+ this.oxyServices.httpService.setTokens('');
315
+
316
+ // Clear storage
317
+ await this.clearSession();
318
+
319
+ // Update state and notify
320
+ this.currentUser = null;
321
+ this.notifyListeners();
322
+ }
323
+
324
+ /**
325
+ * Clear session data from storage.
326
+ */
327
+ private async clearSession(): Promise<void> {
328
+ await this.storage.removeItem(STORAGE_KEYS.ACCESS_TOKEN);
329
+ await this.storage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
330
+ await this.storage.removeItem(STORAGE_KEYS.SESSION);
331
+ await this.storage.removeItem(STORAGE_KEYS.USER);
332
+ await this.storage.removeItem(STORAGE_KEYS.AUTH_METHOD);
333
+ }
334
+
335
+ /**
336
+ * Get current user.
337
+ */
338
+ getCurrentUser(): MinimalUserData | null {
339
+ return this.currentUser;
340
+ }
341
+
342
+ /**
343
+ * Check if user is authenticated.
344
+ */
345
+ isAuthenticated(): boolean {
346
+ return this.currentUser !== null;
347
+ }
348
+
349
+ /**
350
+ * Get stored access token.
351
+ */
352
+ async getAccessToken(): Promise<string | null> {
353
+ return this.storage.getItem(STORAGE_KEYS.ACCESS_TOKEN);
354
+ }
355
+
356
+ /**
357
+ * Get the auth method used for current session.
358
+ */
359
+ async getAuthMethod(): Promise<AuthMethod | null> {
360
+ const method = await this.storage.getItem(STORAGE_KEYS.AUTH_METHOD);
361
+ return method as AuthMethod | null;
362
+ }
363
+
364
+ /**
365
+ * Initialize auth state from storage.
366
+ *
367
+ * Call this on app startup to restore previous session.
368
+ */
369
+ async initialize(): Promise<MinimalUserData | null> {
370
+ try {
371
+ // Try to restore user from storage
372
+ const userJson = await this.storage.getItem(STORAGE_KEYS.USER);
373
+ if (userJson) {
374
+ this.currentUser = JSON.parse(userJson);
375
+ }
376
+
377
+ // Restore token to HTTP client
378
+ const token = await this.storage.getItem(STORAGE_KEYS.ACCESS_TOKEN);
379
+ if (token) {
380
+ this.oxyServices.httpService.setTokens(token);
381
+ }
382
+
383
+ // Check session expiry
384
+ const sessionJson = await this.storage.getItem(STORAGE_KEYS.SESSION);
385
+ if (sessionJson) {
386
+ const session = JSON.parse(sessionJson);
387
+ if (session.expiresAt) {
388
+ const expiresAt = new Date(session.expiresAt).getTime();
389
+ if (expiresAt <= Date.now()) {
390
+ // Session expired, try refresh
391
+ const refreshed = await this.refreshToken();
392
+ if (!refreshed) {
393
+ await this.clearSession();
394
+ this.currentUser = null;
395
+ }
396
+ } else if (this.config.autoRefresh) {
397
+ // Setup refresh timer
398
+ this.setupTokenRefresh(session.expiresAt);
399
+ }
400
+ }
401
+ }
402
+
403
+ return this.currentUser;
404
+ } catch {
405
+ // Failed to restore, start fresh
406
+ await this.clearSession();
407
+ this.currentUser = null;
408
+ return null;
409
+ }
410
+ }
411
+
412
+ /**
413
+ * Destroy the auth manager and clean up resources.
414
+ */
415
+ destroy(): void {
416
+ if (this.refreshTimer) {
417
+ clearTimeout(this.refreshTimer);
418
+ this.refreshTimer = null;
419
+ }
420
+ this.listeners.clear();
421
+ }
422
+ }
423
+
424
+ /**
425
+ * Create an AuthManager instance.
426
+ *
427
+ * @param oxyServices - OxyServices instance
428
+ * @param config - Optional configuration
429
+ * @returns AuthManager instance
430
+ */
431
+ export function createAuthManager(
432
+ oxyServices: OxyServices,
433
+ config?: AuthManagerConfig
434
+ ): AuthManager {
435
+ return new AuthManager(oxyServices, config);
436
+ }