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