@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
@@ -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
  /**
@@ -244,25 +178,33 @@ class OxyServices {
244
178
  return this.cloudURL;
245
179
  }
246
180
 
181
+ /**
182
+ * Get the underlying HTTP client instance
183
+ * Useful for advanced use cases that need direct access to the HttpClient
184
+ */
185
+ getClient() {
186
+ return this.httpClient;
187
+ }
188
+
247
189
  /**
248
190
  * Set authentication tokens
249
191
  */
250
192
  setTokens(accessToken, refreshToken = '') {
251
- this.tokenStore.setTokens(accessToken, refreshToken);
193
+ this.httpClient.setTokens(accessToken, refreshToken);
252
194
  }
253
195
 
254
196
  /**
255
197
  * Clear stored authentication tokens
256
198
  */
257
199
  clearTokens() {
258
- this.tokenStore.clearTokens();
200
+ this.httpClient.clearTokens();
259
201
  }
260
202
 
261
203
  /**
262
204
  * Get the current user ID from the access token
263
205
  */
264
206
  getCurrentUserId() {
265
- const accessToken = this.tokenStore.getAccessToken();
207
+ const accessToken = this.httpClient.getAccessToken();
266
208
  if (!accessToken) {
267
209
  return null;
268
210
  }
@@ -278,21 +220,21 @@ class OxyServices {
278
220
  * Check if the client has a valid access token
279
221
  */
280
222
  hasAccessToken() {
281
- return this.tokenStore.hasAccessToken();
223
+ return this.httpClient.hasAccessToken();
282
224
  }
283
225
 
284
226
  /**
285
227
  * Check if the client has a valid access token (public method)
286
228
  */
287
229
  hasValidToken() {
288
- return this.tokenStore.hasAccessToken();
230
+ return this.httpClient.hasAccessToken();
289
231
  }
290
232
 
291
233
  /**
292
234
  * Get the raw access token (for constructing anchor URLs when needed)
293
235
  */
294
236
  getAccessToken() {
295
- return this.tokenStore.getAccessToken();
237
+ return this.httpClient.getAccessToken();
296
238
  }
297
239
 
298
240
  /**
@@ -311,7 +253,7 @@ class OxyServices {
311
253
  const checkInterval = 100; // Check every 100ms
312
254
 
313
255
  while (Date.now() - startTime < timeoutMs) {
314
- if (this.tokenStore.hasAccessToken()) {
256
+ if (this.httpClient.hasAccessToken()) {
315
257
  return true;
316
258
  }
317
259
  await new Promise(resolve => setTimeout(resolve, checkInterval));
@@ -332,15 +274,13 @@ class OxyServices {
332
274
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
333
275
  try {
334
276
  // First attempt: check if we have a token
335
- if (!this.tokenStore.hasAccessToken()) {
277
+ if (!this.httpClient.hasAccessToken()) {
336
278
  if (attempt === 0) {
337
279
  // On first attempt, wait briefly for authentication to complete
338
- console.log(`🔄 ${operationName} - Waiting for authentication...`);
339
280
  const authReady = await this.waitForAuthentication(authTimeoutMs);
340
281
  if (!authReady) {
341
282
  throw new OxyAuthenticationTimeoutError(operationName, authTimeoutMs);
342
283
  }
343
- console.log(`✅ ${operationName} - Authentication ready, proceeding...`);
344
284
  } else {
345
285
  // On retry attempts, fail immediately if no token
346
286
  throw new OxyAuthenticationError(`Authentication required: ${operationName} requires a valid access token.`, 'AUTH_REQUIRED');
@@ -353,7 +293,6 @@ class OxyServices {
353
293
  const isLastAttempt = attempt === maxRetries;
354
294
  const isAuthError = error?.response?.status === 401 || error?.code === 'MISSING_TOKEN' || error?.message?.includes('Authentication') || error instanceof OxyAuthenticationError;
355
295
  if (isAuthError && !isLastAttempt && !(error instanceof OxyAuthenticationTimeoutError)) {
356
- console.log(`🔄 ${operationName} - Auth error on attempt ${attempt + 1}, retrying in ${retryDelay}ms...`);
357
296
  await new Promise(resolve => setTimeout(resolve, retryDelay));
358
297
  continue;
359
298
  }
@@ -378,20 +317,16 @@ class OxyServices {
378
317
  return false;
379
318
  }
380
319
  try {
381
- const res = await this.client.get('/api/auth/validate');
382
- return res.data.valid === true;
320
+ const res = await this.makeRequest('GET', '/api/auth/validate', undefined, {
321
+ cache: false,
322
+ retry: false
323
+ });
324
+ return res.valid === true;
383
325
  } catch (error) {
384
326
  return false;
385
327
  }
386
328
  }
387
329
 
388
- /**
389
- * Get the HTTP client instance (public for external use)
390
- */
391
- getClient() {
392
- return this.client;
393
- }
394
-
395
330
  /**
396
331
  * Centralized error handling
397
332
  */
@@ -409,8 +344,9 @@ class OxyServices {
409
344
  */
410
345
  async healthCheck() {
411
346
  try {
412
- const res = await this.client.get('/health');
413
- return res.data;
347
+ return await this.makeRequest('GET', '/health', undefined, {
348
+ cache: false
349
+ });
414
350
  } catch (error) {
415
351
  throw this.handleError(error);
416
352
  }
@@ -425,15 +361,17 @@ class OxyServices {
425
361
  */
426
362
  async signUp(username, email, password) {
427
363
  try {
428
- const res = await this.client.post('/api/auth/signup', {
364
+ const res = await this.makeRequest('POST', '/api/auth/signup', {
429
365
  username,
430
366
  email,
431
367
  password
368
+ }, {
369
+ cache: false
432
370
  });
433
- if (!res || !res.data || typeof res.data === 'object' && Object.keys(res.data).length === 0) {
371
+ if (!res || typeof res === 'object' && Object.keys(res).length === 0) {
434
372
  throw new OxyAuthenticationError('Sign up failed', 'SIGNUP_FAILED', 400);
435
373
  }
436
- return res.data;
374
+ return res;
437
375
  } catch (error) {
438
376
  throw this.handleError(error);
439
377
  }
@@ -444,10 +382,11 @@ class OxyServices {
444
382
  */
445
383
  async requestRecovery(identifier) {
446
384
  try {
447
- const res = await this.client.post('/api/auth/recover/request', {
385
+ return await this.makeRequest('POST', '/api/auth/recover/request', {
448
386
  identifier
387
+ }, {
388
+ cache: false
449
389
  });
450
- return res.data;
451
390
  } catch (error) {
452
391
  throw this.handleError(error);
453
392
  }
@@ -458,11 +397,12 @@ class OxyServices {
458
397
  */
459
398
  async verifyRecoveryCode(identifier, code) {
460
399
  try {
461
- const res = await this.client.post('/api/auth/recover/verify', {
400
+ return await this.makeRequest('POST', '/api/auth/recover/verify', {
462
401
  identifier,
463
402
  code
403
+ }, {
404
+ cache: false
464
405
  });
465
- return res.data;
466
406
  } catch (error) {
467
407
  throw this.handleError(error);
468
408
  }
@@ -473,12 +413,13 @@ class OxyServices {
473
413
  */
474
414
  async resetPassword(identifier, code, newPassword) {
475
415
  try {
476
- const res = await this.client.post('/api/auth/recover/reset', {
416
+ return await this.makeRequest('POST', '/api/auth/recover/reset', {
477
417
  identifier,
478
418
  code,
479
419
  newPassword
420
+ }, {
421
+ cache: false
480
422
  });
481
- return res.data;
482
423
  } catch (error) {
483
424
  throw this.handleError(error);
484
425
  }
@@ -489,36 +430,39 @@ class OxyServices {
489
430
  */
490
431
  async resetPasswordWithTotp(identifier, code, newPassword) {
491
432
  try {
492
- const res = await this.client.post('/api/auth/recover/totp/reset', {
433
+ return await this.makeRequest('POST', '/api/auth/recover/totp/reset', {
493
434
  identifier,
494
435
  code,
495
436
  newPassword
437
+ }, {
438
+ cache: false
496
439
  });
497
- return res.data;
498
440
  } catch (error) {
499
441
  throw this.handleError(error);
500
442
  }
501
443
  }
502
444
  async resetPasswordWithBackupCode(identifier, backupCode, newPassword) {
503
445
  try {
504
- const res = await this.client.post('/api/auth/recover/backup/reset', {
446
+ return await this.makeRequest('POST', '/api/auth/recover/backup/reset', {
505
447
  identifier,
506
448
  backupCode,
507
449
  newPassword
450
+ }, {
451
+ cache: false
508
452
  });
509
- return res.data;
510
453
  } catch (error) {
511
454
  throw this.handleError(error);
512
455
  }
513
456
  }
514
457
  async resetPasswordWithRecoveryKey(identifier, recoveryKey, newPassword) {
515
458
  try {
516
- const res = await this.client.post('/api/auth/recover/recovery-key/reset', {
459
+ return await this.makeRequest('POST', '/api/auth/recover/recovery-key/reset', {
517
460
  identifier,
518
461
  recoveryKey,
519
462
  newPassword
463
+ }, {
464
+ cache: false
520
465
  });
521
- return res.data;
522
466
  } catch (error) {
523
467
  throw this.handleError(error);
524
468
  }
@@ -529,13 +473,14 @@ class OxyServices {
529
473
  */
530
474
  async signIn(username, password, deviceName, deviceFingerprint) {
531
475
  try {
532
- const res = await this.client.post('/api/auth/login', {
476
+ return await this.makeRequest('POST', '/api/auth/login', {
533
477
  username,
534
478
  password,
535
479
  deviceName,
536
480
  deviceFingerprint
481
+ }, {
482
+ cache: false
537
483
  });
538
- return res.data;
539
484
  } catch (error) {
540
485
  throw this.handleError(error);
541
486
  }
@@ -546,11 +491,12 @@ class OxyServices {
546
491
  */
547
492
  async verifyTotpLogin(mfaToken, code) {
548
493
  try {
549
- const res = await this.client.post('/api/auth/totp/verify-login', {
494
+ return await this.makeRequest('POST', '/api/auth/totp/verify-login', {
550
495
  mfaToken,
551
496
  code
497
+ }, {
498
+ cache: false
552
499
  });
553
- return res.data;
554
500
  } catch (error) {
555
501
  throw this.handleError(error);
556
502
  }
@@ -561,8 +507,35 @@ class OxyServices {
561
507
  */
562
508
  async getUserBySession(sessionId) {
563
509
  try {
564
- const res = await this.client.get(`/api/session/user/${sessionId}`);
565
- return res.data;
510
+ return await this.makeRequest('GET', `/api/session/user/${sessionId}`, undefined, {
511
+ cache: true,
512
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache for user data
513
+ });
514
+ } catch (error) {
515
+ throw this.handleError(error);
516
+ }
517
+ }
518
+
519
+ /**
520
+ * Batch get multiple user profiles by session IDs (optimized for account switching)
521
+ * Returns array of { sessionId, user } objects
522
+ */
523
+ async getUsersBySessions(sessionIds) {
524
+ try {
525
+ if (!Array.isArray(sessionIds) || sessionIds.length === 0) {
526
+ return [];
527
+ }
528
+
529
+ // Deduplicate and sort sessionIds for consistent cache keys
530
+ const uniqueSessionIds = Array.from(new Set(sessionIds)).sort();
531
+ return await this.makeRequest('POST', '/api/session/users/batch', {
532
+ sessionIds: uniqueSessionIds
533
+ }, {
534
+ cache: true,
535
+ cacheTTL: 2 * 60 * 1000,
536
+ // 2 minutes cache
537
+ deduplicate: true // Important for batch requests
538
+ });
566
539
  } catch (error) {
567
540
  throw this.handleError(error);
568
541
  }
@@ -573,19 +546,15 @@ class OxyServices {
573
546
  */
574
547
  async getTokenBySession(sessionId) {
575
548
  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);
549
+ const res = await this.makeRequest('GET', `/api/session/token/${sessionId}`, undefined, {
550
+ cache: false,
551
+ retry: false
552
+ });
582
553
 
583
554
  // Set the token in the centralized token store
584
- this.setTokens(accessToken);
585
- console.log('🔑 getTokenBySession - Token set in store');
586
- return res.data;
555
+ this.setTokens(res.accessToken);
556
+ return res;
587
557
  } catch (error) {
588
- console.log('❌ getTokenBySession - Error:', error);
589
558
  throw this.handleError(error);
590
559
  }
591
560
  }
@@ -595,8 +564,9 @@ class OxyServices {
595
564
  */
596
565
  async getSessionsBySessionId(sessionId) {
597
566
  try {
598
- const res = await this.client.get(`/api/session/sessions/${sessionId}`);
599
- return res.data;
567
+ return await this.makeRequest('GET', `/api/session/sessions/${sessionId}`, undefined, {
568
+ cache: false
569
+ });
600
570
  } catch (error) {
601
571
  throw this.handleError(error);
602
572
  }
@@ -608,7 +578,9 @@ class OxyServices {
608
578
  async logoutSession(sessionId, targetSessionId) {
609
579
  try {
610
580
  const url = targetSessionId ? `/api/session/logout/${sessionId}/${targetSessionId}` : `/api/session/logout/${sessionId}`;
611
- await this.client.post(url);
581
+ await this.makeRequest('POST', url, undefined, {
582
+ cache: false
583
+ });
612
584
  } catch (error) {
613
585
  throw this.handleError(error);
614
586
  }
@@ -619,7 +591,9 @@ class OxyServices {
619
591
  */
620
592
  async logoutAllSessions(sessionId) {
621
593
  try {
622
- await this.client.post(`/api/session/logout-all/${sessionId}`);
594
+ await this.makeRequest('POST', `/api/session/logout-all/${sessionId}`, undefined, {
595
+ cache: false
596
+ });
623
597
  } catch (error) {
624
598
  throw this.handleError(error);
625
599
  }
@@ -637,9 +611,13 @@ class OxyServices {
637
611
  if (options.useHeaderValidation) {
638
612
  params.append('useHeaderValidation', 'true');
639
613
  }
640
- const url = `/api/session/validate/${sessionId}?${params.toString()}`;
641
- const res = await this.client.get(url);
642
- return res.data;
614
+ const url = `/api/session/validate/${sessionId}`;
615
+ const urlParams = {};
616
+ if (options.deviceFingerprint) urlParams.deviceFingerprint = options.deviceFingerprint;
617
+ if (options.useHeaderValidation) urlParams.useHeaderValidation = 'true';
618
+ return await this.makeRequest('GET', url, urlParams, {
619
+ cache: false
620
+ });
643
621
  } catch (error) {
644
622
  throw this.handleError(error);
645
623
  }
@@ -650,8 +628,9 @@ class OxyServices {
650
628
  */
651
629
  async checkUsernameAvailability(username) {
652
630
  try {
653
- const res = await this.client.get(`/api/auth/check-username/${username}`);
654
- return res.data;
631
+ return await this.makeRequest('GET', `/api/auth/check-username/${username}`, undefined, {
632
+ cache: false
633
+ });
655
634
  } catch (error) {
656
635
  throw this.handleError(error);
657
636
  }
@@ -662,8 +641,9 @@ class OxyServices {
662
641
  */
663
642
  async checkEmailAvailability(email) {
664
643
  try {
665
- const res = await this.client.get(`/api/auth/check-email/${email}`);
666
- return res.data;
644
+ return await this.makeRequest('GET', `/api/auth/check-email/${email}`, undefined, {
645
+ cache: false
646
+ });
667
647
  } catch (error) {
668
648
  throw this.handleError(error);
669
649
  }
@@ -678,8 +658,10 @@ class OxyServices {
678
658
  */
679
659
  async getProfileByUsername(username) {
680
660
  try {
681
- const res = await this.client.get(`/api/profiles/username/${username}`);
682
- return res.data;
661
+ return await this.makeRequest('GET', `/api/profiles/username/${username}`, undefined, {
662
+ cache: true,
663
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache for profiles
664
+ });
683
665
  } catch (error) {
684
666
  throw this.handleError(error);
685
667
  }
@@ -691,44 +673,36 @@ class OxyServices {
691
673
 
692
674
  async startTotpEnrollment(sessionId) {
693
675
  try {
694
- const res = await this.client.post('/api/auth/totp/enroll/start', {
676
+ // Note: x-session-id header is handled by HttpClient interceptors if needed
677
+ return await this.makeRequest('POST', '/api/auth/totp/enroll/start', {
695
678
  sessionId
696
679
  }, {
697
- headers: {
698
- 'x-session-id': sessionId
699
- }
680
+ cache: false
700
681
  });
701
- return res.data;
702
682
  } catch (error) {
703
683
  throw this.handleError(error);
704
684
  }
705
685
  }
706
686
  async verifyTotpEnrollment(sessionId, code) {
707
687
  try {
708
- const res = await this.client.post('/api/auth/totp/enroll/verify', {
688
+ return await this.makeRequest('POST', '/api/auth/totp/enroll/verify', {
709
689
  sessionId,
710
690
  code
711
691
  }, {
712
- headers: {
713
- 'x-session-id': sessionId
714
- }
692
+ cache: false
715
693
  });
716
- return res.data;
717
694
  } catch (error) {
718
695
  throw this.handleError(error);
719
696
  }
720
697
  }
721
698
  async disableTotp(sessionId, code) {
722
699
  try {
723
- const res = await this.client.post('/api/auth/totp/disable', {
700
+ return await this.makeRequest('POST', '/api/auth/totp/disable', {
724
701
  sessionId,
725
702
  code
726
703
  }, {
727
- headers: {
728
- 'x-session-id': sessionId
729
- }
704
+ cache: false
730
705
  });
731
- return res.data;
732
706
  } catch (error) {
733
707
  throw this.handleError(error);
734
708
  }
@@ -744,8 +718,14 @@ class OxyServices {
744
718
  ...pagination
745
719
  };
746
720
  const searchParams = (0, _apiUtils.buildSearchParams)(params);
747
- const res = await this.client.get(`/api/profiles/search?${searchParams.toString()}`);
748
- return res.data;
721
+ const paramsObj = {};
722
+ searchParams.forEach((value, key) => {
723
+ paramsObj[key] = value;
724
+ });
725
+ return await this.makeRequest('GET', '/api/profiles/search', paramsObj, {
726
+ cache: true,
727
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
728
+ });
749
729
  } catch (error) {
750
730
  throw this.handleError(error);
751
731
  }
@@ -756,8 +736,9 @@ class OxyServices {
756
736
  */
757
737
  async getProfileRecommendations() {
758
738
  return this.withAuthRetry(async () => {
759
- const res = await this.client.get('/api/profiles/recommendations');
760
- return res.data;
739
+ return await this.makeRequest('GET', '/api/profiles/recommendations', undefined, {
740
+ cache: true
741
+ });
761
742
  }, 'getProfileRecommendations');
762
743
  }
763
744
 
@@ -766,8 +747,10 @@ class OxyServices {
766
747
  */
767
748
  async getUserById(userId) {
768
749
  try {
769
- const res = await this.client.get(`/api/users/${userId}`);
770
- return res.data;
750
+ return await this.makeRequest('GET', `/api/users/${userId}`, undefined, {
751
+ cache: true,
752
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
753
+ });
771
754
  } catch (error) {
772
755
  throw this.handleError(error);
773
756
  }
@@ -778,8 +761,10 @@ class OxyServices {
778
761
  */
779
762
  async getCurrentUser() {
780
763
  return this.withAuthRetry(async () => {
781
- const res = await this.client.get('/api/users/me');
782
- return res.data;
764
+ return await this.makeRequest('GET', '/api/users/me', undefined, {
765
+ cache: true,
766
+ cacheTTL: 1 * 60 * 1000 // 1 minute cache for current user
767
+ });
783
768
  }, 'getCurrentUser');
784
769
  }
785
770
 
@@ -788,20 +773,134 @@ class OxyServices {
788
773
  */
789
774
  async updateProfile(updates) {
790
775
  try {
791
- const res = await this.client.put('/api/users/me', updates);
792
- return res.data;
776
+ return await this.makeRequest('PUT', '/api/users/me', updates, {
777
+ cache: false
778
+ });
793
779
  } catch (error) {
794
780
  throw this.handleError(error);
795
781
  }
796
782
  }
797
783
 
784
+ // ============================================================================
785
+ // LANGUAGE METHODS
786
+ // ============================================================================
787
+
788
+ /**
789
+ * Get the current language from storage or user profile
790
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
791
+ * @returns The current language code (e.g., 'en-US') or null if not set
792
+ */
793
+ async getCurrentLanguage(storageKeyPrefix = 'oxy_session') {
794
+ try {
795
+ // First try to get from user profile if authenticated
796
+ try {
797
+ const user = await this.getCurrentUser();
798
+ const userLanguage = user?.language;
799
+ if (userLanguage) {
800
+ return (0, _languageUtils.normalizeLanguageCode)(userLanguage) || userLanguage;
801
+ }
802
+ } catch (e) {
803
+ // User not authenticated or error, continue to storage
804
+ }
805
+
806
+ // Fall back to storage
807
+ const storage = await this.getStorage();
808
+ const storageKey = `${storageKeyPrefix}_language`;
809
+ const storedLanguage = await storage.getItem(storageKey);
810
+ if (storedLanguage) {
811
+ return (0, _languageUtils.normalizeLanguageCode)(storedLanguage) || storedLanguage;
812
+ }
813
+ return null;
814
+ } catch (error) {
815
+ if (__DEV__) {
816
+ console.warn('Failed to get current language:', error);
817
+ }
818
+ return null;
819
+ }
820
+ }
821
+
822
+ /**
823
+ * Get the current language with metadata (name, nativeName, etc.)
824
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
825
+ * @returns Language metadata object or null if not set
826
+ */
827
+ async getCurrentLanguageMetadata(storageKeyPrefix = 'oxy_session') {
828
+ const languageCode = await this.getCurrentLanguage(storageKeyPrefix);
829
+ return (0, _languageUtils.getLanguageMetadata)(languageCode);
830
+ }
831
+
832
+ /**
833
+ * Get the current language name (e.g., 'English')
834
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
835
+ * @returns Language name or null if not set
836
+ */
837
+ async getCurrentLanguageName(storageKeyPrefix = 'oxy_session') {
838
+ const languageCode = await this.getCurrentLanguage(storageKeyPrefix);
839
+ if (!languageCode) return null;
840
+ return (0, _languageUtils.getLanguageName)(languageCode);
841
+ }
842
+
843
+ /**
844
+ * Get the current native language name (e.g., 'Español')
845
+ * @param storageKeyPrefix - Optional prefix for storage key (default: 'oxy_session')
846
+ * @returns Native language name or null if not set
847
+ */
848
+ async getCurrentNativeLanguageName(storageKeyPrefix = 'oxy_session') {
849
+ const languageCode = await this.getCurrentLanguage(storageKeyPrefix);
850
+ if (!languageCode) return null;
851
+ return (0, _languageUtils.getNativeLanguageName)(languageCode);
852
+ }
853
+
854
+ /**
855
+ * Get appropriate storage for the platform (similar to DeviceManager)
856
+ * @private
857
+ */
858
+ async getStorage() {
859
+ const isReactNative = typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
860
+ if (isReactNative) {
861
+ try {
862
+ const asyncStorageModule = await Promise.resolve().then(() => _interopRequireWildcard(require('@react-native-async-storage/async-storage')));
863
+ const storage = asyncStorageModule.default;
864
+ return {
865
+ getItem: storage.getItem.bind(storage),
866
+ setItem: storage.setItem.bind(storage),
867
+ removeItem: storage.removeItem.bind(storage)
868
+ };
869
+ } catch (error) {
870
+ console.error('AsyncStorage not available in React Native:', error);
871
+ throw new Error('AsyncStorage is required in React Native environment');
872
+ }
873
+ } else {
874
+ // Use localStorage for web
875
+ return {
876
+ getItem: async key => {
877
+ if (typeof window !== 'undefined' && window.localStorage) {
878
+ return localStorage.getItem(key);
879
+ }
880
+ return null;
881
+ },
882
+ setItem: async (key, value) => {
883
+ if (typeof window !== 'undefined' && window.localStorage) {
884
+ localStorage.setItem(key, value);
885
+ }
886
+ },
887
+ removeItem: async key => {
888
+ if (typeof window !== 'undefined' && window.localStorage) {
889
+ localStorage.removeItem(key);
890
+ }
891
+ }
892
+ };
893
+ }
894
+ }
895
+
798
896
  /**
799
897
  * Update user by ID (admin function)
800
898
  */
801
899
  async updateUser(userId, updates) {
802
900
  try {
803
- const res = await this.client.put(`/api/users/${userId}`, updates);
804
- return res.data;
901
+ return await this.makeRequest('PUT', `/api/users/${userId}`, updates, {
902
+ cache: false
903
+ });
805
904
  } catch (error) {
806
905
  throw this.handleError(error);
807
906
  }
@@ -812,8 +911,9 @@ class OxyServices {
812
911
  */
813
912
  async followUser(userId) {
814
913
  try {
815
- const res = await this.client.post(`/api/users/${userId}/follow`);
816
- return res.data;
914
+ return await this.makeRequest('POST', `/api/users/${userId}/follow`, undefined, {
915
+ cache: false
916
+ });
817
917
  } catch (error) {
818
918
  throw this.handleError(error);
819
919
  }
@@ -824,8 +924,9 @@ class OxyServices {
824
924
  */
825
925
  async unfollowUser(userId) {
826
926
  try {
827
- const res = await this.client.delete(`/api/users/${userId}/follow`);
828
- return res.data;
927
+ return await this.makeRequest('DELETE', `/api/users/${userId}/follow`, undefined, {
928
+ cache: false
929
+ });
829
930
  } catch (error) {
830
931
  throw this.handleError(error);
831
932
  }
@@ -836,8 +937,10 @@ class OxyServices {
836
937
  */
837
938
  async getFollowStatus(userId) {
838
939
  try {
839
- const res = await this.client.get(`/api/users/${userId}/follow-status`);
840
- return res.data;
940
+ return await this.makeRequest('GET', `/api/users/${userId}/follow-status`, undefined, {
941
+ cache: true,
942
+ cacheTTL: 1 * 60 * 1000 // 1 minute cache
943
+ });
841
944
  } catch (error) {
842
945
  throw this.handleError(error);
843
946
  }
@@ -849,8 +952,15 @@ class OxyServices {
849
952
  async getUserFollowers(userId, pagination) {
850
953
  try {
851
954
  const params = (0, _apiUtils.buildPaginationParams)(pagination || {});
852
- const res = await this.client.get(`/api/users/${userId}/followers?${params.toString()}`);
853
- return res.data;
955
+ const response = await this.makeRequest('GET', `/api/users/${userId}/followers`, params, {
956
+ cache: true,
957
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
958
+ });
959
+ return {
960
+ followers: response.data || [],
961
+ total: response.pagination.total,
962
+ hasMore: response.pagination.hasMore
963
+ };
854
964
  } catch (error) {
855
965
  throw this.handleError(error);
856
966
  }
@@ -862,8 +972,15 @@ class OxyServices {
862
972
  async getUserFollowing(userId, pagination) {
863
973
  try {
864
974
  const params = (0, _apiUtils.buildPaginationParams)(pagination || {});
865
- const res = await this.client.get(`/api/users/${userId}/following?${params.toString()}`);
866
- return res.data;
975
+ const response = await this.makeRequest('GET', `/api/users/${userId}/following`, params, {
976
+ cache: true,
977
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
978
+ });
979
+ return {
980
+ following: response.data || [],
981
+ total: response.pagination.total,
982
+ hasMore: response.pagination.hasMore
983
+ };
867
984
  } catch (error) {
868
985
  throw this.handleError(error);
869
986
  }
@@ -874,8 +991,9 @@ class OxyServices {
874
991
  */
875
992
  async getNotifications() {
876
993
  return this.withAuthRetry(async () => {
877
- const res = await this.client.get('/api/notifications');
878
- return res.data;
994
+ return await this.makeRequest('GET', '/api/notifications', undefined, {
995
+ cache: false // Don't cache notifications - always get fresh data
996
+ });
879
997
  }, 'getNotifications');
880
998
  }
881
999
 
@@ -884,8 +1002,10 @@ class OxyServices {
884
1002
  */
885
1003
  async getUnreadCount() {
886
1004
  try {
887
- const res = await this.client.get('/api/notifications/unread-count');
888
- return res.data.count;
1005
+ const res = await this.makeRequest('GET', '/api/notifications/unread-count', undefined, {
1006
+ cache: false // Don't cache unread count - always get fresh data
1007
+ });
1008
+ return res.count;
889
1009
  } catch (error) {
890
1010
  throw this.handleError(error);
891
1011
  }
@@ -896,8 +1016,9 @@ class OxyServices {
896
1016
  */
897
1017
  async createNotification(data) {
898
1018
  try {
899
- const res = await this.client.post('/api/notifications', data);
900
- return res.data;
1019
+ return await this.makeRequest('POST', '/api/notifications', data, {
1020
+ cache: false
1021
+ });
901
1022
  } catch (error) {
902
1023
  throw this.handleError(error);
903
1024
  }
@@ -908,7 +1029,9 @@ class OxyServices {
908
1029
  */
909
1030
  async markNotificationAsRead(notificationId) {
910
1031
  try {
911
- await this.client.put(`/api/notifications/${notificationId}/read`);
1032
+ await this.makeRequest('PUT', `/api/notifications/${notificationId}/read`, undefined, {
1033
+ cache: false
1034
+ });
912
1035
  } catch (error) {
913
1036
  throw this.handleError(error);
914
1037
  }
@@ -919,7 +1042,9 @@ class OxyServices {
919
1042
  */
920
1043
  async markAllNotificationsAsRead() {
921
1044
  try {
922
- await this.client.put('/api/notifications/read-all');
1045
+ await this.makeRequest('PUT', '/api/notifications/read-all', undefined, {
1046
+ cache: false
1047
+ });
923
1048
  } catch (error) {
924
1049
  throw this.handleError(error);
925
1050
  }
@@ -930,7 +1055,9 @@ class OxyServices {
930
1055
  */
931
1056
  async deleteNotification(notificationId) {
932
1057
  try {
933
- await this.client.delete(`/api/notifications/${notificationId}`);
1058
+ await this.makeRequest('DELETE', `/api/notifications/${notificationId}`, undefined, {
1059
+ cache: false
1060
+ });
934
1061
  } catch (error) {
935
1062
  throw this.handleError(error);
936
1063
  }
@@ -945,8 +1072,9 @@ class OxyServices {
945
1072
  */
946
1073
  async createPayment(data) {
947
1074
  try {
948
- const res = await this.client.post('/api/payments', data);
949
- return res.data;
1075
+ return await this.makeRequest('POST', '/api/payments', data, {
1076
+ cache: false
1077
+ });
950
1078
  } catch (error) {
951
1079
  throw this.handleError(error);
952
1080
  }
@@ -957,8 +1085,10 @@ class OxyServices {
957
1085
  */
958
1086
  async getPayment(paymentId) {
959
1087
  try {
960
- const res = await this.client.get(`/api/payments/${paymentId}`);
961
- return res.data;
1088
+ return await this.makeRequest('GET', `/api/payments/${paymentId}`, undefined, {
1089
+ cache: true,
1090
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1091
+ });
962
1092
  } catch (error) {
963
1093
  throw this.handleError(error);
964
1094
  }
@@ -969,8 +1099,9 @@ class OxyServices {
969
1099
  */
970
1100
  async getUserPayments() {
971
1101
  try {
972
- const res = await this.client.get('/api/payments/user');
973
- return res.data;
1102
+ return await this.makeRequest('GET', '/api/payments/user', undefined, {
1103
+ cache: false // Don't cache user payments - always get fresh data
1104
+ });
974
1105
  } catch (error) {
975
1106
  throw this.handleError(error);
976
1107
  }
@@ -985,8 +1116,10 @@ class OxyServices {
985
1116
  */
986
1117
  async getUserKarma(userId) {
987
1118
  try {
988
- const res = await this.client.get(`/api/karma/${userId}`);
989
- return res.data;
1119
+ return await this.makeRequest('GET', `/api/karma/${userId}`, undefined, {
1120
+ cache: true,
1121
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
1122
+ });
990
1123
  } catch (error) {
991
1124
  throw this.handleError(error);
992
1125
  }
@@ -997,11 +1130,12 @@ class OxyServices {
997
1130
  */
998
1131
  async giveKarma(userId, amount, reason) {
999
1132
  try {
1000
- const res = await this.client.post(`/api/karma/${userId}/give`, {
1133
+ return await this.makeRequest('POST', `/api/karma/${userId}/give`, {
1001
1134
  amount,
1002
1135
  reason
1136
+ }, {
1137
+ cache: false
1003
1138
  });
1004
- return res.data;
1005
1139
  } catch (error) {
1006
1140
  throw this.handleError(error);
1007
1141
  }
@@ -1012,8 +1146,10 @@ class OxyServices {
1012
1146
  */
1013
1147
  async getUserKarmaTotal(userId) {
1014
1148
  try {
1015
- const res = await this.client.get(`/api/karma/${userId}/total`);
1016
- return res.data;
1149
+ return await this.makeRequest('GET', `/api/karma/${userId}/total`, undefined, {
1150
+ cache: true,
1151
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
1152
+ });
1017
1153
  } catch (error) {
1018
1154
  throw this.handleError(error);
1019
1155
  }
@@ -1024,11 +1160,13 @@ class OxyServices {
1024
1160
  */
1025
1161
  async getUserKarmaHistory(userId, limit, offset) {
1026
1162
  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;
1163
+ const params = {};
1164
+ if (limit) params.limit = limit;
1165
+ if (offset) params.offset = offset;
1166
+ return await this.makeRequest('GET', `/api/karma/${userId}/history`, params, {
1167
+ cache: true,
1168
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
1169
+ });
1032
1170
  } catch (error) {
1033
1171
  throw this.handleError(error);
1034
1172
  }
@@ -1039,8 +1177,10 @@ class OxyServices {
1039
1177
  */
1040
1178
  async getKarmaLeaderboard() {
1041
1179
  try {
1042
- const res = await this.client.get('/api/karma/leaderboard');
1043
- return res.data;
1180
+ return await this.makeRequest('GET', '/api/karma/leaderboard', undefined, {
1181
+ cache: true,
1182
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1183
+ });
1044
1184
  } catch (error) {
1045
1185
  throw this.handleError(error);
1046
1186
  }
@@ -1051,8 +1191,10 @@ class OxyServices {
1051
1191
  */
1052
1192
  async getKarmaRules() {
1053
1193
  try {
1054
- const res = await this.client.get('/api/karma/rules');
1055
- return res.data;
1194
+ return await this.makeRequest('GET', '/api/karma/rules', undefined, {
1195
+ cache: true,
1196
+ cacheTTL: 30 * 60 * 1000 // 30 minutes cache (rules don't change often)
1197
+ });
1056
1198
  } catch (error) {
1057
1199
  throw this.handleError(error);
1058
1200
  }
@@ -1068,8 +1210,9 @@ class OxyServices {
1068
1210
  async deleteFile(fileId) {
1069
1211
  try {
1070
1212
  // 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;
1213
+ return await this.makeRequest('DELETE', `/api/assets/${encodeURIComponent(fileId)}`, undefined, {
1214
+ cache: false
1215
+ });
1073
1216
  } catch (error) {
1074
1217
  throw this.handleError(error);
1075
1218
  }
@@ -1084,7 +1227,7 @@ class OxyServices {
1084
1227
  if (variant) params.set('variant', variant);
1085
1228
  if (expiresIn) params.set('expiresIn', String(expiresIn));
1086
1229
  params.set('fallback', 'placeholderVisible');
1087
- const token = this.tokenStore.getAccessToken();
1230
+ const token = this.httpClient.getAccessToken();
1088
1231
  if (token) params.set('token', token);
1089
1232
 
1090
1233
  // Use params.toString() to detect whether there are query params.
@@ -1110,12 +1253,12 @@ class OxyServices {
1110
1253
  */
1111
1254
  async listUserFiles(limit, offset) {
1112
1255
  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;
1256
+ const paramsObj = {};
1257
+ if (limit) paramsObj.limit = limit;
1258
+ if (offset) paramsObj.offset = offset;
1259
+ return await this.makeRequest('GET', '/api/assets', paramsObj, {
1260
+ cache: false // Don't cache file lists - always get fresh data
1261
+ });
1119
1262
  } catch (error) {
1120
1263
  throw this.handleError(error);
1121
1264
  }
@@ -1128,8 +1271,14 @@ class OxyServices {
1128
1271
  */
1129
1272
  async getFileContentAsText(fileId, variant) {
1130
1273
  try {
1131
- const urlRes = await this.client.get(`/api/assets/${encodeURIComponent(fileId)}/url${variant ? `?variant=${encodeURIComponent(variant)}` : ''}`);
1132
- const downloadUrl = urlRes.data?.url;
1274
+ const params = variant ? {
1275
+ variant
1276
+ } : undefined;
1277
+ const urlRes = await this.makeRequest('GET', `/api/assets/${encodeURIComponent(fileId)}/url`, params, {
1278
+ cache: true,
1279
+ cacheTTL: 10 * 60 * 1000 // 10 minutes cache for URLs
1280
+ });
1281
+ const downloadUrl = urlRes?.url;
1133
1282
  const response = await fetch(downloadUrl);
1134
1283
  return await response.text();
1135
1284
  } catch (error) {
@@ -1142,8 +1291,14 @@ class OxyServices {
1142
1291
  */
1143
1292
  async getFileContentAsBlob(fileId, variant) {
1144
1293
  try {
1145
- const urlRes = await this.client.get(`/api/assets/${encodeURIComponent(fileId)}/url${variant ? `?variant=${encodeURIComponent(variant)}` : ''}`);
1146
- const downloadUrl = urlRes.data?.url;
1294
+ const params = variant ? {
1295
+ variant
1296
+ } : undefined;
1297
+ const urlRes = await this.makeRequest('GET', `/api/assets/${encodeURIComponent(fileId)}/url`, params, {
1298
+ cache: true,
1299
+ cacheTTL: 10 * 60 * 1000 // 10 minutes cache for URLs
1300
+ });
1301
+ const downloadUrl = urlRes?.url;
1147
1302
  const response = await fetch(downloadUrl);
1148
1303
  return await response.blob();
1149
1304
  } catch (error) {
@@ -1178,12 +1333,13 @@ class OxyServices {
1178
1333
  */
1179
1334
  async assetInit(sha256, size, mime) {
1180
1335
  try {
1181
- const res = await this.client.post('/api/assets/init', {
1336
+ return await this.makeRequest('POST', '/api/assets/init', {
1182
1337
  sha256,
1183
1338
  size,
1184
1339
  mime
1340
+ }, {
1341
+ cache: false
1185
1342
  });
1186
- return res.data;
1187
1343
  } catch (error) {
1188
1344
  throw this.handleError(error);
1189
1345
  }
@@ -1194,15 +1350,16 @@ class OxyServices {
1194
1350
  */
1195
1351
  async assetComplete(fileId, originalName, size, mime, visibility, metadata) {
1196
1352
  try {
1197
- const res = await this.client.post('/api/assets/complete', {
1353
+ return await this.makeRequest('POST', '/api/assets/complete', {
1198
1354
  fileId,
1199
1355
  originalName,
1200
1356
  size,
1201
1357
  mime,
1202
1358
  visibility,
1203
1359
  metadata
1360
+ }, {
1361
+ cache: false
1204
1362
  });
1205
- return res.data;
1206
1363
  } catch (error) {
1207
1364
  throw this.handleError(error);
1208
1365
  }
@@ -1226,10 +1383,11 @@ class OxyServices {
1226
1383
  // Fallback: direct upload via API to avoid CORS issues
1227
1384
  const fd = new FormData();
1228
1385
  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
- }
1386
+ // Use httpClient directly for FormData uploads (bypasses RequestManager for special handling)
1387
+ await this.httpClient.request({
1388
+ method: 'POST',
1389
+ url: `/api/assets/${encodeURIComponent(initResponse.fileId)}/upload-direct`,
1390
+ data: fd
1233
1391
  });
1234
1392
  }
1235
1393
 
@@ -1280,8 +1438,9 @@ class OxyServices {
1280
1438
  };
1281
1439
  if (visibility) body.visibility = visibility;
1282
1440
  if (webhookUrl) body.webhookUrl = webhookUrl;
1283
- const res = await this.client.post(`/api/assets/${fileId}/links`, body);
1284
- return res.data;
1441
+ return await this.makeRequest('POST', `/api/assets/${fileId}/links`, body, {
1442
+ cache: false
1443
+ });
1285
1444
  } catch (error) {
1286
1445
  throw this.handleError(error);
1287
1446
  }
@@ -1292,14 +1451,13 @@ class OxyServices {
1292
1451
  */
1293
1452
  async assetUnlink(fileId, app, entityType, entityId) {
1294
1453
  try {
1295
- const res = await this.client.delete(`/api/assets/${fileId}/links`, {
1296
- data: {
1297
- app,
1298
- entityType,
1299
- entityId
1300
- }
1454
+ return await this.makeRequest('DELETE', `/api/assets/${fileId}/links`, {
1455
+ app,
1456
+ entityType,
1457
+ entityId
1458
+ }, {
1459
+ cache: false
1301
1460
  });
1302
- return res.data;
1303
1461
  } catch (error) {
1304
1462
  throw this.handleError(error);
1305
1463
  }
@@ -1310,8 +1468,10 @@ class OxyServices {
1310
1468
  */
1311
1469
  async assetGet(fileId) {
1312
1470
  try {
1313
- const res = await this.client.get(`/api/assets/${fileId}`);
1314
- return res.data;
1471
+ return await this.makeRequest('GET', `/api/assets/${fileId}`, undefined, {
1472
+ cache: true,
1473
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1474
+ });
1315
1475
  } catch (error) {
1316
1476
  throw this.handleError(error);
1317
1477
  }
@@ -1322,13 +1482,13 @@ class OxyServices {
1322
1482
  */
1323
1483
  async assetGetUrl(fileId, variant, expiresIn) {
1324
1484
  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;
1485
+ const params = {};
1486
+ if (variant) params.variant = variant;
1487
+ if (expiresIn) params.expiresIn = expiresIn;
1488
+ return await this.makeRequest('GET', `/api/assets/${fileId}/url`, params, {
1489
+ cache: true,
1490
+ cacheTTL: 10 * 60 * 1000 // 10 minutes cache for URLs
1491
+ });
1332
1492
  } catch (error) {
1333
1493
  throw this.handleError(error);
1334
1494
  }
@@ -1339,8 +1499,9 @@ class OxyServices {
1339
1499
  */
1340
1500
  async assetRestore(fileId) {
1341
1501
  try {
1342
- const res = await this.client.post(`/api/assets/${fileId}/restore`);
1343
- return res.data;
1502
+ return await this.makeRequest('POST', `/api/assets/${fileId}/restore`, undefined, {
1503
+ cache: false
1504
+ });
1344
1505
  } catch (error) {
1345
1506
  throw this.handleError(error);
1346
1507
  }
@@ -1351,9 +1512,12 @@ class OxyServices {
1351
1512
  */
1352
1513
  async assetDelete(fileId, force = false) {
1353
1514
  try {
1354
- const params = force ? '?force=true' : '';
1355
- const res = await this.client.delete(`/api/assets/${fileId}${params}`);
1356
- return res.data;
1515
+ const params = force ? {
1516
+ force: 'true'
1517
+ } : undefined;
1518
+ return await this.makeRequest('DELETE', `/api/assets/${fileId}`, params, {
1519
+ cache: false
1520
+ });
1357
1521
  } catch (error) {
1358
1522
  throw this.handleError(error);
1359
1523
  }
@@ -1379,10 +1543,11 @@ class OxyServices {
1379
1543
  */
1380
1544
  async assetUpdateVisibility(fileId, visibility) {
1381
1545
  try {
1382
- const res = await this.client.patch(`/api/assets/${fileId}/visibility`, {
1546
+ return await this.makeRequest('PATCH', `/api/assets/${fileId}/visibility`, {
1383
1547
  visibility
1548
+ }, {
1549
+ cache: false
1384
1550
  });
1385
- return res.data;
1386
1551
  } catch (error) {
1387
1552
  throw this.handleError(error);
1388
1553
  }
@@ -1437,8 +1602,11 @@ class OxyServices {
1437
1602
  */
1438
1603
  async getDeveloperApps() {
1439
1604
  try {
1440
- const res = await this.client.get('/api/developer/apps');
1441
- return res.data.apps || [];
1605
+ const res = await this.makeRequest('GET', '/api/developer/apps', undefined, {
1606
+ cache: true,
1607
+ cacheTTL: 2 * 60 * 1000 // 2 minutes cache
1608
+ });
1609
+ return res.apps || [];
1442
1610
  } catch (error) {
1443
1611
  throw this.handleError(error);
1444
1612
  }
@@ -1449,8 +1617,10 @@ class OxyServices {
1449
1617
  */
1450
1618
  async createDeveloperApp(data) {
1451
1619
  try {
1452
- const res = await this.client.post('/api/developer/apps', data);
1453
- return res.data.app;
1620
+ const res = await this.makeRequest('POST', '/api/developer/apps', data, {
1621
+ cache: false
1622
+ });
1623
+ return res.app;
1454
1624
  } catch (error) {
1455
1625
  throw this.handleError(error);
1456
1626
  }
@@ -1461,8 +1631,11 @@ class OxyServices {
1461
1631
  */
1462
1632
  async getDeveloperApp(appId) {
1463
1633
  try {
1464
- const res = await this.client.get(`/api/developer/apps/${appId}`);
1465
- return res.data.app;
1634
+ const res = await this.makeRequest('GET', `/api/developer/apps/${appId}`, undefined, {
1635
+ cache: true,
1636
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1637
+ });
1638
+ return res.app;
1466
1639
  } catch (error) {
1467
1640
  throw this.handleError(error);
1468
1641
  }
@@ -1473,8 +1646,10 @@ class OxyServices {
1473
1646
  */
1474
1647
  async updateDeveloperApp(appId, data) {
1475
1648
  try {
1476
- const res = await this.client.patch(`/api/developer/apps/${appId}`, data);
1477
- return res.data.app;
1649
+ const res = await this.makeRequest('PATCH', `/api/developer/apps/${appId}`, data, {
1650
+ cache: false
1651
+ });
1652
+ return res.app;
1478
1653
  } catch (error) {
1479
1654
  throw this.handleError(error);
1480
1655
  }
@@ -1485,8 +1660,9 @@ class OxyServices {
1485
1660
  */
1486
1661
  async regenerateDeveloperAppSecret(appId) {
1487
1662
  try {
1488
- const res = await this.client.post(`/api/developer/apps/${appId}/regenerate-secret`);
1489
- return res.data;
1663
+ return await this.makeRequest('POST', `/api/developer/apps/${appId}/regenerate-secret`, undefined, {
1664
+ cache: false
1665
+ });
1490
1666
  } catch (error) {
1491
1667
  throw this.handleError(error);
1492
1668
  }
@@ -1497,8 +1673,9 @@ class OxyServices {
1497
1673
  */
1498
1674
  async deleteDeveloperApp(appId) {
1499
1675
  try {
1500
- const res = await this.client.delete(`/api/developer/apps/${appId}`);
1501
- return res.data;
1676
+ return await this.makeRequest('DELETE', `/api/developer/apps/${appId}`, undefined, {
1677
+ cache: false
1678
+ });
1502
1679
  } catch (error) {
1503
1680
  throw this.handleError(error);
1504
1681
  }
@@ -1513,11 +1690,12 @@ class OxyServices {
1513
1690
  */
1514
1691
  async updateLocation(latitude, longitude) {
1515
1692
  try {
1516
- const res = await this.client.post('/api/location', {
1693
+ return await this.makeRequest('POST', '/api/location', {
1517
1694
  latitude,
1518
1695
  longitude
1696
+ }, {
1697
+ cache: false
1519
1698
  });
1520
- return res.data;
1521
1699
  } catch (error) {
1522
1700
  throw this.handleError(error);
1523
1701
  }
@@ -1528,9 +1706,12 @@ class OxyServices {
1528
1706
  */
1529
1707
  async getNearbyUsers(radius) {
1530
1708
  try {
1531
- const params = radius ? `?radius=${radius}` : '';
1532
- const res = await this.client.get(`/api/location/nearby${params}`);
1533
- return res.data;
1709
+ const params = radius ? {
1710
+ radius
1711
+ } : undefined;
1712
+ return await this.makeRequest('GET', '/api/location/nearby', params, {
1713
+ cache: false // Don't cache location data - always get fresh data
1714
+ });
1534
1715
  } catch (error) {
1535
1716
  throw this.handleError(error);
1536
1717
  }
@@ -1545,10 +1726,13 @@ class OxyServices {
1545
1726
  */
1546
1727
  async trackEvent(eventName, properties) {
1547
1728
  try {
1548
- await this.client.post('/api/analytics/events', {
1729
+ await this.makeRequest('POST', '/api/analytics/events', {
1549
1730
  event: eventName,
1550
1731
  properties
1551
- });
1732
+ }, {
1733
+ cache: false,
1734
+ retry: false
1735
+ }); // Don't retry analytics events
1552
1736
  } catch (error) {
1553
1737
  throw this.handleError(error);
1554
1738
  }
@@ -1559,11 +1743,13 @@ class OxyServices {
1559
1743
  */
1560
1744
  async getAnalytics(startDate, endDate) {
1561
1745
  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;
1746
+ const params = {};
1747
+ if (startDate) params.startDate = startDate;
1748
+ if (endDate) params.endDate = endDate;
1749
+ return await this.makeRequest('GET', '/api/analytics', params, {
1750
+ cache: true,
1751
+ cacheTTL: 5 * 60 * 1000 // 5 minutes cache
1752
+ });
1567
1753
  } catch (error) {
1568
1754
  throw this.handleError(error);
1569
1755
  }
@@ -1578,8 +1764,9 @@ class OxyServices {
1578
1764
  */
1579
1765
  async registerDevice(deviceData) {
1580
1766
  try {
1581
- const res = await this.client.post('/api/devices', deviceData);
1582
- return res.data;
1767
+ return await this.makeRequest('POST', '/api/devices', deviceData, {
1768
+ cache: false
1769
+ });
1583
1770
  } catch (error) {
1584
1771
  throw this.handleError(error);
1585
1772
  }
@@ -1590,8 +1777,9 @@ class OxyServices {
1590
1777
  */
1591
1778
  async getUserDevices() {
1592
1779
  try {
1593
- const res = await this.client.get('/api/devices');
1594
- return res.data;
1780
+ return await this.makeRequest('GET', '/api/devices', undefined, {
1781
+ cache: false // Don't cache device list - always get fresh data
1782
+ });
1595
1783
  } catch (error) {
1596
1784
  throw this.handleError(error);
1597
1785
  }
@@ -1602,7 +1790,9 @@ class OxyServices {
1602
1790
  */
1603
1791
  async removeDevice(deviceId) {
1604
1792
  try {
1605
- await this.client.delete(`/api/devices/${deviceId}`);
1793
+ await this.makeRequest('DELETE', `/api/devices/${deviceId}`, undefined, {
1794
+ cache: false
1795
+ });
1606
1796
  } catch (error) {
1607
1797
  throw this.handleError(error);
1608
1798
  }
@@ -1610,11 +1800,17 @@ class OxyServices {
1610
1800
 
1611
1801
  /**
1612
1802
  * Get device sessions
1803
+ * Note: Not cached by default to ensure fresh data, but can be cached via makeRequest if needed
1613
1804
  */
1614
1805
  async getDeviceSessions(sessionId) {
1615
1806
  try {
1616
- const res = await this.client.get(`/api/session/device/sessions/${sessionId}`);
1617
- return res.data;
1807
+ // Use makeRequest for consistent error handling and optional caching
1808
+ // Cache disabled by default to ensure fresh session data
1809
+ return await this.makeRequest('GET', `/api/session/device/sessions/${sessionId}`, undefined, {
1810
+ cache: false,
1811
+ // Don't cache sessions - always get fresh data
1812
+ deduplicate: true // Deduplicate concurrent requests for same sessionId
1813
+ });
1618
1814
  } catch (error) {
1619
1815
  throw this.handleError(error);
1620
1816
  }
@@ -1628,8 +1824,13 @@ class OxyServices {
1628
1824
  const params = new URLSearchParams();
1629
1825
  if (deviceId) params.append('deviceId', deviceId);
1630
1826
  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;
1827
+ const urlParams = {};
1828
+ params.forEach((value, key) => {
1829
+ urlParams[key] = value;
1830
+ });
1831
+ return await this.makeRequest('POST', `/api/session/device/logout-all/${sessionId}`, urlParams, {
1832
+ cache: false
1833
+ });
1633
1834
  } catch (error) {
1634
1835
  throw this.handleError(error);
1635
1836
  }
@@ -1640,10 +1841,11 @@ class OxyServices {
1640
1841
  */
1641
1842
  async updateDeviceName(sessionId, deviceName) {
1642
1843
  try {
1643
- const res = await this.client.put(`/api/session/device/name/${sessionId}`, {
1844
+ return await this.makeRequest('PUT', `/api/session/device/name/${sessionId}`, {
1644
1845
  deviceName
1846
+ }, {
1847
+ cache: false
1645
1848
  });
1646
- return res.data;
1647
1849
  } catch (error) {
1648
1850
  throw this.handleError(error);
1649
1851
  }
@@ -1658,8 +1860,12 @@ class OxyServices {
1658
1860
  */
1659
1861
  async fetchLinkMetadata(url) {
1660
1862
  try {
1661
- const res = await this.client.get(`/api/link-metadata?url=${encodeURIComponent(url)}`);
1662
- return res.data;
1863
+ return await this.makeRequest('GET', '/api/link-metadata', {
1864
+ url
1865
+ }, {
1866
+ cache: true,
1867
+ cacheTTL: 30 * 60 * 1000 // 30 minutes cache for link metadata
1868
+ });
1663
1869
  } catch (error) {
1664
1870
  throw this.handleError(error);
1665
1871
  }