@oxyhq/services 5.13.1 → 5.13.2

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 (204) hide show
  1. package/README.md +71 -0
  2. package/lib/commonjs/core/HttpClient.js +238 -0
  3. package/lib/commonjs/core/HttpClient.js.map +1 -0
  4. package/lib/commonjs/core/OxyServices.js +530 -332
  5. package/lib/commonjs/core/OxyServices.js.map +1 -1
  6. package/lib/commonjs/core/RequestManager.js +199 -0
  7. package/lib/commonjs/core/RequestManager.js.map +1 -0
  8. package/lib/commonjs/core/index.js +38 -1
  9. package/lib/commonjs/core/index.js.map +1 -1
  10. package/lib/commonjs/index.js +36 -0
  11. package/lib/commonjs/index.js.map +1 -1
  12. package/lib/commonjs/ui/components/Avatar.js +94 -27
  13. package/lib/commonjs/ui/components/Avatar.js.map +1 -1
  14. package/lib/commonjs/ui/components/FollowButton.js +1 -0
  15. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  16. package/lib/commonjs/ui/components/internal/TextField.js +13 -8
  17. package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
  18. package/lib/commonjs/ui/context/OxyContext.js +183 -224
  19. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  20. package/lib/commonjs/ui/hooks/useSessionSocket.js +80 -22
  21. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
  22. package/lib/commonjs/ui/index.js +4 -1
  23. package/lib/commonjs/ui/index.js.map +1 -1
  24. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +32 -2
  25. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  26. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +101 -59
  27. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  28. package/lib/commonjs/ui/screens/FileManagementScreen.js +3 -2
  29. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  30. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +75 -117
  31. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  32. package/lib/commonjs/ui/screens/SignInScreen.js +0 -11
  33. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  34. package/lib/commonjs/ui/screens/SignUpScreen.js +14 -16
  35. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  36. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +50 -18
  37. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  38. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +10 -10
  39. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  40. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +16 -26
  41. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +1 -1
  42. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +104 -212
  43. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +1 -1
  44. package/lib/commonjs/ui/stores/accountStore.js +237 -0
  45. package/lib/commonjs/ui/stores/accountStore.js.map +1 -0
  46. package/lib/commonjs/ui/stores/authStore.js +2 -1
  47. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  48. package/lib/commonjs/ui/styles/authStyles.js +14 -7
  49. package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
  50. package/lib/commonjs/utils/asyncUtils.js +9 -22
  51. package/lib/commonjs/utils/asyncUtils.js.map +1 -1
  52. package/lib/commonjs/utils/cache.js +259 -0
  53. package/lib/commonjs/utils/cache.js.map +1 -0
  54. package/lib/commonjs/utils/index.js +99 -0
  55. package/lib/commonjs/utils/index.js.map +1 -1
  56. package/lib/commonjs/utils/languageUtils.js +159 -0
  57. package/lib/commonjs/utils/languageUtils.js.map +1 -0
  58. package/lib/commonjs/utils/requestUtils.js +217 -0
  59. package/lib/commonjs/utils/requestUtils.js.map +1 -0
  60. package/lib/commonjs/utils/sessionUtils.js +191 -0
  61. package/lib/commonjs/utils/sessionUtils.js.map +1 -0
  62. package/lib/module/core/HttpClient.js +232 -0
  63. package/lib/module/core/HttpClient.js.map +1 -0
  64. package/lib/module/core/OxyServices.js +528 -326
  65. package/lib/module/core/OxyServices.js.map +1 -1
  66. package/lib/module/core/RequestManager.js +194 -0
  67. package/lib/module/core/RequestManager.js.map +1 -0
  68. package/lib/module/core/index.js +2 -0
  69. package/lib/module/core/index.js.map +1 -1
  70. package/lib/module/index.js +2 -0
  71. package/lib/module/index.js.map +1 -1
  72. package/lib/module/ui/components/Avatar.js +94 -27
  73. package/lib/module/ui/components/Avatar.js.map +1 -1
  74. package/lib/module/ui/components/FollowButton.js +1 -0
  75. package/lib/module/ui/components/FollowButton.js.map +1 -1
  76. package/lib/module/ui/components/internal/TextField.js +13 -8
  77. package/lib/module/ui/components/internal/TextField.js.map +1 -1
  78. package/lib/module/ui/context/OxyContext.js +182 -223
  79. package/lib/module/ui/context/OxyContext.js.map +1 -1
  80. package/lib/module/ui/hooks/useSessionSocket.js +80 -22
  81. package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
  82. package/lib/module/ui/index.js +4 -2
  83. package/lib/module/ui/index.js.map +1 -1
  84. package/lib/module/ui/screens/AccountSettingsScreen.js +33 -2
  85. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  86. package/lib/module/ui/screens/AccountSwitcherScreen.js +102 -60
  87. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  88. package/lib/module/ui/screens/FileManagementScreen.js +3 -2
  89. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  90. package/lib/module/ui/screens/LanguageSelectorScreen.js +73 -117
  91. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  92. package/lib/module/ui/screens/SignInScreen.js +0 -11
  93. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  94. package/lib/module/ui/screens/SignUpScreen.js +14 -16
  95. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  96. package/lib/module/ui/screens/WelcomeNewUserScreen.js +50 -18
  97. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  98. package/lib/module/ui/screens/internal/SignInPasswordStep.js +10 -10
  99. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  100. package/lib/module/ui/screens/steps/SignInPasswordStep.js +16 -26
  101. package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +1 -1
  102. package/lib/module/ui/screens/steps/SignInUsernameStep.js +105 -214
  103. package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +1 -1
  104. package/lib/module/ui/stores/accountStore.js +229 -0
  105. package/lib/module/ui/stores/accountStore.js.map +1 -0
  106. package/lib/module/ui/stores/authStore.js +2 -1
  107. package/lib/module/ui/stores/authStore.js.map +1 -1
  108. package/lib/module/ui/styles/authStyles.js +14 -7
  109. package/lib/module/ui/styles/authStyles.js.map +1 -1
  110. package/lib/module/utils/asyncUtils.js +10 -22
  111. package/lib/module/utils/asyncUtils.js.map +1 -1
  112. package/lib/module/utils/cache.js +250 -0
  113. package/lib/module/utils/cache.js.map +1 -0
  114. package/lib/module/utils/index.js +7 -0
  115. package/lib/module/utils/index.js.map +1 -1
  116. package/lib/module/utils/languageUtils.js +151 -0
  117. package/lib/module/utils/languageUtils.js.map +1 -0
  118. package/lib/module/utils/requestUtils.js +210 -0
  119. package/lib/module/utils/requestUtils.js.map +1 -0
  120. package/lib/module/utils/sessionUtils.js +180 -0
  121. package/lib/module/utils/sessionUtils.js.map +1 -0
  122. package/lib/typescript/core/HttpClient.d.ts +64 -0
  123. package/lib/typescript/core/HttpClient.d.ts.map +1 -0
  124. package/lib/typescript/core/OxyServices.d.ts +82 -71
  125. package/lib/typescript/core/OxyServices.d.ts.map +1 -1
  126. package/lib/typescript/core/RequestManager.d.ts +67 -0
  127. package/lib/typescript/core/RequestManager.d.ts.map +1 -0
  128. package/lib/typescript/core/index.d.ts +2 -0
  129. package/lib/typescript/core/index.d.ts.map +1 -1
  130. package/lib/typescript/index.d.ts +2 -0
  131. package/lib/typescript/index.d.ts.map +1 -1
  132. package/lib/typescript/models/interfaces.d.ts +15 -0
  133. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  134. package/lib/typescript/models/session.d.ts +1 -0
  135. package/lib/typescript/models/session.d.ts.map +1 -1
  136. package/lib/typescript/ui/components/Avatar.d.ts +6 -7
  137. package/lib/typescript/ui/components/Avatar.d.ts.map +1 -1
  138. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
  139. package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
  140. package/lib/typescript/ui/context/OxyContext.d.ts +4 -0
  141. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  142. package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
  143. package/lib/typescript/ui/index.d.ts +2 -2
  144. package/lib/typescript/ui/index.d.ts.map +1 -1
  145. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  146. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  147. package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts +3 -3
  148. package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  149. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  150. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
  151. package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  152. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
  153. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +1 -1
  154. package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +1 -1
  155. package/lib/typescript/ui/stores/accountStore.d.ts +34 -0
  156. package/lib/typescript/ui/stores/accountStore.d.ts.map +1 -0
  157. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  158. package/lib/typescript/ui/styles/authStyles.d.ts +18 -2
  159. package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
  160. package/lib/typescript/utils/asyncUtils.d.ts +2 -0
  161. package/lib/typescript/utils/asyncUtils.d.ts.map +1 -1
  162. package/lib/typescript/utils/cache.d.ts +128 -0
  163. package/lib/typescript/utils/cache.d.ts.map +1 -0
  164. package/lib/typescript/utils/index.d.ts +4 -0
  165. package/lib/typescript/utils/index.d.ts.map +1 -1
  166. package/lib/typescript/utils/languageUtils.d.ts +38 -0
  167. package/lib/typescript/utils/languageUtils.d.ts.map +1 -0
  168. package/lib/typescript/utils/requestUtils.d.ts +122 -0
  169. package/lib/typescript/utils/requestUtils.d.ts.map +1 -0
  170. package/lib/typescript/utils/sessionUtils.d.ts +55 -0
  171. package/lib/typescript/utils/sessionUtils.d.ts.map +1 -0
  172. package/package.json +1 -1
  173. package/src/core/HttpClient.ts +277 -0
  174. package/src/core/OxyServices.ts +458 -351
  175. package/src/core/RequestManager.ts +240 -0
  176. package/src/core/index.ts +10 -0
  177. package/src/index.ts +10 -0
  178. package/src/models/interfaces.ts +19 -0
  179. package/src/models/session.ts +1 -1
  180. package/src/ui/components/Avatar.tsx +151 -35
  181. package/src/ui/components/FollowButton.tsx +1 -0
  182. package/src/ui/components/internal/TextField.tsx +7 -6
  183. package/src/ui/context/OxyContext.tsx +213 -217
  184. package/src/ui/hooks/useSessionSocket.ts +72 -18
  185. package/src/ui/index.ts +4 -1
  186. package/src/ui/screens/AccountSettingsScreen.tsx +34 -2
  187. package/src/ui/screens/AccountSwitcherScreen.tsx +102 -68
  188. package/src/ui/screens/FileManagementScreen.tsx +1 -1
  189. package/src/ui/screens/LanguageSelectorScreen.tsx +86 -143
  190. package/src/ui/screens/SignInScreen.tsx +0 -7
  191. package/src/ui/screens/SignUpScreen.tsx +14 -15
  192. package/src/ui/screens/WelcomeNewUserScreen.tsx +52 -15
  193. package/src/ui/screens/internal/SignInPasswordStep.tsx +4 -6
  194. package/src/ui/screens/steps/SignInPasswordStep.tsx +4 -8
  195. package/src/ui/screens/steps/SignInUsernameStep.tsx +110 -256
  196. package/src/ui/stores/accountStore.ts +285 -0
  197. package/src/ui/stores/authStore.ts +2 -1
  198. package/src/ui/styles/authStyles.ts +14 -7
  199. package/src/utils/asyncUtils.ts +10 -24
  200. package/src/utils/cache.ts +264 -0
  201. package/src/utils/index.ts +19 -0
  202. package/src/utils/languageUtils.ts +174 -0
  203. package/src/utils/requestUtils.ts +234 -0
  204. package/src/utils/sessionUtils.ts +206 -0
@@ -4,12 +4,13 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.oxyClient = exports.OxyServices = exports.OxyAuthenticationTimeoutError = exports.OxyAuthenticationError = exports.OXY_CLOUD_URL = exports.OXY_API_URL = void 0;
7
- var _axios = _interopRequireDefault(require("axios"));
8
7
  var _jwtDecode = require("jwt-decode");
8
+ var _languageUtils = require("../utils/languageUtils");
9
9
  var _errorUtils = require("../utils/errorUtils");
10
10
  var _apiUtils = require("../utils/apiUtils");
11
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
- /**
11
+ var _HttpClient = require("./HttpClient");
12
+ var _RequestManager = require("./RequestManager");
13
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } /**
13
14
  * OxyServices - Unified client for Oxy API and Oxy Cloud
14
15
  *
15
16
  * # Usage Examples
@@ -66,14 +67,11 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
66
67
  * - `cloudURL`: Oxy Cloud/CDN endpoint (e.g., https://cloud.oxy.so)
67
68
  *
68
69
  * See method JSDoc for more details and options.
69
- */
70
-
71
- /**
70
+ */ /**
72
71
  * OxyConfig - Configuration for OxyServices
73
72
  * @property baseURL - The Oxy API base URL (e.g., https://api.oxy.so)
74
73
  * @property cloudURL - The Oxy Cloud (file storage/CDN) URL (e.g., https://cloud.oxy.so)
75
74
  */
76
-
77
75
  /**
78
76
  * Custom error types for better error handling
79
77
  */
@@ -97,43 +95,13 @@ class OxyAuthenticationTimeoutError extends OxyAuthenticationError {
97
95
  * OxyServices - Unified client library for interacting with the Oxy API
98
96
  *
99
97
  * This class provides all API functionality in one simple, easy-to-use interface.
100
- * No need to manage multiple service instances - everything is available directly.
98
+ * Architecture:
99
+ * - HttpClient: Handles HTTP communication and authentication
100
+ * - RequestManager: Handles caching, deduplication, queuing, and retry
101
+ * - OxyServices: Provides high-level API methods
101
102
  */
102
- // Centralized token store
103
103
  exports.OxyAuthenticationTimeoutError = OxyAuthenticationTimeoutError;
104
- class TokenStore {
105
- accessToken = null;
106
- refreshToken = null;
107
- constructor() {}
108
- static getInstance() {
109
- if (!TokenStore.instance) {
110
- TokenStore.instance = new TokenStore();
111
- }
112
- return TokenStore.instance;
113
- }
114
- setTokens(accessToken, refreshToken = '') {
115
- this.accessToken = accessToken;
116
- this.refreshToken = refreshToken;
117
- }
118
- getAccessToken() {
119
- return this.accessToken;
120
- }
121
- getRefreshToken() {
122
- return this.refreshToken;
123
- }
124
- clearTokens() {
125
- this.accessToken = null;
126
- this.refreshToken = null;
127
- }
128
- hasAccessToken() {
129
- return !!this.accessToken;
130
- }
131
- }
132
104
  class OxyServices {
133
- /**
134
- * Creates a new instance of the OxyServices client
135
- * @param config - Configuration for the client
136
- */
137
105
  /**
138
106
  * Creates a new instance of the OxyServices client
139
107
  * @param config - Configuration for the client
@@ -141,89 +109,27 @@ class OxyServices {
141
109
  * config.cloudURL: Oxy Cloud URL (e.g., https://cloud.oxy.so)
142
110
  */
143
111
  constructor(config) {
144
- this.client = _axios.default.create({
145
- baseURL: config.baseURL,
146
- timeout: 5000 // 5 second timeout
147
- });
112
+ this.config = config;
148
113
  this.cloudURL = config.cloudURL || OXY_CLOUD_URL;
149
- this.tokenStore = TokenStore.getInstance();
150
- this.setupInterceptors();
114
+
115
+ // Initialize HTTP client (handles authentication and interceptors)
116
+ this.httpClient = new _HttpClient.HttpClient(config);
117
+
118
+ // Initialize request manager (handles caching, deduplication, queuing, retry)
119
+ this.requestManager = new _RequestManager.RequestManager(this.httpClient, config);
151
120
  }
152
121
 
153
122
  // Test-only utility to reset global tokens between jest tests
154
123
  static __resetTokensForTests() {
155
- try {
156
- TokenStore.getInstance().clearTokens();
157
- } catch {}
124
+ _HttpClient.HttpClient.__resetTokensForTests();
158
125
  }
159
126
 
160
127
  /**
161
- * Setup axios interceptors for authentication and error handling
128
+ * Make a request with all performance optimizations
129
+ * This is the main method for all API calls - ensures authentication and performance features
162
130
  */
163
- setupInterceptors() {
164
- // Request interceptor for adding auth header and handling token refresh
165
- this.client.interceptors.request.use(async req => {
166
- console.log('🔍 Interceptor - URL:', req.url);
167
- console.log('🔍 Interceptor - Has token:', this.tokenStore.hasAccessToken());
168
- const accessToken = this.tokenStore.getAccessToken();
169
- if (!accessToken) {
170
- console.log('❌ Interceptor - No token available');
171
- return req;
172
- }
173
- try {
174
- console.log('✅ Interceptor - Adding Authorization header');
175
- const decoded = (0, _jwtDecode.jwtDecode)(accessToken);
176
- const currentTime = Math.floor(Date.now() / 1000);
177
-
178
- // If token expires in less than 60 seconds, refresh it
179
- if (decoded.exp && decoded.exp - currentTime < 60) {
180
- // For session-based tokens, get a new token from the session
181
- if (decoded.sessionId) {
182
- try {
183
- // Create a new axios instance to avoid interceptor recursion
184
- const refreshClient = _axios.default.create({
185
- baseURL: this.client.defaults.baseURL,
186
- timeout: this.client.defaults.timeout
187
- });
188
- const res = await refreshClient.get(`/api/session/token/${decoded.sessionId}`);
189
- this.tokenStore.setTokens(res.data.accessToken);
190
- req.headers.Authorization = `Bearer ${res.data.accessToken}`;
191
- console.log('✅ Interceptor - Token refreshed and Authorization header set');
192
- } catch (refreshError) {
193
- // If refresh fails, use current token anyway
194
- req.headers.Authorization = `Bearer ${accessToken}`;
195
- console.log('❌ Interceptor - Token refresh failed, using current token');
196
- }
197
- } else {
198
- // No session ID, use current token
199
- req.headers.Authorization = `Bearer ${accessToken}`;
200
- console.log('✅ Interceptor - No session ID, using current token');
201
- }
202
- } else {
203
- // Add authorization header with current token
204
- req.headers.Authorization = `Bearer ${accessToken}`;
205
- console.log('✅ Interceptor - Authorization header set with current token');
206
- }
207
- } catch (error) {
208
- console.log('❌ Interceptor - Error processing token:', error);
209
- // Even if there's an error, still try to use the token
210
- req.headers.Authorization = `Bearer ${accessToken}`;
211
- console.log('⚠️ Interceptor - Using token despite error');
212
- }
213
- return req;
214
- }, error => {
215
- console.log('❌ Interceptor - Request error:', error);
216
- return Promise.reject(error);
217
- });
218
-
219
- // Response interceptor for handling auth errors
220
- this.client.interceptors.response.use(response => response, error => {
221
- if (error.response?.status === 401) {
222
- console.log('❌ Response interceptor - 401 Unauthorized, clearing tokens');
223
- this.clearTokens();
224
- }
225
- return Promise.reject(error);
226
- });
131
+ async makeRequest(method, url, data, options = {}) {
132
+ return this.requestManager.request(method, url, data, options);
227
133
  }
228
134
 
229
135
  // ============================================================================
@@ -234,7 +140,35 @@ class OxyServices {
234
140
  * Get the configured Oxy API base URL
235
141
  */
236
142
  getBaseURL() {
237
- return this.client.defaults.baseURL || '';
143
+ return this.httpClient.getBaseURL();
144
+ }
145
+
146
+ /**
147
+ * Get performance metrics
148
+ */
149
+ getMetrics() {
150
+ return this.requestManager.getMetrics();
151
+ }
152
+
153
+ /**
154
+ * Clear request cache
155
+ */
156
+ clearCache() {
157
+ this.requestManager.clearCache();
158
+ }
159
+
160
+ /**
161
+ * Clear specific cache entry
162
+ */
163
+ clearCacheEntry(key) {
164
+ this.requestManager.clearCacheEntry(key);
165
+ }
166
+
167
+ /**
168
+ * Get cache statistics
169
+ */
170
+ getCacheStats() {
171
+ return this.requestManager.getCacheStats();
238
172
  }
239
173
 
240
174
  /**
@@ -248,21 +182,21 @@ class OxyServices {
248
182
  * Set authentication tokens
249
183
  */
250
184
  setTokens(accessToken, refreshToken = '') {
251
- this.tokenStore.setTokens(accessToken, refreshToken);
185
+ this.httpClient.setTokens(accessToken, refreshToken);
252
186
  }
253
187
 
254
188
  /**
255
189
  * Clear stored authentication tokens
256
190
  */
257
191
  clearTokens() {
258
- this.tokenStore.clearTokens();
192
+ this.httpClient.clearTokens();
259
193
  }
260
194
 
261
195
  /**
262
196
  * Get the current user ID from the access token
263
197
  */
264
198
  getCurrentUserId() {
265
- const accessToken = this.tokenStore.getAccessToken();
199
+ const accessToken = this.httpClient.getAccessToken();
266
200
  if (!accessToken) {
267
201
  return null;
268
202
  }
@@ -278,21 +212,21 @@ class OxyServices {
278
212
  * Check if the client has a valid access token
279
213
  */
280
214
  hasAccessToken() {
281
- return this.tokenStore.hasAccessToken();
215
+ return this.httpClient.hasAccessToken();
282
216
  }
283
217
 
284
218
  /**
285
219
  * Check if the client has a valid access token (public method)
286
220
  */
287
221
  hasValidToken() {
288
- return this.tokenStore.hasAccessToken();
222
+ return this.httpClient.hasAccessToken();
289
223
  }
290
224
 
291
225
  /**
292
226
  * Get the raw access token (for constructing anchor URLs when needed)
293
227
  */
294
228
  getAccessToken() {
295
- return this.tokenStore.getAccessToken();
229
+ return this.httpClient.getAccessToken();
296
230
  }
297
231
 
298
232
  /**
@@ -311,7 +245,7 @@ class OxyServices {
311
245
  const checkInterval = 100; // Check every 100ms
312
246
 
313
247
  while (Date.now() - startTime < timeoutMs) {
314
- if (this.tokenStore.hasAccessToken()) {
248
+ if (this.httpClient.hasAccessToken()) {
315
249
  return true;
316
250
  }
317
251
  await new Promise(resolve => setTimeout(resolve, checkInterval));
@@ -332,15 +266,13 @@ class OxyServices {
332
266
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
333
267
  try {
334
268
  // First attempt: check if we have a token
335
- if (!this.tokenStore.hasAccessToken()) {
269
+ if (!this.httpClient.hasAccessToken()) {
336
270
  if (attempt === 0) {
337
271
  // On first attempt, wait briefly for authentication to complete
338
- console.log(`🔄 ${operationName} - Waiting for authentication...`);
339
272
  const authReady = await this.waitForAuthentication(authTimeoutMs);
340
273
  if (!authReady) {
341
274
  throw new OxyAuthenticationTimeoutError(operationName, authTimeoutMs);
342
275
  }
343
- console.log(`✅ ${operationName} - Authentication ready, proceeding...`);
344
276
  } else {
345
277
  // On retry attempts, fail immediately if no token
346
278
  throw new OxyAuthenticationError(`Authentication required: ${operationName} requires a valid access token.`, 'AUTH_REQUIRED');
@@ -353,7 +285,6 @@ class OxyServices {
353
285
  const isLastAttempt = attempt === maxRetries;
354
286
  const isAuthError = error?.response?.status === 401 || error?.code === 'MISSING_TOKEN' || error?.message?.includes('Authentication') || error instanceof OxyAuthenticationError;
355
287
  if (isAuthError && !isLastAttempt && !(error instanceof OxyAuthenticationTimeoutError)) {
356
- console.log(`🔄 ${operationName} - Auth error on attempt ${attempt + 1}, retrying in ${retryDelay}ms...`);
357
288
  await new Promise(resolve => setTimeout(resolve, retryDelay));
358
289
  continue;
359
290
  }
@@ -378,20 +309,16 @@ class OxyServices {
378
309
  return false;
379
310
  }
380
311
  try {
381
- const res = await this.client.get('/api/auth/validate');
382
- return res.data.valid === true;
312
+ const res = await this.makeRequest('GET', '/api/auth/validate', undefined, {
313
+ cache: false,
314
+ retry: false
315
+ });
316
+ return res.valid === true;
383
317
  } catch (error) {
384
318
  return false;
385
319
  }
386
320
  }
387
321
 
388
- /**
389
- * Get the HTTP client instance (public for external use)
390
- */
391
- getClient() {
392
- return this.client;
393
- }
394
-
395
322
  /**
396
323
  * Centralized error handling
397
324
  */
@@ -409,8 +336,9 @@ class OxyServices {
409
336
  */
410
337
  async healthCheck() {
411
338
  try {
412
- const res = await this.client.get('/health');
413
- return res.data;
339
+ return await this.makeRequest('GET', '/health', undefined, {
340
+ cache: false
341
+ });
414
342
  } catch (error) {
415
343
  throw this.handleError(error);
416
344
  }
@@ -425,15 +353,17 @@ class OxyServices {
425
353
  */
426
354
  async signUp(username, email, password) {
427
355
  try {
428
- const res = await this.client.post('/api/auth/signup', {
356
+ const res = await this.makeRequest('POST', '/api/auth/signup', {
429
357
  username,
430
358
  email,
431
359
  password
360
+ }, {
361
+ cache: false
432
362
  });
433
- if (!res || !res.data || typeof res.data === 'object' && Object.keys(res.data).length === 0) {
363
+ if (!res || typeof res === 'object' && Object.keys(res).length === 0) {
434
364
  throw new OxyAuthenticationError('Sign up failed', 'SIGNUP_FAILED', 400);
435
365
  }
436
- return res.data;
366
+ return res;
437
367
  } catch (error) {
438
368
  throw this.handleError(error);
439
369
  }
@@ -444,10 +374,11 @@ class OxyServices {
444
374
  */
445
375
  async requestRecovery(identifier) {
446
376
  try {
447
- const res = await this.client.post('/api/auth/recover/request', {
377
+ return await this.makeRequest('POST', '/api/auth/recover/request', {
448
378
  identifier
379
+ }, {
380
+ cache: false
449
381
  });
450
- return res.data;
451
382
  } catch (error) {
452
383
  throw this.handleError(error);
453
384
  }
@@ -458,11 +389,12 @@ class OxyServices {
458
389
  */
459
390
  async verifyRecoveryCode(identifier, code) {
460
391
  try {
461
- const res = await this.client.post('/api/auth/recover/verify', {
392
+ return await this.makeRequest('POST', '/api/auth/recover/verify', {
462
393
  identifier,
463
394
  code
395
+ }, {
396
+ cache: false
464
397
  });
465
- return res.data;
466
398
  } catch (error) {
467
399
  throw this.handleError(error);
468
400
  }
@@ -473,12 +405,13 @@ class OxyServices {
473
405
  */
474
406
  async resetPassword(identifier, code, newPassword) {
475
407
  try {
476
- const res = await this.client.post('/api/auth/recover/reset', {
408
+ return await this.makeRequest('POST', '/api/auth/recover/reset', {
477
409
  identifier,
478
410
  code,
479
411
  newPassword
412
+ }, {
413
+ cache: false
480
414
  });
481
- return res.data;
482
415
  } catch (error) {
483
416
  throw this.handleError(error);
484
417
  }
@@ -489,36 +422,39 @@ class OxyServices {
489
422
  */
490
423
  async resetPasswordWithTotp(identifier, code, newPassword) {
491
424
  try {
492
- const res = await this.client.post('/api/auth/recover/totp/reset', {
425
+ return await this.makeRequest('POST', '/api/auth/recover/totp/reset', {
493
426
  identifier,
494
427
  code,
495
428
  newPassword
429
+ }, {
430
+ cache: false
496
431
  });
497
- return res.data;
498
432
  } catch (error) {
499
433
  throw this.handleError(error);
500
434
  }
501
435
  }
502
436
  async resetPasswordWithBackupCode(identifier, backupCode, newPassword) {
503
437
  try {
504
- const res = await this.client.post('/api/auth/recover/backup/reset', {
438
+ return await this.makeRequest('POST', '/api/auth/recover/backup/reset', {
505
439
  identifier,
506
440
  backupCode,
507
441
  newPassword
442
+ }, {
443
+ cache: false
508
444
  });
509
- return res.data;
510
445
  } catch (error) {
511
446
  throw this.handleError(error);
512
447
  }
513
448
  }
514
449
  async resetPasswordWithRecoveryKey(identifier, recoveryKey, newPassword) {
515
450
  try {
516
- const res = await this.client.post('/api/auth/recover/recovery-key/reset', {
451
+ return await this.makeRequest('POST', '/api/auth/recover/recovery-key/reset', {
517
452
  identifier,
518
453
  recoveryKey,
519
454
  newPassword
455
+ }, {
456
+ cache: false
520
457
  });
521
- return res.data;
522
458
  } catch (error) {
523
459
  throw this.handleError(error);
524
460
  }
@@ -529,13 +465,14 @@ class OxyServices {
529
465
  */
530
466
  async signIn(username, password, deviceName, deviceFingerprint) {
531
467
  try {
532
- const res = await this.client.post('/api/auth/login', {
468
+ return await this.makeRequest('POST', '/api/auth/login', {
533
469
  username,
534
470
  password,
535
471
  deviceName,
536
472
  deviceFingerprint
473
+ }, {
474
+ cache: false
537
475
  });
538
- return res.data;
539
476
  } catch (error) {
540
477
  throw this.handleError(error);
541
478
  }
@@ -546,11 +483,12 @@ class OxyServices {
546
483
  */
547
484
  async verifyTotpLogin(mfaToken, code) {
548
485
  try {
549
- const res = await this.client.post('/api/auth/totp/verify-login', {
486
+ return await this.makeRequest('POST', '/api/auth/totp/verify-login', {
550
487
  mfaToken,
551
488
  code
489
+ }, {
490
+ cache: false
552
491
  });
553
- return res.data;
554
492
  } catch (error) {
555
493
  throw this.handleError(error);
556
494
  }
@@ -561,8 +499,35 @@ class OxyServices {
561
499
  */
562
500
  async getUserBySession(sessionId) {
563
501
  try {
564
- const res = await this.client.get(`/api/session/user/${sessionId}`);
565
- return res.data;
502
+ return await this.makeRequest('GET', `/api/session/user/${sessionId}`, undefined, {
503
+ cache: true,
504
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache for user data
505
+ });
506
+ } catch (error) {
507
+ throw this.handleError(error);
508
+ }
509
+ }
510
+
511
+ /**
512
+ * Batch get multiple user profiles by session IDs (optimized for account switching)
513
+ * Returns array of { sessionId, user } objects
514
+ */
515
+ async getUsersBySessions(sessionIds) {
516
+ try {
517
+ if (!Array.isArray(sessionIds) || sessionIds.length === 0) {
518
+ return [];
519
+ }
520
+
521
+ // Deduplicate and sort sessionIds for consistent cache keys
522
+ const uniqueSessionIds = Array.from(new Set(sessionIds)).sort();
523
+ return await this.makeRequest('POST', '/api/session/users/batch', {
524
+ sessionIds: uniqueSessionIds
525
+ }, {
526
+ cache: true,
527
+ cacheTTL: 2 * 60 * 1000,
528
+ // 2 minutes cache
529
+ deduplicate: true // Important for batch requests
530
+ });
566
531
  } catch (error) {
567
532
  throw this.handleError(error);
568
533
  }
@@ -573,19 +538,15 @@ class OxyServices {
573
538
  */
574
539
  async getTokenBySession(sessionId) {
575
540
  try {
576
- console.log('🔑 getTokenBySession - Fetching token for session:', sessionId);
577
- const res = await this.client.get(`/api/session/token/${sessionId}`);
578
- const {
579
- accessToken
580
- } = res.data;
581
- console.log('🔑 getTokenBySession - Token received:', !!accessToken);
541
+ const res = await this.makeRequest('GET', `/api/session/token/${sessionId}`, undefined, {
542
+ cache: false,
543
+ retry: false
544
+ });
582
545
 
583
546
  // Set the token in the centralized token store
584
- this.setTokens(accessToken);
585
- console.log('🔑 getTokenBySession - Token set in store');
586
- return res.data;
547
+ this.setTokens(res.accessToken);
548
+ return res;
587
549
  } catch (error) {
588
- console.log('❌ getTokenBySession - Error:', error);
589
550
  throw this.handleError(error);
590
551
  }
591
552
  }
@@ -595,8 +556,9 @@ class OxyServices {
595
556
  */
596
557
  async getSessionsBySessionId(sessionId) {
597
558
  try {
598
- const res = await this.client.get(`/api/session/sessions/${sessionId}`);
599
- return res.data;
559
+ return await this.makeRequest('GET', `/api/session/sessions/${sessionId}`, undefined, {
560
+ cache: false
561
+ });
600
562
  } catch (error) {
601
563
  throw this.handleError(error);
602
564
  }
@@ -608,7 +570,9 @@ class OxyServices {
608
570
  async logoutSession(sessionId, targetSessionId) {
609
571
  try {
610
572
  const url = targetSessionId ? `/api/session/logout/${sessionId}/${targetSessionId}` : `/api/session/logout/${sessionId}`;
611
- await this.client.post(url);
573
+ await this.makeRequest('POST', url, undefined, {
574
+ cache: false
575
+ });
612
576
  } catch (error) {
613
577
  throw this.handleError(error);
614
578
  }
@@ -619,7 +583,9 @@ class OxyServices {
619
583
  */
620
584
  async logoutAllSessions(sessionId) {
621
585
  try {
622
- await this.client.post(`/api/session/logout-all/${sessionId}`);
586
+ await this.makeRequest('POST', `/api/session/logout-all/${sessionId}`, undefined, {
587
+ cache: false
588
+ });
623
589
  } catch (error) {
624
590
  throw this.handleError(error);
625
591
  }
@@ -637,9 +603,13 @@ class OxyServices {
637
603
  if (options.useHeaderValidation) {
638
604
  params.append('useHeaderValidation', 'true');
639
605
  }
640
- const url = `/api/session/validate/${sessionId}?${params.toString()}`;
641
- const res = await this.client.get(url);
642
- return res.data;
606
+ const url = `/api/session/validate/${sessionId}`;
607
+ const urlParams = {};
608
+ if (options.deviceFingerprint) urlParams.deviceFingerprint = options.deviceFingerprint;
609
+ if (options.useHeaderValidation) urlParams.useHeaderValidation = 'true';
610
+ return await this.makeRequest('GET', url, urlParams, {
611
+ cache: false
612
+ });
643
613
  } catch (error) {
644
614
  throw this.handleError(error);
645
615
  }
@@ -650,8 +620,9 @@ class OxyServices {
650
620
  */
651
621
  async checkUsernameAvailability(username) {
652
622
  try {
653
- const res = await this.client.get(`/api/auth/check-username/${username}`);
654
- return res.data;
623
+ return await this.makeRequest('GET', `/api/auth/check-username/${username}`, undefined, {
624
+ cache: false
625
+ });
655
626
  } catch (error) {
656
627
  throw this.handleError(error);
657
628
  }
@@ -662,8 +633,9 @@ class OxyServices {
662
633
  */
663
634
  async checkEmailAvailability(email) {
664
635
  try {
665
- const res = await this.client.get(`/api/auth/check-email/${email}`);
666
- return res.data;
636
+ return await this.makeRequest('GET', `/api/auth/check-email/${email}`, undefined, {
637
+ cache: false
638
+ });
667
639
  } catch (error) {
668
640
  throw this.handleError(error);
669
641
  }
@@ -678,8 +650,10 @@ class OxyServices {
678
650
  */
679
651
  async getProfileByUsername(username) {
680
652
  try {
681
- const res = await this.client.get(`/api/profiles/username/${username}`);
682
- return res.data;
653
+ return await this.makeRequest('GET', `/api/profiles/username/${username}`, undefined, {
654
+ cache: true,
655
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache for profiles
656
+ });
683
657
  } catch (error) {
684
658
  throw this.handleError(error);
685
659
  }
@@ -691,44 +665,36 @@ class OxyServices {
691
665
 
692
666
  async startTotpEnrollment(sessionId) {
693
667
  try {
694
- const res = await this.client.post('/api/auth/totp/enroll/start', {
668
+ // Note: x-session-id header is handled by HttpClient interceptors if needed
669
+ return await this.makeRequest('POST', '/api/auth/totp/enroll/start', {
695
670
  sessionId
696
671
  }, {
697
- headers: {
698
- 'x-session-id': sessionId
699
- }
672
+ cache: false
700
673
  });
701
- return res.data;
702
674
  } catch (error) {
703
675
  throw this.handleError(error);
704
676
  }
705
677
  }
706
678
  async verifyTotpEnrollment(sessionId, code) {
707
679
  try {
708
- const res = await this.client.post('/api/auth/totp/enroll/verify', {
680
+ return await this.makeRequest('POST', '/api/auth/totp/enroll/verify', {
709
681
  sessionId,
710
682
  code
711
683
  }, {
712
- headers: {
713
- 'x-session-id': sessionId
714
- }
684
+ cache: false
715
685
  });
716
- return res.data;
717
686
  } catch (error) {
718
687
  throw this.handleError(error);
719
688
  }
720
689
  }
721
690
  async disableTotp(sessionId, code) {
722
691
  try {
723
- const res = await this.client.post('/api/auth/totp/disable', {
692
+ return await this.makeRequest('POST', '/api/auth/totp/disable', {
724
693
  sessionId,
725
694
  code
726
695
  }, {
727
- headers: {
728
- 'x-session-id': sessionId
729
- }
696
+ cache: false
730
697
  });
731
- return res.data;
732
698
  } catch (error) {
733
699
  throw this.handleError(error);
734
700
  }
@@ -744,8 +710,14 @@ class OxyServices {
744
710
  ...pagination
745
711
  };
746
712
  const searchParams = (0, _apiUtils.buildSearchParams)(params);
747
- const res = await this.client.get(`/api/profiles/search?${searchParams.toString()}`);
748
- return res.data;
713
+ const paramsObj = {};
714
+ searchParams.forEach((value, key) => {
715
+ paramsObj[key] = value;
716
+ });
717
+ return await this.makeRequest('GET', '/api/profiles/search', paramsObj, {
718
+ cache: true,
719
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
720
+ });
749
721
  } catch (error) {
750
722
  throw this.handleError(error);
751
723
  }
@@ -756,8 +728,9 @@ class OxyServices {
756
728
  */
757
729
  async getProfileRecommendations() {
758
730
  return this.withAuthRetry(async () => {
759
- const res = await this.client.get('/api/profiles/recommendations');
760
- return res.data;
731
+ return await this.makeRequest('GET', '/api/profiles/recommendations', undefined, {
732
+ cache: true
733
+ });
761
734
  }, 'getProfileRecommendations');
762
735
  }
763
736
 
@@ -766,8 +739,10 @@ class OxyServices {
766
739
  */
767
740
  async getUserById(userId) {
768
741
  try {
769
- const res = await this.client.get(`/api/users/${userId}`);
770
- return res.data;
742
+ return await this.makeRequest('GET', `/api/users/${userId}`, undefined, {
743
+ cache: true,
744
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
745
+ });
771
746
  } catch (error) {
772
747
  throw this.handleError(error);
773
748
  }
@@ -778,8 +753,10 @@ class OxyServices {
778
753
  */
779
754
  async getCurrentUser() {
780
755
  return this.withAuthRetry(async () => {
781
- const res = await this.client.get('/api/users/me');
782
- return res.data;
756
+ return await this.makeRequest('GET', '/api/users/me', undefined, {
757
+ cache: true,
758
+ cacheTTL: 1 * 60 * 1000 // 1 minute cache for current user
759
+ });
783
760
  }, 'getCurrentUser');
784
761
  }
785
762
 
@@ -788,20 +765,134 @@ class OxyServices {
788
765
  */
789
766
  async updateProfile(updates) {
790
767
  try {
791
- const res = await this.client.put('/api/users/me', updates);
792
- return res.data;
768
+ return await this.makeRequest('PUT', '/api/users/me', updates, {
769
+ cache: false
770
+ });
793
771
  } catch (error) {
794
772
  throw this.handleError(error);
795
773
  }
796
774
  }
797
775
 
776
+ // ============================================================================
777
+ // LANGUAGE METHODS
778
+ // ============================================================================
779
+
780
+ /**
781
+ * Get the current language from storage or user profile
782
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
783
+ * @returns The current language code (e.g., 'en-US') or null if not set
784
+ */
785
+ async getCurrentLanguage(storageKeyPrefix = 'oxy_session') {
786
+ try {
787
+ // First try to get from user profile if authenticated
788
+ try {
789
+ const user = await this.getCurrentUser();
790
+ const userLanguage = user?.language;
791
+ if (userLanguage) {
792
+ return (0, _languageUtils.normalizeLanguageCode)(userLanguage) || userLanguage;
793
+ }
794
+ } catch (e) {
795
+ // User not authenticated or error, continue to storage
796
+ }
797
+
798
+ // Fall back to storage
799
+ const storage = await this.getStorage();
800
+ const storageKey = `${storageKeyPrefix}_language`;
801
+ const storedLanguage = await storage.getItem(storageKey);
802
+ if (storedLanguage) {
803
+ return (0, _languageUtils.normalizeLanguageCode)(storedLanguage) || storedLanguage;
804
+ }
805
+ return null;
806
+ } catch (error) {
807
+ if (__DEV__) {
808
+ console.warn('Failed to get current language:', error);
809
+ }
810
+ return null;
811
+ }
812
+ }
813
+
814
+ /**
815
+ * Get the current language with metadata (name, nativeName, etc.)
816
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
817
+ * @returns Language metadata object or null if not set
818
+ */
819
+ async getCurrentLanguageMetadata(storageKeyPrefix = 'oxy_session') {
820
+ const languageCode = await this.getCurrentLanguage(storageKeyPrefix);
821
+ return (0, _languageUtils.getLanguageMetadata)(languageCode);
822
+ }
823
+
824
+ /**
825
+ * Get the current language name (e.g., 'English')
826
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
827
+ * @returns Language name or null if not set
828
+ */
829
+ async getCurrentLanguageName(storageKeyPrefix = 'oxy_session') {
830
+ const languageCode = await this.getCurrentLanguage(storageKeyPrefix);
831
+ if (!languageCode) return null;
832
+ return (0, _languageUtils.getLanguageName)(languageCode);
833
+ }
834
+
835
+ /**
836
+ * Get the current native language name (e.g., 'Español')
837
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
838
+ * @returns Native language name or null if not set
839
+ */
840
+ async getCurrentNativeLanguageName(storageKeyPrefix = 'oxy_session') {
841
+ const languageCode = await this.getCurrentLanguage(storageKeyPrefix);
842
+ if (!languageCode) return null;
843
+ return (0, _languageUtils.getNativeLanguageName)(languageCode);
844
+ }
845
+
846
+ /**
847
+ * Get appropriate storage for the platform (similar to DeviceManager)
848
+ * @private
849
+ */
850
+ async getStorage() {
851
+ const isReactNative = typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
852
+ if (isReactNative) {
853
+ try {
854
+ const asyncStorageModule = await Promise.resolve().then(() => _interopRequireWildcard(require('@react-native-async-storage/async-storage')));
855
+ const storage = asyncStorageModule.default;
856
+ return {
857
+ getItem: storage.getItem.bind(storage),
858
+ setItem: storage.setItem.bind(storage),
859
+ removeItem: storage.removeItem.bind(storage)
860
+ };
861
+ } catch (error) {
862
+ console.error('AsyncStorage not available in React Native:', error);
863
+ throw new Error('AsyncStorage is required in React Native environment');
864
+ }
865
+ } else {
866
+ // Use localStorage for web
867
+ return {
868
+ getItem: async key => {
869
+ if (typeof window !== 'undefined' && window.localStorage) {
870
+ return localStorage.getItem(key);
871
+ }
872
+ return null;
873
+ },
874
+ setItem: async (key, value) => {
875
+ if (typeof window !== 'undefined' && window.localStorage) {
876
+ localStorage.setItem(key, value);
877
+ }
878
+ },
879
+ removeItem: async key => {
880
+ if (typeof window !== 'undefined' && window.localStorage) {
881
+ localStorage.removeItem(key);
882
+ }
883
+ }
884
+ };
885
+ }
886
+ }
887
+
798
888
  /**
799
889
  * Update user by ID (admin function)
800
890
  */
801
891
  async updateUser(userId, updates) {
802
892
  try {
803
- const res = await this.client.put(`/api/users/${userId}`, updates);
804
- return res.data;
893
+ return await this.makeRequest('PUT', `/api/users/${userId}`, updates, {
894
+ cache: false
895
+ });
805
896
  } catch (error) {
806
897
  throw this.handleError(error);
807
898
  }
@@ -812,8 +903,9 @@ class OxyServices {
812
903
  */
813
904
  async followUser(userId) {
814
905
  try {
815
- const res = await this.client.post(`/api/users/${userId}/follow`);
816
- return res.data;
906
+ return await this.makeRequest('POST', `/api/users/${userId}/follow`, undefined, {
907
+ cache: false
908
+ });
817
909
  } catch (error) {
818
910
  throw this.handleError(error);
819
911
  }
@@ -824,8 +916,9 @@ class OxyServices {
824
916
  */
825
917
  async unfollowUser(userId) {
826
918
  try {
827
- const res = await this.client.delete(`/api/users/${userId}/follow`);
828
- return res.data;
919
+ return await this.makeRequest('DELETE', `/api/users/${userId}/follow`, undefined, {
920
+ cache: false
921
+ });
829
922
  } catch (error) {
830
923
  throw this.handleError(error);
831
924
  }
@@ -836,8 +929,10 @@ class OxyServices {
836
929
  */
837
930
  async getFollowStatus(userId) {
838
931
  try {
839
- const res = await this.client.get(`/api/users/${userId}/follow-status`);
840
- return res.data;
932
+ return await this.makeRequest('GET', `/api/users/${userId}/follow-status`, undefined, {
933
+ cache: true,
934
+ cacheTTL: 1 * 60 * 1000 // 1 minute cache
935
+ });
841
936
  } catch (error) {
842
937
  throw this.handleError(error);
843
938
  }
@@ -849,8 +944,15 @@ class OxyServices {
849
944
  async getUserFollowers(userId, pagination) {
850
945
  try {
851
946
  const params = (0, _apiUtils.buildPaginationParams)(pagination || {});
852
- const res = await this.client.get(`/api/users/${userId}/followers?${params.toString()}`);
853
- return res.data;
947
+ const response = await this.makeRequest('GET', `/api/users/${userId}/followers`, params, {
948
+ cache: true,
949
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
950
+ });
951
+ return {
952
+ followers: response.data || [],
953
+ total: response.pagination.total,
954
+ hasMore: response.pagination.hasMore
955
+ };
854
956
  } catch (error) {
855
957
  throw this.handleError(error);
856
958
  }
@@ -862,8 +964,15 @@ class OxyServices {
862
964
  async getUserFollowing(userId, pagination) {
863
965
  try {
864
966
  const params = (0, _apiUtils.buildPaginationParams)(pagination || {});
865
- const res = await this.client.get(`/api/users/${userId}/following?${params.toString()}`);
866
- return res.data;
967
+ const response = await this.makeRequest('GET', `/api/users/${userId}/following`, params, {
968
+ cache: true,
969
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
970
+ });
971
+ return {
972
+ following: response.data || [],
973
+ total: response.pagination.total,
974
+ hasMore: response.pagination.hasMore
975
+ };
867
976
  } catch (error) {
868
977
  throw this.handleError(error);
869
978
  }
@@ -874,8 +983,9 @@ class OxyServices {
874
983
  */
875
984
  async getNotifications() {
876
985
  return this.withAuthRetry(async () => {
877
- const res = await this.client.get('/api/notifications');
878
- return res.data;
986
+ return await this.makeRequest('GET', '/api/notifications', undefined, {
987
+ cache: false // Don't cache notifications - always get fresh data
988
+ });
879
989
  }, 'getNotifications');
880
990
  }
881
991
 
@@ -884,8 +994,10 @@ class OxyServices {
884
994
  */
885
995
  async getUnreadCount() {
886
996
  try {
887
- const res = await this.client.get('/api/notifications/unread-count');
888
- return res.data.count;
997
+ const res = await this.makeRequest('GET', '/api/notifications/unread-count', undefined, {
998
+ cache: false // Don't cache unread count - always get fresh data
999
+ });
1000
+ return res.count;
889
1001
  } catch (error) {
890
1002
  throw this.handleError(error);
891
1003
  }
@@ -896,8 +1008,9 @@ class OxyServices {
896
1008
  */
897
1009
  async createNotification(data) {
898
1010
  try {
899
- const res = await this.client.post('/api/notifications', data);
900
- return res.data;
1011
+ return await this.makeRequest('POST', '/api/notifications', data, {
1012
+ cache: false
1013
+ });
901
1014
  } catch (error) {
902
1015
  throw this.handleError(error);
903
1016
  }
@@ -908,7 +1021,9 @@ class OxyServices {
908
1021
  */
909
1022
  async markNotificationAsRead(notificationId) {
910
1023
  try {
911
- await this.client.put(`/api/notifications/${notificationId}/read`);
1024
+ await this.makeRequest('PUT', `/api/notifications/${notificationId}/read`, undefined, {
1025
+ cache: false
1026
+ });
912
1027
  } catch (error) {
913
1028
  throw this.handleError(error);
914
1029
  }
@@ -919,7 +1034,9 @@ class OxyServices {
919
1034
  */
920
1035
  async markAllNotificationsAsRead() {
921
1036
  try {
922
- await this.client.put('/api/notifications/read-all');
1037
+ await this.makeRequest('PUT', '/api/notifications/read-all', undefined, {
1038
+ cache: false
1039
+ });
923
1040
  } catch (error) {
924
1041
  throw this.handleError(error);
925
1042
  }
@@ -930,7 +1047,9 @@ class OxyServices {
930
1047
  */
931
1048
  async deleteNotification(notificationId) {
932
1049
  try {
933
- await this.client.delete(`/api/notifications/${notificationId}`);
1050
+ await this.makeRequest('DELETE', `/api/notifications/${notificationId}`, undefined, {
1051
+ cache: false
1052
+ });
934
1053
  } catch (error) {
935
1054
  throw this.handleError(error);
936
1055
  }
@@ -945,8 +1064,9 @@ class OxyServices {
945
1064
  */
946
1065
  async createPayment(data) {
947
1066
  try {
948
- const res = await this.client.post('/api/payments', data);
949
- return res.data;
1067
+ return await this.makeRequest('POST', '/api/payments', data, {
1068
+ cache: false
1069
+ });
950
1070
  } catch (error) {
951
1071
  throw this.handleError(error);
952
1072
  }
@@ -957,8 +1077,10 @@ class OxyServices {
957
1077
  */
958
1078
  async getPayment(paymentId) {
959
1079
  try {
960
- const res = await this.client.get(`/api/payments/${paymentId}`);
961
- return res.data;
1080
+ return await this.makeRequest('GET', `/api/payments/${paymentId}`, undefined, {
1081
+ cache: true,
1082
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1083
+ });
962
1084
  } catch (error) {
963
1085
  throw this.handleError(error);
964
1086
  }
@@ -969,8 +1091,9 @@ class OxyServices {
969
1091
  */
970
1092
  async getUserPayments() {
971
1093
  try {
972
- const res = await this.client.get('/api/payments/user');
973
- return res.data;
1094
+ return await this.makeRequest('GET', '/api/payments/user', undefined, {
1095
+ cache: false // Don't cache user payments - always get fresh data
1096
+ });
974
1097
  } catch (error) {
975
1098
  throw this.handleError(error);
976
1099
  }
@@ -985,8 +1108,10 @@ class OxyServices {
985
1108
  */
986
1109
  async getUserKarma(userId) {
987
1110
  try {
988
- const res = await this.client.get(`/api/karma/${userId}`);
989
- return res.data;
1111
+ return await this.makeRequest('GET', `/api/karma/${userId}`, undefined, {
1112
+ cache: true,
1113
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
1114
+ });
990
1115
  } catch (error) {
991
1116
  throw this.handleError(error);
992
1117
  }
@@ -997,11 +1122,12 @@ class OxyServices {
997
1122
  */
998
1123
  async giveKarma(userId, amount, reason) {
999
1124
  try {
1000
- const res = await this.client.post(`/api/karma/${userId}/give`, {
1125
+ return await this.makeRequest('POST', `/api/karma/${userId}/give`, {
1001
1126
  amount,
1002
1127
  reason
1128
+ }, {
1129
+ cache: false
1003
1130
  });
1004
- return res.data;
1005
1131
  } catch (error) {
1006
1132
  throw this.handleError(error);
1007
1133
  }
@@ -1012,8 +1138,10 @@ class OxyServices {
1012
1138
  */
1013
1139
  async getUserKarmaTotal(userId) {
1014
1140
  try {
1015
- const res = await this.client.get(`/api/karma/${userId}/total`);
1016
- return res.data;
1141
+ return await this.makeRequest('GET', `/api/karma/${userId}/total`, undefined, {
1142
+ cache: true,
1143
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
1144
+ });
1017
1145
  } catch (error) {
1018
1146
  throw this.handleError(error);
1019
1147
  }
@@ -1024,11 +1152,13 @@ class OxyServices {
1024
1152
  */
1025
1153
  async getUserKarmaHistory(userId, limit, offset) {
1026
1154
  try {
1027
- const params = new URLSearchParams();
1028
- if (limit) params.append('limit', limit.toString());
1029
- if (offset) params.append('offset', offset.toString());
1030
- const res = await this.client.get(`/api/karma/${userId}/history?${params.toString()}`);
1031
- return res.data;
1155
+ const params = {};
1156
+ if (limit) params.limit = limit;
1157
+ if (offset) params.offset = offset;
1158
+ return await this.makeRequest('GET', `/api/karma/${userId}/history`, params, {
1159
+ cache: true,
1160
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
1161
+ });
1032
1162
  } catch (error) {
1033
1163
  throw this.handleError(error);
1034
1164
  }
@@ -1039,8 +1169,10 @@ class OxyServices {
1039
1169
  */
1040
1170
  async getKarmaLeaderboard() {
1041
1171
  try {
1042
- const res = await this.client.get('/api/karma/leaderboard');
1043
- return res.data;
1172
+ return await this.makeRequest('GET', '/api/karma/leaderboard', undefined, {
1173
+ cache: true,
1174
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1175
+ });
1044
1176
  } catch (error) {
1045
1177
  throw this.handleError(error);
1046
1178
  }
@@ -1051,8 +1183,10 @@ class OxyServices {
1051
1183
  */
1052
1184
  async getKarmaRules() {
1053
1185
  try {
1054
- const res = await this.client.get('/api/karma/rules');
1055
- return res.data;
1186
+ return await this.makeRequest('GET', '/api/karma/rules', undefined, {
1187
+ cache: true,
1188
+ cacheTTL: 30 * 60 * 1000 // 30 minutes cache (rules don't change often)
1189
+ });
1056
1190
  } catch (error) {
1057
1191
  throw this.handleError(error);
1058
1192
  }
@@ -1068,8 +1202,9 @@ class OxyServices {
1068
1202
  async deleteFile(fileId) {
1069
1203
  try {
1070
1204
  // Central Asset Service delete with force=true behavior controlled by caller via assetDelete
1071
- const res = await this.client.delete(`/api/assets/${encodeURIComponent(fileId)}`);
1072
- return res.data;
1205
+ return await this.makeRequest('DELETE', `/api/assets/${encodeURIComponent(fileId)}`, undefined, {
1206
+ cache: false
1207
+ });
1073
1208
  } catch (error) {
1074
1209
  throw this.handleError(error);
1075
1210
  }
@@ -1084,7 +1219,7 @@ class OxyServices {
1084
1219
  if (variant) params.set('variant', variant);
1085
1220
  if (expiresIn) params.set('expiresIn', String(expiresIn));
1086
1221
  params.set('fallback', 'placeholderVisible');
1087
- const token = this.tokenStore.getAccessToken();
1222
+ const token = this.httpClient.getAccessToken();
1088
1223
  if (token) params.set('token', token);
1089
1224
 
1090
1225
  // Use params.toString() to detect whether there are query params.
@@ -1110,12 +1245,12 @@ class OxyServices {
1110
1245
  */
1111
1246
  async listUserFiles(limit, offset) {
1112
1247
  try {
1113
- const params = new URLSearchParams();
1114
- if (limit) params.append('limit', String(limit));
1115
- if (offset) params.append('offset', String(offset));
1116
- const qs = params.toString();
1117
- const res = await this.client.get(`/api/assets${qs ? `?${qs}` : ''}`);
1118
- return res.data;
1248
+ const paramsObj = {};
1249
+ if (limit) paramsObj.limit = limit;
1250
+ if (offset) paramsObj.offset = offset;
1251
+ return await this.makeRequest('GET', '/api/assets', paramsObj, {
1252
+ cache: false // Don't cache file lists - always get fresh data
1253
+ });
1119
1254
  } catch (error) {
1120
1255
  throw this.handleError(error);
1121
1256
  }
@@ -1128,8 +1263,14 @@ class OxyServices {
1128
1263
  */
1129
1264
  async getFileContentAsText(fileId, variant) {
1130
1265
  try {
1131
- const urlRes = await this.client.get(`/api/assets/${encodeURIComponent(fileId)}/url${variant ? `?variant=${encodeURIComponent(variant)}` : ''}`);
1132
- const downloadUrl = urlRes.data?.url;
1266
+ const params = variant ? {
1267
+ variant
1268
+ } : undefined;
1269
+ const urlRes = await this.makeRequest('GET', `/api/assets/${encodeURIComponent(fileId)}/url`, params, {
1270
+ cache: true,
1271
+ cacheTTL: 10 * 60 * 1000 // 10 minutes cache for URLs
1272
+ });
1273
+ const downloadUrl = urlRes?.url;
1133
1274
  const response = await fetch(downloadUrl);
1134
1275
  return await response.text();
1135
1276
  } catch (error) {
@@ -1142,8 +1283,14 @@ class OxyServices {
1142
1283
  */
1143
1284
  async getFileContentAsBlob(fileId, variant) {
1144
1285
  try {
1145
- const urlRes = await this.client.get(`/api/assets/${encodeURIComponent(fileId)}/url${variant ? `?variant=${encodeURIComponent(variant)}` : ''}`);
1146
- const downloadUrl = urlRes.data?.url;
1286
+ const params = variant ? {
1287
+ variant
1288
+ } : undefined;
1289
+ const urlRes = await this.makeRequest('GET', `/api/assets/${encodeURIComponent(fileId)}/url`, params, {
1290
+ cache: true,
1291
+ cacheTTL: 10 * 60 * 1000 // 10 minutes cache for URLs
1292
+ });
1293
+ const downloadUrl = urlRes?.url;
1147
1294
  const response = await fetch(downloadUrl);
1148
1295
  return await response.blob();
1149
1296
  } catch (error) {
@@ -1178,12 +1325,13 @@ class OxyServices {
1178
1325
  */
1179
1326
  async assetInit(sha256, size, mime) {
1180
1327
  try {
1181
- const res = await this.client.post('/api/assets/init', {
1328
+ return await this.makeRequest('POST', '/api/assets/init', {
1182
1329
  sha256,
1183
1330
  size,
1184
1331
  mime
1332
+ }, {
1333
+ cache: false
1185
1334
  });
1186
- return res.data;
1187
1335
  } catch (error) {
1188
1336
  throw this.handleError(error);
1189
1337
  }
@@ -1194,15 +1342,16 @@ class OxyServices {
1194
1342
  */
1195
1343
  async assetComplete(fileId, originalName, size, mime, visibility, metadata) {
1196
1344
  try {
1197
- const res = await this.client.post('/api/assets/complete', {
1345
+ return await this.makeRequest('POST', '/api/assets/complete', {
1198
1346
  fileId,
1199
1347
  originalName,
1200
1348
  size,
1201
1349
  mime,
1202
1350
  visibility,
1203
1351
  metadata
1352
+ }, {
1353
+ cache: false
1204
1354
  });
1205
- return res.data;
1206
1355
  } catch (error) {
1207
1356
  throw this.handleError(error);
1208
1357
  }
@@ -1226,10 +1375,11 @@ class OxyServices {
1226
1375
  // Fallback: direct upload via API to avoid CORS issues
1227
1376
  const fd = new FormData();
1228
1377
  fd.append('file', file);
1229
- await this.client.post(`/api/assets/${encodeURIComponent(initResponse.fileId)}/upload-direct`, fd, {
1230
- headers: {
1231
- 'Content-Type': 'multipart/form-data'
1232
- }
1378
+ // Use httpClient directly for FormData uploads (bypasses RequestManager for special handling)
1379
+ await this.httpClient.request({
1380
+ method: 'POST',
1381
+ url: `/api/assets/${encodeURIComponent(initResponse.fileId)}/upload-direct`,
1382
+ data: fd
1233
1383
  });
1234
1384
  }
1235
1385
 
@@ -1280,8 +1430,9 @@ class OxyServices {
1280
1430
  };
1281
1431
  if (visibility) body.visibility = visibility;
1282
1432
  if (webhookUrl) body.webhookUrl = webhookUrl;
1283
- const res = await this.client.post(`/api/assets/${fileId}/links`, body);
1284
- return res.data;
1433
+ return await this.makeRequest('POST', `/api/assets/${fileId}/links`, body, {
1434
+ cache: false
1435
+ });
1285
1436
  } catch (error) {
1286
1437
  throw this.handleError(error);
1287
1438
  }
@@ -1292,14 +1443,13 @@ class OxyServices {
1292
1443
  */
1293
1444
  async assetUnlink(fileId, app, entityType, entityId) {
1294
1445
  try {
1295
- const res = await this.client.delete(`/api/assets/${fileId}/links`, {
1296
- data: {
1297
- app,
1298
- entityType,
1299
- entityId
1300
- }
1446
+ return await this.makeRequest('DELETE', `/api/assets/${fileId}/links`, {
1447
+ app,
1448
+ entityType,
1449
+ entityId
1450
+ }, {
1451
+ cache: false
1301
1452
  });
1302
- return res.data;
1303
1453
  } catch (error) {
1304
1454
  throw this.handleError(error);
1305
1455
  }
@@ -1310,8 +1460,10 @@ class OxyServices {
1310
1460
  */
1311
1461
  async assetGet(fileId) {
1312
1462
  try {
1313
- const res = await this.client.get(`/api/assets/${fileId}`);
1314
- return res.data;
1463
+ return await this.makeRequest('GET', `/api/assets/${fileId}`, undefined, {
1464
+ cache: true,
1465
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1466
+ });
1315
1467
  } catch (error) {
1316
1468
  throw this.handleError(error);
1317
1469
  }
@@ -1322,13 +1474,13 @@ class OxyServices {
1322
1474
  */
1323
1475
  async assetGetUrl(fileId, variant, expiresIn) {
1324
1476
  try {
1325
- const params = new URLSearchParams();
1326
- if (variant) params.set('variant', variant);
1327
- if (expiresIn) params.set('expiresIn', expiresIn.toString());
1328
- const queryString = params.toString();
1329
- const url = `/api/assets/${fileId}/url${queryString ? `?${queryString}` : ''}`;
1330
- const res = await this.client.get(url);
1331
- return res.data;
1477
+ const params = {};
1478
+ if (variant) params.variant = variant;
1479
+ if (expiresIn) params.expiresIn = expiresIn;
1480
+ return await this.makeRequest('GET', `/api/assets/${fileId}/url`, params, {
1481
+ cache: true,
1482
+ cacheTTL: 10 * 60 * 1000 // 10 minutes cache for URLs
1483
+ });
1332
1484
  } catch (error) {
1333
1485
  throw this.handleError(error);
1334
1486
  }
@@ -1339,8 +1491,9 @@ class OxyServices {
1339
1491
  */
1340
1492
  async assetRestore(fileId) {
1341
1493
  try {
1342
- const res = await this.client.post(`/api/assets/${fileId}/restore`);
1343
- return res.data;
1494
+ return await this.makeRequest('POST', `/api/assets/${fileId}/restore`, undefined, {
1495
+ cache: false
1496
+ });
1344
1497
  } catch (error) {
1345
1498
  throw this.handleError(error);
1346
1499
  }
@@ -1351,9 +1504,12 @@ class OxyServices {
1351
1504
  */
1352
1505
  async assetDelete(fileId, force = false) {
1353
1506
  try {
1354
- const params = force ? '?force=true' : '';
1355
- const res = await this.client.delete(`/api/assets/${fileId}${params}`);
1356
- return res.data;
1507
+ const params = force ? {
1508
+ force: 'true'
1509
+ } : undefined;
1510
+ return await this.makeRequest('DELETE', `/api/assets/${fileId}`, params, {
1511
+ cache: false
1512
+ });
1357
1513
  } catch (error) {
1358
1514
  throw this.handleError(error);
1359
1515
  }
@@ -1379,10 +1535,11 @@ class OxyServices {
1379
1535
  */
1380
1536
  async assetUpdateVisibility(fileId, visibility) {
1381
1537
  try {
1382
- const res = await this.client.patch(`/api/assets/${fileId}/visibility`, {
1538
+ return await this.makeRequest('PATCH', `/api/assets/${fileId}/visibility`, {
1383
1539
  visibility
1540
+ }, {
1541
+ cache: false
1384
1542
  });
1385
- return res.data;
1386
1543
  } catch (error) {
1387
1544
  throw this.handleError(error);
1388
1545
  }
@@ -1437,8 +1594,11 @@ class OxyServices {
1437
1594
  */
1438
1595
  async getDeveloperApps() {
1439
1596
  try {
1440
- const res = await this.client.get('/api/developer/apps');
1441
- return res.data.apps || [];
1597
+ const res = await this.makeRequest('GET', '/api/developer/apps', undefined, {
1598
+ cache: true,
1599
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
1600
+ });
1601
+ return res.apps || [];
1442
1602
  } catch (error) {
1443
1603
  throw this.handleError(error);
1444
1604
  }
@@ -1449,8 +1609,10 @@ class OxyServices {
1449
1609
  */
1450
1610
  async createDeveloperApp(data) {
1451
1611
  try {
1452
- const res = await this.client.post('/api/developer/apps', data);
1453
- return res.data.app;
1612
+ const res = await this.makeRequest('POST', '/api/developer/apps', data, {
1613
+ cache: false
1614
+ });
1615
+ return res.app;
1454
1616
  } catch (error) {
1455
1617
  throw this.handleError(error);
1456
1618
  }
@@ -1461,8 +1623,11 @@ class OxyServices {
1461
1623
  */
1462
1624
  async getDeveloperApp(appId) {
1463
1625
  try {
1464
- const res = await this.client.get(`/api/developer/apps/${appId}`);
1465
- return res.data.app;
1626
+ const res = await this.makeRequest('GET', `/api/developer/apps/${appId}`, undefined, {
1627
+ cache: true,
1628
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1629
+ });
1630
+ return res.app;
1466
1631
  } catch (error) {
1467
1632
  throw this.handleError(error);
1468
1633
  }
@@ -1473,8 +1638,10 @@ class OxyServices {
1473
1638
  */
1474
1639
  async updateDeveloperApp(appId, data) {
1475
1640
  try {
1476
- const res = await this.client.patch(`/api/developer/apps/${appId}`, data);
1477
- return res.data.app;
1641
+ const res = await this.makeRequest('PATCH', `/api/developer/apps/${appId}`, data, {
1642
+ cache: false
1643
+ });
1644
+ return res.app;
1478
1645
  } catch (error) {
1479
1646
  throw this.handleError(error);
1480
1647
  }
@@ -1485,8 +1652,9 @@ class OxyServices {
1485
1652
  */
1486
1653
  async regenerateDeveloperAppSecret(appId) {
1487
1654
  try {
1488
- const res = await this.client.post(`/api/developer/apps/${appId}/regenerate-secret`);
1489
- return res.data;
1655
+ return await this.makeRequest('POST', `/api/developer/apps/${appId}/regenerate-secret`, undefined, {
1656
+ cache: false
1657
+ });
1490
1658
  } catch (error) {
1491
1659
  throw this.handleError(error);
1492
1660
  }
@@ -1497,8 +1665,9 @@ class OxyServices {
1497
1665
  */
1498
1666
  async deleteDeveloperApp(appId) {
1499
1667
  try {
1500
- const res = await this.client.delete(`/api/developer/apps/${appId}`);
1501
- return res.data;
1668
+ return await this.makeRequest('DELETE', `/api/developer/apps/${appId}`, undefined, {
1669
+ cache: false
1670
+ });
1502
1671
  } catch (error) {
1503
1672
  throw this.handleError(error);
1504
1673
  }
@@ -1513,11 +1682,12 @@ class OxyServices {
1513
1682
  */
1514
1683
  async updateLocation(latitude, longitude) {
1515
1684
  try {
1516
- const res = await this.client.post('/api/location', {
1685
+ return await this.makeRequest('POST', '/api/location', {
1517
1686
  latitude,
1518
1687
  longitude
1688
+ }, {
1689
+ cache: false
1519
1690
  });
1520
- return res.data;
1521
1691
  } catch (error) {
1522
1692
  throw this.handleError(error);
1523
1693
  }
@@ -1528,9 +1698,12 @@ class OxyServices {
1528
1698
  */
1529
1699
  async getNearbyUsers(radius) {
1530
1700
  try {
1531
- const params = radius ? `?radius=${radius}` : '';
1532
- const res = await this.client.get(`/api/location/nearby${params}`);
1533
- return res.data;
1701
+ const params = radius ? {
1702
+ radius
1703
+ } : undefined;
1704
+ return await this.makeRequest('GET', '/api/location/nearby', params, {
1705
+ cache: false // Don't cache location data - always get fresh data
1706
+ });
1534
1707
  } catch (error) {
1535
1708
  throw this.handleError(error);
1536
1709
  }
@@ -1545,10 +1718,13 @@ class OxyServices {
1545
1718
  */
1546
1719
  async trackEvent(eventName, properties) {
1547
1720
  try {
1548
- await this.client.post('/api/analytics/events', {
1721
+ await this.makeRequest('POST', '/api/analytics/events', {
1549
1722
  event: eventName,
1550
1723
  properties
1551
- });
1724
+ }, {
1725
+ cache: false,
1726
+ retry: false
1727
+ }); // Don't retry analytics events
1552
1728
  } catch (error) {
1553
1729
  throw this.handleError(error);
1554
1730
  }
@@ -1559,11 +1735,13 @@ class OxyServices {
1559
1735
  */
1560
1736
  async getAnalytics(startDate, endDate) {
1561
1737
  try {
1562
- const params = new URLSearchParams();
1563
- if (startDate) params.append('startDate', startDate);
1564
- if (endDate) params.append('endDate', endDate);
1565
- const res = await this.client.get(`/api/analytics?${params.toString()}`);
1566
- return res.data;
1738
+ const params = {};
1739
+ if (startDate) params.startDate = startDate;
1740
+ if (endDate) params.endDate = endDate;
1741
+ return await this.makeRequest('GET', '/api/analytics', params, {
1742
+ cache: true,
1743
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1744
+ });
1567
1745
  } catch (error) {
1568
1746
  throw this.handleError(error);
1569
1747
  }
@@ -1578,8 +1756,9 @@ class OxyServices {
1578
1756
  */
1579
1757
  async registerDevice(deviceData) {
1580
1758
  try {
1581
- const res = await this.client.post('/api/devices', deviceData);
1582
- return res.data;
1759
+ return await this.makeRequest('POST', '/api/devices', deviceData, {
1760
+ cache: false
1761
+ });
1583
1762
  } catch (error) {
1584
1763
  throw this.handleError(error);
1585
1764
  }
@@ -1590,8 +1769,9 @@ class OxyServices {
1590
1769
  */
1591
1770
  async getUserDevices() {
1592
1771
  try {
1593
- const res = await this.client.get('/api/devices');
1594
- return res.data;
1772
+ return await this.makeRequest('GET', '/api/devices', undefined, {
1773
+ cache: false // Don't cache device list - always get fresh data
1774
+ });
1595
1775
  } catch (error) {
1596
1776
  throw this.handleError(error);
1597
1777
  }
@@ -1602,7 +1782,9 @@ class OxyServices {
1602
1782
  */
1603
1783
  async removeDevice(deviceId) {
1604
1784
  try {
1605
- await this.client.delete(`/api/devices/${deviceId}`);
1785
+ await this.makeRequest('DELETE', `/api/devices/${deviceId}`, undefined, {
1786
+ cache: false
1787
+ });
1606
1788
  } catch (error) {
1607
1789
  throw this.handleError(error);
1608
1790
  }
@@ -1610,11 +1792,17 @@ class OxyServices {
1610
1792
 
1611
1793
  /**
1612
1794
  * Get device sessions
1795
+ * Note: Not cached by default to ensure fresh data, but can be cached via makeRequest if needed
1613
1796
  */
1614
1797
  async getDeviceSessions(sessionId) {
1615
1798
  try {
1616
- const res = await this.client.get(`/api/session/device/sessions/${sessionId}`);
1617
- return res.data;
1799
+ // Use makeRequest for consistent error handling and optional caching
1800
+ // Cache disabled by default to ensure fresh session data
1801
+ return await this.makeRequest('GET', `/api/session/device/sessions/${sessionId}`, undefined, {
1802
+ cache: false,
1803
+ // Don't cache sessions - always get fresh data
1804
+ deduplicate: true // Deduplicate concurrent requests for same sessionId
1805
+ });
1618
1806
  } catch (error) {
1619
1807
  throw this.handleError(error);
1620
1808
  }
@@ -1628,8 +1816,13 @@ class OxyServices {
1628
1816
  const params = new URLSearchParams();
1629
1817
  if (deviceId) params.append('deviceId', deviceId);
1630
1818
  if (excludeCurrent) params.append('excludeCurrent', 'true');
1631
- const res = await this.client.post(`/api/session/device/logout-all/${sessionId}?${params.toString()}`);
1632
- return res.data;
1819
+ const urlParams = {};
1820
+ params.forEach((value, key) => {
1821
+ urlParams[key] = value;
1822
+ });
1823
+ return await this.makeRequest('POST', `/api/session/device/logout-all/${sessionId}`, urlParams, {
1824
+ cache: false
1825
+ });
1633
1826
  } catch (error) {
1634
1827
  throw this.handleError(error);
1635
1828
  }
@@ -1640,10 +1833,11 @@ class OxyServices {
1640
1833
  */
1641
1834
  async updateDeviceName(sessionId, deviceName) {
1642
1835
  try {
1643
- const res = await this.client.put(`/api/session/device/name/${sessionId}`, {
1836
+ return await this.makeRequest('PUT', `/api/session/device/name/${sessionId}`, {
1644
1837
  deviceName
1838
+ }, {
1839
+ cache: false
1645
1840
  });
1646
- return res.data;
1647
1841
  } catch (error) {
1648
1842
  throw this.handleError(error);
1649
1843
  }
@@ -1658,8 +1852,12 @@ class OxyServices {
1658
1852
  */
1659
1853
  async fetchLinkMetadata(url) {
1660
1854
  try {
1661
- const res = await this.client.get(`/api/link-metadata?url=${encodeURIComponent(url)}`);
1662
- return res.data;
1855
+ return await this.makeRequest('GET', '/api/link-metadata', {
1856
+ url
1857
+ }, {
1858
+ cache: true,
1859
+ cacheTTL: 30 * 60 * 1000 // 30 minutes cache for link metadata
1860
+ });
1663
1861
  } catch (error) {
1664
1862
  throw this.handleError(error);
1665
1863
  }