@oxyhq/services 5.9.2 → 5.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/README.md +1 -33
  2. package/lib/commonjs/core/OxyServices.js +159 -0
  3. package/lib/commonjs/core/OxyServices.js.map +1 -0
  4. package/lib/commonjs/core/OxyServicesMain.js +51 -0
  5. package/lib/commonjs/core/OxyServicesMain.js.map +1 -0
  6. package/lib/commonjs/core/analytics/AnalyticsService.js +67 -0
  7. package/lib/commonjs/core/analytics/AnalyticsService.js.map +1 -0
  8. package/lib/commonjs/core/auth/AuthService.js +526 -0
  9. package/lib/commonjs/core/auth/AuthService.js.map +1 -0
  10. package/lib/commonjs/core/devices/DeviceService.js +61 -0
  11. package/lib/commonjs/core/devices/DeviceService.js.map +1 -0
  12. package/lib/commonjs/core/files/FileService.js +176 -0
  13. package/lib/commonjs/core/files/FileService.js.map +1 -0
  14. package/lib/commonjs/core/index.js +103 -1701
  15. package/lib/commonjs/core/index.js.map +1 -1
  16. package/lib/commonjs/core/karma/KarmaService.js +100 -0
  17. package/lib/commonjs/core/karma/KarmaService.js.map +1 -0
  18. package/lib/commonjs/core/locations/LocationService.js +131 -0
  19. package/lib/commonjs/core/locations/LocationService.js.map +1 -0
  20. package/lib/commonjs/core/payments/PaymentService.js +124 -0
  21. package/lib/commonjs/core/payments/PaymentService.js.map +1 -0
  22. package/lib/commonjs/core/users/UserService.js +234 -0
  23. package/lib/commonjs/core/users/UserService.js.map +1 -0
  24. package/lib/commonjs/index.js +164 -3
  25. package/lib/commonjs/index.js.map +1 -1
  26. package/lib/commonjs/models/session.js +2 -0
  27. package/lib/commonjs/{types/middleware.js.map → models/session.js.map} +1 -1
  28. package/lib/commonjs/ui/context/OxyContext.js +28 -24
  29. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  30. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +2 -2
  31. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  32. package/lib/commonjs/ui/screens/FileManagementScreen.js +12 -12
  33. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  34. package/lib/commonjs/ui/screens/ProfileScreen.js +2 -2
  35. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  36. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  37. package/lib/commonjs/ui/screens/SignInScreen.js +1 -1
  38. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  39. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +1 -1
  40. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  41. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +1 -1
  42. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  43. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +1 -1
  44. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  45. package/lib/commonjs/ui/stores/followStore.js +4 -4
  46. package/lib/commonjs/ui/stores/followStore.js.map +1 -1
  47. package/lib/commonjs/utils/apiUtils.js +93 -0
  48. package/lib/commonjs/utils/apiUtils.js.map +1 -0
  49. package/lib/commonjs/utils/asyncUtils.js +219 -0
  50. package/lib/commonjs/utils/asyncUtils.js.map +1 -0
  51. package/lib/commonjs/utils/errorUtils.js +148 -0
  52. package/lib/commonjs/utils/errorUtils.js.map +1 -0
  53. package/lib/commonjs/utils/hookUtils.js +399 -0
  54. package/lib/commonjs/utils/hookUtils.js.map +1 -0
  55. package/lib/commonjs/utils/loggerUtils.js +160 -0
  56. package/lib/commonjs/utils/loggerUtils.js.map +1 -0
  57. package/lib/commonjs/utils/validationUtils.js +174 -0
  58. package/lib/commonjs/utils/validationUtils.js.map +1 -0
  59. package/lib/module/core/OxyServices.js +153 -0
  60. package/lib/module/core/OxyServices.js.map +1 -0
  61. package/lib/module/core/OxyServicesMain.js +47 -0
  62. package/lib/module/core/OxyServicesMain.js.map +1 -0
  63. package/lib/module/core/analytics/AnalyticsService.js +62 -0
  64. package/lib/module/core/analytics/AnalyticsService.js.map +1 -0
  65. package/lib/module/core/auth/AuthService.js +521 -0
  66. package/lib/module/core/auth/AuthService.js.map +1 -0
  67. package/lib/module/core/devices/DeviceService.js +57 -0
  68. package/lib/module/core/devices/DeviceService.js.map +1 -0
  69. package/lib/module/core/files/FileService.js +171 -0
  70. package/lib/module/core/files/FileService.js.map +1 -0
  71. package/lib/module/core/index.js +25 -1690
  72. package/lib/module/core/index.js.map +1 -1
  73. package/lib/module/core/karma/KarmaService.js +95 -0
  74. package/lib/module/core/karma/KarmaService.js.map +1 -0
  75. package/lib/module/core/locations/LocationService.js +127 -0
  76. package/lib/module/core/locations/LocationService.js.map +1 -0
  77. package/lib/module/core/payments/PaymentService.js +119 -0
  78. package/lib/module/core/payments/PaymentService.js.map +1 -0
  79. package/lib/module/core/users/UserService.js +230 -0
  80. package/lib/module/core/users/UserService.js.map +1 -0
  81. package/lib/module/index.js +8 -4
  82. package/lib/module/index.js.map +1 -1
  83. package/lib/module/models/session.js +2 -0
  84. package/lib/module/{types/middleware.js.map → models/session.js.map} +1 -1
  85. package/lib/module/ui/context/OxyContext.js +28 -24
  86. package/lib/module/ui/context/OxyContext.js.map +1 -1
  87. package/lib/module/ui/screens/AccountSwitcherScreen.js +2 -2
  88. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  89. package/lib/module/ui/screens/FileManagementScreen.js +12 -12
  90. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  91. package/lib/module/ui/screens/ProfileScreen.js +2 -2
  92. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  93. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  94. package/lib/module/ui/screens/SignInScreen.js +1 -1
  95. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  96. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +1 -1
  97. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  98. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +1 -1
  99. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  100. package/lib/module/ui/screens/karma/KarmaRulesScreen.js +1 -1
  101. package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  102. package/lib/module/ui/stores/followStore.js +4 -4
  103. package/lib/module/ui/stores/followStore.js.map +1 -1
  104. package/lib/module/utils/apiUtils.js +85 -0
  105. package/lib/module/utils/apiUtils.js.map +1 -0
  106. package/lib/module/utils/asyncUtils.js +202 -0
  107. package/lib/module/utils/asyncUtils.js.map +1 -0
  108. package/lib/module/utils/errorUtils.js +139 -0
  109. package/lib/module/utils/errorUtils.js.map +1 -0
  110. package/lib/module/utils/hookUtils.js +381 -0
  111. package/lib/module/utils/hookUtils.js.map +1 -0
  112. package/lib/module/utils/loggerUtils.js +149 -0
  113. package/lib/module/utils/loggerUtils.js.map +1 -0
  114. package/lib/module/utils/validationUtils.js +154 -0
  115. package/lib/module/utils/validationUtils.js.map +1 -0
  116. package/lib/typescript/core/OxyServices.d.ts +64 -0
  117. package/lib/typescript/core/OxyServices.d.ts.map +1 -0
  118. package/lib/typescript/core/OxyServicesMain.d.ts +33 -0
  119. package/lib/typescript/core/OxyServicesMain.d.ts.map +1 -0
  120. package/lib/typescript/core/analytics/AnalyticsService.d.ts +26 -0
  121. package/lib/typescript/core/analytics/AnalyticsService.d.ts.map +1 -0
  122. package/lib/typescript/core/auth/AuthService.d.ts +165 -0
  123. package/lib/typescript/core/auth/AuthService.d.ts.map +1 -0
  124. package/lib/typescript/core/devices/DeviceService.d.ts +20 -0
  125. package/lib/typescript/core/devices/DeviceService.d.ts.map +1 -0
  126. package/lib/typescript/core/files/FileService.d.ts +59 -0
  127. package/lib/typescript/core/files/FileService.d.ts.map +1 -0
  128. package/lib/typescript/core/index.d.ts +19 -656
  129. package/lib/typescript/core/index.d.ts.map +1 -1
  130. package/lib/typescript/core/karma/KarmaService.d.ts +50 -0
  131. package/lib/typescript/core/karma/KarmaService.d.ts.map +1 -0
  132. package/lib/typescript/core/locations/LocationService.d.ts +39 -0
  133. package/lib/typescript/core/locations/LocationService.d.ts.map +1 -0
  134. package/lib/typescript/core/payments/PaymentService.d.ts +50 -0
  135. package/lib/typescript/core/payments/PaymentService.d.ts.map +1 -0
  136. package/lib/typescript/core/users/UserService.d.ts +111 -0
  137. package/lib/typescript/core/users/UserService.d.ts.map +1 -0
  138. package/lib/typescript/index.d.ts +7 -3
  139. package/lib/typescript/index.d.ts.map +1 -1
  140. package/lib/typescript/models/{secureSession.d.ts → session.d.ts} +4 -4
  141. package/lib/typescript/models/session.d.ts.map +1 -0
  142. package/lib/typescript/ui/context/OxyContext.d.ts +2 -2
  143. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  144. package/lib/typescript/utils/apiUtils.d.ts +61 -0
  145. package/lib/typescript/utils/apiUtils.d.ts.map +1 -0
  146. package/lib/typescript/utils/asyncUtils.d.ts +64 -0
  147. package/lib/typescript/utils/asyncUtils.d.ts.map +1 -0
  148. package/lib/typescript/utils/errorUtils.d.ts +45 -0
  149. package/lib/typescript/utils/errorUtils.d.ts.map +1 -0
  150. package/lib/typescript/utils/hookUtils.d.ts +102 -0
  151. package/lib/typescript/utils/hookUtils.d.ts.map +1 -0
  152. package/lib/typescript/utils/loggerUtils.d.ts +49 -0
  153. package/lib/typescript/utils/loggerUtils.d.ts.map +1 -0
  154. package/lib/typescript/utils/validationUtils.d.ts +80 -0
  155. package/lib/typescript/utils/validationUtils.d.ts.map +1 -0
  156. package/package.json +2 -8
  157. package/src/core/OxyServices.ts +168 -0
  158. package/src/core/OxyServicesMain.ts +57 -0
  159. package/src/core/analytics/AnalyticsService.ts +64 -0
  160. package/src/core/auth/AuthService.ts +544 -0
  161. package/src/core/devices/DeviceService.ts +55 -0
  162. package/src/core/files/FileService.ts +194 -0
  163. package/src/core/index.ts +27 -1765
  164. package/src/core/karma/KarmaService.ts +104 -0
  165. package/src/core/locations/LocationService.ts +141 -0
  166. package/src/core/payments/PaymentService.ts +133 -0
  167. package/src/core/users/UserService.ts +241 -0
  168. package/src/index.ts +29 -8
  169. package/src/models/{secureSession.ts → session.ts} +5 -5
  170. package/src/ui/context/OxyContext.tsx +34 -30
  171. package/src/ui/screens/AccountSwitcherScreen.tsx +4 -4
  172. package/src/ui/screens/FileManagementScreen.tsx +12 -12
  173. package/src/ui/screens/ProfileScreen.tsx +3 -3
  174. package/src/ui/screens/SessionManagementScreen.tsx +2 -2
  175. package/src/ui/screens/SignInScreen.tsx +1 -1
  176. package/src/ui/screens/karma/KarmaCenterScreen.tsx +2 -2
  177. package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +3 -3
  178. package/src/ui/screens/karma/KarmaRulesScreen.tsx +3 -3
  179. package/src/ui/stores/followStore.ts +4 -4
  180. package/src/utils/apiUtils.ts +102 -0
  181. package/src/utils/asyncUtils.ts +265 -0
  182. package/src/utils/errorUtils.ts +172 -0
  183. package/src/utils/hookUtils.ts +397 -0
  184. package/src/utils/loggerUtils.ts +153 -0
  185. package/src/utils/validationUtils.ts +158 -0
  186. package/lib/commonjs/middleware.js +0 -17
  187. package/lib/commonjs/middleware.js.map +0 -1
  188. package/lib/commonjs/models/secureSession.js +0 -2
  189. package/lib/commonjs/models/secureSession.js.map +0 -1
  190. package/lib/commonjs/types/middleware.js +0 -6
  191. package/lib/module/middleware.js +0 -12
  192. package/lib/module/middleware.js.map +0 -1
  193. package/lib/module/models/secureSession.js +0 -2
  194. package/lib/module/models/secureSession.js.map +0 -1
  195. package/lib/module/types/middleware.js +0 -4
  196. package/lib/typescript/middleware.d.ts +0 -9
  197. package/lib/typescript/middleware.d.ts.map +0 -1
  198. package/lib/typescript/models/secureSession.d.ts.map +0 -1
  199. package/lib/typescript/types/middleware.d.ts +0 -19
  200. package/lib/typescript/types/middleware.d.ts.map +0 -1
  201. package/src/middleware.ts +0 -11
  202. package/src/types/middleware.ts +0 -20
@@ -1,1705 +1,40 @@
1
1
  "use strict";
2
2
 
3
- import axios from 'axios';
4
- import { jwtDecode } from 'jwt-decode';
5
-
6
- // Remove all FormData, form-data, and polyfill logic. Delete uploadFile and uploadFiles methods. Add a comment to use the new raw upload approach instead.
7
-
8
- // Import secure session types
9
-
10
- /**
11
- * Default cloud URL for Oxy services, cloud is where the user files are. (e.g. images, videos, etc.). Not the API.
12
- */
13
- export const OXY_CLOUD_URL = 'https://cloud.oxy.so';
14
-
15
- // Export device management utilities
16
- export { DeviceManager } from '../utils/deviceManager';
17
3
  /**
18
- * OxyServices - Client library for interacting with the Oxy API
4
+ * OxyServices Core Module - Modular Architecture
19
5
  *
20
- * Note: For authentication status in UI components, use `isAuthenticated` from useOxy() context
21
- * instead of checking token status directly on this service.
6
+ * This module exports the main OxyServices class and all individual service modules
7
+ * for a clean, maintainable, and focused architecture.
22
8
  */
23
- export class OxyServices {
24
- accessToken = null;
25
- refreshToken = null;
26
-
27
- /**
28
- * Creates a new instance of the OxyServices client
29
- * @param config - Configuration for the client
30
- */
31
- constructor(config) {
32
- this.client = axios.create({
33
- baseURL: config.baseURL,
34
- timeout: 10000 // 10 second timeout
35
- });
36
-
37
- // Interceptor for adding auth header and handling token refresh
38
- this.client.interceptors.request.use(async req => {
39
- if (!this.accessToken) {
40
- return req;
41
- }
42
-
43
- // Check if token is expired and refresh if needed
44
- try {
45
- const decoded = jwtDecode(this.accessToken);
46
- const currentTime = Math.floor(Date.now() / 1000);
47
-
48
- // If token expires in less than 60 seconds, refresh it
49
- if (decoded.exp - currentTime < 60) {
50
- // For session-based tokens, get a new token from the session
51
- if (decoded.sessionId) {
52
- try {
53
- const res = await this.client.get(`/secure-session/token/${decoded.sessionId}`);
54
- this.accessToken = res.data.accessToken;
55
- } catch (refreshError) {
56
- // If refresh fails, clear tokens
57
- this.clearTokens();
58
- }
59
- }
60
- }
61
- } catch (error) {
62
- // If token can't be decoded, continue with request and let server handle it
63
- console.warn('Error decoding JWT token', error);
64
- }
65
- req.headers = req.headers || {};
66
- req.headers.Authorization = `Bearer ${this.accessToken}`;
67
- return req;
68
- });
69
-
70
- // Response interceptor for handling errors
71
- this.client.interceptors.response.use(response => response, async error => {
72
- const originalRequest = error.config;
73
- // If the error is due to an expired token and we haven't tried refreshing yet
74
- if (error.response?.status === 401 && this.accessToken && originalRequest && !originalRequest.headers?.['X-Retry-After-Refresh']) {
75
- try {
76
- // Check if token is session-based and try to refresh
77
- const decoded = jwtDecode(this.accessToken);
78
- if (decoded.sessionId) {
79
- const res = await this.client.get(`/secure-session/token/${decoded.sessionId}`);
80
- this.accessToken = res.data.accessToken;
81
-
82
- // Retry the original request with new token
83
- const newRequest = {
84
- ...originalRequest
85
- };
86
- if (newRequest.headers) {
87
- newRequest.headers.Authorization = `Bearer ${this.accessToken}`;
88
- newRequest.headers['X-Retry-After-Refresh'] = 'true';
89
- }
90
- return this.client(newRequest);
91
- }
92
- } catch (refreshError) {
93
- // If refresh fails, force user to login again
94
- this.clearTokens();
95
- return Promise.reject(refreshError);
96
- }
97
- }
98
-
99
- // Format error response
100
- const apiError = {
101
- message: error.response?.data?.error || error.response?.data?.message || 'An unknown error occurred',
102
- code: error.response?.data?.code || 'UNKNOWN_ERROR',
103
- status: error.response?.status || 500,
104
- details: error.response?.data
105
- };
106
-
107
- // If the error is an invalid session, clear tokens
108
- if (apiError.code === 'INVALID_SESSION' || apiError.message === 'Invalid session') {
109
- this.clearTokens();
110
- }
111
- return Promise.reject(apiError);
112
- });
113
- }
114
-
115
- /**
116
- * Gets the base URL configured for this OxyServices instance
117
- * @returns The base URL
118
- */
119
- getBaseURL() {
120
- return this.client.defaults.baseURL || '';
121
- }
122
-
123
- /**
124
- * Set authentication tokens manually
125
- * @param accessToken - The access token
126
- * @param refreshToken - The refresh token (optional for session-based auth)
127
- */
128
- setTokens(accessToken, refreshToken = '') {
129
- this.accessToken = accessToken;
130
- this.refreshToken = refreshToken;
131
- }
132
-
133
- /**
134
- * Clear stored authentication tokens
135
- */
136
- clearTokens() {
137
- this.accessToken = null;
138
- this.refreshToken = null;
139
- }
140
-
141
- /**
142
- * Get the current user ID from the stored token
143
- * @returns User ID or null if not authenticated
144
- */
145
- getCurrentUserId() {
146
- if (!this.accessToken) return null;
147
- try {
148
- const decoded = jwtDecode(this.accessToken);
149
- return decoded.userId || decoded.id || null;
150
- } catch (error) {
151
- return null;
152
- }
153
- }
154
-
155
- /**
156
- * Internal method to check if we have an access token
157
- * @private
158
- * @returns Boolean indicating if access token exists
159
- * @internal - Use `isAuthenticated` from useOxy() context in UI components instead
160
- */
161
- hasAccessToken() {
162
- return this.accessToken !== null;
163
- }
164
-
165
- /**
166
- * Validate current access token
167
- * @returns Boolean indicating if the token is valid
168
- */
169
- async validate() {
170
- try {
171
- // Check if token contains sessionId (new session-based system)
172
- if (this.accessToken) {
173
- try {
174
- const decoded = jwtDecode(this.accessToken);
175
- if (decoded.sessionId) {
176
- // Use session-based validation
177
- const res = await this.client.get(`/secure-session/validate/${decoded.sessionId}`);
178
- return res.data.valid;
179
- }
180
- } catch (decodeError) {
181
- // If token can't be decoded, fall back to old validation
182
- console.warn('Error decoding JWT token for session validation:', decodeError);
183
- }
184
- }
185
-
186
- // Fall back to old validation method
187
- const res = await this.client.get('/auth/validate');
188
- return res.data.valid;
189
- } catch (error) {
190
- return false;
191
- }
192
- }
193
-
194
- /* Session Management Methods */
195
-
196
- /**
197
- * Get device sessions for a specific session ID
198
- * @param sessionId - The session ID to get device sessions for
199
- * @param deviceId - Optional device ID filter
200
- * @returns Array of device sessions
201
- */
202
- async getDeviceSessions(sessionId, deviceId) {
203
- try {
204
- const params = deviceId ? {
205
- deviceId
206
- } : {};
207
- const res = await this.client.get(`/secure-session/device/sessions/${sessionId}`, {
208
- params
209
- });
210
-
211
- // Map backend response to frontend interface
212
- return (res.data.sessions || []).map(session => ({
213
- sessionId: session.sessionId,
214
- deviceId: res.data.deviceId || '',
215
- deviceName: session.deviceInfo?.deviceName || 'Unknown Device',
216
- isActive: true,
217
- // All returned sessions are active
218
- lastActive: session.lastActive,
219
- expiresAt: session.expiresAt || new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
220
- isCurrent: session.sessionId === sessionId,
221
- user: session.user,
222
- createdAt: session.createdAt
223
- }));
224
- } catch (error) {
225
- throw this.handleError(error);
226
- }
227
- }
228
-
229
- /**
230
- * Logout all device sessions for a specific device
231
- * @param sessionId - The session ID
232
- * @param deviceId - Optional device ID (uses current session's device if not provided)
233
- * @param excludeCurrent - Whether to exclude the current session from logout
234
- * @returns Logout response
235
- */
236
- async logoutAllDeviceSessions(sessionId, deviceId, excludeCurrent) {
237
- try {
238
- const data = {};
239
- if (deviceId) data.deviceId = deviceId;
240
- if (excludeCurrent !== undefined) data.excludeCurrent = excludeCurrent;
241
- const res = await this.client.post(`/secure-session/device/logout-all/${sessionId}`, data);
242
- return res.data;
243
- } catch (error) {
244
- throw this.handleError(error);
245
- }
246
- }
247
-
248
- /**
249
- * Update device name for a session
250
- * @param sessionId - The session ID
251
- * @param deviceName - The new device name
252
- * @returns Update response
253
- */
254
- async updateDeviceName(sessionId, deviceName) {
255
- try {
256
- const res = await this.client.put(`/secure-session/device/name/${sessionId}`, {
257
- deviceName
258
- });
259
- return res.data;
260
- } catch (error) {
261
- throw this.handleError(error);
262
- }
263
- }
264
-
265
- /* Profile Methods */
266
-
267
- /**
268
- * Fetch profile by username
269
- * @param username - The username to look up
270
- * @returns User profile data
271
- */
272
- async getProfileByUsername(username) {
273
- try {
274
- const res = await this.client.get(`/profiles/username/${username}`);
275
- return res.data;
276
- } catch (error) {
277
- throw this.handleError(error);
278
- }
279
- }
280
-
281
- /**
282
- * Search profiles
283
- * @param query - Search query string
284
- * @param limit - Maximum number of results to return
285
- * @param offset - Number of results to skip for pagination
286
- * @returns Array of matching user profiles
287
- */
288
- async searchProfiles(query, limit, offset) {
289
- try {
290
- const params = {
291
- query
292
- };
293
- if (limit !== undefined) params.limit = limit;
294
- if (offset !== undefined) params.offset = offset;
295
- const res = await this.client.get('/profiles/search', {
296
- params
297
- });
298
- return res.data;
299
- } catch (error) {
300
- throw this.handleError(error);
301
- }
302
- }
303
-
304
- /**
305
- * Get recommended profiles for the authenticated user
306
- * @returns Array of recommended profiles
307
- */
308
- async getProfileRecommendations() {
309
- try {
310
- const res = await this.client.get('/profiles/recommendations');
311
- return res.data;
312
- } catch (error) {
313
- throw this.handleError(error);
314
- }
315
- }
316
-
317
- /* User Methods */
318
-
319
- /**
320
- * Get general user by ID
321
- * @param userId - The user ID to look up
322
- * @returns User data
323
- */
324
- async getUserById(userId) {
325
- try {
326
- const res = await this.client.get(`/users/${userId}`);
327
- return res.data;
328
- } catch (error) {
329
- throw this.handleError(error);
330
- }
331
- }
332
-
333
- /**
334
- * Get the currently authenticated user's profile
335
- * @returns User data for the current user
336
- */
337
- async getCurrentUser() {
338
- try {
339
- console.log('OxyServices: Fetching current user...');
340
- const res = await this.client.get('/users/me');
341
- console.log('OxyServices: Current user response:', {
342
- hasUser: !!res.data,
343
- userLinksMetadata: res.data?.linksMetadata,
344
- userLinks: res.data?.links,
345
- userWebsite: res.data?.website
346
- });
347
- return res.data;
348
- } catch (error) {
349
- console.error('OxyServices: Error fetching current user:', error);
350
- throw this.handleError(error);
351
- }
352
- }
353
-
354
- /**
355
- * Update the authenticated user's profile
356
- * @param updates - Object containing fields to update
357
- * @returns Updated user data
358
- */
359
- async updateProfile(updates) {
360
- try {
361
- console.log('OxyServices: Updating profile with:', updates);
362
- const res = await this.client.put('/users/me', updates);
363
- console.log('OxyServices: Profile update response:', res.data);
364
- return res.data;
365
- } catch (error) {
366
- console.error('OxyServices: Error updating profile:', error);
367
- throw this.handleError(error);
368
- }
369
- }
370
-
371
- /**
372
- * Update user profile (requires auth)
373
- * @param userId - User ID to update (must match authenticated user or have admin rights)
374
- * @param updates - Object containing fields to update
375
- * @returns Updated user data
376
- */
377
- async updateUser(userId, updates) {
378
- try {
379
- const res = await this.client.put(`/users/${userId}`, updates);
380
- return res.data;
381
- } catch (error) {
382
- throw this.handleError(error);
383
- }
384
- }
385
-
386
- /**
387
- * Follow a user
388
- * @param userId - User ID to follow
389
- * @returns Status of the follow operation
390
- */
391
- async followUser(userId) {
392
- try {
393
- const res = await this.client.post(`/users/${userId}/follow`);
394
- return res.data;
395
- } catch (error) {
396
- throw this.handleError(error);
397
- }
398
- }
399
-
400
- /**
401
- * Unfollow a user
402
- * @param userId - User ID to unfollow
403
- * @returns Status of the unfollow operation
404
- */
405
- async unfollowUser(userId) {
406
- try {
407
- const res = await this.client.delete(`/users/${userId}/follow`);
408
- return res.data;
409
- } catch (error) {
410
- throw this.handleError(error);
411
- }
412
- }
413
-
414
- /**
415
- * Get follow status for a user
416
- * @param userId - User ID to check follow status for
417
- * @returns Whether the current user is following the specified user
418
- */
419
- async getFollowStatus(userId) {
420
- try {
421
- const res = await this.client.get(`/users/${userId}/following-status`);
422
- return res.data;
423
- } catch (error) {
424
- throw this.handleError(error);
425
- }
426
- }
427
-
428
- /**
429
- * Get all followers of a user
430
- * @param userId - User ID to get followers for
431
- * @param limit - Maximum number of followers to return
432
- * @param offset - Number of followers to skip for pagination
433
- * @returns Array of users who follow the specified user and pagination info
434
- */
435
- async getUserFollowers(userId, limit, offset) {
436
- try {
437
- const params = {};
438
- if (limit !== undefined) params.limit = limit;
439
- if (offset !== undefined) params.offset = offset;
440
- const res = await this.client.get(`/users/${userId}/followers`, {
441
- params
442
- });
443
- return res.data;
444
- } catch (error) {
445
- throw this.handleError(error);
446
- }
447
- }
448
-
449
- /**
450
- * Get all users that a user is following
451
- * @param userId - User ID to get following list for
452
- * @param limit - Maximum number of users to return
453
- * @param offset - Number of users to skip for pagination
454
- * @returns Array of users the specified user follows and pagination info
455
- */
456
- async getUserFollowing(userId, limit, offset) {
457
- try {
458
- const params = {};
459
- if (limit !== undefined) params.limit = limit;
460
- if (offset !== undefined) params.offset = offset;
461
- const res = await this.client.get(`/users/${userId}/following`, {
462
- params
463
- });
464
- return res.data;
465
- } catch (error) {
466
- throw this.handleError(error);
467
- }
468
- }
469
-
470
- /* Notification Methods */
471
-
472
- /**
473
- * Fetch all notifications for the authenticated user
474
- * @returns Array of notifications
475
- */
476
- async getNotifications() {
477
- try {
478
- const res = await this.client.get('/notifications');
479
- return res.data;
480
- } catch (error) {
481
- throw this.handleError(error);
482
- }
483
- }
484
-
485
- /**
486
- * Get count of unread notifications
487
- * @returns Number of unread notifications
488
- */
489
- async getUnreadCount() {
490
- try {
491
- const res = await this.client.get('/notifications/unread-count');
492
- return res.data;
493
- } catch (error) {
494
- throw this.handleError(error);
495
- }
496
- }
497
-
498
- /**
499
- * Create a new notification (admin use)
500
- * @param data - Notification data
501
- * @returns Created notification
502
- */
503
- async createNotification(data) {
504
- try {
505
- const res = await this.client.post('/notifications', data);
506
- return res.data;
507
- } catch (error) {
508
- throw this.handleError(error);
509
- }
510
- }
511
-
512
- /**
513
- * Mark a single notification as read
514
- * @param notificationId - ID of notification to mark as read
515
- */
516
- async markNotificationAsRead(notificationId) {
517
- try {
518
- await this.client.put(`/notifications/${notificationId}/read`);
519
- } catch (error) {
520
- throw this.handleError(error);
521
- }
522
- }
523
-
524
- /**
525
- * Mark all notifications as read
526
- */
527
- async markAllNotificationsAsRead() {
528
- try {
529
- await this.client.put('/notifications/read-all');
530
- } catch (error) {
531
- throw this.handleError(error);
532
- }
533
- }
534
-
535
- /**
536
- * Delete a notification
537
- * @param notificationId - ID of notification to delete
538
- */
539
- async deleteNotification(notificationId) {
540
- try {
541
- await this.client.delete(`/notifications/${notificationId}`);
542
- } catch (error) {
543
- throw this.handleError(error);
544
- }
545
- }
546
-
547
- /* Payment Methods */
548
-
549
- /**
550
- * Process a payment
551
- * @param data - Payment data including user ID, plan, and payment method
552
- * @returns Payment result with transaction ID
553
- */
554
- async processPayment(data) {
555
- try {
556
- const res = await this.client.post('/payments/process', data);
557
- return res.data;
558
- } catch (error) {
559
- throw this.handleError(error);
560
- }
561
- }
562
-
563
- /**
564
- * Validate a payment method
565
- * @param paymentMethod - Payment method to validate
566
- * @returns Object indicating if the payment method is valid
567
- */
568
- async validatePaymentMethod(paymentMethod) {
569
- try {
570
- const res = await this.client.post('/payments/validate', {
571
- paymentMethod
572
- });
573
- return res.data;
574
- } catch (error) {
575
- throw this.handleError(error);
576
- }
577
- }
578
-
579
- /**
580
- * Get saved payment methods for a user
581
- * @param userId - User ID to get payment methods for
582
- * @returns Array of payment methods
583
- */
584
- async getPaymentMethods(userId) {
585
- try {
586
- const res = await this.client.get(`/payments/methods/${userId}`);
587
- return res.data;
588
- } catch (error) {
589
- throw this.handleError(error);
590
- }
591
- }
592
-
593
- /* Analytics Methods */
594
-
595
- /**
596
- * Get analytics data
597
- * @param userId - User ID to get analytics for
598
- * @param period - Time period for analytics (e.g., "day", "week", "month")
599
- * @returns Analytics data
600
- */
601
- async getAnalytics(userId, period) {
602
- try {
603
- const params = {
604
- userID: userId
605
- };
606
- if (period) params.period = period;
607
- const res = await this.client.get('/analytics', {
608
- params
609
- });
610
- return res.data;
611
- } catch (error) {
612
- throw this.handleError(error);
613
- }
614
- }
615
-
616
- /**
617
- * Update analytics (internal use)
618
- * @param userId - User ID to update analytics for
619
- * @param type - Type of analytics to update
620
- * @param data - Analytics data to update
621
- * @returns Message indicating success
622
- */
623
- async updateAnalytics(userId, type, data) {
624
- try {
625
- const res = await this.client.post('/analytics/update', {
626
- userID: userId,
627
- type,
628
- data
629
- });
630
- return res.data;
631
- } catch (error) {
632
- throw this.handleError(error);
633
- }
634
- }
635
-
636
- /**
637
- * Get content viewers analytics
638
- * @param userId - User ID to get viewer data for
639
- * @param period - Time period for analytics
640
- * @returns Array of content viewer data
641
- */
642
- async getContentViewers(userId, period) {
643
- try {
644
- const params = {
645
- userID: userId
646
- };
647
- if (period) params.period = period;
648
- const res = await this.client.get('/analytics/viewers', {
649
- params
650
- });
651
- return res.data;
652
- } catch (error) {
653
- throw this.handleError(error);
654
- }
655
- }
656
-
657
- /**
658
- * Get follower analytics details
659
- * @param userId - User ID to get follower data for
660
- * @param period - Time period for follower data
661
- * @returns Follower details
662
- */
663
- async getFollowerDetails(userId, period) {
664
- try {
665
- const params = {
666
- userID: userId
667
- };
668
- if (period) params.period = period;
669
- const res = await this.client.get('/analytics/followers', {
670
- params
671
- });
672
- return res.data;
673
- } catch (error) {
674
- throw this.handleError(error);
675
- }
676
- }
677
-
678
- /* Wallet Methods */
679
-
680
- /**
681
- * Get wallet info
682
- * @param userId - User ID to get wallet for
683
- * @returns Wallet data
684
- */
685
- async getWallet(userId) {
686
- try {
687
- const res = await this.client.get(`/wallet/${userId}`);
688
- return res.data;
689
- } catch (error) {
690
- throw this.handleError(error);
691
- }
692
- }
693
-
694
- /**
695
- * Get transaction history
696
- * @param userId - User ID to get transactions for
697
- * @param limit - Maximum number of transactions to return
698
- * @param offset - Number of transactions to skip for pagination
699
- * @returns Array of transactions and pagination info
700
- */
701
- async getTransactionHistory(userId, limit, offset) {
702
- try {
703
- const params = {};
704
- if (limit !== undefined) params.limit = limit;
705
- if (offset !== undefined) params.offset = offset;
706
- const res = await this.client.get(`/wallet/transactions/${userId}`, {
707
- params
708
- });
709
- return res.data;
710
- } catch (error) {
711
- throw this.handleError(error);
712
- }
713
- }
714
-
715
- /**
716
- * Get a specific transaction
717
- * @param transactionId - ID of transaction to retrieve
718
- * @returns Transaction data
719
- */
720
- async getTransaction(transactionId) {
721
- try {
722
- const res = await this.client.get(`/wallet/transaction/${transactionId}`);
723
- return res.data;
724
- } catch (error) {
725
- throw this.handleError(error);
726
- }
727
- }
728
-
729
- /**
730
- * Transfer funds between users
731
- * @param data - Transfer details including source, destination, and amount
732
- * @returns Transaction response
733
- */
734
- async transferFunds(data) {
735
- try {
736
- const res = await this.client.post('/wallet/transfer', data);
737
- return res.data;
738
- } catch (error) {
739
- throw this.handleError(error);
740
- }
741
- }
742
-
743
- /**
744
- * Process a purchase
745
- * @param data - Purchase details including user, item, and amount
746
- * @returns Transaction response
747
- */
748
- async processPurchase(data) {
749
- try {
750
- const res = await this.client.post('/wallet/purchase', data);
751
- return res.data;
752
- } catch (error) {
753
- throw this.handleError(error);
754
- }
755
- }
756
9
 
757
- /**
758
- * Request a withdrawal
759
- * @param data - Withdrawal details including user, amount, and address
760
- * @returns Transaction response
761
- */
762
- async requestWithdrawal(data) {
763
- try {
764
- const res = await this.client.post('/wallet/withdraw', data);
765
- return res.data;
766
- } catch (error) {
767
- throw this.handleError(error);
768
- }
769
- }
10
+ // Main OxyServices class (backward compatible)
11
+ export { OxyServicesMain as OxyServices } from './OxyServicesMain';
770
12
 
771
- /* Karma Methods */
13
+ // Individual service classes for focused usage
14
+ export { AuthService } from './auth/AuthService';
15
+ export { UserService } from './users/UserService';
16
+ export { PaymentService } from './payments/PaymentService';
17
+ export { KarmaService } from './karma/KarmaService';
18
+ export { FileService } from './files/FileService';
19
+ export { LocationService } from './locations/LocationService';
20
+ export { AnalyticsService } from './analytics/AnalyticsService';
21
+ export { DeviceService } from './devices/DeviceService';
772
22
 
773
- /**
774
- * Get karma leaderboard
775
- * @returns Array of karma leaderboard entries
776
- */
777
- async getKarmaLeaderboard() {
778
- try {
779
- const res = await this.client.get('/karma/leaderboard');
780
- return res.data;
781
- } catch (error) {
782
- throw this.handleError(error);
783
- }
784
- }
23
+ // Base class for custom service extensions
24
+ export { OxyServices as BaseOxyServices } from './OxyServices';
785
25
 
786
- /**
787
- * Get karma rules
788
- * @returns Array of karma rules
789
- */
790
- async getKarmaRules() {
791
- try {
792
- const res = await this.client.get('/karma/rules');
793
- return res.data;
794
- } catch (error) {
795
- throw this.handleError(error);
796
- }
797
- }
798
-
799
- /**
800
- * Get total karma for a user
801
- * @param userId - User ID to get karma for
802
- * @returns Object with total karma points
803
- */
804
- async getUserKarmaTotal(userId) {
805
- try {
806
- const res = await this.client.get(`/karma/${userId}/total`);
807
- return res.data;
808
- } catch (error) {
809
- throw this.handleError(error);
810
- }
811
- }
812
-
813
- /**
814
- * Get karma history for a user
815
- * @param userId - User ID to get karma history for
816
- * @param limit - Maximum number of history entries to return
817
- * @param offset - Number of entries to skip for pagination
818
- * @returns Karma history entries and pagination info
819
- */
820
- async getUserKarmaHistory(userId, limit, offset) {
821
- try {
822
- const params = {};
823
- if (limit !== undefined) params.limit = limit;
824
- if (offset !== undefined) params.offset = offset;
825
- const res = await this.client.get(`/karma/${userId}/history`, {
826
- params
827
- });
828
- return res.data;
829
- } catch (error) {
830
- throw this.handleError(error);
831
- }
832
- }
833
-
834
- /**
835
- * Award karma points to a user
836
- * @param data - Karma award details
837
- * @returns Karma award response
838
- */
839
- async awardKarma(data) {
840
- try {
841
- const res = await this.client.post('/karma/award', data);
842
- return res.data;
843
- } catch (error) {
844
- throw this.handleError(error);
845
- }
846
- }
847
-
848
- /**
849
- * Deduct karma points from a user
850
- * @param data - Karma deduction details
851
- * @returns Karma deduction response
852
- */
853
- async deductKarma(data) {
854
- try {
855
- const res = await this.client.post('/karma/deduct', data);
856
- return res.data;
857
- } catch (error) {
858
- throw this.handleError(error);
859
- }
860
- }
861
-
862
- /**
863
- * Create or update karma rule (admin)
864
- * @param data - Karma rule data
865
- * @returns Created or updated karma rule
866
- */
867
- async createOrUpdateKarmaRule(data) {
868
- try {
869
- const res = await this.client.post('/karma/rules', data);
870
- return res.data;
871
- } catch (error) {
872
- throw this.handleError(error);
873
- }
874
- }
875
-
876
- /* File Management Methods */
877
-
878
- /**
879
- * Upload a file using GridFS
880
- * @param file - The file to upload (File or Blob in browser, Buffer in Node.js)
881
- * @param filename - The name of the file
882
- * @param metadata - Optional metadata to associate with the file
883
- * @returns File metadata including ID and download URL
884
- */
885
- async uploadFile(file,
886
- // Use 'any' to handle Buffer type in cross-platform scenarios
887
- filename, metadata) {
888
- // This method is deprecated. Use uploadFilesRaw instead.
889
- // For now, we'll throw an error as the underlying logic is removed.
890
- throw new Error('uploadFile is deprecated. Use uploadFilesRaw instead.');
891
- }
892
-
893
- /**
894
- * Upload multiple files using GridFS
895
- * @param files - Array of files to upload
896
- * @param filenames - Array of filenames (must match files array length)
897
- * @param metadata - Optional metadata to associate with all files
898
- * @returns Array of file metadata
899
- */
900
- async uploadFiles(files, filenames, metadata) {
901
- // This method is deprecated. Use uploadFilesRaw instead.
902
- // For now, we'll throw an error as the underlying logic is removed.
903
- throw new Error('uploadFiles is deprecated. Use uploadFilesRaw instead.');
904
- }
905
-
906
- /**
907
- * Get file metadata by ID
908
- * @param fileId - ID of the file to retrieve metadata for
909
- * @returns File metadata
910
- */
911
- async getFileMetadata(fileId) {
912
- try {
913
- const res = await this.client.get(`/files/${fileId}/metadata`);
914
- return res.data;
915
- } catch (error) {
916
- throw this.handleError(error);
917
- }
918
- }
919
-
920
- /**
921
- * Update file metadata
922
- * @param fileId - ID of the file to update
923
- * @param updates - Metadata updates to apply
924
- * @returns Updated file metadata
925
- */
926
- async updateFileMetadata(fileId, updates) {
927
- try {
928
- const res = await this.client.put(`/files/${fileId}/metadata`, updates);
929
- return res.data;
930
- } catch (error) {
931
- throw this.handleError(error);
932
- }
933
- }
934
-
935
- /**
936
- * Delete a file by ID
937
- * @param fileId - ID of the file to delete
938
- * @returns Status of the delete operation
939
- */
940
- async deleteFile(fileId) {
941
- try {
942
- console.log('Deleting file with ID:', fileId);
943
- const res = await this.client.delete(`/files/${fileId}`);
944
- console.log('Delete response:', res.data);
945
- return res.data;
946
- } catch (error) {
947
- console.error('Delete file error:', error);
948
- console.error('Error response:', error.response?.data);
949
- console.error('Error status:', error.response?.status);
950
-
951
- // Provide more specific error messages based on status code
952
- if (error.response?.status === 404) {
953
- throw new Error('File not found or already deleted');
954
- } else if (error.response?.status === 403) {
955
- throw new Error('You do not have permission to delete this file');
956
- } else if (error.response?.status === 400) {
957
- throw new Error('Invalid file ID format');
958
- }
959
- throw this.handleError(error);
960
- }
961
- }
962
-
963
- /**
964
- * Get download URL for a file
965
- * @param fileId - ID of the file to get download URL for
966
- * @returns Full URL to download the file
967
- */
968
- getFileDownloadUrl(fileId) {
969
- return `${this.client.defaults.baseURL}/files/${fileId}`;
970
- }
971
-
972
- /**
973
- * Stream a file (useful for playing audio/video without full download)
974
- * @param fileId - ID of the file to stream
975
- * @returns Full URL to stream the file
976
- */
977
- getFileStreamUrl(fileId) {
978
- return `${this.client.defaults.baseURL}/files/${fileId}`;
979
- }
980
-
981
- /**
982
- * List files for a specific user
983
- * @param userId - User ID to list files for
984
- * @param limit - Maximum number of files to return
985
- * @param offset - Number of files to skip for pagination
986
- * @param filters - Optional filters for the file list (e.g., contentType)
987
- * @returns Array of file metadata and pagination info
988
- */
989
- async listUserFiles(userId, limit, offset, filters) {
990
- try {
991
- const params = {};
992
- if (limit !== undefined) params.limit = limit;
993
- if (offset !== undefined) params.offset = offset;
994
- if (filters) Object.assign(params, filters);
995
- const res = await this.client.get(`/files/list/${userId}`, {
996
- params
997
- });
998
-
999
- // Handle backend response format: backend returns FileMetadata[] directly
1000
- // but interface expects { files: FileMetadata[], total: number, hasMore: boolean }
1001
- const rawFiles = Array.isArray(res.data) ? res.data : res.data.files || [];
1002
-
1003
- // Transform GridFS files to match FileMetadata interface (map _id to id)
1004
- const filesArray = rawFiles.map(file => ({
1005
- ...file,
1006
- id: file._id?.toString() || file.id,
1007
- uploadDate: file.uploadDate?.toISOString ? file.uploadDate.toISOString() : file.uploadDate
1008
- }));
1009
- return {
1010
- files: filesArray,
1011
- total: filesArray.length,
1012
- hasMore: false // No pagination in current backend implementation
1013
- };
1014
- } catch (error) {
1015
- throw this.handleError(error);
1016
- }
1017
- }
1018
-
1019
- /**
1020
- * Sign up a new user and create a session
1021
- * @param username - Desired username
1022
- * @param email - User's email address
1023
- * @param password - User's password
1024
- * @returns Object containing the message, token and user data
1025
- */
1026
- async signUp(username, email, password) {
1027
- try {
1028
- // First, create the user account
1029
- const res = await this.client.post('/secure-session/register', {
1030
- username,
1031
- email,
1032
- password
1033
- });
1034
- const {
1035
- message,
1036
- user
1037
- } = res.data;
1038
-
1039
- // Then log them in to create a session
1040
- const loginRes = await this.secureLogin(username, password);
1041
-
1042
- // Get the access token for the session
1043
- const tokenRes = await this.getTokenBySession(loginRes.sessionId);
1044
- return {
1045
- message,
1046
- token: tokenRes.accessToken,
1047
- user: loginRes.user
1048
- };
1049
- } catch (error) {
1050
- throw this.handleError(error);
1051
- }
1052
- }
1053
-
1054
- /**
1055
- * Secure login that creates a device-based session
1056
- * @param username - User's username or email
1057
- * @param password - User's password
1058
- * @param deviceName - Optional device name
1059
- * @param deviceFingerprint - Optional device fingerprint
1060
- * @returns Login response with session data
1061
- */
1062
- async secureLogin(username, password, deviceName, deviceFingerprint) {
1063
- try {
1064
- const payload = {
1065
- username,
1066
- password,
1067
- deviceName
1068
- };
1069
- if (deviceFingerprint) {
1070
- payload.deviceFingerprint = deviceFingerprint;
1071
- }
1072
- const res = await this.client.post('/secure-session/login', payload);
1073
- return res.data;
1074
- } catch (error) {
1075
- throw this.handleError(error);
1076
- }
1077
- }
1078
-
1079
- /**
1080
- * Get full user data by session ID
1081
- * @param sessionId - The session ID
1082
- * @returns Full user data
1083
- */
1084
- async getUserBySession(sessionId) {
1085
- try {
1086
- const res = await this.client.get(`/secure-session/user/${sessionId}`);
1087
- return res.data.user;
1088
- } catch (error) {
1089
- throw this.handleError(error);
1090
- }
1091
- }
1092
-
1093
- /**
1094
- * Get access token by session ID (for API calls)
1095
- * @param sessionId - The session ID
1096
- * @returns Access token and expiry info
1097
- */
1098
- async getTokenBySession(sessionId) {
1099
- try {
1100
- const res = await this.client.get(`/secure-session/token/${sessionId}`);
1101
- // Set the token for subsequent API calls
1102
- this.accessToken = res.data.accessToken;
1103
- return res.data;
1104
- } catch (error) {
1105
- throw this.handleError(error);
1106
- }
1107
- }
1108
-
1109
- /**
1110
- * Get all active sessions for current user
1111
- * @param sessionId - Current session ID
1112
- * @returns Array of user sessions
1113
- */
1114
- async getSessionsBySessionId(sessionId) {
1115
- console.log('getSessionsBySessionId called with sessionId:', sessionId);
1116
- try {
1117
- const res = await this.client.get(`/secure-session/sessions/${sessionId}`);
1118
- console.log('getSessionsBySessionId response:', res.data);
1119
- return res.data.sessions;
1120
- } catch (error) {
1121
- console.error('getSessionsBySessionId error:', error);
1122
- throw this.handleError(error);
1123
- }
1124
- }
1125
-
1126
- /**
1127
- * Logout specific session
1128
- * @param sessionId - Current session ID
1129
- * @param targetSessionId - Optional target session to logout (defaults to current)
1130
- */
1131
- async logoutSecureSession(sessionId, targetSessionId) {
1132
- try {
1133
- await this.client.post(`/secure-session/logout/${sessionId}`, {
1134
- targetSessionId
1135
- });
1136
-
1137
- // If we're logging out the current session, clear the access token
1138
- if (!targetSessionId || targetSessionId === sessionId) {
1139
- this.accessToken = null;
1140
- this.refreshToken = null;
1141
- }
1142
- } catch (error) {
1143
- throw this.handleError(error);
1144
- }
1145
- }
1146
-
1147
- /**
1148
- * Logout all sessions for current user
1149
- * @param sessionId - Current session ID
1150
- */
1151
- async logoutAllSecureSessions(sessionId) {
1152
- console.log('logoutAllSecureSessions called with sessionId:', sessionId);
1153
- console.log('API client defaults:', this.client.defaults);
1154
- try {
1155
- const response = await this.client.post(`/secure-session/logout-all/${sessionId}`);
1156
- console.log('logoutAllSecureSessions response:', response.status, response.data);
1157
-
1158
- // Clear tokens since all sessions are logged out
1159
- this.accessToken = null;
1160
- this.refreshToken = null;
1161
- console.log('Tokens cleared successfully');
1162
- } catch (error) {
1163
- console.error('logoutAllSecureSessions error:', error);
1164
- if (error && typeof error === 'object' && 'response' in error) {
1165
- const axiosError = error;
1166
- console.error('Error response data:', axiosError.response?.data);
1167
- console.error('Error response status:', axiosError.response?.status);
1168
- }
1169
- throw this.handleError(error);
1170
- }
1171
- }
1172
-
1173
- /**
1174
- * Validate session
1175
- * @param sessionId - The session ID to validate
1176
- * @returns Session validation status with user data
1177
- */
1178
- async validateSession(sessionId) {
1179
- try {
1180
- const res = await this.client.get(`/secure-session/validate/${sessionId}`);
1181
- return res.data;
1182
- } catch (error) {
1183
- throw this.handleError(error);
1184
- }
1185
- }
1186
-
1187
- /**
1188
- * Validate session using x-session-id header
1189
- * @param sessionId - The session ID to validate (sent as header)
1190
- * @param deviceFingerprint - Optional device fingerprint for enhanced security
1191
- * @returns Session validation status with user data
1192
- */
1193
- async validateSessionFromHeader(sessionId, deviceFingerprint) {
1194
- try {
1195
- const headers = {
1196
- 'x-session-id': sessionId
1197
- };
1198
- if (deviceFingerprint) {
1199
- headers['x-device-fingerprint'] = deviceFingerprint;
1200
- }
1201
- const res = await this.client.get('/secure-session/validate-header', {
1202
- headers
1203
- });
1204
- return res.data;
1205
- } catch (error) {
1206
- throw this.handleError(error);
1207
- }
1208
- }
1209
-
1210
- /**
1211
- * Validate session using automatic header detection
1212
- * The validateSession endpoint will automatically read from x-session-id header
1213
- * @param sessionId - The session ID to validate (sent as header)
1214
- * @param deviceFingerprint - Optional device fingerprint for enhanced security
1215
- * @returns Session validation status with user data
1216
- */
1217
- async validateSessionAuto(sessionId, deviceFingerprint) {
1218
- try {
1219
- const headers = {
1220
- 'x-session-id': sessionId
1221
- };
1222
- if (deviceFingerprint) {
1223
- headers['x-device-fingerprint'] = deviceFingerprint;
1224
- }
1225
-
1226
- // Call the regular validateSession endpoint which now auto-reads from headers
1227
- // Use 'auto' as placeholder since the controller reads from header
1228
- const res = await this.client.get('/secure-session/validate/auto', {
1229
- headers
1230
- });
1231
- return res.data;
1232
- } catch (error) {
1233
- throw this.handleError(error);
1234
- }
1235
- }
1236
-
1237
- /**
1238
- * Create authentication middleware for Express.js applications
1239
- * This is the recommended way to protect routes in server applications
1240
- * @returns Express middleware function
1241
- */
1242
- createAuthMiddleware() {
1243
- return async (req, res, next) => {
1244
- try {
1245
- const authHeader = req.headers.authorization;
1246
- if (!authHeader?.startsWith('Bearer ')) {
1247
- return res.status(401).json({
1248
- error: 'Authentication required',
1249
- message: 'Invalid or missing authorization header'
1250
- });
1251
- }
1252
- const token = authHeader.split(' ')[1];
1253
-
1254
- // Use the authenticateToken method
1255
- const result = await this.authenticateToken(token);
1256
- if (!result.valid) {
1257
- return res.status(401).json({
1258
- error: 'Invalid token',
1259
- message: result.error || 'The provided authentication token is invalid'
1260
- });
1261
- }
1262
-
1263
- // Set user information on request object
1264
- req.userId = result.userId || undefined;
1265
- req.accessToken = token;
1266
- if (result.user) {
1267
- req.user = result.user;
1268
- } else if (result.userId) {
1269
- req.user = {
1270
- id: result.userId
1271
- };
1272
- }
1273
- next();
1274
- } catch (error) {
1275
- console.error('Auth middleware error:', error);
1276
- return res.status(500).json({
1277
- error: 'Server error',
1278
- message: 'An error occurred while authenticating your request'
1279
- });
1280
- }
1281
- };
1282
- }
1283
-
1284
- /**
1285
- * Helper method for validating tokens without Express middleware
1286
- * Useful for standalone token validation in various contexts
1287
- * @param token - The access token to validate
1288
- * @returns Object with validation result and user information
1289
- */
1290
- async authenticateToken(token) {
1291
- try {
1292
- if (!token) {
1293
- return {
1294
- valid: false,
1295
- error: 'Token is required'
1296
- };
1297
- }
1298
-
1299
- // Check if token contains sessionId (new session-based system)
1300
- try {
1301
- const decoded = jwtDecode(token);
1302
- const userId = decoded.userId || decoded.id;
1303
- if (decoded.sessionId) {
1304
- // Use session-based validation
1305
- const tempOxyServices = new OxyServices({
1306
- baseURL: this.client.defaults.baseURL || ''
1307
- });
1308
- tempOxyServices.setTokens(token, '');
1309
- const validation = await tempOxyServices.validateSession(decoded.sessionId);
1310
- if (validation.valid) {
1311
- return {
1312
- valid: true,
1313
- userId,
1314
- user: validation.user
1315
- };
1316
- } else {
1317
- return {
1318
- valid: false,
1319
- error: 'Invalid or expired session'
1320
- };
1321
- }
1322
- } else {
1323
- // Use old validation method
1324
- const tempOxyServices = new OxyServices({
1325
- baseURL: this.client.defaults.baseURL || ''
1326
- });
1327
- tempOxyServices.setTokens(token, '');
1328
- const isValid = await tempOxyServices.validate();
1329
- if (!isValid) {
1330
- return {
1331
- valid: false,
1332
- error: 'Invalid or expired token'
1333
- };
1334
- }
1335
- if (!userId) {
1336
- return {
1337
- valid: false,
1338
- error: 'Invalid token payload'
1339
- };
1340
- }
1341
-
1342
- // Try to get user profile
1343
- let user;
1344
- try {
1345
- user = await tempOxyServices.getUserById(userId);
1346
- } catch (error) {
1347
- // Continue without full user data
1348
- user = {
1349
- id: userId
1350
- };
1351
- }
1352
- return {
1353
- valid: true,
1354
- userId,
1355
- user
1356
- };
1357
- }
1358
- } catch (decodeError) {
1359
- return {
1360
- valid: false,
1361
- error: 'Invalid token payload'
1362
- };
1363
- }
1364
- } catch (error) {
1365
- return {
1366
- valid: false,
1367
- error: error instanceof Error ? error.message : 'Token validation failed'
1368
- };
1369
- }
1370
- }
1371
-
1372
- /**
1373
- * Centralized error handling
1374
- * @private
1375
- * @param error - Error object from API call
1376
- * @returns Formatted API error
1377
- */
1378
- handleError(error) {
1379
- if (error && error.code && error.status) {
1380
- // Already formatted as ApiError
1381
- return error;
1382
- }
1383
- const apiError = {
1384
- message: error?.message || error?.response?.data?.message || 'Unknown error occurred',
1385
- code: error?.response?.data?.code || 'UNKNOWN_ERROR',
1386
- status: error?.response?.status || 500,
1387
- details: error?.response?.data
1388
- };
1389
- return apiError;
1390
- }
1391
-
1392
- /**
1393
- * Check if a username is available
1394
- * @param username - The username to check
1395
- * @returns Promise with availability status
1396
- */
1397
- async checkUsernameAvailability(username) {
1398
- try {
1399
- const res = await this.client.get(`/auth/check-username/${username}`);
1400
- return res.data;
1401
- } catch (error) {
1402
- // If the endpoint doesn't exist, fall back to basic validation
1403
- if (error.response?.status === 404) {
1404
- console.warn('Username validation endpoint not found, using fallback validation');
1405
- return {
1406
- available: true,
1407
- message: 'Username validation not available'
1408
- };
1409
- }
1410
-
1411
- // If it's a validation error (400), return the error message
1412
- if (error.response?.status === 400) {
1413
- return error.response.data;
1414
- }
1415
-
1416
- // For other errors, log and return a fallback
1417
- console.error('Username validation error:', error);
1418
- return {
1419
- available: true,
1420
- message: 'Unable to validate username'
1421
- };
1422
- }
1423
- }
1424
-
1425
- /**
1426
- * Check if an email is available
1427
- * @param email - The email to check
1428
- * @returns Promise with availability status
1429
- */
1430
- async checkEmailAvailability(email) {
1431
- try {
1432
- const res = await this.client.post('/auth/check-email', {
1433
- email
1434
- });
1435
- return res.data;
1436
- } catch (error) {
1437
- // If the endpoint doesn't exist, fall back to basic validation
1438
- if (error.response?.status === 404) {
1439
- console.warn('Email validation endpoint not found, using fallback validation');
1440
- return {
1441
- available: true,
1442
- message: 'Email validation not available'
1443
- };
1444
- }
1445
-
1446
- // If it's a validation error (400), return the error message
1447
- if (error.response?.status === 400) {
1448
- return error.response.data;
1449
- }
1450
-
1451
- // For other errors, log and return a fallback
1452
- console.error('Email validation error:', error);
1453
- return {
1454
- available: true,
1455
- message: 'Unable to validate email'
1456
- };
1457
- }
1458
- }
1459
-
1460
- /**
1461
- * Get user profile by username
1462
- * @param username - The username to look up
1463
- * @returns Promise with user profile
1464
- */
1465
- async getUserProfileByUsername(username) {
1466
- try {
1467
- const res = await this.client.get(`/profiles/username/${username}`);
1468
- return res.data;
1469
- } catch (error) {
1470
- throw this.handleError(error);
1471
- }
1472
- }
1473
-
1474
- /**
1475
- * Health check endpoint to verify API connectivity
1476
- * @returns Health status and basic server info
1477
- */
1478
- async healthCheck() {
1479
- try {
1480
- const res = await this.client.get('/');
1481
- return res.data;
1482
- } catch (error) {
1483
- throw this.handleError(error);
1484
- }
1485
- }
1486
-
1487
- /**
1488
- * Download file content using authenticated request
1489
- * @param fileId - The file ID to download
1490
- * @returns Response object for further processing
1491
- */
1492
- async downloadFileContent(fileId) {
1493
- try {
1494
- const downloadUrl = this.getFileDownloadUrl(fileId);
1495
- const response = await fetch(downloadUrl);
1496
- if (!response.ok) {
1497
- throw new Error(`Download failed: ${response.status} ${response.statusText}`);
1498
- }
1499
- return response;
1500
- } catch (error) {
1501
- throw this.handleError(error);
1502
- }
1503
- }
1504
-
1505
- /**
1506
- * Get file content as text using authenticated request
1507
- * @param fileId - The file ID to get content for
1508
- * @returns File content as string
1509
- */
1510
- async getFileContentAsText(fileId) {
1511
- try {
1512
- const response = await this.downloadFileContent(fileId);
1513
- return await response.text();
1514
- } catch (error) {
1515
- throw this.handleError(error);
1516
- }
1517
- }
1518
-
1519
- /**
1520
- * Get file content as blob using authenticated request
1521
- * @param fileId - The file ID to get content for
1522
- * @returns File content as blob
1523
- */
1524
- async getFileContentAsBlob(fileId) {
1525
- try {
1526
- const response = await this.downloadFileContent(fileId);
1527
- return await response.blob();
1528
- } catch (error) {
1529
- throw this.handleError(error);
1530
- }
1531
- }
1532
-
1533
- /**
1534
- * Fetch metadata for a URL (title, description, image)
1535
- * @param url - The URL to fetch metadata for
1536
- * @returns Promise with metadata object
1537
- */
1538
- async fetchLinkMetadata(url) {
1539
- try {
1540
- const response = await this.client.post('/link-metadata/fetch-metadata', {
1541
- url
1542
- });
1543
- return response.data;
1544
- } catch (error) {
1545
- throw this.handleError(error);
1546
- }
1547
- }
1548
-
1549
- /**
1550
- * Search for locations using the enhanced location search API
1551
- * @param query - Search query string
1552
- * @param limit - Maximum number of results (default: 5)
1553
- * @param countrycodes - Optional country codes filter (e.g., "us,ca")
1554
- * @returns Promise with array of location results
1555
- */
1556
- async searchLocations(query, limit = 5, countrycodes) {
1557
- try {
1558
- const params = new URLSearchParams({
1559
- query,
1560
- limit: limit.toString()
1561
- });
1562
- if (countrycodes) {
1563
- params.append('countrycodes', countrycodes);
1564
- }
1565
- const res = await this.client.get(`/location-search/search?${params.toString()}`);
1566
- return res.data.results;
1567
- } catch (error) {
1568
- throw this.handleError(error);
1569
- }
1570
- }
1571
-
1572
- /**
1573
- * Get detailed information about a specific location by coordinates
1574
- * @param lat - Latitude
1575
- * @param lon - Longitude
1576
- * @returns Promise with detailed location information
1577
- */
1578
- async getLocationDetails(lat, lon) {
1579
- try {
1580
- const res = await this.client.get(`/location-search/details?lat=${lat}&lon=${lon}`);
1581
- return res.data.result;
1582
- } catch (error) {
1583
- throw this.handleError(error);
1584
- }
1585
- }
1586
-
1587
- /**
1588
- * Find locations near a point using geospatial queries
1589
- * @param lat - Latitude
1590
- * @param lon - Longitude
1591
- * @param maxDistance - Maximum distance in meters (default: 10000)
1592
- * @param limit - Maximum number of results (default: 10)
1593
- * @param skip - Number of results to skip (default: 0)
1594
- * @returns Promise with nearby locations
1595
- */
1596
- async findLocationsNear(lat, lon, maxDistance = 10000, limit = 10, skip = 0) {
1597
- try {
1598
- const params = new URLSearchParams({
1599
- lat: lat.toString(),
1600
- lon: lon.toString(),
1601
- maxDistance: maxDistance.toString(),
1602
- limit: limit.toString(),
1603
- skip: skip.toString()
1604
- });
1605
- const res = await this.client.get(`/location-search/near?${params.toString()}`);
1606
- return res.data;
1607
- } catch (error) {
1608
- throw this.handleError(error);
1609
- }
1610
- }
1611
-
1612
- /**
1613
- * Search locations in database by text
1614
- * @param query - Search query
1615
- * @param limit - Maximum number of results (default: 10)
1616
- * @param skip - Number of results to skip (default: 0)
1617
- * @param type - Filter by location type
1618
- * @param country - Filter by country
1619
- * @param city - Filter by city
1620
- * @returns Promise with search results
1621
- */
1622
- async searchLocationsInDB(query, limit = 10, skip = 0, type, country, city) {
1623
- try {
1624
- const params = new URLSearchParams({
1625
- query,
1626
- limit: limit.toString(),
1627
- skip: skip.toString()
1628
- });
1629
- if (type) params.append('type', type);
1630
- if (country) params.append('country', country);
1631
- if (city) params.append('city', city);
1632
- const res = await this.client.get(`/location-search/db-search?${params.toString()}`);
1633
- return res.data;
1634
- } catch (error) {
1635
- throw this.handleError(error);
1636
- }
1637
- }
1638
-
1639
- /**
1640
- * Get location statistics
1641
- * @returns Promise with location statistics
1642
- */
1643
- async getLocationStats() {
1644
- try {
1645
- const res = await this.client.get('/location-search/stats');
1646
- return res.data.stats;
1647
- } catch (error) {
1648
- throw this.handleError(error);
1649
- }
1650
- }
1651
-
1652
- /**
1653
- * Get cache statistics
1654
- * @returns Promise with cache statistics
1655
- */
1656
- async getLocationCacheStats() {
1657
- try {
1658
- const res = await this.client.get('/location-search/cache/stats');
1659
- return res.data.stats;
1660
- } catch (error) {
1661
- throw this.handleError(error);
1662
- }
1663
- }
1664
-
1665
- /**
1666
- * Clear location cache
1667
- * @returns Promise with success status
1668
- */
1669
- async clearLocationCache() {
1670
- try {
1671
- const res = await this.client.delete('/location-search/cache');
1672
- return res.data;
1673
- } catch (error) {
1674
- throw this.handleError(error);
1675
- }
1676
- }
1677
-
1678
- /**
1679
- * Get performance statistics
1680
- * @returns Promise with performance statistics
1681
- */
1682
- async getLocationPerformanceStats() {
1683
- try {
1684
- const res = await this.client.get('/location-search/performance');
1685
- return res.data;
1686
- } catch (error) {
1687
- throw this.handleError(error);
1688
- }
1689
- }
1690
- }
1691
-
1692
- // Default export for backward compatibility
1693
- export default OxyServices;
26
+ // Constants
27
+ export { OXY_CLOUD_URL } from './files/FileService';
1694
28
 
1695
29
  // Re-export all models and types for convenience
1696
30
  export * from '../models/interfaces';
1697
- export * from '../models/secureSession';
31
+ export * from '../models/session';
1698
32
 
1699
- // Clean middleware exports - these will be available for server-side use
1700
- // Note: These require Express.js and are only for server-side applications
33
+ // Export device management utilities
34
+ export { DeviceManager } from '../utils/deviceManager';
35
+ // Import the main class for default export
36
+ import { OxyServicesMain } from './OxyServicesMain';
1701
37
 
1702
- if (typeof FormData === 'undefined') {
1703
- console.warn('[OxyHQ/Services] FormData is not available. If you are using Hermes, add "import \'react-native-url-polyfill/auto\'" at the top of your app entry file.');
1704
- }
38
+ // Default export for backward compatibility
39
+ export default OxyServicesMain;
1705
40
  //# sourceMappingURL=index.js.map