@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.
- 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 +538 -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 +536 -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 +88 -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 +466 -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
|
/**
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
382
|
-
|
|
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
|
-
|
|
413
|
-
|
|
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.
|
|
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 ||
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
565
|
-
|
|
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
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
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
|
-
|
|
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
|
-
|
|
599
|
-
|
|
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.
|
|
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.
|
|
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}
|
|
641
|
-
const
|
|
642
|
-
|
|
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
|
-
|
|
654
|
-
|
|
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
|
-
|
|
666
|
-
|
|
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
|
-
|
|
682
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
688
|
+
return await this.makeRequest('POST', '/api/auth/totp/enroll/verify', {
|
|
709
689
|
sessionId,
|
|
710
690
|
code
|
|
711
691
|
}, {
|
|
712
|
-
|
|
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
|
-
|
|
700
|
+
return await this.makeRequest('POST', '/api/auth/totp/disable', {
|
|
724
701
|
sessionId,
|
|
725
702
|
code
|
|
726
703
|
}, {
|
|
727
|
-
|
|
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
|
|
748
|
-
|
|
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
|
-
|
|
760
|
-
|
|
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
|
-
|
|
770
|
-
|
|
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
|
-
|
|
782
|
-
|
|
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
|
-
|
|
792
|
-
|
|
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
|
-
|
|
804
|
-
|
|
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
|
-
|
|
816
|
-
|
|
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
|
-
|
|
828
|
-
|
|
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
|
-
|
|
840
|
-
|
|
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
|
|
853
|
-
|
|
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
|
|
866
|
-
|
|
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
|
-
|
|
878
|
-
|
|
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.
|
|
888
|
-
|
|
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
|
-
|
|
900
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
949
|
-
|
|
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
|
-
|
|
961
|
-
|
|
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
|
-
|
|
973
|
-
|
|
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
|
-
|
|
989
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1016
|
-
|
|
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 =
|
|
1028
|
-
if (limit) params.
|
|
1029
|
-
if (offset) params.
|
|
1030
|
-
|
|
1031
|
-
|
|
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
|
-
|
|
1043
|
-
|
|
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
|
-
|
|
1055
|
-
|
|
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
|
-
|
|
1072
|
-
|
|
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.
|
|
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
|
|
1114
|
-
if (limit)
|
|
1115
|
-
if (offset)
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
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
|
|
1132
|
-
|
|
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
|
|
1146
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
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
|
-
|
|
1284
|
-
|
|
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
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
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
|
-
|
|
1314
|
-
|
|
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 =
|
|
1326
|
-
if (variant) params.
|
|
1327
|
-
if (expiresIn) params.
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
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
|
-
|
|
1343
|
-
|
|
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 ?
|
|
1355
|
-
|
|
1356
|
-
|
|
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
|
-
|
|
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.
|
|
1441
|
-
|
|
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.
|
|
1453
|
-
|
|
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.
|
|
1465
|
-
|
|
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.
|
|
1477
|
-
|
|
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
|
-
|
|
1489
|
-
|
|
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
|
-
|
|
1501
|
-
|
|
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
|
-
|
|
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 ?
|
|
1532
|
-
|
|
1533
|
-
|
|
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.
|
|
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 =
|
|
1563
|
-
if (startDate) params.
|
|
1564
|
-
if (endDate) params.
|
|
1565
|
-
|
|
1566
|
-
|
|
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
|
-
|
|
1582
|
-
|
|
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
|
-
|
|
1594
|
-
|
|
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.
|
|
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
|
-
|
|
1617
|
-
|
|
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
|
|
1632
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1662
|
-
|
|
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
|
}
|