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