@oxyhq/services 5.13.1 → 5.13.3

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 +538 -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 +536 -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 +88 -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 +466 -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
@@ -58,8 +58,8 @@
58
58
  *
59
59
  * See method JSDoc for more details and options.
60
60
  */
61
- import axios from 'axios';
62
61
  import { jwtDecode } from 'jwt-decode';
62
+ import { normalizeLanguageCode, getLanguageMetadata, getLanguageName, getNativeLanguageName } from '../utils/languageUtils';
63
63
 
64
64
  /**
65
65
  * OxyConfig - Configuration for OxyServices
@@ -69,6 +69,8 @@ import { jwtDecode } from 'jwt-decode';
69
69
 
70
70
  import { handleHttpError } from '../utils/errorUtils';
71
71
  import { buildSearchParams, buildPaginationParams } from '../utils/apiUtils';
72
+ import { HttpClient } from './HttpClient';
73
+ import { RequestManager } from './RequestManager';
72
74
  /**
73
75
  * Custom error types for better error handling
74
76
  */
@@ -91,42 +93,12 @@ export class OxyAuthenticationTimeoutError extends OxyAuthenticationError {
91
93
  * OxyServices - Unified client library for interacting with the Oxy API
92
94
  *
93
95
  * This class provides all API functionality in one simple, easy-to-use interface.
94
- * No need to manage multiple service instances - everything is available directly.
96
+ * Architecture:
97
+ * - HttpClient: Handles HTTP communication and authentication
98
+ * - RequestManager: Handles caching, deduplication, queuing, and retry
99
+ * - OxyServices: Provides high-level API methods
95
100
  */
96
- // Centralized token store
97
- class TokenStore {
98
- accessToken = null;
99
- refreshToken = null;
100
- constructor() {}
101
- static getInstance() {
102
- if (!TokenStore.instance) {
103
- TokenStore.instance = new TokenStore();
104
- }
105
- return TokenStore.instance;
106
- }
107
- setTokens(accessToken, refreshToken = '') {
108
- this.accessToken = accessToken;
109
- this.refreshToken = refreshToken;
110
- }
111
- getAccessToken() {
112
- return this.accessToken;
113
- }
114
- getRefreshToken() {
115
- return this.refreshToken;
116
- }
117
- clearTokens() {
118
- this.accessToken = null;
119
- this.refreshToken = null;
120
- }
121
- hasAccessToken() {
122
- return !!this.accessToken;
123
- }
124
- }
125
101
  export class OxyServices {
126
- /**
127
- * Creates a new instance of the OxyServices client
128
- * @param config - Configuration for the client
129
- */
130
102
  /**
131
103
  * Creates a new instance of the OxyServices client
132
104
  * @param config - Configuration for the client
@@ -134,89 +106,27 @@ export class OxyServices {
134
106
  * config.cloudURL: Oxy Cloud URL (e.g., https://cloud.oxy.so)
135
107
  */
136
108
  constructor(config) {
137
- this.client = axios.create({
138
- baseURL: config.baseURL,
139
- timeout: 5000 // 5 second timeout
140
- });
109
+ this.config = config;
141
110
  this.cloudURL = config.cloudURL || OXY_CLOUD_URL;
142
- this.tokenStore = TokenStore.getInstance();
143
- this.setupInterceptors();
111
+
112
+ // Initialize HTTP client (handles authentication and interceptors)
113
+ this.httpClient = new HttpClient(config);
114
+
115
+ // Initialize request manager (handles caching, deduplication, queuing, retry)
116
+ this.requestManager = new RequestManager(this.httpClient, config);
144
117
  }
145
118
 
146
119
  // Test-only utility to reset global tokens between jest tests
147
120
  static __resetTokensForTests() {
148
- try {
149
- TokenStore.getInstance().clearTokens();
150
- } catch {}
121
+ HttpClient.__resetTokensForTests();
151
122
  }
152
123
 
153
124
  /**
154
- * Setup axios interceptors for authentication and error handling
125
+ * Make a request with all performance optimizations
126
+ * This is the main method for all API calls - ensures authentication and performance features
155
127
  */
156
- setupInterceptors() {
157
- // Request interceptor for adding auth header and handling token refresh
158
- this.client.interceptors.request.use(async req => {
159
- console.log('🔍 Interceptor - URL:', req.url);
160
- console.log('🔍 Interceptor - Has token:', this.tokenStore.hasAccessToken());
161
- const accessToken = this.tokenStore.getAccessToken();
162
- if (!accessToken) {
163
- console.log('❌ Interceptor - No token available');
164
- return req;
165
- }
166
- try {
167
- console.log('✅ Interceptor - Adding Authorization header');
168
- const decoded = jwtDecode(accessToken);
169
- const currentTime = Math.floor(Date.now() / 1000);
170
-
171
- // If token expires in less than 60 seconds, refresh it
172
- if (decoded.exp && decoded.exp - currentTime < 60) {
173
- // For session-based tokens, get a new token from the session
174
- if (decoded.sessionId) {
175
- try {
176
- // Create a new axios instance to avoid interceptor recursion
177
- const refreshClient = axios.create({
178
- baseURL: this.client.defaults.baseURL,
179
- timeout: this.client.defaults.timeout
180
- });
181
- const res = await refreshClient.get(`/api/session/token/${decoded.sessionId}`);
182
- this.tokenStore.setTokens(res.data.accessToken);
183
- req.headers.Authorization = `Bearer ${res.data.accessToken}`;
184
- console.log('✅ Interceptor - Token refreshed and Authorization header set');
185
- } catch (refreshError) {
186
- // If refresh fails, use current token anyway
187
- req.headers.Authorization = `Bearer ${accessToken}`;
188
- console.log('❌ Interceptor - Token refresh failed, using current token');
189
- }
190
- } else {
191
- // No session ID, use current token
192
- req.headers.Authorization = `Bearer ${accessToken}`;
193
- console.log('✅ Interceptor - No session ID, using current token');
194
- }
195
- } else {
196
- // Add authorization header with current token
197
- req.headers.Authorization = `Bearer ${accessToken}`;
198
- console.log('✅ Interceptor - Authorization header set with current token');
199
- }
200
- } catch (error) {
201
- console.log('❌ Interceptor - Error processing token:', error);
202
- // Even if there's an error, still try to use the token
203
- req.headers.Authorization = `Bearer ${accessToken}`;
204
- console.log('⚠️ Interceptor - Using token despite error');
205
- }
206
- return req;
207
- }, error => {
208
- console.log('❌ Interceptor - Request error:', error);
209
- return Promise.reject(error);
210
- });
211
-
212
- // Response interceptor for handling auth errors
213
- this.client.interceptors.response.use(response => response, error => {
214
- if (error.response?.status === 401) {
215
- console.log('❌ Response interceptor - 401 Unauthorized, clearing tokens');
216
- this.clearTokens();
217
- }
218
- return Promise.reject(error);
219
- });
128
+ async makeRequest(method, url, data, options = {}) {
129
+ return this.requestManager.request(method, url, data, options);
220
130
  }
221
131
 
222
132
  // ============================================================================
@@ -227,7 +137,35 @@ export class OxyServices {
227
137
  * Get the configured Oxy API base URL
228
138
  */
229
139
  getBaseURL() {
230
- return this.client.defaults.baseURL || '';
140
+ return this.httpClient.getBaseURL();
141
+ }
142
+
143
+ /**
144
+ * Get performance metrics
145
+ */
146
+ getMetrics() {
147
+ return this.requestManager.getMetrics();
148
+ }
149
+
150
+ /**
151
+ * Clear request cache
152
+ */
153
+ clearCache() {
154
+ this.requestManager.clearCache();
155
+ }
156
+
157
+ /**
158
+ * Clear specific cache entry
159
+ */
160
+ clearCacheEntry(key) {
161
+ this.requestManager.clearCacheEntry(key);
162
+ }
163
+
164
+ /**
165
+ * Get cache statistics
166
+ */
167
+ getCacheStats() {
168
+ return this.requestManager.getCacheStats();
231
169
  }
232
170
 
233
171
  /**
@@ -237,25 +175,33 @@ export class OxyServices {
237
175
  return this.cloudURL;
238
176
  }
239
177
 
178
+ /**
179
+ * Get the underlying HTTP client instance
180
+ * Useful for advanced use cases that need direct access to the HttpClient
181
+ */
182
+ getClient() {
183
+ return this.httpClient;
184
+ }
185
+
240
186
  /**
241
187
  * Set authentication tokens
242
188
  */
243
189
  setTokens(accessToken, refreshToken = '') {
244
- this.tokenStore.setTokens(accessToken, refreshToken);
190
+ this.httpClient.setTokens(accessToken, refreshToken);
245
191
  }
246
192
 
247
193
  /**
248
194
  * Clear stored authentication tokens
249
195
  */
250
196
  clearTokens() {
251
- this.tokenStore.clearTokens();
197
+ this.httpClient.clearTokens();
252
198
  }
253
199
 
254
200
  /**
255
201
  * Get the current user ID from the access token
256
202
  */
257
203
  getCurrentUserId() {
258
- const accessToken = this.tokenStore.getAccessToken();
204
+ const accessToken = this.httpClient.getAccessToken();
259
205
  if (!accessToken) {
260
206
  return null;
261
207
  }
@@ -271,21 +217,21 @@ export class OxyServices {
271
217
  * Check if the client has a valid access token
272
218
  */
273
219
  hasAccessToken() {
274
- return this.tokenStore.hasAccessToken();
220
+ return this.httpClient.hasAccessToken();
275
221
  }
276
222
 
277
223
  /**
278
224
  * Check if the client has a valid access token (public method)
279
225
  */
280
226
  hasValidToken() {
281
- return this.tokenStore.hasAccessToken();
227
+ return this.httpClient.hasAccessToken();
282
228
  }
283
229
 
284
230
  /**
285
231
  * Get the raw access token (for constructing anchor URLs when needed)
286
232
  */
287
233
  getAccessToken() {
288
- return this.tokenStore.getAccessToken();
234
+ return this.httpClient.getAccessToken();
289
235
  }
290
236
 
291
237
  /**
@@ -304,7 +250,7 @@ export class OxyServices {
304
250
  const checkInterval = 100; // Check every 100ms
305
251
 
306
252
  while (Date.now() - startTime < timeoutMs) {
307
- if (this.tokenStore.hasAccessToken()) {
253
+ if (this.httpClient.hasAccessToken()) {
308
254
  return true;
309
255
  }
310
256
  await new Promise(resolve => setTimeout(resolve, checkInterval));
@@ -325,15 +271,13 @@ export class OxyServices {
325
271
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
326
272
  try {
327
273
  // First attempt: check if we have a token
328
- if (!this.tokenStore.hasAccessToken()) {
274
+ if (!this.httpClient.hasAccessToken()) {
329
275
  if (attempt === 0) {
330
276
  // On first attempt, wait briefly for authentication to complete
331
- console.log(`🔄 ${operationName} - Waiting for authentication...`);
332
277
  const authReady = await this.waitForAuthentication(authTimeoutMs);
333
278
  if (!authReady) {
334
279
  throw new OxyAuthenticationTimeoutError(operationName, authTimeoutMs);
335
280
  }
336
- console.log(`✅ ${operationName} - Authentication ready, proceeding...`);
337
281
  } else {
338
282
  // On retry attempts, fail immediately if no token
339
283
  throw new OxyAuthenticationError(`Authentication required: ${operationName} requires a valid access token.`, 'AUTH_REQUIRED');
@@ -346,7 +290,6 @@ export class OxyServices {
346
290
  const isLastAttempt = attempt === maxRetries;
347
291
  const isAuthError = error?.response?.status === 401 || error?.code === 'MISSING_TOKEN' || error?.message?.includes('Authentication') || error instanceof OxyAuthenticationError;
348
292
  if (isAuthError && !isLastAttempt && !(error instanceof OxyAuthenticationTimeoutError)) {
349
- console.log(`🔄 ${operationName} - Auth error on attempt ${attempt + 1}, retrying in ${retryDelay}ms...`);
350
293
  await new Promise(resolve => setTimeout(resolve, retryDelay));
351
294
  continue;
352
295
  }
@@ -371,20 +314,16 @@ export class OxyServices {
371
314
  return false;
372
315
  }
373
316
  try {
374
- const res = await this.client.get('/api/auth/validate');
375
- return res.data.valid === true;
317
+ const res = await this.makeRequest('GET', '/api/auth/validate', undefined, {
318
+ cache: false,
319
+ retry: false
320
+ });
321
+ return res.valid === true;
376
322
  } catch (error) {
377
323
  return false;
378
324
  }
379
325
  }
380
326
 
381
- /**
382
- * Get the HTTP client instance (public for external use)
383
- */
384
- getClient() {
385
- return this.client;
386
- }
387
-
388
327
  /**
389
328
  * Centralized error handling
390
329
  */
@@ -402,8 +341,9 @@ export class OxyServices {
402
341
  */
403
342
  async healthCheck() {
404
343
  try {
405
- const res = await this.client.get('/health');
406
- return res.data;
344
+ return await this.makeRequest('GET', '/health', undefined, {
345
+ cache: false
346
+ });
407
347
  } catch (error) {
408
348
  throw this.handleError(error);
409
349
  }
@@ -418,15 +358,17 @@ export class OxyServices {
418
358
  */
419
359
  async signUp(username, email, password) {
420
360
  try {
421
- const res = await this.client.post('/api/auth/signup', {
361
+ const res = await this.makeRequest('POST', '/api/auth/signup', {
422
362
  username,
423
363
  email,
424
364
  password
365
+ }, {
366
+ cache: false
425
367
  });
426
- if (!res || !res.data || typeof res.data === 'object' && Object.keys(res.data).length === 0) {
368
+ if (!res || typeof res === 'object' && Object.keys(res).length === 0) {
427
369
  throw new OxyAuthenticationError('Sign up failed', 'SIGNUP_FAILED', 400);
428
370
  }
429
- return res.data;
371
+ return res;
430
372
  } catch (error) {
431
373
  throw this.handleError(error);
432
374
  }
@@ -437,10 +379,11 @@ export class OxyServices {
437
379
  */
438
380
  async requestRecovery(identifier) {
439
381
  try {
440
- const res = await this.client.post('/api/auth/recover/request', {
382
+ return await this.makeRequest('POST', '/api/auth/recover/request', {
441
383
  identifier
384
+ }, {
385
+ cache: false
442
386
  });
443
- return res.data;
444
387
  } catch (error) {
445
388
  throw this.handleError(error);
446
389
  }
@@ -451,11 +394,12 @@ export class OxyServices {
451
394
  */
452
395
  async verifyRecoveryCode(identifier, code) {
453
396
  try {
454
- const res = await this.client.post('/api/auth/recover/verify', {
397
+ return await this.makeRequest('POST', '/api/auth/recover/verify', {
455
398
  identifier,
456
399
  code
400
+ }, {
401
+ cache: false
457
402
  });
458
- return res.data;
459
403
  } catch (error) {
460
404
  throw this.handleError(error);
461
405
  }
@@ -466,12 +410,13 @@ export class OxyServices {
466
410
  */
467
411
  async resetPassword(identifier, code, newPassword) {
468
412
  try {
469
- const res = await this.client.post('/api/auth/recover/reset', {
413
+ return await this.makeRequest('POST', '/api/auth/recover/reset', {
470
414
  identifier,
471
415
  code,
472
416
  newPassword
417
+ }, {
418
+ cache: false
473
419
  });
474
- return res.data;
475
420
  } catch (error) {
476
421
  throw this.handleError(error);
477
422
  }
@@ -482,36 +427,39 @@ export class OxyServices {
482
427
  */
483
428
  async resetPasswordWithTotp(identifier, code, newPassword) {
484
429
  try {
485
- const res = await this.client.post('/api/auth/recover/totp/reset', {
430
+ return await this.makeRequest('POST', '/api/auth/recover/totp/reset', {
486
431
  identifier,
487
432
  code,
488
433
  newPassword
434
+ }, {
435
+ cache: false
489
436
  });
490
- return res.data;
491
437
  } catch (error) {
492
438
  throw this.handleError(error);
493
439
  }
494
440
  }
495
441
  async resetPasswordWithBackupCode(identifier, backupCode, newPassword) {
496
442
  try {
497
- const res = await this.client.post('/api/auth/recover/backup/reset', {
443
+ return await this.makeRequest('POST', '/api/auth/recover/backup/reset', {
498
444
  identifier,
499
445
  backupCode,
500
446
  newPassword
447
+ }, {
448
+ cache: false
501
449
  });
502
- return res.data;
503
450
  } catch (error) {
504
451
  throw this.handleError(error);
505
452
  }
506
453
  }
507
454
  async resetPasswordWithRecoveryKey(identifier, recoveryKey, newPassword) {
508
455
  try {
509
- const res = await this.client.post('/api/auth/recover/recovery-key/reset', {
456
+ return await this.makeRequest('POST', '/api/auth/recover/recovery-key/reset', {
510
457
  identifier,
511
458
  recoveryKey,
512
459
  newPassword
460
+ }, {
461
+ cache: false
513
462
  });
514
- return res.data;
515
463
  } catch (error) {
516
464
  throw this.handleError(error);
517
465
  }
@@ -522,13 +470,14 @@ export class OxyServices {
522
470
  */
523
471
  async signIn(username, password, deviceName, deviceFingerprint) {
524
472
  try {
525
- const res = await this.client.post('/api/auth/login', {
473
+ return await this.makeRequest('POST', '/api/auth/login', {
526
474
  username,
527
475
  password,
528
476
  deviceName,
529
477
  deviceFingerprint
478
+ }, {
479
+ cache: false
530
480
  });
531
- return res.data;
532
481
  } catch (error) {
533
482
  throw this.handleError(error);
534
483
  }
@@ -539,11 +488,12 @@ export class OxyServices {
539
488
  */
540
489
  async verifyTotpLogin(mfaToken, code) {
541
490
  try {
542
- const res = await this.client.post('/api/auth/totp/verify-login', {
491
+ return await this.makeRequest('POST', '/api/auth/totp/verify-login', {
543
492
  mfaToken,
544
493
  code
494
+ }, {
495
+ cache: false
545
496
  });
546
- return res.data;
547
497
  } catch (error) {
548
498
  throw this.handleError(error);
549
499
  }
@@ -554,8 +504,35 @@ export class OxyServices {
554
504
  */
555
505
  async getUserBySession(sessionId) {
556
506
  try {
557
- const res = await this.client.get(`/api/session/user/${sessionId}`);
558
- return res.data;
507
+ return await this.makeRequest('GET', `/api/session/user/${sessionId}`, undefined, {
508
+ cache: true,
509
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache for user data
510
+ });
511
+ } catch (error) {
512
+ throw this.handleError(error);
513
+ }
514
+ }
515
+
516
+ /**
517
+ * Batch get multiple user profiles by session IDs (optimized for account switching)
518
+ * Returns array of { sessionId, user } objects
519
+ */
520
+ async getUsersBySessions(sessionIds) {
521
+ try {
522
+ if (!Array.isArray(sessionIds) || sessionIds.length === 0) {
523
+ return [];
524
+ }
525
+
526
+ // Deduplicate and sort sessionIds for consistent cache keys
527
+ const uniqueSessionIds = Array.from(new Set(sessionIds)).sort();
528
+ return await this.makeRequest('POST', '/api/session/users/batch', {
529
+ sessionIds: uniqueSessionIds
530
+ }, {
531
+ cache: true,
532
+ cacheTTL: 2 * 60 * 1000,
533
+ // 2 minutes cache
534
+ deduplicate: true // Important for batch requests
535
+ });
559
536
  } catch (error) {
560
537
  throw this.handleError(error);
561
538
  }
@@ -566,19 +543,15 @@ export class OxyServices {
566
543
  */
567
544
  async getTokenBySession(sessionId) {
568
545
  try {
569
- console.log('🔑 getTokenBySession - Fetching token for session:', sessionId);
570
- const res = await this.client.get(`/api/session/token/${sessionId}`);
571
- const {
572
- accessToken
573
- } = res.data;
574
- console.log('🔑 getTokenBySession - Token received:', !!accessToken);
546
+ const res = await this.makeRequest('GET', `/api/session/token/${sessionId}`, undefined, {
547
+ cache: false,
548
+ retry: false
549
+ });
575
550
 
576
551
  // Set the token in the centralized token store
577
- this.setTokens(accessToken);
578
- console.log('🔑 getTokenBySession - Token set in store');
579
- return res.data;
552
+ this.setTokens(res.accessToken);
553
+ return res;
580
554
  } catch (error) {
581
- console.log('❌ getTokenBySession - Error:', error);
582
555
  throw this.handleError(error);
583
556
  }
584
557
  }
@@ -588,8 +561,9 @@ export class OxyServices {
588
561
  */
589
562
  async getSessionsBySessionId(sessionId) {
590
563
  try {
591
- const res = await this.client.get(`/api/session/sessions/${sessionId}`);
592
- return res.data;
564
+ return await this.makeRequest('GET', `/api/session/sessions/${sessionId}`, undefined, {
565
+ cache: false
566
+ });
593
567
  } catch (error) {
594
568
  throw this.handleError(error);
595
569
  }
@@ -601,7 +575,9 @@ export class OxyServices {
601
575
  async logoutSession(sessionId, targetSessionId) {
602
576
  try {
603
577
  const url = targetSessionId ? `/api/session/logout/${sessionId}/${targetSessionId}` : `/api/session/logout/${sessionId}`;
604
- await this.client.post(url);
578
+ await this.makeRequest('POST', url, undefined, {
579
+ cache: false
580
+ });
605
581
  } catch (error) {
606
582
  throw this.handleError(error);
607
583
  }
@@ -612,7 +588,9 @@ export class OxyServices {
612
588
  */
613
589
  async logoutAllSessions(sessionId) {
614
590
  try {
615
- await this.client.post(`/api/session/logout-all/${sessionId}`);
591
+ await this.makeRequest('POST', `/api/session/logout-all/${sessionId}`, undefined, {
592
+ cache: false
593
+ });
616
594
  } catch (error) {
617
595
  throw this.handleError(error);
618
596
  }
@@ -630,9 +608,13 @@ export class OxyServices {
630
608
  if (options.useHeaderValidation) {
631
609
  params.append('useHeaderValidation', 'true');
632
610
  }
633
- const url = `/api/session/validate/${sessionId}?${params.toString()}`;
634
- const res = await this.client.get(url);
635
- return res.data;
611
+ const url = `/api/session/validate/${sessionId}`;
612
+ const urlParams = {};
613
+ if (options.deviceFingerprint) urlParams.deviceFingerprint = options.deviceFingerprint;
614
+ if (options.useHeaderValidation) urlParams.useHeaderValidation = 'true';
615
+ return await this.makeRequest('GET', url, urlParams, {
616
+ cache: false
617
+ });
636
618
  } catch (error) {
637
619
  throw this.handleError(error);
638
620
  }
@@ -643,8 +625,9 @@ export class OxyServices {
643
625
  */
644
626
  async checkUsernameAvailability(username) {
645
627
  try {
646
- const res = await this.client.get(`/api/auth/check-username/${username}`);
647
- return res.data;
628
+ return await this.makeRequest('GET', `/api/auth/check-username/${username}`, undefined, {
629
+ cache: false
630
+ });
648
631
  } catch (error) {
649
632
  throw this.handleError(error);
650
633
  }
@@ -655,8 +638,9 @@ export class OxyServices {
655
638
  */
656
639
  async checkEmailAvailability(email) {
657
640
  try {
658
- const res = await this.client.get(`/api/auth/check-email/${email}`);
659
- return res.data;
641
+ return await this.makeRequest('GET', `/api/auth/check-email/${email}`, undefined, {
642
+ cache: false
643
+ });
660
644
  } catch (error) {
661
645
  throw this.handleError(error);
662
646
  }
@@ -671,8 +655,10 @@ export class OxyServices {
671
655
  */
672
656
  async getProfileByUsername(username) {
673
657
  try {
674
- const res = await this.client.get(`/api/profiles/username/${username}`);
675
- return res.data;
658
+ return await this.makeRequest('GET', `/api/profiles/username/${username}`, undefined, {
659
+ cache: true,
660
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache for profiles
661
+ });
676
662
  } catch (error) {
677
663
  throw this.handleError(error);
678
664
  }
@@ -684,44 +670,36 @@ export class OxyServices {
684
670
 
685
671
  async startTotpEnrollment(sessionId) {
686
672
  try {
687
- const res = await this.client.post('/api/auth/totp/enroll/start', {
673
+ // Note: x-session-id header is handled by HttpClient interceptors if needed
674
+ return await this.makeRequest('POST', '/api/auth/totp/enroll/start', {
688
675
  sessionId
689
676
  }, {
690
- headers: {
691
- 'x-session-id': sessionId
692
- }
677
+ cache: false
693
678
  });
694
- return res.data;
695
679
  } catch (error) {
696
680
  throw this.handleError(error);
697
681
  }
698
682
  }
699
683
  async verifyTotpEnrollment(sessionId, code) {
700
684
  try {
701
- const res = await this.client.post('/api/auth/totp/enroll/verify', {
685
+ return await this.makeRequest('POST', '/api/auth/totp/enroll/verify', {
702
686
  sessionId,
703
687
  code
704
688
  }, {
705
- headers: {
706
- 'x-session-id': sessionId
707
- }
689
+ cache: false
708
690
  });
709
- return res.data;
710
691
  } catch (error) {
711
692
  throw this.handleError(error);
712
693
  }
713
694
  }
714
695
  async disableTotp(sessionId, code) {
715
696
  try {
716
- const res = await this.client.post('/api/auth/totp/disable', {
697
+ return await this.makeRequest('POST', '/api/auth/totp/disable', {
717
698
  sessionId,
718
699
  code
719
700
  }, {
720
- headers: {
721
- 'x-session-id': sessionId
722
- }
701
+ cache: false
723
702
  });
724
- return res.data;
725
703
  } catch (error) {
726
704
  throw this.handleError(error);
727
705
  }
@@ -737,8 +715,14 @@ export class OxyServices {
737
715
  ...pagination
738
716
  };
739
717
  const searchParams = buildSearchParams(params);
740
- const res = await this.client.get(`/api/profiles/search?${searchParams.toString()}`);
741
- return res.data;
718
+ const paramsObj = {};
719
+ searchParams.forEach((value, key) => {
720
+ paramsObj[key] = value;
721
+ });
722
+ return await this.makeRequest('GET', '/api/profiles/search', paramsObj, {
723
+ cache: true,
724
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
725
+ });
742
726
  } catch (error) {
743
727
  throw this.handleError(error);
744
728
  }
@@ -749,8 +733,9 @@ export class OxyServices {
749
733
  */
750
734
  async getProfileRecommendations() {
751
735
  return this.withAuthRetry(async () => {
752
- const res = await this.client.get('/api/profiles/recommendations');
753
- return res.data;
736
+ return await this.makeRequest('GET', '/api/profiles/recommendations', undefined, {
737
+ cache: true
738
+ });
754
739
  }, 'getProfileRecommendations');
755
740
  }
756
741
 
@@ -759,8 +744,10 @@ export class OxyServices {
759
744
  */
760
745
  async getUserById(userId) {
761
746
  try {
762
- const res = await this.client.get(`/api/users/${userId}`);
763
- return res.data;
747
+ return await this.makeRequest('GET', `/api/users/${userId}`, undefined, {
748
+ cache: true,
749
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
750
+ });
764
751
  } catch (error) {
765
752
  throw this.handleError(error);
766
753
  }
@@ -771,8 +758,10 @@ export class OxyServices {
771
758
  */
772
759
  async getCurrentUser() {
773
760
  return this.withAuthRetry(async () => {
774
- const res = await this.client.get('/api/users/me');
775
- return res.data;
761
+ return await this.makeRequest('GET', '/api/users/me', undefined, {
762
+ cache: true,
763
+ cacheTTL: 1 * 60 * 1000 // 1 minute cache for current user
764
+ });
776
765
  }, 'getCurrentUser');
777
766
  }
778
767
 
@@ -781,20 +770,134 @@ export class OxyServices {
781
770
  */
782
771
  async updateProfile(updates) {
783
772
  try {
784
- const res = await this.client.put('/api/users/me', updates);
785
- return res.data;
773
+ return await this.makeRequest('PUT', '/api/users/me', updates, {
774
+ cache: false
775
+ });
786
776
  } catch (error) {
787
777
  throw this.handleError(error);
788
778
  }
789
779
  }
790
780
 
781
+ // ============================================================================
782
+ // LANGUAGE METHODS
783
+ // ============================================================================
784
+
785
+ /**
786
+ * Get the current language from storage or user profile
787
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
788
+ * @returns The current language code (e.g., 'en-US') or null if not set
789
+ */
790
+ async getCurrentLanguage(storageKeyPrefix = 'oxy_session') {
791
+ try {
792
+ // First try to get from user profile if authenticated
793
+ try {
794
+ const user = await this.getCurrentUser();
795
+ const userLanguage = user?.language;
796
+ if (userLanguage) {
797
+ return normalizeLanguageCode(userLanguage) || userLanguage;
798
+ }
799
+ } catch (e) {
800
+ // User not authenticated or error, continue to storage
801
+ }
802
+
803
+ // Fall back to storage
804
+ const storage = await this.getStorage();
805
+ const storageKey = `${storageKeyPrefix}_language`;
806
+ const storedLanguage = await storage.getItem(storageKey);
807
+ if (storedLanguage) {
808
+ return normalizeLanguageCode(storedLanguage) || storedLanguage;
809
+ }
810
+ return null;
811
+ } catch (error) {
812
+ if (__DEV__) {
813
+ console.warn('Failed to get current language:', error);
814
+ }
815
+ return null;
816
+ }
817
+ }
818
+
819
+ /**
820
+ * Get the current language with metadata (name, nativeName, etc.)
821
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
822
+ * @returns Language metadata object or null if not set
823
+ */
824
+ async getCurrentLanguageMetadata(storageKeyPrefix = 'oxy_session') {
825
+ const languageCode = await this.getCurrentLanguage(storageKeyPrefix);
826
+ return getLanguageMetadata(languageCode);
827
+ }
828
+
829
+ /**
830
+ * Get the current language name (e.g., 'English')
831
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
832
+ * @returns Language name or null if not set
833
+ */
834
+ async getCurrentLanguageName(storageKeyPrefix = 'oxy_session') {
835
+ const languageCode = await this.getCurrentLanguage(storageKeyPrefix);
836
+ if (!languageCode) return null;
837
+ return getLanguageName(languageCode);
838
+ }
839
+
840
+ /**
841
+ * Get the current native language name (e.g., 'Español')
842
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
843
+ * @returns Native language name or null if not set
844
+ */
845
+ async getCurrentNativeLanguageName(storageKeyPrefix = 'oxy_session') {
846
+ const languageCode = await this.getCurrentLanguage(storageKeyPrefix);
847
+ if (!languageCode) return null;
848
+ return getNativeLanguageName(languageCode);
849
+ }
850
+
851
+ /**
852
+ * Get appropriate storage for the platform (similar to DeviceManager)
853
+ * @private
854
+ */
855
+ async getStorage() {
856
+ const isReactNative = typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
857
+ if (isReactNative) {
858
+ try {
859
+ const asyncStorageModule = await import('@react-native-async-storage/async-storage');
860
+ const storage = asyncStorageModule.default;
861
+ return {
862
+ getItem: storage.getItem.bind(storage),
863
+ setItem: storage.setItem.bind(storage),
864
+ removeItem: storage.removeItem.bind(storage)
865
+ };
866
+ } catch (error) {
867
+ console.error('AsyncStorage not available in React Native:', error);
868
+ throw new Error('AsyncStorage is required in React Native environment');
869
+ }
870
+ } else {
871
+ // Use localStorage for web
872
+ return {
873
+ getItem: async key => {
874
+ if (typeof window !== 'undefined' && window.localStorage) {
875
+ return localStorage.getItem(key);
876
+ }
877
+ return null;
878
+ },
879
+ setItem: async (key, value) => {
880
+ if (typeof window !== 'undefined' && window.localStorage) {
881
+ localStorage.setItem(key, value);
882
+ }
883
+ },
884
+ removeItem: async key => {
885
+ if (typeof window !== 'undefined' && window.localStorage) {
886
+ localStorage.removeItem(key);
887
+ }
888
+ }
889
+ };
890
+ }
891
+ }
892
+
791
893
  /**
792
894
  * Update user by ID (admin function)
793
895
  */
794
896
  async updateUser(userId, updates) {
795
897
  try {
796
- const res = await this.client.put(`/api/users/${userId}`, updates);
797
- return res.data;
898
+ return await this.makeRequest('PUT', `/api/users/${userId}`, updates, {
899
+ cache: false
900
+ });
798
901
  } catch (error) {
799
902
  throw this.handleError(error);
800
903
  }
@@ -805,8 +908,9 @@ export class OxyServices {
805
908
  */
806
909
  async followUser(userId) {
807
910
  try {
808
- const res = await this.client.post(`/api/users/${userId}/follow`);
809
- return res.data;
911
+ return await this.makeRequest('POST', `/api/users/${userId}/follow`, undefined, {
912
+ cache: false
913
+ });
810
914
  } catch (error) {
811
915
  throw this.handleError(error);
812
916
  }
@@ -817,8 +921,9 @@ export class OxyServices {
817
921
  */
818
922
  async unfollowUser(userId) {
819
923
  try {
820
- const res = await this.client.delete(`/api/users/${userId}/follow`);
821
- return res.data;
924
+ return await this.makeRequest('DELETE', `/api/users/${userId}/follow`, undefined, {
925
+ cache: false
926
+ });
822
927
  } catch (error) {
823
928
  throw this.handleError(error);
824
929
  }
@@ -829,8 +934,10 @@ export class OxyServices {
829
934
  */
830
935
  async getFollowStatus(userId) {
831
936
  try {
832
- const res = await this.client.get(`/api/users/${userId}/follow-status`);
833
- return res.data;
937
+ return await this.makeRequest('GET', `/api/users/${userId}/follow-status`, undefined, {
938
+ cache: true,
939
+ cacheTTL: 1 * 60 * 1000 // 1 minute cache
940
+ });
834
941
  } catch (error) {
835
942
  throw this.handleError(error);
836
943
  }
@@ -842,8 +949,15 @@ export class OxyServices {
842
949
  async getUserFollowers(userId, pagination) {
843
950
  try {
844
951
  const params = buildPaginationParams(pagination || {});
845
- const res = await this.client.get(`/api/users/${userId}/followers?${params.toString()}`);
846
- return res.data;
952
+ const response = await this.makeRequest('GET', `/api/users/${userId}/followers`, params, {
953
+ cache: true,
954
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
955
+ });
956
+ return {
957
+ followers: response.data || [],
958
+ total: response.pagination.total,
959
+ hasMore: response.pagination.hasMore
960
+ };
847
961
  } catch (error) {
848
962
  throw this.handleError(error);
849
963
  }
@@ -855,8 +969,15 @@ export class OxyServices {
855
969
  async getUserFollowing(userId, pagination) {
856
970
  try {
857
971
  const params = buildPaginationParams(pagination || {});
858
- const res = await this.client.get(`/api/users/${userId}/following?${params.toString()}`);
859
- return res.data;
972
+ const response = await this.makeRequest('GET', `/api/users/${userId}/following`, params, {
973
+ cache: true,
974
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
975
+ });
976
+ return {
977
+ following: response.data || [],
978
+ total: response.pagination.total,
979
+ hasMore: response.pagination.hasMore
980
+ };
860
981
  } catch (error) {
861
982
  throw this.handleError(error);
862
983
  }
@@ -867,8 +988,9 @@ export class OxyServices {
867
988
  */
868
989
  async getNotifications() {
869
990
  return this.withAuthRetry(async () => {
870
- const res = await this.client.get('/api/notifications');
871
- return res.data;
991
+ return await this.makeRequest('GET', '/api/notifications', undefined, {
992
+ cache: false // Don't cache notifications - always get fresh data
993
+ });
872
994
  }, 'getNotifications');
873
995
  }
874
996
 
@@ -877,8 +999,10 @@ export class OxyServices {
877
999
  */
878
1000
  async getUnreadCount() {
879
1001
  try {
880
- const res = await this.client.get('/api/notifications/unread-count');
881
- return res.data.count;
1002
+ const res = await this.makeRequest('GET', '/api/notifications/unread-count', undefined, {
1003
+ cache: false // Don't cache unread count - always get fresh data
1004
+ });
1005
+ return res.count;
882
1006
  } catch (error) {
883
1007
  throw this.handleError(error);
884
1008
  }
@@ -889,8 +1013,9 @@ export class OxyServices {
889
1013
  */
890
1014
  async createNotification(data) {
891
1015
  try {
892
- const res = await this.client.post('/api/notifications', data);
893
- return res.data;
1016
+ return await this.makeRequest('POST', '/api/notifications', data, {
1017
+ cache: false
1018
+ });
894
1019
  } catch (error) {
895
1020
  throw this.handleError(error);
896
1021
  }
@@ -901,7 +1026,9 @@ export class OxyServices {
901
1026
  */
902
1027
  async markNotificationAsRead(notificationId) {
903
1028
  try {
904
- await this.client.put(`/api/notifications/${notificationId}/read`);
1029
+ await this.makeRequest('PUT', `/api/notifications/${notificationId}/read`, undefined, {
1030
+ cache: false
1031
+ });
905
1032
  } catch (error) {
906
1033
  throw this.handleError(error);
907
1034
  }
@@ -912,7 +1039,9 @@ export class OxyServices {
912
1039
  */
913
1040
  async markAllNotificationsAsRead() {
914
1041
  try {
915
- await this.client.put('/api/notifications/read-all');
1042
+ await this.makeRequest('PUT', '/api/notifications/read-all', undefined, {
1043
+ cache: false
1044
+ });
916
1045
  } catch (error) {
917
1046
  throw this.handleError(error);
918
1047
  }
@@ -923,7 +1052,9 @@ export class OxyServices {
923
1052
  */
924
1053
  async deleteNotification(notificationId) {
925
1054
  try {
926
- await this.client.delete(`/api/notifications/${notificationId}`);
1055
+ await this.makeRequest('DELETE', `/api/notifications/${notificationId}`, undefined, {
1056
+ cache: false
1057
+ });
927
1058
  } catch (error) {
928
1059
  throw this.handleError(error);
929
1060
  }
@@ -938,8 +1069,9 @@ export class OxyServices {
938
1069
  */
939
1070
  async createPayment(data) {
940
1071
  try {
941
- const res = await this.client.post('/api/payments', data);
942
- return res.data;
1072
+ return await this.makeRequest('POST', '/api/payments', data, {
1073
+ cache: false
1074
+ });
943
1075
  } catch (error) {
944
1076
  throw this.handleError(error);
945
1077
  }
@@ -950,8 +1082,10 @@ export class OxyServices {
950
1082
  */
951
1083
  async getPayment(paymentId) {
952
1084
  try {
953
- const res = await this.client.get(`/api/payments/${paymentId}`);
954
- return res.data;
1085
+ return await this.makeRequest('GET', `/api/payments/${paymentId}`, undefined, {
1086
+ cache: true,
1087
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1088
+ });
955
1089
  } catch (error) {
956
1090
  throw this.handleError(error);
957
1091
  }
@@ -962,8 +1096,9 @@ export class OxyServices {
962
1096
  */
963
1097
  async getUserPayments() {
964
1098
  try {
965
- const res = await this.client.get('/api/payments/user');
966
- return res.data;
1099
+ return await this.makeRequest('GET', '/api/payments/user', undefined, {
1100
+ cache: false // Don't cache user payments - always get fresh data
1101
+ });
967
1102
  } catch (error) {
968
1103
  throw this.handleError(error);
969
1104
  }
@@ -978,8 +1113,10 @@ export class OxyServices {
978
1113
  */
979
1114
  async getUserKarma(userId) {
980
1115
  try {
981
- const res = await this.client.get(`/api/karma/${userId}`);
982
- return res.data;
1116
+ return await this.makeRequest('GET', `/api/karma/${userId}`, undefined, {
1117
+ cache: true,
1118
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
1119
+ });
983
1120
  } catch (error) {
984
1121
  throw this.handleError(error);
985
1122
  }
@@ -990,11 +1127,12 @@ export class OxyServices {
990
1127
  */
991
1128
  async giveKarma(userId, amount, reason) {
992
1129
  try {
993
- const res = await this.client.post(`/api/karma/${userId}/give`, {
1130
+ return await this.makeRequest('POST', `/api/karma/${userId}/give`, {
994
1131
  amount,
995
1132
  reason
1133
+ }, {
1134
+ cache: false
996
1135
  });
997
- return res.data;
998
1136
  } catch (error) {
999
1137
  throw this.handleError(error);
1000
1138
  }
@@ -1005,8 +1143,10 @@ export class OxyServices {
1005
1143
  */
1006
1144
  async getUserKarmaTotal(userId) {
1007
1145
  try {
1008
- const res = await this.client.get(`/api/karma/${userId}/total`);
1009
- return res.data;
1146
+ return await this.makeRequest('GET', `/api/karma/${userId}/total`, undefined, {
1147
+ cache: true,
1148
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
1149
+ });
1010
1150
  } catch (error) {
1011
1151
  throw this.handleError(error);
1012
1152
  }
@@ -1017,11 +1157,13 @@ export class OxyServices {
1017
1157
  */
1018
1158
  async getUserKarmaHistory(userId, limit, offset) {
1019
1159
  try {
1020
- const params = new URLSearchParams();
1021
- if (limit) params.append('limit', limit.toString());
1022
- if (offset) params.append('offset', offset.toString());
1023
- const res = await this.client.get(`/api/karma/${userId}/history?${params.toString()}`);
1024
- return res.data;
1160
+ const params = {};
1161
+ if (limit) params.limit = limit;
1162
+ if (offset) params.offset = offset;
1163
+ return await this.makeRequest('GET', `/api/karma/${userId}/history`, params, {
1164
+ cache: true,
1165
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
1166
+ });
1025
1167
  } catch (error) {
1026
1168
  throw this.handleError(error);
1027
1169
  }
@@ -1032,8 +1174,10 @@ export class OxyServices {
1032
1174
  */
1033
1175
  async getKarmaLeaderboard() {
1034
1176
  try {
1035
- const res = await this.client.get('/api/karma/leaderboard');
1036
- return res.data;
1177
+ return await this.makeRequest('GET', '/api/karma/leaderboard', undefined, {
1178
+ cache: true,
1179
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1180
+ });
1037
1181
  } catch (error) {
1038
1182
  throw this.handleError(error);
1039
1183
  }
@@ -1044,8 +1188,10 @@ export class OxyServices {
1044
1188
  */
1045
1189
  async getKarmaRules() {
1046
1190
  try {
1047
- const res = await this.client.get('/api/karma/rules');
1048
- return res.data;
1191
+ return await this.makeRequest('GET', '/api/karma/rules', undefined, {
1192
+ cache: true,
1193
+ cacheTTL: 30 * 60 * 1000 // 30 minutes cache (rules don't change often)
1194
+ });
1049
1195
  } catch (error) {
1050
1196
  throw this.handleError(error);
1051
1197
  }
@@ -1061,8 +1207,9 @@ export class OxyServices {
1061
1207
  async deleteFile(fileId) {
1062
1208
  try {
1063
1209
  // Central Asset Service delete with force=true behavior controlled by caller via assetDelete
1064
- const res = await this.client.delete(`/api/assets/${encodeURIComponent(fileId)}`);
1065
- return res.data;
1210
+ return await this.makeRequest('DELETE', `/api/assets/${encodeURIComponent(fileId)}`, undefined, {
1211
+ cache: false
1212
+ });
1066
1213
  } catch (error) {
1067
1214
  throw this.handleError(error);
1068
1215
  }
@@ -1077,7 +1224,7 @@ export class OxyServices {
1077
1224
  if (variant) params.set('variant', variant);
1078
1225
  if (expiresIn) params.set('expiresIn', String(expiresIn));
1079
1226
  params.set('fallback', 'placeholderVisible');
1080
- const token = this.tokenStore.getAccessToken();
1227
+ const token = this.httpClient.getAccessToken();
1081
1228
  if (token) params.set('token', token);
1082
1229
 
1083
1230
  // Use params.toString() to detect whether there are query params.
@@ -1103,12 +1250,12 @@ export class OxyServices {
1103
1250
  */
1104
1251
  async listUserFiles(limit, offset) {
1105
1252
  try {
1106
- const params = new URLSearchParams();
1107
- if (limit) params.append('limit', String(limit));
1108
- if (offset) params.append('offset', String(offset));
1109
- const qs = params.toString();
1110
- const res = await this.client.get(`/api/assets${qs ? `?${qs}` : ''}`);
1111
- return res.data;
1253
+ const paramsObj = {};
1254
+ if (limit) paramsObj.limit = limit;
1255
+ if (offset) paramsObj.offset = offset;
1256
+ return await this.makeRequest('GET', '/api/assets', paramsObj, {
1257
+ cache: false // Don't cache file lists - always get fresh data
1258
+ });
1112
1259
  } catch (error) {
1113
1260
  throw this.handleError(error);
1114
1261
  }
@@ -1121,8 +1268,14 @@ export class OxyServices {
1121
1268
  */
1122
1269
  async getFileContentAsText(fileId, variant) {
1123
1270
  try {
1124
- const urlRes = await this.client.get(`/api/assets/${encodeURIComponent(fileId)}/url${variant ? `?variant=${encodeURIComponent(variant)}` : ''}`);
1125
- const downloadUrl = urlRes.data?.url;
1271
+ const params = variant ? {
1272
+ variant
1273
+ } : undefined;
1274
+ const urlRes = await this.makeRequest('GET', `/api/assets/${encodeURIComponent(fileId)}/url`, params, {
1275
+ cache: true,
1276
+ cacheTTL: 10 * 60 * 1000 // 10 minutes cache for URLs
1277
+ });
1278
+ const downloadUrl = urlRes?.url;
1126
1279
  const response = await fetch(downloadUrl);
1127
1280
  return await response.text();
1128
1281
  } catch (error) {
@@ -1135,8 +1288,14 @@ export class OxyServices {
1135
1288
  */
1136
1289
  async getFileContentAsBlob(fileId, variant) {
1137
1290
  try {
1138
- const urlRes = await this.client.get(`/api/assets/${encodeURIComponent(fileId)}/url${variant ? `?variant=${encodeURIComponent(variant)}` : ''}`);
1139
- const downloadUrl = urlRes.data?.url;
1291
+ const params = variant ? {
1292
+ variant
1293
+ } : undefined;
1294
+ const urlRes = await this.makeRequest('GET', `/api/assets/${encodeURIComponent(fileId)}/url`, params, {
1295
+ cache: true,
1296
+ cacheTTL: 10 * 60 * 1000 // 10 minutes cache for URLs
1297
+ });
1298
+ const downloadUrl = urlRes?.url;
1140
1299
  const response = await fetch(downloadUrl);
1141
1300
  return await response.blob();
1142
1301
  } catch (error) {
@@ -1171,12 +1330,13 @@ export class OxyServices {
1171
1330
  */
1172
1331
  async assetInit(sha256, size, mime) {
1173
1332
  try {
1174
- const res = await this.client.post('/api/assets/init', {
1333
+ return await this.makeRequest('POST', '/api/assets/init', {
1175
1334
  sha256,
1176
1335
  size,
1177
1336
  mime
1337
+ }, {
1338
+ cache: false
1178
1339
  });
1179
- return res.data;
1180
1340
  } catch (error) {
1181
1341
  throw this.handleError(error);
1182
1342
  }
@@ -1187,15 +1347,16 @@ export class OxyServices {
1187
1347
  */
1188
1348
  async assetComplete(fileId, originalName, size, mime, visibility, metadata) {
1189
1349
  try {
1190
- const res = await this.client.post('/api/assets/complete', {
1350
+ return await this.makeRequest('POST', '/api/assets/complete', {
1191
1351
  fileId,
1192
1352
  originalName,
1193
1353
  size,
1194
1354
  mime,
1195
1355
  visibility,
1196
1356
  metadata
1357
+ }, {
1358
+ cache: false
1197
1359
  });
1198
- return res.data;
1199
1360
  } catch (error) {
1200
1361
  throw this.handleError(error);
1201
1362
  }
@@ -1219,10 +1380,11 @@ export class OxyServices {
1219
1380
  // Fallback: direct upload via API to avoid CORS issues
1220
1381
  const fd = new FormData();
1221
1382
  fd.append('file', file);
1222
- await this.client.post(`/api/assets/${encodeURIComponent(initResponse.fileId)}/upload-direct`, fd, {
1223
- headers: {
1224
- 'Content-Type': 'multipart/form-data'
1225
- }
1383
+ // Use httpClient directly for FormData uploads (bypasses RequestManager for special handling)
1384
+ await this.httpClient.request({
1385
+ method: 'POST',
1386
+ url: `/api/assets/${encodeURIComponent(initResponse.fileId)}/upload-direct`,
1387
+ data: fd
1226
1388
  });
1227
1389
  }
1228
1390
 
@@ -1273,8 +1435,9 @@ export class OxyServices {
1273
1435
  };
1274
1436
  if (visibility) body.visibility = visibility;
1275
1437
  if (webhookUrl) body.webhookUrl = webhookUrl;
1276
- const res = await this.client.post(`/api/assets/${fileId}/links`, body);
1277
- return res.data;
1438
+ return await this.makeRequest('POST', `/api/assets/${fileId}/links`, body, {
1439
+ cache: false
1440
+ });
1278
1441
  } catch (error) {
1279
1442
  throw this.handleError(error);
1280
1443
  }
@@ -1285,14 +1448,13 @@ export class OxyServices {
1285
1448
  */
1286
1449
  async assetUnlink(fileId, app, entityType, entityId) {
1287
1450
  try {
1288
- const res = await this.client.delete(`/api/assets/${fileId}/links`, {
1289
- data: {
1290
- app,
1291
- entityType,
1292
- entityId
1293
- }
1451
+ return await this.makeRequest('DELETE', `/api/assets/${fileId}/links`, {
1452
+ app,
1453
+ entityType,
1454
+ entityId
1455
+ }, {
1456
+ cache: false
1294
1457
  });
1295
- return res.data;
1296
1458
  } catch (error) {
1297
1459
  throw this.handleError(error);
1298
1460
  }
@@ -1303,8 +1465,10 @@ export class OxyServices {
1303
1465
  */
1304
1466
  async assetGet(fileId) {
1305
1467
  try {
1306
- const res = await this.client.get(`/api/assets/${fileId}`);
1307
- return res.data;
1468
+ return await this.makeRequest('GET', `/api/assets/${fileId}`, undefined, {
1469
+ cache: true,
1470
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1471
+ });
1308
1472
  } catch (error) {
1309
1473
  throw this.handleError(error);
1310
1474
  }
@@ -1315,13 +1479,13 @@ export class OxyServices {
1315
1479
  */
1316
1480
  async assetGetUrl(fileId, variant, expiresIn) {
1317
1481
  try {
1318
- const params = new URLSearchParams();
1319
- if (variant) params.set('variant', variant);
1320
- if (expiresIn) params.set('expiresIn', expiresIn.toString());
1321
- const queryString = params.toString();
1322
- const url = `/api/assets/${fileId}/url${queryString ? `?${queryString}` : ''}`;
1323
- const res = await this.client.get(url);
1324
- return res.data;
1482
+ const params = {};
1483
+ if (variant) params.variant = variant;
1484
+ if (expiresIn) params.expiresIn = expiresIn;
1485
+ return await this.makeRequest('GET', `/api/assets/${fileId}/url`, params, {
1486
+ cache: true,
1487
+ cacheTTL: 10 * 60 * 1000 // 10 minutes cache for URLs
1488
+ });
1325
1489
  } catch (error) {
1326
1490
  throw this.handleError(error);
1327
1491
  }
@@ -1332,8 +1496,9 @@ export class OxyServices {
1332
1496
  */
1333
1497
  async assetRestore(fileId) {
1334
1498
  try {
1335
- const res = await this.client.post(`/api/assets/${fileId}/restore`);
1336
- return res.data;
1499
+ return await this.makeRequest('POST', `/api/assets/${fileId}/restore`, undefined, {
1500
+ cache: false
1501
+ });
1337
1502
  } catch (error) {
1338
1503
  throw this.handleError(error);
1339
1504
  }
@@ -1344,9 +1509,12 @@ export class OxyServices {
1344
1509
  */
1345
1510
  async assetDelete(fileId, force = false) {
1346
1511
  try {
1347
- const params = force ? '?force=true' : '';
1348
- const res = await this.client.delete(`/api/assets/${fileId}${params}`);
1349
- return res.data;
1512
+ const params = force ? {
1513
+ force: 'true'
1514
+ } : undefined;
1515
+ return await this.makeRequest('DELETE', `/api/assets/${fileId}`, params, {
1516
+ cache: false
1517
+ });
1350
1518
  } catch (error) {
1351
1519
  throw this.handleError(error);
1352
1520
  }
@@ -1372,10 +1540,11 @@ export class OxyServices {
1372
1540
  */
1373
1541
  async assetUpdateVisibility(fileId, visibility) {
1374
1542
  try {
1375
- const res = await this.client.patch(`/api/assets/${fileId}/visibility`, {
1543
+ return await this.makeRequest('PATCH', `/api/assets/${fileId}/visibility`, {
1376
1544
  visibility
1545
+ }, {
1546
+ cache: false
1377
1547
  });
1378
- return res.data;
1379
1548
  } catch (error) {
1380
1549
  throw this.handleError(error);
1381
1550
  }
@@ -1430,8 +1599,11 @@ export class OxyServices {
1430
1599
  */
1431
1600
  async getDeveloperApps() {
1432
1601
  try {
1433
- const res = await this.client.get('/api/developer/apps');
1434
- return res.data.apps || [];
1602
+ const res = await this.makeRequest('GET', '/api/developer/apps', undefined, {
1603
+ cache: true,
1604
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
1605
+ });
1606
+ return res.apps || [];
1435
1607
  } catch (error) {
1436
1608
  throw this.handleError(error);
1437
1609
  }
@@ -1442,8 +1614,10 @@ export class OxyServices {
1442
1614
  */
1443
1615
  async createDeveloperApp(data) {
1444
1616
  try {
1445
- const res = await this.client.post('/api/developer/apps', data);
1446
- return res.data.app;
1617
+ const res = await this.makeRequest('POST', '/api/developer/apps', data, {
1618
+ cache: false
1619
+ });
1620
+ return res.app;
1447
1621
  } catch (error) {
1448
1622
  throw this.handleError(error);
1449
1623
  }
@@ -1454,8 +1628,11 @@ export class OxyServices {
1454
1628
  */
1455
1629
  async getDeveloperApp(appId) {
1456
1630
  try {
1457
- const res = await this.client.get(`/api/developer/apps/${appId}`);
1458
- return res.data.app;
1631
+ const res = await this.makeRequest('GET', `/api/developer/apps/${appId}`, undefined, {
1632
+ cache: true,
1633
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1634
+ });
1635
+ return res.app;
1459
1636
  } catch (error) {
1460
1637
  throw this.handleError(error);
1461
1638
  }
@@ -1466,8 +1643,10 @@ export class OxyServices {
1466
1643
  */
1467
1644
  async updateDeveloperApp(appId, data) {
1468
1645
  try {
1469
- const res = await this.client.patch(`/api/developer/apps/${appId}`, data);
1470
- return res.data.app;
1646
+ const res = await this.makeRequest('PATCH', `/api/developer/apps/${appId}`, data, {
1647
+ cache: false
1648
+ });
1649
+ return res.app;
1471
1650
  } catch (error) {
1472
1651
  throw this.handleError(error);
1473
1652
  }
@@ -1478,8 +1657,9 @@ export class OxyServices {
1478
1657
  */
1479
1658
  async regenerateDeveloperAppSecret(appId) {
1480
1659
  try {
1481
- const res = await this.client.post(`/api/developer/apps/${appId}/regenerate-secret`);
1482
- return res.data;
1660
+ return await this.makeRequest('POST', `/api/developer/apps/${appId}/regenerate-secret`, undefined, {
1661
+ cache: false
1662
+ });
1483
1663
  } catch (error) {
1484
1664
  throw this.handleError(error);
1485
1665
  }
@@ -1490,8 +1670,9 @@ export class OxyServices {
1490
1670
  */
1491
1671
  async deleteDeveloperApp(appId) {
1492
1672
  try {
1493
- const res = await this.client.delete(`/api/developer/apps/${appId}`);
1494
- return res.data;
1673
+ return await this.makeRequest('DELETE', `/api/developer/apps/${appId}`, undefined, {
1674
+ cache: false
1675
+ });
1495
1676
  } catch (error) {
1496
1677
  throw this.handleError(error);
1497
1678
  }
@@ -1506,11 +1687,12 @@ export class OxyServices {
1506
1687
  */
1507
1688
  async updateLocation(latitude, longitude) {
1508
1689
  try {
1509
- const res = await this.client.post('/api/location', {
1690
+ return await this.makeRequest('POST', '/api/location', {
1510
1691
  latitude,
1511
1692
  longitude
1693
+ }, {
1694
+ cache: false
1512
1695
  });
1513
- return res.data;
1514
1696
  } catch (error) {
1515
1697
  throw this.handleError(error);
1516
1698
  }
@@ -1521,9 +1703,12 @@ export class OxyServices {
1521
1703
  */
1522
1704
  async getNearbyUsers(radius) {
1523
1705
  try {
1524
- const params = radius ? `?radius=${radius}` : '';
1525
- const res = await this.client.get(`/api/location/nearby${params}`);
1526
- return res.data;
1706
+ const params = radius ? {
1707
+ radius
1708
+ } : undefined;
1709
+ return await this.makeRequest('GET', '/api/location/nearby', params, {
1710
+ cache: false // Don't cache location data - always get fresh data
1711
+ });
1527
1712
  } catch (error) {
1528
1713
  throw this.handleError(error);
1529
1714
  }
@@ -1538,10 +1723,13 @@ export class OxyServices {
1538
1723
  */
1539
1724
  async trackEvent(eventName, properties) {
1540
1725
  try {
1541
- await this.client.post('/api/analytics/events', {
1726
+ await this.makeRequest('POST', '/api/analytics/events', {
1542
1727
  event: eventName,
1543
1728
  properties
1544
- });
1729
+ }, {
1730
+ cache: false,
1731
+ retry: false
1732
+ }); // Don't retry analytics events
1545
1733
  } catch (error) {
1546
1734
  throw this.handleError(error);
1547
1735
  }
@@ -1552,11 +1740,13 @@ export class OxyServices {
1552
1740
  */
1553
1741
  async getAnalytics(startDate, endDate) {
1554
1742
  try {
1555
- const params = new URLSearchParams();
1556
- if (startDate) params.append('startDate', startDate);
1557
- if (endDate) params.append('endDate', endDate);
1558
- const res = await this.client.get(`/api/analytics?${params.toString()}`);
1559
- return res.data;
1743
+ const params = {};
1744
+ if (startDate) params.startDate = startDate;
1745
+ if (endDate) params.endDate = endDate;
1746
+ return await this.makeRequest('GET', '/api/analytics', params, {
1747
+ cache: true,
1748
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1749
+ });
1560
1750
  } catch (error) {
1561
1751
  throw this.handleError(error);
1562
1752
  }
@@ -1571,8 +1761,9 @@ export class OxyServices {
1571
1761
  */
1572
1762
  async registerDevice(deviceData) {
1573
1763
  try {
1574
- const res = await this.client.post('/api/devices', deviceData);
1575
- return res.data;
1764
+ return await this.makeRequest('POST', '/api/devices', deviceData, {
1765
+ cache: false
1766
+ });
1576
1767
  } catch (error) {
1577
1768
  throw this.handleError(error);
1578
1769
  }
@@ -1583,8 +1774,9 @@ export class OxyServices {
1583
1774
  */
1584
1775
  async getUserDevices() {
1585
1776
  try {
1586
- const res = await this.client.get('/api/devices');
1587
- return res.data;
1777
+ return await this.makeRequest('GET', '/api/devices', undefined, {
1778
+ cache: false // Don't cache device list - always get fresh data
1779
+ });
1588
1780
  } catch (error) {
1589
1781
  throw this.handleError(error);
1590
1782
  }
@@ -1595,7 +1787,9 @@ export class OxyServices {
1595
1787
  */
1596
1788
  async removeDevice(deviceId) {
1597
1789
  try {
1598
- await this.client.delete(`/api/devices/${deviceId}`);
1790
+ await this.makeRequest('DELETE', `/api/devices/${deviceId}`, undefined, {
1791
+ cache: false
1792
+ });
1599
1793
  } catch (error) {
1600
1794
  throw this.handleError(error);
1601
1795
  }
@@ -1603,11 +1797,17 @@ export class OxyServices {
1603
1797
 
1604
1798
  /**
1605
1799
  * Get device sessions
1800
+ * Note: Not cached by default to ensure fresh data, but can be cached via makeRequest if needed
1606
1801
  */
1607
1802
  async getDeviceSessions(sessionId) {
1608
1803
  try {
1609
- const res = await this.client.get(`/api/session/device/sessions/${sessionId}`);
1610
- return res.data;
1804
+ // Use makeRequest for consistent error handling and optional caching
1805
+ // Cache disabled by default to ensure fresh session data
1806
+ return await this.makeRequest('GET', `/api/session/device/sessions/${sessionId}`, undefined, {
1807
+ cache: false,
1808
+ // Don't cache sessions - always get fresh data
1809
+ deduplicate: true // Deduplicate concurrent requests for same sessionId
1810
+ });
1611
1811
  } catch (error) {
1612
1812
  throw this.handleError(error);
1613
1813
  }
@@ -1621,8 +1821,13 @@ export class OxyServices {
1621
1821
  const params = new URLSearchParams();
1622
1822
  if (deviceId) params.append('deviceId', deviceId);
1623
1823
  if (excludeCurrent) params.append('excludeCurrent', 'true');
1624
- const res = await this.client.post(`/api/session/device/logout-all/${sessionId}?${params.toString()}`);
1625
- return res.data;
1824
+ const urlParams = {};
1825
+ params.forEach((value, key) => {
1826
+ urlParams[key] = value;
1827
+ });
1828
+ return await this.makeRequest('POST', `/api/session/device/logout-all/${sessionId}`, urlParams, {
1829
+ cache: false
1830
+ });
1626
1831
  } catch (error) {
1627
1832
  throw this.handleError(error);
1628
1833
  }
@@ -1633,10 +1838,11 @@ export class OxyServices {
1633
1838
  */
1634
1839
  async updateDeviceName(sessionId, deviceName) {
1635
1840
  try {
1636
- const res = await this.client.put(`/api/session/device/name/${sessionId}`, {
1841
+ return await this.makeRequest('PUT', `/api/session/device/name/${sessionId}`, {
1637
1842
  deviceName
1843
+ }, {
1844
+ cache: false
1638
1845
  });
1639
- return res.data;
1640
1846
  } catch (error) {
1641
1847
  throw this.handleError(error);
1642
1848
  }
@@ -1651,8 +1857,12 @@ export class OxyServices {
1651
1857
  */
1652
1858
  async fetchLinkMetadata(url) {
1653
1859
  try {
1654
- const res = await this.client.get(`/api/link-metadata?url=${encodeURIComponent(url)}`);
1655
- return res.data;
1860
+ return await this.makeRequest('GET', '/api/link-metadata', {
1861
+ url
1862
+ }, {
1863
+ cache: true,
1864
+ cacheTTL: 30 * 60 * 1000 // 30 minutes cache for link metadata
1865
+ });
1656
1866
  } catch (error) {
1657
1867
  throw this.handleError(error);
1658
1868
  }