@oxyhq/services 5.10.4 → 5.10.6

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 (142) hide show
  1. package/README.md +62 -14
  2. package/lib/commonjs/core/OxyServices.js +797 -5
  3. package/lib/commonjs/core/OxyServices.js.map +1 -1
  4. package/lib/commonjs/core/index.js +8 -83
  5. package/lib/commonjs/core/index.js.map +1 -1
  6. package/lib/commonjs/index.js +31 -1
  7. package/lib/commonjs/index.js.map +1 -1
  8. package/lib/commonjs/ui/screens/FileManagementScreen.js +12 -12
  9. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  10. package/lib/commonjs/ui/screens/ProfileScreen.js +2 -2
  11. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  12. package/lib/commonjs/ui/screens/SignInScreen.js +1 -1
  13. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  14. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +1 -1
  15. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  16. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +1 -1
  17. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  18. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +1 -1
  19. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  20. package/lib/commonjs/ui/stores/followStore.js +4 -4
  21. package/lib/commonjs/ui/stores/followStore.js.map +1 -1
  22. package/lib/commonjs/utils/s3FileManager.js +243 -0
  23. package/lib/commonjs/utils/s3FileManager.js.map +1 -0
  24. package/lib/commonjs/utils/s3FileManagerExample.js +407 -0
  25. package/lib/commonjs/utils/s3FileManagerExample.js.map +1 -0
  26. package/lib/commonjs/utils/s3FileManagerRN.js +274 -0
  27. package/lib/commonjs/utils/s3FileManagerRN.js.map +1 -0
  28. package/lib/module/core/OxyServices.js +796 -4
  29. package/lib/module/core/OxyServices.js.map +1 -1
  30. package/lib/module/core/index.js +9 -24
  31. package/lib/module/core/index.js.map +1 -1
  32. package/lib/module/index.js +4 -0
  33. package/lib/module/index.js.map +1 -1
  34. package/lib/module/ui/screens/FileManagementScreen.js +12 -12
  35. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  36. package/lib/module/ui/screens/ProfileScreen.js +2 -2
  37. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  38. package/lib/module/ui/screens/SignInScreen.js +1 -1
  39. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  40. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +1 -1
  41. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  42. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +1 -1
  43. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  44. package/lib/module/ui/screens/karma/KarmaRulesScreen.js +1 -1
  45. package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  46. package/lib/module/ui/stores/followStore.js +4 -4
  47. package/lib/module/ui/stores/followStore.js.map +1 -1
  48. package/lib/module/utils/s3FileManager.js +237 -0
  49. package/lib/module/utils/s3FileManager.js.map +1 -0
  50. package/lib/module/utils/s3FileManagerExample.js +400 -0
  51. package/lib/module/utils/s3FileManagerExample.js.map +1 -0
  52. package/lib/module/utils/s3FileManagerRN.js +268 -0
  53. package/lib/module/utils/s3FileManagerRN.js.map +1 -0
  54. package/lib/typescript/core/OxyServices.d.ts +292 -3
  55. package/lib/typescript/core/OxyServices.d.ts.map +1 -1
  56. package/lib/typescript/core/index.d.ts +7 -16
  57. package/lib/typescript/core/index.d.ts.map +1 -1
  58. package/lib/typescript/index.d.ts +4 -0
  59. package/lib/typescript/index.d.ts.map +1 -1
  60. package/lib/typescript/utils/s3FileManager.d.ts +81 -0
  61. package/lib/typescript/utils/s3FileManager.d.ts.map +1 -0
  62. package/lib/typescript/utils/s3FileManagerExample.d.ts +87 -0
  63. package/lib/typescript/utils/s3FileManagerExample.d.ts.map +1 -0
  64. package/lib/typescript/utils/s3FileManagerRN.d.ts +104 -0
  65. package/lib/typescript/utils/s3FileManagerRN.d.ts.map +1 -0
  66. package/package.json +3 -1
  67. package/src/core/OxyServices.ts +881 -46
  68. package/src/core/index.ts +9 -24
  69. package/src/index.ts +17 -1
  70. package/src/ui/screens/FileManagementScreen.tsx +12 -12
  71. package/src/ui/screens/ProfileScreen.tsx +3 -3
  72. package/src/ui/screens/SignInScreen.tsx +1 -1
  73. package/src/ui/screens/karma/KarmaCenterScreen.tsx +2 -2
  74. package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +1 -1
  75. package/src/ui/screens/karma/KarmaRulesScreen.tsx +1 -1
  76. package/src/ui/stores/followStore.ts +4 -4
  77. package/src/utils/s3FileManager.ts +281 -0
  78. package/src/utils/s3FileManagerExample.ts +432 -0
  79. package/src/utils/s3FileManagerRN.ts +322 -0
  80. package/lib/commonjs/core/OxyServicesMain.js +0 -51
  81. package/lib/commonjs/core/OxyServicesMain.js.map +0 -1
  82. package/lib/commonjs/core/analytics/AnalyticsService.js +0 -67
  83. package/lib/commonjs/core/analytics/AnalyticsService.js.map +0 -1
  84. package/lib/commonjs/core/auth/AuthService.js +0 -538
  85. package/lib/commonjs/core/auth/AuthService.js.map +0 -1
  86. package/lib/commonjs/core/devices/DeviceService.js +0 -61
  87. package/lib/commonjs/core/devices/DeviceService.js.map +0 -1
  88. package/lib/commonjs/core/files/FileService.js +0 -180
  89. package/lib/commonjs/core/files/FileService.js.map +0 -1
  90. package/lib/commonjs/core/karma/KarmaService.js +0 -100
  91. package/lib/commonjs/core/karma/KarmaService.js.map +0 -1
  92. package/lib/commonjs/core/locations/LocationService.js +0 -131
  93. package/lib/commonjs/core/locations/LocationService.js.map +0 -1
  94. package/lib/commonjs/core/payments/PaymentService.js +0 -124
  95. package/lib/commonjs/core/payments/PaymentService.js.map +0 -1
  96. package/lib/commonjs/core/users/UserService.js +0 -234
  97. package/lib/commonjs/core/users/UserService.js.map +0 -1
  98. package/lib/module/core/OxyServicesMain.js +0 -47
  99. package/lib/module/core/OxyServicesMain.js.map +0 -1
  100. package/lib/module/core/analytics/AnalyticsService.js +0 -62
  101. package/lib/module/core/analytics/AnalyticsService.js.map +0 -1
  102. package/lib/module/core/auth/AuthService.js +0 -533
  103. package/lib/module/core/auth/AuthService.js.map +0 -1
  104. package/lib/module/core/devices/DeviceService.js +0 -57
  105. package/lib/module/core/devices/DeviceService.js.map +0 -1
  106. package/lib/module/core/files/FileService.js +0 -175
  107. package/lib/module/core/files/FileService.js.map +0 -1
  108. package/lib/module/core/karma/KarmaService.js +0 -95
  109. package/lib/module/core/karma/KarmaService.js.map +0 -1
  110. package/lib/module/core/locations/LocationService.js +0 -127
  111. package/lib/module/core/locations/LocationService.js.map +0 -1
  112. package/lib/module/core/payments/PaymentService.js +0 -119
  113. package/lib/module/core/payments/PaymentService.js.map +0 -1
  114. package/lib/module/core/users/UserService.js +0 -230
  115. package/lib/module/core/users/UserService.js.map +0 -1
  116. package/lib/typescript/core/OxyServicesMain.d.ts +0 -33
  117. package/lib/typescript/core/OxyServicesMain.d.ts.map +0 -1
  118. package/lib/typescript/core/analytics/AnalyticsService.d.ts +0 -26
  119. package/lib/typescript/core/analytics/AnalyticsService.d.ts.map +0 -1
  120. package/lib/typescript/core/auth/AuthService.d.ts +0 -165
  121. package/lib/typescript/core/auth/AuthService.d.ts.map +0 -1
  122. package/lib/typescript/core/devices/DeviceService.d.ts +0 -20
  123. package/lib/typescript/core/devices/DeviceService.d.ts.map +0 -1
  124. package/lib/typescript/core/files/FileService.d.ts +0 -59
  125. package/lib/typescript/core/files/FileService.d.ts.map +0 -1
  126. package/lib/typescript/core/karma/KarmaService.d.ts +0 -50
  127. package/lib/typescript/core/karma/KarmaService.d.ts.map +0 -1
  128. package/lib/typescript/core/locations/LocationService.d.ts +0 -39
  129. package/lib/typescript/core/locations/LocationService.d.ts.map +0 -1
  130. package/lib/typescript/core/payments/PaymentService.d.ts +0 -50
  131. package/lib/typescript/core/payments/PaymentService.d.ts.map +0 -1
  132. package/lib/typescript/core/users/UserService.d.ts +0 -111
  133. package/lib/typescript/core/users/UserService.d.ts.map +0 -1
  134. package/src/core/OxyServicesMain.ts +0 -57
  135. package/src/core/analytics/AnalyticsService.ts +0 -64
  136. package/src/core/auth/AuthService.ts +0 -560
  137. package/src/core/devices/DeviceService.ts +0 -55
  138. package/src/core/files/FileService.ts +0 -198
  139. package/src/core/karma/KarmaService.ts +0 -104
  140. package/src/core/locations/LocationService.ts +0 -141
  141. package/src/core/payments/PaymentService.ts +0 -133
  142. package/src/core/users/UserService.ts +0 -241
@@ -1,7 +1,9 @@
1
1
  import axios, { AxiosInstance, InternalAxiosRequestConfig } from 'axios';
2
2
  import { jwtDecode } from 'jwt-decode';
3
- import { OxyConfig, ApiError, User } from '../models/interfaces';
3
+ import { OxyConfig, ApiError, User, Notification } from '../models/interfaces';
4
+ import { SessionLoginResponse } from '../models/session';
4
5
  import { handleHttpError } from '../utils/errorUtils';
6
+ import { buildSearchParams, buildPaginationParams, PaginationParams } from '../utils/apiUtils';
5
7
 
6
8
  interface JwtPayload {
7
9
  exp?: number;
@@ -11,10 +13,10 @@ interface JwtPayload {
11
13
  }
12
14
 
13
15
  /**
14
- * OxyServices - Base client library for interacting with the Oxy API
16
+ * OxyServices - Unified client library for interacting with the Oxy API
15
17
  *
16
- * This class provides the core HTTP client setup, token management, and error handling.
17
- * Specific functionality is delegated to focused service modules.
18
+ * This class provides all API functionality in one simple, easy-to-use interface.
19
+ * No need to manage multiple service instances - everything is available directly.
18
20
  */
19
21
  // Centralized token store
20
22
  class TokenStore {
@@ -129,92 +131,922 @@ export class OxyServices {
129
131
  });
130
132
  }
131
133
 
134
+ // ============================================================================
135
+ // CORE METHODS (HTTP Client, Token Management, Error Handling)
136
+ // ============================================================================
137
+
138
+ /**
139
+ * Get the configured base URL
140
+ */
141
+ public getBaseURL(): string {
142
+ return this.client.defaults.baseURL || '';
143
+ }
144
+
145
+ /**
146
+ * Set authentication tokens
147
+ */
148
+ public setTokens(accessToken: string, refreshToken: string = ''): void {
149
+ this.tokenStore.setTokens(accessToken, refreshToken);
150
+ }
151
+
152
+ /**
153
+ * Clear stored authentication tokens
154
+ */
155
+ public clearTokens(): void {
156
+ this.tokenStore.clearTokens();
157
+ }
158
+
159
+ /**
160
+ * Get the current user ID from the access token
161
+ */
162
+ public getCurrentUserId(): string | null {
163
+ const accessToken = this.tokenStore.getAccessToken();
164
+ if (!accessToken) {
165
+ return null;
166
+ }
167
+
168
+ try {
169
+ const decoded = jwtDecode<JwtPayload>(accessToken);
170
+ return decoded.userId || decoded.id || null;
171
+ } catch (error) {
172
+ return null;
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Check if the client has a valid access token
178
+ */
179
+ private hasAccessToken(): boolean {
180
+ return this.tokenStore.hasAccessToken();
181
+ }
182
+
183
+ /**
184
+ * Validate the current access token with the server
185
+ */
186
+ async validate(): Promise<boolean> {
187
+ if (!this.hasAccessToken()) {
188
+ return false;
189
+ }
190
+
191
+ try {
192
+ const res = await this.client.get('/api/auth/validate');
193
+ return res.data.valid === true;
194
+ } catch (error) {
195
+ return false;
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Get the HTTP client instance (public for external use)
201
+ */
202
+ public getClient(): AxiosInstance {
203
+ return this.client;
204
+ }
205
+
206
+ /**
207
+ * Centralized error handling
208
+ */
209
+ protected handleError(error: any): ApiError {
210
+ return handleHttpError(error);
211
+ }
212
+
213
+ /**
214
+ * Health check endpoint
215
+ */
216
+ async healthCheck(): Promise<{
217
+ status: string;
218
+ users?: number;
219
+ timestamp?: string;
220
+ [key: string]: any
221
+ }> {
222
+ try {
223
+ const res = await this.client.get('/health');
224
+ return res.data;
225
+ } catch (error) {
226
+ throw this.handleError(error);
227
+ }
228
+ }
229
+
230
+ // ============================================================================
231
+ // AUTHENTICATION METHODS
232
+ // ============================================================================
233
+
234
+ /**
235
+ * Sign up a new user
236
+ */
237
+ async signUp(username: string, email: string, password: string): Promise<{ message: string; token: string; user: User }> {
238
+ try {
239
+ const res = await this.client.post('/api/auth/signup', {
240
+ username,
241
+ email,
242
+ password
243
+ });
244
+ return res.data;
245
+ } catch (error) {
246
+ throw this.handleError(error);
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Sign in with device management
252
+ */
253
+ async signIn(username: string, password: string, deviceName?: string, deviceFingerprint?: any): Promise<SessionLoginResponse> {
254
+ try {
255
+ const res = await this.client.post('/api/auth/login', {
256
+ username,
257
+ password,
258
+ deviceName,
259
+ deviceFingerprint
260
+ });
261
+ return res.data;
262
+ } catch (error) {
263
+ throw this.handleError(error);
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Get user by session ID
269
+ */
270
+ async getUserBySession(sessionId: string): Promise<User> {
271
+ try {
272
+ const res = await this.client.get(`/api/session/user/${sessionId}`);
273
+ return res.data;
274
+ } catch (error) {
275
+ throw this.handleError(error);
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Get access token by session ID and set it in the token store
281
+ */
282
+ async getTokenBySession(sessionId: string): Promise<{ accessToken: string; expiresAt: string }> {
283
+ try {
284
+ console.log('🔑 getTokenBySession - Fetching token for session:', sessionId);
285
+ const res = await this.client.get(`/api/session/token/${sessionId}`);
286
+ const { accessToken } = res.data;
287
+
288
+ console.log('🔑 getTokenBySession - Token received:', !!accessToken);
289
+
290
+ // Set the token in the centralized token store
291
+ this.setTokens(accessToken);
292
+ console.log('🔑 getTokenBySession - Token set in store');
293
+
294
+ return res.data;
295
+ } catch (error) {
296
+ console.log('❌ getTokenBySession - Error:', error);
297
+ throw this.handleError(error);
298
+ }
299
+ }
300
+
301
+ /**
302
+ * Get sessions by session ID
303
+ */
304
+ async getSessionsBySessionId(sessionId: string): Promise<any[]> {
305
+ try {
306
+ const res = await this.client.get(`/api/session/sessions/${sessionId}`);
307
+ return res.data;
308
+ } catch (error) {
309
+ throw this.handleError(error);
310
+ }
311
+ }
312
+
313
+ /**
314
+ * Logout from a specific session
315
+ */
316
+ async logoutSession(sessionId: string, targetSessionId?: string): Promise<void> {
317
+ try {
318
+ const url = targetSessionId
319
+ ? `/api/session/logout/${sessionId}/${targetSessionId}`
320
+ : `/api/session/logout/${sessionId}`;
321
+
322
+ await this.client.post(url);
323
+ } catch (error) {
324
+ throw this.handleError(error);
325
+ }
326
+ }
327
+
328
+ /**
329
+ * Logout from all sessions
330
+ */
331
+ async logoutAllSessions(sessionId: string): Promise<void> {
332
+ try {
333
+ await this.client.post(`/api/session/logout-all/${sessionId}`);
334
+ } catch (error) {
335
+ throw this.handleError(error);
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Validate session
341
+ */
342
+ async validateSession(
343
+ sessionId: string,
344
+ options: {
345
+ deviceFingerprint?: string;
346
+ useHeaderValidation?: boolean;
347
+ } = {}
348
+ ): Promise<{
349
+ valid: boolean;
350
+ expiresAt: string;
351
+ lastActivity: string;
352
+ user: User;
353
+ sessionId?: string;
354
+ source?: string;
355
+ }> {
356
+ try {
357
+ const params = new URLSearchParams();
358
+ if (options.deviceFingerprint) {
359
+ params.append('deviceFingerprint', options.deviceFingerprint);
360
+ }
361
+ if (options.useHeaderValidation) {
362
+ params.append('useHeaderValidation', 'true');
363
+ }
364
+
365
+ const url = `/api/session/validate/${sessionId}?${params.toString()}`;
366
+ const res = await this.client.get(url);
367
+ return res.data;
368
+ } catch (error) {
369
+ throw this.handleError(error);
370
+ }
371
+ }
372
+
373
+ /**
374
+ * Check username availability
375
+ */
376
+ async checkUsernameAvailability(username: string): Promise<{ available: boolean; message: string }> {
377
+ try {
378
+ const res = await this.client.get(`/api/auth/check-username/${username}`);
379
+ return res.data;
380
+ } catch (error) {
381
+ throw this.handleError(error);
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Check email availability
387
+ */
388
+ async checkEmailAvailability(email: string): Promise<{ available: boolean; message: string }> {
389
+ try {
390
+ const res = await this.client.get(`/api/auth/check-email/${email}`);
391
+ return res.data;
392
+ } catch (error) {
393
+ throw this.handleError(error);
394
+ }
395
+ }
396
+
397
+ // ============================================================================
398
+ // USER METHODS
399
+ // ============================================================================
400
+
401
+ /**
402
+ * Get profile by username
403
+ */
404
+ async getProfileByUsername(username: string): Promise<User> {
405
+ try {
406
+ const res = await this.client.get(`/api/profiles/username/${username}`);
407
+ return res.data;
408
+ } catch (error) {
409
+ throw this.handleError(error);
410
+ }
411
+ }
412
+
413
+ /**
414
+ * Search user profiles
415
+ */
416
+ async searchProfiles(query: string, pagination?: PaginationParams): Promise<User[]> {
417
+ try {
418
+ const params = { query, ...pagination };
419
+ const searchParams = buildSearchParams(params);
420
+
421
+ const res = await this.client.get(`/api/profiles/search?${searchParams.toString()}`);
422
+ return res.data;
423
+ } catch (error) {
424
+ throw this.handleError(error);
425
+ }
426
+ }
427
+
428
+ /**
429
+ * Get profile recommendations
430
+ */
431
+ async getProfileRecommendations(): Promise<Array<{
432
+ id: string;
433
+ username: string;
434
+ name?: { first?: string; last?: string; full?: string };
435
+ description?: string;
436
+ _count?: { followers: number; following: number };
437
+ [key: string]: any;
438
+ }>> {
439
+ try {
440
+ const res = await this.client.get('/api/profiles/recommendations');
441
+ return res.data;
442
+ } catch (error) {
443
+ throw this.handleError(error);
444
+ }
445
+ }
446
+
447
+ /**
448
+ * Get user by ID
449
+ */
450
+ async getUserById(userId: string): Promise<User> {
451
+ try {
452
+ const res = await this.client.get(`/api/users/${userId}`);
453
+ return res.data;
454
+ } catch (error) {
455
+ throw this.handleError(error);
456
+ }
457
+ }
458
+
459
+ /**
460
+ * Get current user
461
+ */
462
+ async getCurrentUser(): Promise<User> {
463
+ try {
464
+ const res = await this.client.get('/api/users/me');
465
+ return res.data;
466
+ } catch (error) {
467
+ throw this.handleError(error);
468
+ }
469
+ }
470
+
471
+ /**
472
+ * Update user profile
473
+ */
474
+ async updateProfile(updates: Record<string, any>): Promise<User> {
475
+ try {
476
+ const res = await this.client.put('/api/users/me', updates);
477
+ return res.data;
478
+ } catch (error) {
479
+ throw this.handleError(error);
480
+ }
481
+ }
482
+
483
+ /**
484
+ * Update user by ID (admin function)
485
+ */
486
+ async updateUser(userId: string, updates: Record<string, any>): Promise<User> {
487
+ try {
488
+ const res = await this.client.put(`/api/users/${userId}`, updates);
489
+ return res.data;
490
+ } catch (error) {
491
+ throw this.handleError(error);
492
+ }
493
+ }
494
+
495
+ /**
496
+ * Follow a user
497
+ */
498
+ async followUser(userId: string): Promise<{ success: boolean; message: string }> {
499
+ try {
500
+ const res = await this.client.post(`/api/users/${userId}/follow`);
501
+ return res.data;
502
+ } catch (error) {
503
+ throw this.handleError(error);
504
+ }
505
+ }
506
+
507
+ /**
508
+ * Unfollow a user
509
+ */
510
+ async unfollowUser(userId: string): Promise<{ success: boolean; message: string }> {
511
+ try {
512
+ const res = await this.client.delete(`/api/users/${userId}/follow`);
513
+ return res.data;
514
+ } catch (error) {
515
+ throw this.handleError(error);
516
+ }
517
+ }
518
+
519
+ /**
520
+ * Get follow status
521
+ */
522
+ async getFollowStatus(userId: string): Promise<{ isFollowing: boolean }> {
523
+ try {
524
+ const res = await this.client.get(`/api/users/${userId}/follow-status`);
525
+ return res.data;
526
+ } catch (error) {
527
+ throw this.handleError(error);
528
+ }
529
+ }
530
+
531
+ /**
532
+ * Get user followers
533
+ */
534
+ async getUserFollowers(
535
+ userId: string,
536
+ pagination?: PaginationParams
537
+ ): Promise<{ followers: User[]; total: number; hasMore: boolean }> {
538
+ try {
539
+ const params = buildPaginationParams(pagination || {});
540
+ const res = await this.client.get(`/api/users/${userId}/followers?${params.toString()}`);
541
+ return res.data;
542
+ } catch (error) {
543
+ throw this.handleError(error);
544
+ }
545
+ }
546
+
547
+ /**
548
+ * Get user following
549
+ */
550
+ async getUserFollowing(
551
+ userId: string,
552
+ pagination?: PaginationParams
553
+ ): Promise<{ following: User[]; total: number; hasMore: boolean }> {
554
+ try {
555
+ const params = buildPaginationParams(pagination || {});
556
+ const res = await this.client.get(`/api/users/${userId}/following?${params.toString()}`);
557
+ return res.data;
558
+ } catch (error) {
559
+ throw this.handleError(error);
560
+ }
561
+ }
562
+
563
+ /**
564
+ * Get notifications
565
+ */
566
+ async getNotifications(): Promise<Notification[]> {
567
+ try {
568
+ const res = await this.client.get('/api/notifications');
569
+ return res.data;
570
+ } catch (error) {
571
+ throw this.handleError(error);
572
+ }
573
+ }
574
+
575
+ /**
576
+ * Get unread notification count
577
+ */
578
+ async getUnreadCount(): Promise<number> {
579
+ try {
580
+ const res = await this.client.get('/api/notifications/unread-count');
581
+ return res.data.count;
582
+ } catch (error) {
583
+ throw this.handleError(error);
584
+ }
585
+ }
586
+
587
+ /**
588
+ * Create notification
589
+ */
590
+ async createNotification(data: Partial<Notification>): Promise<Notification> {
591
+ try {
592
+ const res = await this.client.post('/api/notifications', data);
593
+ return res.data;
594
+ } catch (error) {
595
+ throw this.handleError(error);
596
+ }
597
+ }
598
+
599
+ /**
600
+ * Mark notification as read
601
+ */
602
+ async markNotificationAsRead(notificationId: string): Promise<void> {
603
+ try {
604
+ await this.client.put(`/api/notifications/${notificationId}/read`);
605
+ } catch (error) {
606
+ throw this.handleError(error);
607
+ }
608
+ }
609
+
610
+ /**
611
+ * Mark all notifications as read
612
+ */
613
+ async markAllNotificationsAsRead(): Promise<void> {
614
+ try {
615
+ await this.client.put('/api/notifications/read-all');
616
+ } catch (error) {
617
+ throw this.handleError(error);
618
+ }
619
+ }
620
+
621
+ /**
622
+ * Delete notification
623
+ */
624
+ async deleteNotification(notificationId: string): Promise<void> {
625
+ try {
626
+ await this.client.delete(`/api/notifications/${notificationId}`);
627
+ } catch (error) {
628
+ throw this.handleError(error);
629
+ }
630
+ }
631
+
632
+ // ============================================================================
633
+ // PAYMENT METHODS
634
+ // ============================================================================
635
+
132
636
  /**
133
- * Get the configured base URL
637
+ * Create a payment
134
638
  */
135
- public getBaseURL(): string {
136
- return this.client.defaults.baseURL || '';
639
+ async createPayment(data: any): Promise<any> {
640
+ try {
641
+ const res = await this.client.post('/api/payments', data);
642
+ return res.data;
643
+ } catch (error) {
644
+ throw this.handleError(error);
645
+ }
137
646
  }
138
647
 
139
648
  /**
140
- * Set authentication tokens
649
+ * Get payment by ID
141
650
  */
142
- public setTokens(accessToken: string, refreshToken: string = ''): void {
143
- this.tokenStore.setTokens(accessToken, refreshToken);
651
+ async getPayment(paymentId: string): Promise<any> {
652
+ try {
653
+ const res = await this.client.get(`/api/payments/${paymentId}`);
654
+ return res.data;
655
+ } catch (error) {
656
+ throw this.handleError(error);
657
+ }
144
658
  }
145
659
 
146
660
  /**
147
- * Clear stored authentication tokens
661
+ * Get user payments
148
662
  */
149
- public clearTokens(): void {
150
- this.tokenStore.clearTokens();
663
+ async getUserPayments(): Promise<any[]> {
664
+ try {
665
+ const res = await this.client.get('/api/payments/user');
666
+ return res.data;
667
+ } catch (error) {
668
+ throw this.handleError(error);
669
+ }
151
670
  }
152
671
 
672
+ // ============================================================================
673
+ // KARMA METHODS
674
+ // ============================================================================
675
+
153
676
  /**
154
- * Get the current user ID from the access token
677
+ * Get user karma
155
678
  */
156
- public getCurrentUserId(): string | null {
157
- const accessToken = this.tokenStore.getAccessToken();
158
- if (!accessToken) {
159
- return null;
679
+ async getUserKarma(userId: string): Promise<any> {
680
+ try {
681
+ const res = await this.client.get(`/api/karma/${userId}`);
682
+ return res.data;
683
+ } catch (error) {
684
+ throw this.handleError(error);
160
685
  }
161
-
686
+ }
687
+
688
+ /**
689
+ * Give karma to user
690
+ */
691
+ async giveKarma(userId: string, amount: number, reason?: string): Promise<any> {
162
692
  try {
163
- const decoded = jwtDecode<JwtPayload>(accessToken);
164
- return decoded.userId || decoded.id || null;
693
+ const res = await this.client.post(`/api/karma/${userId}/give`, {
694
+ amount,
695
+ reason
696
+ });
697
+ return res.data;
165
698
  } catch (error) {
166
- return null;
699
+ throw this.handleError(error);
167
700
  }
168
701
  }
169
702
 
170
703
  /**
171
- * Check if the client has a valid access token
704
+ * Get user karma total
172
705
  */
173
- private hasAccessToken(): boolean {
174
- return this.tokenStore.hasAccessToken();
706
+ async getUserKarmaTotal(userId: string): Promise<any> {
707
+ try {
708
+ const res = await this.client.get(`/api/karma/${userId}/total`);
709
+ return res.data;
710
+ } catch (error) {
711
+ throw this.handleError(error);
712
+ }
175
713
  }
176
714
 
177
715
  /**
178
- * Validate the current access token with the server
716
+ * Get user karma history
179
717
  */
180
- async validate(): Promise<boolean> {
181
- if (!this.hasAccessToken()) {
182
- return false;
718
+ async getUserKarmaHistory(userId: string, limit?: number, offset?: number): Promise<any> {
719
+ try {
720
+ const params = new URLSearchParams();
721
+ if (limit) params.append('limit', limit.toString());
722
+ if (offset) params.append('offset', offset.toString());
723
+
724
+ const res = await this.client.get(`/api/karma/${userId}/history?${params.toString()}`);
725
+ return res.data;
726
+ } catch (error) {
727
+ throw this.handleError(error);
728
+ }
729
+ }
730
+
731
+ /**
732
+ * Get karma leaderboard
733
+ */
734
+ async getKarmaLeaderboard(): Promise<any> {
735
+ try {
736
+ const res = await this.client.get('/api/karma/leaderboard');
737
+ return res.data;
738
+ } catch (error) {
739
+ throw this.handleError(error);
183
740
  }
741
+ }
184
742
 
743
+ /**
744
+ * Get karma rules
745
+ */
746
+ async getKarmaRules(): Promise<any> {
185
747
  try {
186
- const res = await this.client.get('/api/auth/validate');
187
- return res.data.valid === true;
748
+ const res = await this.client.get('/api/karma/rules');
749
+ return res.data;
188
750
  } catch (error) {
189
- return false;
751
+ throw this.handleError(error);
190
752
  }
191
753
  }
192
754
 
755
+ // ============================================================================
756
+ // FILE METHODS
757
+ // ============================================================================
758
+
193
759
  /**
194
- * Get the HTTP client instance (protected for use by service modules)
760
+ * Upload file
195
761
  */
196
- protected getClient(): AxiosInstance {
197
- return this.client;
762
+ async uploadFile(file: File | FormData, options?: any): Promise<any> {
763
+ try {
764
+ const formData = file instanceof FormData ? file : new FormData();
765
+ if (file instanceof File) {
766
+ formData.append('file', file);
767
+ }
768
+
769
+ const res = await this.client.post('/api/files/upload', formData, {
770
+ headers: {
771
+ 'Content-Type': 'multipart/form-data',
772
+ },
773
+ ...options
774
+ });
775
+ return res.data;
776
+ } catch (error) {
777
+ throw this.handleError(error);
778
+ }
198
779
  }
199
780
 
200
781
  /**
201
- * Centralized error handling
782
+ * Get file by ID
202
783
  */
203
- protected handleError(error: any): ApiError {
204
- return handleHttpError(error);
784
+ async getFile(fileId: string): Promise<any> {
785
+ try {
786
+ const res = await this.client.get(`/api/files/${fileId}`);
787
+ return res.data;
788
+ } catch (error) {
789
+ throw this.handleError(error);
790
+ }
205
791
  }
206
792
 
207
793
  /**
208
- * Health check endpoint
794
+ * Delete file
209
795
  */
210
- async healthCheck(): Promise<{
211
- status: string;
212
- users?: number;
213
- timestamp?: string;
214
- [key: string]: any
796
+ async deleteFile(fileId: string): Promise<any> {
797
+ try {
798
+ const res = await this.client.delete(`/api/files/${fileId}`);
799
+ return res.data;
800
+ } catch (error) {
801
+ throw this.handleError(error);
802
+ }
803
+ }
804
+
805
+ /**
806
+ * Get file download URL
807
+ */
808
+ getFileDownloadUrl(fileId: string): string {
809
+ return `${OXY_CLOUD_URL}/files/${fileId}/download`;
810
+ }
811
+
812
+ /**
813
+ * Get file stream URL
814
+ */
815
+ getFileStreamUrl(fileId: string): string {
816
+ return `${OXY_CLOUD_URL}/files/${fileId}/stream`;
817
+ }
818
+
819
+ /**
820
+ * List user files
821
+ */
822
+ async listUserFiles(
823
+ userId: string,
824
+ limit?: number,
825
+ offset?: number,
826
+ filters?: Record<string, any>
827
+ ): Promise<any> {
828
+ try {
829
+ const params = new URLSearchParams();
830
+ if (limit) params.append('limit', limit.toString());
831
+ if (offset) params.append('offset', offset.toString());
832
+
833
+ if (filters) {
834
+ Object.entries(filters).forEach(([key, value]) => {
835
+ params.append(key, value.toString());
836
+ });
837
+ }
838
+
839
+ const res = await this.client.get(`/api/files/list/${userId}?${params.toString()}`);
840
+ return res.data;
841
+ } catch (error) {
842
+ throw this.handleError(error);
843
+ }
844
+ }
845
+
846
+ /**
847
+ * Download file content
848
+ */
849
+ async downloadFileContent(fileId: string): Promise<Response> {
850
+ try {
851
+ const res = await this.client.get(`/api/files/${fileId}`, {
852
+ responseType: 'blob'
853
+ });
854
+ return res.data;
855
+ } catch (error) {
856
+ throw this.handleError(error);
857
+ }
858
+ }
859
+
860
+ /**
861
+ * Get file content as text
862
+ */
863
+ async getFileContentAsText(fileId: string): Promise<string> {
864
+ try {
865
+ const res = await this.client.get(`/api/files/${fileId}`, {
866
+ headers: {
867
+ 'Accept': 'text/plain'
868
+ }
869
+ });
870
+ return res.data;
871
+ } catch (error) {
872
+ throw this.handleError(error);
873
+ }
874
+ }
875
+
876
+ /**
877
+ * Get file content as blob
878
+ */
879
+ async getFileContentAsBlob(fileId: string): Promise<Blob> {
880
+ try {
881
+ const res = await this.client.get(`/api/files/${fileId}`, {
882
+ responseType: 'blob'
883
+ });
884
+ return res.data;
885
+ } catch (error) {
886
+ throw this.handleError(error);
887
+ }
888
+ }
889
+
890
+ // ============================================================================
891
+ // LOCATION METHODS
892
+ // ============================================================================
893
+
894
+ /**
895
+ * Update user location
896
+ */
897
+ async updateLocation(latitude: number, longitude: number): Promise<any> {
898
+ try {
899
+ const res = await this.client.post('/api/location', {
900
+ latitude,
901
+ longitude
902
+ });
903
+ return res.data;
904
+ } catch (error) {
905
+ throw this.handleError(error);
906
+ }
907
+ }
908
+
909
+ /**
910
+ * Get nearby users
911
+ */
912
+ async getNearbyUsers(radius?: number): Promise<any[]> {
913
+ try {
914
+ const params = radius ? `?radius=${radius}` : '';
915
+ const res = await this.client.get(`/api/location/nearby${params}`);
916
+ return res.data;
917
+ } catch (error) {
918
+ throw this.handleError(error);
919
+ }
920
+ }
921
+
922
+ // ============================================================================
923
+ // ANALYTICS METHODS
924
+ // ============================================================================
925
+
926
+ /**
927
+ * Track event
928
+ */
929
+ async trackEvent(eventName: string, properties?: Record<string, any>): Promise<void> {
930
+ try {
931
+ await this.client.post('/api/analytics/events', {
932
+ event: eventName,
933
+ properties
934
+ });
935
+ } catch (error) {
936
+ throw this.handleError(error);
937
+ }
938
+ }
939
+
940
+ /**
941
+ * Get analytics data
942
+ */
943
+ async getAnalytics(startDate?: string, endDate?: string): Promise<any> {
944
+ try {
945
+ const params = new URLSearchParams();
946
+ if (startDate) params.append('startDate', startDate);
947
+ if (endDate) params.append('endDate', endDate);
948
+
949
+ const res = await this.client.get(`/api/analytics?${params.toString()}`);
950
+ return res.data;
951
+ } catch (error) {
952
+ throw this.handleError(error);
953
+ }
954
+ }
955
+
956
+ // ============================================================================
957
+ // DEVICE METHODS
958
+ // ============================================================================
959
+
960
+ /**
961
+ * Register device
962
+ */
963
+ async registerDevice(deviceData: any): Promise<any> {
964
+ try {
965
+ const res = await this.client.post('/api/devices', deviceData);
966
+ return res.data;
967
+ } catch (error) {
968
+ throw this.handleError(error);
969
+ }
970
+ }
971
+
972
+ /**
973
+ * Get user devices
974
+ */
975
+ async getUserDevices(): Promise<any[]> {
976
+ try {
977
+ const res = await this.client.get('/api/devices');
978
+ return res.data;
979
+ } catch (error) {
980
+ throw this.handleError(error);
981
+ }
982
+ }
983
+
984
+ /**
985
+ * Remove device
986
+ */
987
+ async removeDevice(deviceId: string): Promise<void> {
988
+ try {
989
+ await this.client.delete(`/api/devices/${deviceId}`);
990
+ } catch (error) {
991
+ throw this.handleError(error);
992
+ }
993
+ }
994
+
995
+ /**
996
+ * Get device sessions
997
+ */
998
+ async getDeviceSessions(sessionId: string): Promise<any[]> {
999
+ try {
1000
+ const res = await this.client.get(`/api/devices/sessions/${sessionId}`);
1001
+ return res.data;
1002
+ } catch (error) {
1003
+ throw this.handleError(error);
1004
+ }
1005
+ }
1006
+
1007
+ /**
1008
+ * Logout all device sessions
1009
+ */
1010
+ async logoutAllDeviceSessions(sessionId: string, deviceId?: string, excludeCurrent?: boolean): Promise<any> {
1011
+ try {
1012
+ const params = new URLSearchParams();
1013
+ if (deviceId) params.append('deviceId', deviceId);
1014
+ if (excludeCurrent) params.append('excludeCurrent', 'true');
1015
+
1016
+ const res = await this.client.post(`/api/devices/logout-all/${sessionId}?${params.toString()}`);
1017
+ return res.data;
1018
+ } catch (error) {
1019
+ throw this.handleError(error);
1020
+ }
1021
+ }
1022
+
1023
+ /**
1024
+ * Update device name
1025
+ */
1026
+ async updateDeviceName(sessionId: string, deviceName: string): Promise<any> {
1027
+ try {
1028
+ const res = await this.client.put(`/api/devices/name/${sessionId}`, { deviceName });
1029
+ return res.data;
1030
+ } catch (error) {
1031
+ throw this.handleError(error);
1032
+ }
1033
+ }
1034
+
1035
+ // ============================================================================
1036
+ // UTILITY METHODS
1037
+ // ============================================================================
1038
+
1039
+ /**
1040
+ * Fetch link metadata
1041
+ */
1042
+ async fetchLinkMetadata(url: string): Promise<{
1043
+ url: string;
1044
+ title: string;
1045
+ description: string;
1046
+ image?: string;
215
1047
  }> {
216
1048
  try {
217
- const res = await this.client.get('/health');
1049
+ const res = await this.client.get(`/api/link-metadata?url=${encodeURIComponent(url)}`);
218
1050
  return res.data;
219
1051
  } catch (error) {
220
1052
  throw this.handleError(error);
@@ -357,4 +1189,7 @@ export class OxyServices {
357
1189
  }
358
1190
  };
359
1191
  }
360
- }
1192
+ }
1193
+
1194
+ // Export the cloud URL constant
1195
+ export const OXY_CLOUD_URL = 'https://cloud.oxyhq.com';