@explorins/pers-sdk 1.2.3 → 1.2.4

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 (85) hide show
  1. package/dist/auth-admin/api/auth-admin-api.d.ts +3 -2
  2. package/dist/auth-admin/api/auth-admin-api.d.ts.map +1 -1
  3. package/dist/auth-admin.cjs +7 -3
  4. package/dist/auth-admin.cjs.map +1 -1
  5. package/dist/auth-admin.js +7 -3
  6. package/dist/auth-admin.js.map +1 -1
  7. package/dist/business/api/business-api.d.ts +17 -32
  8. package/dist/business/api/business-api.d.ts.map +1 -1
  9. package/dist/business.cjs +26 -50
  10. package/dist/business.cjs.map +1 -1
  11. package/dist/business.js +26 -50
  12. package/dist/business.js.map +1 -1
  13. package/dist/campaign/api/campaign-api.d.ts +47 -30
  14. package/dist/campaign/api/campaign-api.d.ts.map +1 -1
  15. package/dist/campaign/index.d.ts +5 -5
  16. package/dist/campaign/services/campaign-service.d.ts +6 -6
  17. package/dist/campaign/services/campaign-service.d.ts.map +1 -1
  18. package/dist/campaign.cjs +62 -41
  19. package/dist/campaign.cjs.map +1 -1
  20. package/dist/campaign.js +62 -41
  21. package/dist/campaign.js.map +1 -1
  22. package/dist/index.cjs +719 -439
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.js +718 -440
  25. package/dist/index.js.map +1 -1
  26. package/dist/package.json +1 -1
  27. package/dist/redemption/api/redemption-api.d.ts +58 -14
  28. package/dist/redemption/api/redemption-api.d.ts.map +1 -1
  29. package/dist/redemption/index.d.ts +2 -2
  30. package/dist/redemption/models/index.d.ts +1 -1
  31. package/dist/redemption/models/index.d.ts.map +1 -1
  32. package/dist/redemption/services/redemption-service.d.ts +3 -3
  33. package/dist/redemption/services/redemption-service.d.ts.map +1 -1
  34. package/dist/redemption.cjs +89 -15
  35. package/dist/redemption.cjs.map +1 -1
  36. package/dist/redemption.js +89 -15
  37. package/dist/redemption.js.map +1 -1
  38. package/dist/shared/interfaces/pers-shared-lib.interfaces.d.ts +3 -3
  39. package/dist/shared/interfaces/pers-shared-lib.interfaces.d.ts.map +1 -1
  40. package/dist/transaction/api/transaction-api.d.ts +23 -19
  41. package/dist/transaction/api/transaction-api.d.ts.map +1 -1
  42. package/dist/transaction/index.d.ts +3 -7
  43. package/dist/transaction/index.d.ts.map +1 -1
  44. package/dist/transaction/models/index.d.ts +0 -1
  45. package/dist/transaction/models/index.d.ts.map +1 -1
  46. package/dist/transaction/services/transaction-service.d.ts +5 -7
  47. package/dist/transaction/services/transaction-service.d.ts.map +1 -1
  48. package/dist/transaction.cjs +85 -50
  49. package/dist/transaction.cjs.map +1 -1
  50. package/dist/transaction.js +85 -50
  51. package/dist/transaction.js.map +1 -1
  52. package/dist/web3/application/index.d.ts +6 -0
  53. package/dist/web3/application/index.d.ts.map +1 -0
  54. package/dist/web3/application/web3-application.service.d.ts +53 -0
  55. package/dist/web3/application/web3-application.service.d.ts.map +1 -0
  56. package/dist/web3/domain/models/index.d.ts +58 -0
  57. package/dist/web3/domain/models/index.d.ts.map +1 -0
  58. package/dist/web3/domain/services/contract-domain.service.d.ts +20 -0
  59. package/dist/web3/domain/services/contract-domain.service.d.ts.map +1 -0
  60. package/dist/web3/domain/services/index.d.ts +8 -0
  61. package/dist/web3/domain/services/index.d.ts.map +1 -0
  62. package/dist/web3/domain/services/metadata-domain.service.d.ts +12 -0
  63. package/dist/web3/domain/services/metadata-domain.service.d.ts.map +1 -0
  64. package/dist/web3/domain/services/token-domain.service.d.ts +48 -0
  65. package/dist/web3/domain/services/token-domain.service.d.ts.map +1 -0
  66. package/dist/web3/index.d.ts +10 -11
  67. package/dist/web3/index.d.ts.map +1 -1
  68. package/dist/web3/infrastructure/api/index.d.ts +6 -0
  69. package/dist/web3/infrastructure/api/index.d.ts.map +1 -0
  70. package/dist/web3/infrastructure/api/ipfs-api.d.ts +15 -0
  71. package/dist/web3/infrastructure/api/ipfs-api.d.ts.map +1 -0
  72. package/dist/web3/{api → infrastructure/api}/web3-api.d.ts +6 -2
  73. package/dist/web3/infrastructure/api/web3-api.d.ts.map +1 -0
  74. package/dist/web3/infrastructure/index.d.ts +2 -0
  75. package/dist/web3/infrastructure/index.d.ts.map +1 -0
  76. package/dist/web3.cjs +509 -336
  77. package/dist/web3.cjs.map +1 -1
  78. package/dist/web3.js +507 -336
  79. package/dist/web3.js.map +1 -1
  80. package/package.json +1 -1
  81. package/dist/web3/api/web3-api.d.ts.map +0 -1
  82. package/dist/web3/models/index.d.ts +0 -92
  83. package/dist/web3/models/index.d.ts.map +0 -1
  84. package/dist/web3/services/web3-service.d.ts +0 -21
  85. package/dist/web3/services/web3-service.d.ts.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var persShared = require('@explorins/pers-shared');
3
4
  var jwtDecode = require('jwt-decode');
4
5
  var Web3 = require('web3');
5
6
  var ethers = require('ethers');
@@ -503,13 +504,15 @@ function createPersSDK(httpClient, config) {
503
504
  /**
504
505
  * Platform-Agnostic Business API Client
505
506
  *
506
- * Updated to match the new RESTful /businesses endpoints.
507
- * Uses @explorins/pers-shared DTOs for full type safety and consistency with backend.
507
+ * Updated to match the actual RESTful endpoints:
508
+ * - /businesses for business operations
509
+ * - /business-types for business type operations (separate controller)
508
510
  */
509
511
  class BusinessApi {
510
512
  constructor(apiClient) {
511
513
  this.apiClient = apiClient;
512
514
  this.basePath = '/businesses';
515
+ this.businessTypesPath = '/business-types'; // ✅ FIX: Separate controller
513
516
  }
514
517
  // ==========================================
515
518
  // 🌐 BUSINESS TYPES MANAGEMENT
@@ -517,38 +520,38 @@ class BusinessApi {
517
520
  /**
518
521
  * Get all business types (project key required)
519
522
  *
520
- * Endpoint: GET /businesses/types
523
+ * Endpoint: GET /business-types
521
524
  * Auth: @ApiSecurity('projectKey')
522
525
  */
523
526
  async getAllBusinessTypes() {
524
- return this.apiClient.get(`${this.basePath}/types`);
527
+ return this.apiClient.get(this.businessTypesPath); // ✅ FIX: Correct path
525
528
  }
526
529
  /**
527
530
  * ADMIN: Create business type
528
531
  *
529
- * Endpoint: POST /businesses/types
532
+ * Endpoint: POST /business-types
530
533
  * Auth: @TenantAdmin()
531
534
  */
532
535
  async createBusinessType(dto) {
533
- return this.apiClient.post(`${this.basePath}/types`, dto);
536
+ return this.apiClient.post(this.businessTypesPath, dto); // ✅ FIX: Correct path
534
537
  }
535
538
  /**
536
539
  * ADMIN: Update business type
537
540
  *
538
- * Endpoint: PUT /businesses/types
541
+ * Endpoint: PUT /business-types
539
542
  * Auth: @TenantAdmin()
540
543
  */
541
544
  async updateBusinessType(dto) {
542
- return this.apiClient.put(`${this.basePath}/types`, dto);
545
+ return this.apiClient.put(this.businessTypesPath, dto); // ✅ FIX: Correct path
543
546
  }
544
547
  /**
545
548
  * ADMIN: Delete business type
546
549
  *
547
- * Endpoint: DELETE /businesses/types/{id}
550
+ * Endpoint: DELETE /business-types/{id}
548
551
  * Auth: @TenantAdmin()
549
552
  */
550
553
  async deleteBusinessType(id) {
551
- return this.apiClient.delete(`${this.basePath}/types/${id}`);
554
+ return this.apiClient.delete(`${this.businessTypesPath}/${id}`); // ✅ FIX: Correct path
552
555
  }
553
556
  // ==========================================
554
557
  // 🏢 BUSINESS MANAGEMENT
@@ -563,20 +566,13 @@ class BusinessApi {
563
566
  return this.apiClient.get(`${this.basePath}/me`);
564
567
  }
565
568
  /**
566
- * Get all active businesses (project key required)
567
- *
568
- * Endpoint: GET /businesses
569
- * Auth: @ApiSecurity('projectKey')
570
- * Note: Regular users automatically get active businesses only
571
- */
572
- async getActiveBusinesses() {
573
- return this.apiClient.get(`${this.basePath}`);
574
- }
575
- /**
576
- * Get all businesses with filtering (admin users can access inactive)
569
+ * Get all businesses with role-based filtering
577
570
  *
578
571
  * Endpoint: GET /businesses?active={boolean}&sanitize={mode}
579
572
  * Auth: @ApiSecurity('projectKey') (enhanced with role-based filtering)
573
+ * Note:
574
+ * - Project API Key users: Active businesses only (automatically filtered)
575
+ * - Admin JWT users: Full access with all query parameters
580
576
  */
581
577
  async getAllBusinesses(options) {
582
578
  const params = new URLSearchParams();
@@ -591,23 +587,16 @@ class BusinessApi {
591
587
  return this.apiClient.get(url);
592
588
  }
593
589
  /**
594
- * ADMIN: Get all businesses (admin endpoint with full access)
590
+ * Get all active businesses (convenience method)
595
591
  *
596
- * Endpoint: GET /businesses/admin
597
- * Auth: @TenantAdmin()
592
+ * Endpoint: GET /businesses
593
+ * Auth: @ApiSecurity('projectKey')
598
594
  */
599
- async getAllBusinessesAdmin(options) {
600
- const params = new URLSearchParams();
601
- if (options?.active !== undefined) {
602
- params.append('active', String(options.active));
603
- }
604
- if (options?.sanitize) {
605
- params.append('sanitize', options.sanitize);
606
- }
607
- const queryString = params.toString();
608
- const url = queryString ? `${this.basePath}?${queryString}` : this.basePath;
609
- return this.apiClient.get(url);
595
+ async getActiveBusinesses() {
596
+ return this.apiClient.get(this.basePath);
610
597
  }
598
+ // ✅ REMOVED: getAllBusinessesAdmin() - No separate /admin endpoint exists
599
+ // The unified endpoint handles role-based access automatically
611
600
  /**
612
601
  * Get business by ID
613
602
  *
@@ -637,18 +626,15 @@ class BusinessApi {
637
626
  * Returns: BusinessApiKeyDTO | BusinessTokenBalancesDTO
638
627
  */
639
628
  async createBusiness(dto) {
640
- return this.apiClient.post(`${this.basePath}`, dto);
629
+ return this.apiClient.post(this.basePath, dto);
641
630
  }
642
631
  /**
643
632
  * ADMIN: Create business by display name (convenience method)
644
- *
645
- * This is a convenience wrapper that creates the proper DTO structure
646
633
  */
647
634
  async createBusinessByDisplayName(displayName) {
648
635
  const dto = {
649
636
  displayName,
650
637
  // Add other required fields based on BusinessCreateRequestDTO structure
651
- // You may need to check the DTO definition for required fields
652
638
  };
653
639
  return this.createBusiness(dto);
654
640
  }
@@ -673,21 +659,12 @@ class BusinessApi {
673
659
  /**
674
660
  * ADMIN: Toggle business active status
675
661
  *
676
- * Endpoint: PUT /businesses/{id}/activate
662
+ * Endpoint: PUT /businesses/{id}/status
677
663
  * Auth: @TenantAdmin()
678
664
  */
679
665
  async toggleBusinessActive(id, isActive) {
680
666
  const dto = { isActive };
681
- return this.apiClient.put(`${this.basePath}/${id}/status`, dto);
682
- }
683
- /**
684
- * ADMIN: Generate new business API key
685
- *
686
- * Endpoint: PUT /businesses/{id}/api-key
687
- * Auth: @TenantAdmin()
688
- */
689
- async generateNewBusinessApiKey(id) {
690
- return this.apiClient.put(`${this.basePath}/${id}/api-key`, {});
667
+ return this.apiClient.put(`${this.basePath}/${id}/status`, dto); // ✅ FIX: Correct endpoint
691
668
  }
692
669
  }
693
670
 
@@ -823,6 +800,15 @@ class TransactionApi {
823
800
  async getTransactionById(transactionId) {
824
801
  return this.apiClient.get(`${this.basePath}/${transactionId}`);
825
802
  }
803
+ /**
804
+ * Unique method to create a transaction
805
+ * @param request
806
+ * @returns
807
+ */
808
+ async createTransaction(request) {
809
+ return this.apiClient.post(`${this.basePath}`, request);
810
+ // return this.apiClient.post<TransactionDTO>(`${this.basePath}/system`, request);
811
+ }
826
812
  // ==========================================
827
813
  // AUTHENTICATED USER OPERATIONS
828
814
  // ==========================================
@@ -831,9 +817,9 @@ class TransactionApi {
831
817
  *
832
818
  * UPDATED: /transaction/auth/transaction → /transactions/user
833
819
  */
834
- async createAuthTransaction(request) {
835
- return this.apiClient.post(`${this.basePath}/user`, request);
836
- }
820
+ /* async createAuthTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
821
+ return this.apiClient.post<TransactionRequestResponseDTO>(`${this.basePath}`, request);
822
+ } */
837
823
  /**
838
824
  * AUTH: Get user's sent transactions
839
825
  *
@@ -878,14 +864,6 @@ class TransactionApi {
878
864
  return this.apiClient.get(`${this.basePath}/me/sent?${params.toString()}`);
879
865
  }
880
866
  }
881
- /**
882
- * AUTH: Prepare client signed transaction
883
- *
884
- * UPDATED: /transaction/auth/prepare-signing → /transactions/prepare
885
- */
886
- async prepareClientSignedTransaction(request) {
887
- return this.apiClient.post(`${this.basePath}/prepare`, request);
888
- }
889
867
  /**
890
868
  * AUTH: Prepare existing transaction for client-side signing
891
869
  *
@@ -899,8 +877,8 @@ class TransactionApi {
899
877
  *
900
878
  * NEW ENDPOINT: POST /transactions/{id}/submit
901
879
  */
902
- async submitSignedTransaction(transactionId, signedData) {
903
- return this.apiClient.post(`${this.basePath}/${transactionId}/submit`, signedData);
880
+ async submitSignedTransaction(signedTxData) {
881
+ return this.apiClient.post(`${this.basePath}/submit`, signedTxData);
904
882
  }
905
883
  /**
906
884
  * AUTH: Burn user tokens
@@ -908,14 +886,15 @@ class TransactionApi {
908
886
  * UPDATED: Uses new user transaction endpoint with burn-specific parameters
909
887
  * Note: This might need backend confirmation on burn functionality implementation
910
888
  */
911
- async burnUserTokens(request) {
912
- // Map burn request to TransactionRequestDTO format for new endpoint
913
- const transactionRequest = {
914
- ...request,
915
- // Add any specific burn transaction parameters here
916
- };
917
- return this.apiClient.post(`${this.basePath}/user`, transactionRequest);
918
- }
889
+ /* async burnUserTokens(request: UserBurnTokenRequestDTO): Promise<TransactionRequestResponseDTO> {
890
+ // Map burn request to TransactionRequestDTO format for new endpoint
891
+ const transactionRequest: TransactionRequestDTO = {
892
+ ...request,
893
+ // Add any specific burn transaction parameters here
894
+ } as any;
895
+
896
+ return this.apiClient.post<TransactionRequestResponseDTO>(`${this.basePath}`, transactionRequest);
897
+ } */
919
898
  // ==========================================
920
899
  // BUSINESS OPERATIONS
921
900
  // ==========================================
@@ -924,9 +903,9 @@ class TransactionApi {
924
903
  *
925
904
  * UPDATED: /transaction/business/transaction → /transactions/business
926
905
  */
927
- async createBusinessTransaction(request) {
928
- return this.apiClient.post(`${this.basePath}/business`, request);
929
- }
906
+ /* async createBusinessTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
907
+ return this.apiClient.post<TransactionRequestResponseDTO>(`${this.basePath}`, request);
908
+ } */
930
909
  // ==========================================
931
910
  // ADMIN OPERATIONS
932
911
  // ==========================================
@@ -935,8 +914,17 @@ class TransactionApi {
935
914
  *
936
915
  * UPDATED: /transaction/admin/transaction → /transactions/admin
937
916
  */
938
- async createAdminTransaction(request) {
939
- return this.apiClient.post(`${this.basePath}/system`, request);
917
+ /* async createAdminTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
918
+ // return this.apiClient.post<TransactionRequestResponseDTO>(`${this.basePath}`, request);
919
+ return this.apiClient.post<TransactionDTO>(`${this.basePath}/system`, request);
920
+ } */
921
+ /**
922
+ * AUTH: Prepare client signed transaction
923
+ *
924
+ * UPDATED: /transaction/auth/prepare-signing → /transactions/prepare
925
+ */
926
+ async prepareClientSignedTransaction(request) {
927
+ return this.apiClient.post(`${this.basePath}`, request);
940
928
  }
941
929
  /**
942
930
  * ADMIN: Get all tenant transactions
@@ -1015,16 +1003,31 @@ class TransactionApi {
1015
1003
  *
1016
1004
  * NEW ENDPOINT: POST /transactions/query-sender
1017
1005
  */
1006
+ /**
1007
+ * Query transactions by sender using unified endpoint
1008
+ */
1018
1009
  async queryTransactionsBySender(accountSelector) {
1019
- return this.apiClient.post(`${this.basePath}/query-sender`, accountSelector);
1010
+ // Build query parameters safely
1011
+ const queryParams = {};
1012
+ if (accountSelector.accountId) {
1013
+ queryParams['participantId'] = accountSelector.accountId;
1014
+ }
1015
+ queryParams['role'] = persShared.TransactionRole.SENDER.toString();
1016
+ const params = new URLSearchParams(queryParams);
1017
+ return this.apiClient.get(`${this.basePath}?${params.toString()}`).then(response => response); // Extract items from paginated response
1020
1018
  }
1021
1019
  /**
1022
- * ADMIN: Query transactions by recipient
1023
- *
1024
- * NEW ENDPOINT: POST /transactions/query-recipient
1020
+ * Query transactions by recipient using unified endpoint
1025
1021
  */
1026
1022
  async queryTransactionsByRecipient(accountSelector) {
1027
- return this.apiClient.post(`${this.basePath}/query-recipient`, accountSelector);
1023
+ // Build query parameters safely
1024
+ const queryParams = {};
1025
+ if (accountSelector.accountId) {
1026
+ queryParams['participantId'] = accountSelector.accountId;
1027
+ }
1028
+ queryParams['role'] = persShared.TransactionRole.RECIPIENT.toString();
1029
+ const params = new URLSearchParams(queryParams);
1030
+ return this.apiClient.get(`${this.basePath}?${params.toString()}`).then(response => response); // Extract items from paginated response
1028
1031
  }
1029
1032
  /**
1030
1033
  * ADMIN: Get transaction analytics
@@ -1075,8 +1078,14 @@ class TransactionService {
1075
1078
  /**
1076
1079
  * AUTH: Create authenticated transaction
1077
1080
  */
1078
- async createAuthTransaction(request) {
1079
- return this.transactionApi.createAuthTransaction(request);
1081
+ /* async createAuthTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
1082
+ return this.transactionApi.createAuthTransaction(request);
1083
+ } */
1084
+ async createTransaction(request) {
1085
+ return this.transactionApi.createTransaction(request);
1086
+ }
1087
+ async submitSignedTransaction(signedTxData) {
1088
+ return this.transactionApi.submitSignedTransaction(signedTxData);
1080
1089
  }
1081
1090
  /**
1082
1091
  * AUTH: Get user transaction history by type
@@ -1087,33 +1096,33 @@ class TransactionService {
1087
1096
  /**
1088
1097
  * AUTH: Prepare client signed transaction
1089
1098
  */
1090
- async prepareClientSignedTransaction(request) {
1091
- return this.transactionApi.prepareClientSignedTransaction(request);
1092
- }
1099
+ /* async prepareClientSignedTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
1100
+ return this.transactionApi.prepareClientSignedTransaction(request);
1101
+ } */
1093
1102
  /**
1094
1103
  * AUTH: Burn user tokens
1095
1104
  */
1096
- async burnUserTokens(request) {
1097
- return this.transactionApi.burnUserTokens(request);
1098
- }
1105
+ /* async burnUserTokens(request: UserBurnTokenRequestDTO): Promise<TransactionRequestResponseDTO> {
1106
+ return this.transactionApi.burnUserTokens(request);
1107
+ } */
1099
1108
  // ==========================================
1100
1109
  // BUSINESS OPERATIONS
1101
1110
  // ==========================================
1102
1111
  /**
1103
1112
  * BUSINESS: Create business transaction
1104
1113
  */
1105
- async createBusinessTransaction(request) {
1106
- return this.transactionApi.createBusinessTransaction(request);
1107
- }
1114
+ /* async createBusinessTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
1115
+ return this.transactionApi.createBusinessTransaction(request);
1116
+ } */
1108
1117
  // ==========================================
1109
1118
  // ADMIN OPERATIONS
1110
1119
  // ==========================================
1111
1120
  /**
1112
1121
  * ADMIN: Create admin transaction
1113
1122
  */
1114
- async createAdminTransaction(request) {
1115
- return this.transactionApi.createAdminTransaction(request);
1116
- }
1123
+ /* async createAdminTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
1124
+ return this.transactionApi.createAdminTransaction(request);
1125
+ } */
1117
1126
  /**
1118
1127
  * ADMIN: Get all tenant transactions
1119
1128
  */
@@ -1167,15 +1176,16 @@ function createTransactionSDK(apiClient) {
1167
1176
  // Direct access to service methods (primary interface)
1168
1177
  // Public methods
1169
1178
  getTransactionById: (transactionId) => transactionService.getTransactionById(transactionId),
1179
+ createTransaction: (request) => transactionService.createTransaction(request),
1170
1180
  // Auth methods
1171
- createAuthTransaction: (request) => transactionService.createAuthTransaction(request),
1181
+ // createAuthTransaction: (request: TransactionRequestDTO) => transactionService.createAuthTransaction(request),
1172
1182
  getUserTransactionHistory: (type) => transactionService.getUserTransactionHistory(type),
1173
- prepareClientSignedTransaction: (request) => transactionService.prepareClientSignedTransaction(request),
1174
- burnUserTokens: (request) => transactionService.burnUserTokens(request),
1183
+ //prepareClientSignedTransaction: (request: TransactionRequestDTO) => transactionService.prepareClientSignedTransaction(request),
1184
+ // burnUserTokens: (request: UserBurnTokenRequestDTO) => transactionService.burnUserTokens(request),
1175
1185
  // Business methods
1176
- createBusinessTransaction: (request) => transactionService.createBusinessTransaction(request),
1186
+ // createBusinessTransaction: (request: TransactionRequestDTO) => transactionService.createBusinessTransaction(request),
1177
1187
  // Admin methods
1178
- createAdminTransaction: (request) => transactionService.createAdminTransaction(request),
1188
+ // createAdminTransaction: (request: TransactionRequestDTO) => transactionService.createAdminTransaction(request),
1179
1189
  getTenantTransactions: () => transactionService.getTenantTransactions(),
1180
1190
  getPaginatedTransactions: (params) => transactionService.getPaginatedTransactions(params),
1181
1191
  exportTransactionsCSV: () => transactionService.exportTransactionsCSV(),
@@ -1277,9 +1287,11 @@ class AuthAdminApi {
1277
1287
  * Note: JWT handling and auth bypass headers may need special implementation
1278
1288
  */
1279
1289
  async loginTenantAdmin(jwt) {
1280
- // TODO: Implement proper JWT and bypass header handling when PersApiClient supports it
1281
- const requestBody = { authToken: jwt };
1282
- return this.apiClient.post(`${this.basePath}/token`, requestBody);
1290
+ const body = {
1291
+ authToken: jwt,
1292
+ authType: persShared.AccountOwnerType.TENANT
1293
+ };
1294
+ return this.apiClient.post(`${this.basePath}/token`, body);
1283
1295
  }
1284
1296
  /**
1285
1297
  * ADMIN: Refresh access token
@@ -1588,81 +1600,102 @@ class CampaignApi {
1588
1600
  * NEW: POST /campaign-claims/user
1589
1601
  */
1590
1602
  async claimCampaign(request) {
1591
- return this.apiClient.post('/campaign-claims/user', request);
1603
+ return this.apiClient.post('/campaign-claims', request);
1592
1604
  }
1593
1605
  /**
1594
1606
  * USER: Get claims for logged user
1595
1607
  * NEW: GET /campaign-claims/users/me
1596
1608
  */
1597
1609
  async getClaimsForLoggedUser() {
1598
- return this.apiClient.get('/campaign-claims/users/me');
1610
+ return this.apiClient.get('/campaign-claims/me');
1599
1611
  }
1600
1612
  /**
1601
- * BUSINESS: Claim campaign reward for customer
1602
- * NEW: POST /campaign-claims/business
1603
- */
1604
- async businessClaimCampaign(request) {
1605
- return this.apiClient.post('/campaign-claims/business', request);
1613
+ * ADMIN: Get all campaign claims
1614
+ * Updated to use unified endpoint
1615
+ */
1616
+ async getCampaignClaims() {
1617
+ // Admin context - no parameters needed for all claims
1618
+ return this.apiClient.get('/campaign-claims');
1606
1619
  }
1607
1620
  /**
1608
- * SYSTEM: Process automated claim
1609
- * NEW: POST /campaign-claims/system
1621
+ * ADMIN: Get campaign claims by campaign ID
1622
+ * Updated to use query parameters
1610
1623
  */
1611
- async systemClaimCampaign(request) {
1612
- return this.apiClient.post('/campaign-claims/system', request);
1624
+ async getCampaignClaimsByCampaignId(campaignId) {
1625
+ return this.apiClient.get(`/campaign-claims?campaignId=${campaignId}`);
1613
1626
  }
1614
1627
  /**
1615
- * ADMIN: Manual claim processing
1616
- * NEW: POST /campaign-claims/admin
1628
+ * ADMIN: Get campaign claims by user ID
1629
+ * Updated to use query parameters
1617
1630
  */
1618
- async adminClaimCampaign(request) {
1619
- return this.apiClient.post('/campaign-claims/admin', request);
1631
+ async getCampaignClaimsByUserId(userId) {
1632
+ return this.apiClient.get(`/campaign-claims?userId=${userId}`);
1620
1633
  }
1621
1634
  /**
1622
- * ADMIN: Get all campaign claims
1623
- * NEW: GET /campaign-claims/admin
1635
+ * ADMIN: Get campaign claims by business ID
1636
+ * Updated to use query parameters
1624
1637
  */
1625
- async getCampaignClaims() {
1626
- return this.apiClient.get('/campaign-claims/admin');
1638
+ async getCampaignClaimsByBusinessId(businessId) {
1639
+ return this.apiClient.get(`/campaign-claims?businessId=${businessId}`);
1627
1640
  }
1628
1641
  /**
1629
- * ADMIN: Get campaign claims by campaign ID
1630
- * NEW: GET /campaign-claims/admin/{campaignId}
1642
+ * ADMIN: Get campaign claims by user ID for specific campaign
1643
+ * Combined filtering using query parameters
1631
1644
  */
1632
- async getCampaignClaimsByCampaignId(campaignId) {
1633
- return this.apiClient.get(`/campaign-claims/admin/${campaignId}`);
1645
+ async getCampaignClaimsByUserAndCampaign(userId, campaignId) {
1646
+ return this.apiClient.get(`/campaign-claims?userId=${userId}&campaignId=${campaignId}`);
1634
1647
  }
1635
1648
  /**
1636
- * ADMIN: Get campaign claims by user ID
1637
- * NEW: GET /campaign-claims/admin/users/{userId}
1649
+ * ADMIN: Get campaign claims by business ID for specific campaign
1650
+ * Combined filtering using query parameters
1638
1651
  */
1639
- async getCampaignClaimsByUserId(userId) {
1640
- return this.apiClient.get(`/campaign-claims/admin/users/${userId}`);
1652
+ async getCampaignClaimsByBusinessAndCampaign(businessId, campaignId) {
1653
+ return this.apiClient.get(`/campaign-claims?businessId=${businessId}&campaignId=${campaignId}`);
1641
1654
  }
1642
1655
  /**
1643
- * ADMIN: Get campaign claims by business ID
1644
- * NEW: GET /campaign-claims/admin/businesses/{businessId}
1656
+ * USER: Get user's own claims (all campaigns)
1657
+ * Use convenience endpoint
1645
1658
  */
1646
- async getCampaignClaimsByBusinessId(businessId) {
1647
- return this.apiClient.get(`/campaign-claims/admin/businesses/${businessId}`);
1659
+ async getUserClaims() {
1660
+ return this.apiClient.get('/campaign-claims/me');
1648
1661
  }
1649
1662
  /**
1650
1663
  * USER: Get user's claims for specific campaign
1651
- * NEW: GET /campaign-claims/campaigns/{campaignId}/users/me
1664
+ * Use convenience endpoint with query parameter
1652
1665
  */
1653
1666
  async getUserClaimsForCampaign(campaignId) {
1654
- return this.apiClient.get(`/campaign-claims/campaigns/${campaignId}/users/me`);
1667
+ return this.apiClient.get(`/campaign-claims/me?campaignId=${campaignId}`);
1668
+ }
1669
+ /**
1670
+ * BUSINESS: Get business claims (all campaigns)
1671
+ * Uses unified endpoint with business context
1672
+ */
1673
+ async getBusinessClaims() {
1674
+ return this.apiClient.get('/campaign-claims');
1675
+ }
1676
+ /**
1677
+ * BUSINESS: Get business claims for specific campaign
1678
+ * Uses unified endpoint with business context and campaign filter
1679
+ */
1680
+ async getBusinessClaimsForCampaign(campaignId) {
1681
+ return this.apiClient.get(`/campaign-claims?campaignId=${campaignId}`);
1682
+ }
1683
+ /**
1684
+ * Helper: Build query string from parameters
1685
+ */
1686
+ buildQueryString(params) {
1687
+ const validParams = Object.entries(params)
1688
+ .filter(([_, value]) => value !== undefined)
1689
+ .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
1690
+ .join('&');
1691
+ return validParams ? `?${validParams}` : '';
1655
1692
  }
1656
- // ==========================================
1657
- // BACKWARD COMPATIBILITY (DEPRECATED)
1658
- // ==========================================
1659
1693
  /**
1660
- * @deprecated Use getCampaigns() instead
1661
- * LEGACY: Get campaigns with active filter
1694
+ * Flexible admin claims query with multiple filters
1662
1695
  */
1663
- async getCampaignsLegacy(active) {
1664
- console.warn('CampaignApi.getCampaignsLegacy() is deprecated. Use getCampaigns() instead.');
1665
- return this.getCampaigns(active !== undefined ? { active } : undefined);
1696
+ async getAdminClaims(filters) {
1697
+ const queryString = this.buildQueryString(filters || {});
1698
+ return this.apiClient.get(`/campaign-claims${queryString}`);
1666
1699
  }
1667
1700
  }
1668
1701
 
@@ -2173,20 +2206,21 @@ function createPaymentSDK(apiClient) {
2173
2206
  /**
2174
2207
  * Platform-Agnostic Redemption API Client (UPDATED - RESTful Design)
2175
2208
  *
2176
- * Updated to work with the new RESTful /redemptions endpoints.
2209
+ * Updated to work with the new RESTful /redemptions and /redemption-redeems endpoints.
2177
2210
  * Handles redemption operations using the PERS backend with intelligent access detection.
2178
2211
  * Uses @explorins/pers-shared DTOs for consistency with backend.
2179
2212
  *
2180
- * Migration Update: Updated all endpoints from /redemption to /redemptions
2213
+ * Migration Update: Updated all endpoints for unified controller pattern
2181
2214
  * - Removed role revelation from URLs (no more /admin, /auth paths)
2182
2215
  * - Added intelligent access detection for unified endpoints
2183
- * - Updated toggle endpoint to follow /status pattern
2184
- * - Enhanced redemption process with path-based IDs
2216
+ * - Added new /redemption-redeems endpoints for redeem processing
2217
+ * - Enhanced redemption process with role-based access control
2185
2218
  */
2186
2219
  class RedemptionApi {
2187
2220
  constructor(apiClient) {
2188
2221
  this.apiClient = apiClient;
2189
2222
  this.basePath = '/redemptions';
2223
+ this.redeemsPath = '/redemption-redeems';
2190
2224
  }
2191
2225
  // ==========================================
2192
2226
  // PUBLIC OPERATIONS (Project Key)
@@ -2221,7 +2255,7 @@ class RedemptionApi {
2221
2255
  * Updated: /redemption/type → /redemptions/types
2222
2256
  */
2223
2257
  async getRedemptionTypes() {
2224
- return this.apiClient.get(`${this.basePath}/types`);
2258
+ return this.apiClient.get(`/redemption-types`);
2225
2259
  }
2226
2260
  /**
2227
2261
  * PUBLIC: Get redemption by ID
@@ -2234,33 +2268,106 @@ class RedemptionApi {
2234
2268
  /**
2235
2269
  * PUBLIC: Get available supply for redemption
2236
2270
  *
2237
- * Updated: /redemption/:id/available-supply → /redemptions/:id/available-supply
2271
+ * Updated: /redemption/:id/available-supply → /redemptions/:id/supply
2238
2272
  */
2239
2273
  async getRedemptionAvailableSupply(id) {
2240
- return this.apiClient.get(`${this.basePath}/${id}/available-supply`);
2274
+ return this.apiClient.get(`${this.basePath}/${id}/supply`);
2241
2275
  }
2242
2276
  // ==========================================
2243
- // USER OPERATIONS (JWT + Project Key)
2277
+ // REDEMPTION EXECUTION (NEW UNIFIED ENDPOINT)
2244
2278
  // ==========================================
2245
2279
  /**
2246
- * USER: Redeem a redemption
2280
+ * Execute redemption (unified endpoint)
2247
2281
  *
2248
- * Updated: /redemption/auth/redeem /redemptions/:id/redeem
2249
- * Enhanced: Path-based redemption ID for better RESTful design
2282
+ * NEW: POST /redemption-redeems - Role-based processing
2283
+ * - USER: Direct user redemption processing
2284
+ * - ADMIN: Can process redemptions for any account type
2285
+ * - BUSINESS: Process redemptions for customers
2250
2286
  */
2251
2287
  async redeemRedemption(redemptionId) {
2252
2288
  const body = {
2253
2289
  redemptionId: redemptionId,
2254
2290
  };
2255
- return this.apiClient.post(`${this.basePath}/${redemptionId}/redeem`, body);
2291
+ return this.apiClient.post(this.redeemsPath, body);
2292
+ }
2293
+ // ==========================================
2294
+ // REDEMPTION REDEEMS QUERIES (NEW ENDPOINTS)
2295
+ // ==========================================
2296
+ /**
2297
+ * Get redemption redeems with filtering (unified endpoint)
2298
+ *
2299
+ * NEW: GET /redemption-redeems with query parameters
2300
+ * Role-based access: Users see only their own, admins can filter by userId/businessId
2301
+ */
2302
+ async getRedemptionRedeems(filters) {
2303
+ let url = this.redeemsPath;
2304
+ const params = new URLSearchParams();
2305
+ if (filters?.redemptionId)
2306
+ params.append('redemptionId', filters.redemptionId);
2307
+ if (filters?.userId)
2308
+ params.append('userId', filters.userId);
2309
+ if (filters?.businessId)
2310
+ params.append('businessId', filters.businessId);
2311
+ const queryString = params.toString();
2312
+ if (queryString) {
2313
+ url += `?${queryString}`;
2314
+ }
2315
+ return this.apiClient.get(url);
2316
+ }
2317
+ /**
2318
+ * Get specific redemption redeem by ID
2319
+ *
2320
+ * NEW: GET /redemption-redeems/:id
2321
+ */
2322
+ async getRedemptionRedeemById(id) {
2323
+ return this.apiClient.get(`${this.redeemsPath}/${id}`);
2324
+ }
2325
+ /**
2326
+ * USER: Get my redemption redeems (convenience endpoint)
2327
+ *
2328
+ * NEW: GET /redemption-redeems/me with optional filtering
2329
+ */
2330
+ async getMyRedemptionRedeems(redemptionId) {
2331
+ let url = `${this.redeemsPath}/me`;
2332
+ if (redemptionId) {
2333
+ url += `?redemptionId=${redemptionId}`;
2334
+ }
2335
+ return this.apiClient.get(url);
2336
+ }
2337
+ /**
2338
+ * ADMIN: Get redemption redeems by user ID
2339
+ *
2340
+ * NEW: GET /redemption-redeems?userId=X
2341
+ */
2342
+ async getRedemptionRedeemsByUserId(userId, redemptionId) {
2343
+ return this.getRedemptionRedeems({ userId, redemptionId });
2344
+ }
2345
+ /**
2346
+ * ADMIN: Get redemption redeems by business ID
2347
+ *
2348
+ * NEW: GET /redemption-redeems?businessId=X
2349
+ */
2350
+ async getRedemptionRedeemsByBusinessId(businessId, redemptionId) {
2351
+ return this.getRedemptionRedeems({ businessId, redemptionId });
2256
2352
  }
2353
+ /**
2354
+ * ADMIN: Get redemption redeems by redemption ID
2355
+ *
2356
+ * NEW: GET /redemption-redeems?redemptionId=X
2357
+ */
2358
+ async getRedemptionRedeemsByRedemptionId(redemptionId) {
2359
+ return this.getRedemptionRedeems({ redemptionId });
2360
+ }
2361
+ // ==========================================
2362
+ // USER OPERATIONS (JWT + Project Key)
2363
+ // ==========================================
2257
2364
  /**
2258
2365
  * USER: Get user redemption history
2259
2366
  *
2260
- * Updated: /redemption/auth/redeem /redemptions/me/history
2367
+ * Updated: Uses new convenience endpoint /redemption-redeems/me
2261
2368
  */
2262
2369
  async getUserRedemptionHistory() {
2263
- return this.apiClient.get(`${this.basePath}/me/history`);
2370
+ return this.getMyRedemptionRedeems();
2264
2371
  }
2265
2372
  /**
2266
2373
  * USER: Get user redemptions (backward compatibility)
@@ -2329,7 +2436,7 @@ class RedemptionApi {
2329
2436
  * Updated: /redemption/admin/type → /redemptions/types
2330
2437
  */
2331
2438
  async createRedemptionType(redemptionType) {
2332
- return this.apiClient.post(`${this.basePath}/types`, redemptionType);
2439
+ return this.apiClient.post(`${this.basePath}/redemption-types`, redemptionType);
2333
2440
  }
2334
2441
  // ==========================================
2335
2442
  // TOKEN UNIT MANAGEMENT (Admin)
@@ -4064,311 +4171,445 @@ function createWeb3ChainSDK(apiClient, providerService) {
4064
4171
  };
4065
4172
  }
4066
4173
 
4067
- class Web3Api {
4068
- constructor(web3ChainService) {
4069
- this.web3ChainService = web3ChainService;
4174
+ /**
4175
+ * TokenDomainService - Domain service for token operations
4176
+ * Implements business logic for token balance, metadata, and collection operations
4177
+ */
4178
+ class TokenDomainService {
4179
+ constructor(web3Api, metadataService, contractService) {
4180
+ this.web3Api = web3Api;
4181
+ this.metadataService = metadataService;
4182
+ this.contractService = contractService;
4070
4183
  }
4071
4184
  async getTokenBalance(request) {
4072
- const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
4073
- const tokenContract = web3Ts.getSmartContractInstance(request.contractAddress, request.abi, web3);
4074
- const balance = await web3Ts.getAddressTokenBalanceByContract(tokenContract, request.accountAddress, request.tokenId);
4075
- return Number(balance);
4076
- }
4077
- async getTokenUri(request) {
4078
- const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
4079
- // ✅ DIRECT: Use web3-ts functions directly
4080
- const tokenContract = web3Ts.getSmartContractInstance(request.contractAddress, request.abi, web3);
4081
- const tokenId = Number(request.tokenId);
4082
- const tokenUri = await web3Ts.getTokenUri(tokenContract, tokenId);
4083
- return String(tokenUri);
4084
- }
4085
- async getTokenOfOwnerByIndex(request) {
4086
- const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
4087
- // ✅ DIRECT: Use web3-ts functions directly
4088
- const tokenContract = web3Ts.getSmartContractInstance(request.contractAddress, request.abi, web3);
4089
- const tokenId = await web3Ts.getTokenOfOwnerByIndex(tokenContract, request.accountAddress, request.tokenIndex);
4090
- return String(tokenId);
4091
- }
4092
- }
4093
-
4094
- class SimpleCache {
4095
- constructor() {
4096
- this.storage = {};
4097
- this.defaultTTL = 10 * 1000; // 10 seconds
4098
- }
4099
- set(key, data, ttl) {
4100
- this.storage[key] = {
4101
- data,
4102
- timestamp: Date.now(),
4103
- ttl: ttl ?? this.defaultTTL
4104
- };
4105
- }
4106
- get(key) {
4107
- const entry = this.storage[key];
4108
- if (!entry) {
4109
- return null;
4110
- }
4111
- const now = Date.now();
4112
- const isExpired = (now - entry.timestamp) > entry.ttl;
4113
- if (isExpired) {
4114
- delete this.storage[key];
4115
- return null;
4116
- }
4117
- return entry.data;
4118
- }
4119
- clear() {
4120
- this.storage = {};
4121
- }
4122
- cleanup() {
4123
- const now = Date.now();
4124
- Object.keys(this.storage).forEach(key => {
4125
- const entry = this.storage[key];
4126
- if ((now - entry.timestamp) > entry.ttl) {
4127
- delete this.storage[key];
4128
- }
4129
- });
4130
- }
4131
- }
4132
-
4133
- class Web3Service {
4134
- constructor(web3Api, web3ChainService) {
4135
- this.web3Api = web3Api;
4136
- this.web3ChainService = web3ChainService;
4137
- //temporary fix, remove when the backend supports custom gateways
4138
- this.defaultIpfsGatewayDomain = 'pers.mypinata.cloud';
4139
- // ✅ CACHE: Simple 10-second cache instance
4140
- this.cache = new SimpleCache();
4141
- this.cleanupInterval = null;
4142
- this.cleanupInterval = setInterval(() => {
4143
- this.cache.cleanup();
4144
- }, 30 * 1000);
4145
- }
4146
- destroy() {
4147
- if (this.cleanupInterval) {
4148
- clearInterval(this.cleanupInterval);
4149
- this.cleanupInterval = null;
4150
- }
4151
- this.cache.clear();
4152
- }
4153
- async getERC20Balance(request) {
4154
- const cacheKey = `erc20_balance_${request.accountAddress}_${request.token.contractAddress}_${request.token.chainId}`;
4155
- // ✅ CACHE CHECK: Try to get from cache first
4156
- const cached = this.cache.get(cacheKey);
4157
- if (cached) {
4158
- console.debug(`💾 [Web3Service] Using cached ERC20 balance for ${request.token.symbol}`);
4159
- return cached;
4160
- }
4161
- console.debug(`🔄 [Web3Service] Fetching fresh ERC20 balance for ${request.token.symbol}`);
4162
- const rawBalance = await this.web3Api.getTokenBalance({
4185
+ const balance = await this.web3Api.getTokenBalance({
4163
4186
  accountAddress: request.accountAddress,
4164
- contractAddress: request.token.contractAddress,
4165
- abi: request.token.abi,
4166
- tokenId: null, // Always null for ERC20
4167
- chainId: request.token.chainId
4187
+ contractAddress: request.contractAddress,
4188
+ abi: request.abi,
4189
+ tokenId: request.tokenId,
4190
+ chainId: request.chainId
4168
4191
  });
4169
- const decimals = request.token.decimals ?? 18;
4170
- const symbol = request.token.symbol ?? 'UNKNOWN';
4171
- const response = {
4172
- rawBalance,
4173
- formattedBalance: this.formatBalance(rawBalance, decimals),
4174
- decimals,
4175
- symbol,
4176
- hasBalance: rawBalance > 0
4192
+ return {
4193
+ tokenId: request.tokenId,
4194
+ balance,
4195
+ hasBalance: balance > 0,
4196
+ metadata: null
4177
4197
  };
4178
- // ✅ CACHE SET: Store result in cache
4179
- this.cache.set(cacheKey, response);
4180
- return response;
4181
- }
4182
- async getERC1155Collection(request) {
4183
- // ✅ CACHE KEY: Create unique cache key for collection request
4184
- const contractAddresses = request.tokens.map(t => t.contractAddress).sort().join(',');
4185
- const cacheKey = `erc1155_collection_${request.accountAddress}_${contractAddresses}`;
4186
- // ✅ CACHE CHECK: Try to get from cache first
4187
- const cached = this.cache.get(cacheKey);
4188
- if (cached) {
4189
- console.debug(`💾 [Web3Service] Using cached ERC1155 collection for ${request.accountAddress}`);
4190
- return cached;
4191
- }
4192
- console.debug(`🔄 [Web3Service] Fetching fresh ERC1155 collection for ${request.accountAddress}`);
4193
- const tokenResults = await Promise.all(request.tokens.map(async (token) => {
4194
- // ✅ FIXED: Handle null metadata properly
4195
- const tokenIds = token.metadata?.map(m => m.tokenMetadataIncrementalId?.toString()).filter((id) => id !== undefined) ?? [];
4196
- // Check balance for each known tokenId
4197
- const balanceResults = await Promise.allSettled(tokenIds.map(async (tokenId) => {
4198
- try {
4199
- const rawBalance = await this.web3Api.getTokenBalance({
4200
- accountAddress: request.accountAddress,
4201
- contractAddress: token.contractAddress,
4202
- abi: token.abi,
4203
- tokenId,
4204
- chainId: token.chainId
4205
- });
4206
- const decimals = token.decimals ?? 0; // ERC1155 usually no decimals
4207
- return {
4208
- tokenId,
4209
- balance: rawBalance,
4210
- formattedBalance: this.formatBalance(rawBalance, decimals),
4211
- hasBalance: rawBalance > 0,
4212
- // ✅ FIXED: Convert null to undefined for findMetadata
4213
- metadata: this.findMetadata(token.metadata ?? undefined, tokenId)
4214
- };
4215
- }
4216
- catch (error) {
4217
- console.warn(`Failed to get balance for token ${token.contractAddress}:${tokenId}`, error);
4218
- return null; // Skip failed tokens
4219
- }
4220
- }));
4221
- // Filter successful results with balance > 0
4222
- const successfulResults = [];
4223
- for (const result of balanceResults) {
4224
- if (result.status === 'fulfilled' && result.value !== null && result.value.hasBalance) {
4225
- successfulResults.push(result.value);
4198
+ }
4199
+ async getTokenWithMetadata(params) {
4200
+ try {
4201
+ const balance = await this.web3Api.getTokenBalance({
4202
+ accountAddress: params.accountAddress,
4203
+ contractAddress: params.contractAddress,
4204
+ abi: params.abi,
4205
+ tokenId: params.tokenId,
4206
+ chainId: params.chainId
4207
+ });
4208
+ let metadata = null;
4209
+ if (balance > 0) {
4210
+ const tokenUri = await this.web3Api.getTokenUri({
4211
+ contractAddress: params.contractAddress,
4212
+ abi: params.abi,
4213
+ tokenId: params.tokenId,
4214
+ chainId: params.chainId
4215
+ });
4216
+ if (tokenUri) {
4217
+ metadata = await this.metadataService.fetchAndProcessMetadata(tokenUri, params.chainId);
4226
4218
  }
4227
4219
  }
4228
4220
  return {
4229
- token,
4230
- results: successfulResults
4221
+ tokenId: params.tokenId,
4222
+ balance,
4223
+ hasBalance: balance > 0,
4224
+ metadata
4231
4225
  };
4232
- }));
4233
- const response = {
4234
- accountAddress: request.accountAddress,
4235
- tokens: tokenResults.filter(t => t.results.length > 0)
4236
- };
4237
- // ✅ CACHE SET: Store complete collection result
4238
- this.cache.set(cacheKey, response);
4239
- return response;
4240
- }
4241
- async getERC721Collection(request) {
4242
- // ✅ CACHE KEY: Create unique cache key for NFT collection
4243
- const contractAddresses = request.nftContracts.map(t => t.contractAddress).sort().join(',');
4244
- const maxNFTs = request.maxNFTsPerContract || 50;
4245
- const cacheKey = `erc721_collection_${request.accountAddress}_${contractAddresses}_${maxNFTs}`;
4246
- // ✅ CACHE CHECK: Try to get from cache first
4247
- const cached = this.cache.get(cacheKey);
4248
- if (cached) {
4249
- console.debug(`💾 [Web3Service] Using cached ERC721 collection for ${request.accountAddress}`);
4250
- return cached;
4251
4226
  }
4252
- console.debug(`🔄 [Web3Service] Fetching fresh ERC721 collection for ${request.accountAddress}`);
4253
- const startTime = Date.now();
4254
- const contractResults = await Promise.all(request.nftContracts.map(async (token) => {
4255
- try {
4256
- const totalBalance = await this.web3Api.getTokenBalance({
4257
- accountAddress: request.accountAddress,
4258
- contractAddress: token.contractAddress,
4259
- abi: token.abi,
4260
- tokenId: null,
4261
- chainId: token.chainId
4227
+ catch (error) {
4228
+ console.error('Error getting token with metadata:', error);
4229
+ return {
4230
+ tokenId: params.tokenId,
4231
+ balance: 0,
4232
+ hasBalance: false,
4233
+ metadata: null
4234
+ };
4235
+ }
4236
+ }
4237
+ async getTokenCollection(params) {
4238
+ try {
4239
+ const contractAnalysis = this.contractService.analyzeContract(params.abi);
4240
+ const tokens = [];
4241
+ if (!contractAnalysis.hasEnumeration && !contractAnalysis.isERC1155) {
4242
+ console.warn('Contract does not support enumeration, cannot retrieve full collection');
4243
+ return {
4244
+ accountAddress: params.accountAddress,
4245
+ contractAddress: params.contractAddress,
4246
+ totalBalance: 0,
4247
+ tokensRetrieved: 0,
4248
+ tokens: [],
4249
+ note: 'Contract does not support enumeration'
4250
+ };
4251
+ }
4252
+ else if (contractAnalysis.isERC1155) {
4253
+ const tokenIdsToProcess = params.tokenIds || [];
4254
+ if (tokenIdsToProcess.length > 0) {
4255
+ for (const tokenId of tokenIdsToProcess) {
4256
+ const tokenBalance = await this.getTokenWithMetadata({
4257
+ accountAddress: params.accountAddress,
4258
+ contractAddress: params.contractAddress,
4259
+ abi: params.abi,
4260
+ tokenId,
4261
+ chainId: params.chainId
4262
+ });
4263
+ tokens.push(tokenBalance);
4264
+ }
4265
+ }
4266
+ console.log('ERC-1155 User balances:', tokens);
4267
+ // ERC-1155: Cannot enumerate without knowing token IDs
4268
+ // Would need to use events or provide specific token IDs
4269
+ console.warn('ERC-1155 collection retrieval requires specific token IDs or event analysis');
4270
+ return {
4271
+ accountAddress: params.accountAddress,
4272
+ contractAddress: params.contractAddress,
4273
+ totalBalance: 0,
4274
+ tokensRetrieved: 0,
4275
+ tokens: tokens,
4276
+ note: 'ERC-1155 collection retrieval requires specific token IDs. Use getTokenWithMetadata() for individual tokens.'
4277
+ };
4278
+ }
4279
+ // Handle different token standards
4280
+ if (contractAnalysis.isERC721) {
4281
+ // ERC-721: Get user's total balance and enumerate through tokens
4282
+ const userBalance = await this.web3Api.getTokenBalance({
4283
+ accountAddress: params.accountAddress,
4284
+ contractAddress: params.contractAddress,
4285
+ abi: params.abi,
4286
+ tokenId: null, // null for ERC-721 total balance
4287
+ chainId: params.chainId
4262
4288
  });
4263
- if (totalBalance === 0) {
4289
+ console.log(`ERC-721 User balance for ${params.accountAddress}:`, userBalance);
4290
+ if (userBalance === 0) {
4264
4291
  return {
4265
- token,
4266
- totalNFTs: 0,
4267
- nfts: [],
4268
- hasMore: false
4292
+ accountAddress: params.accountAddress,
4293
+ contractAddress: params.contractAddress,
4294
+ totalBalance: 0,
4295
+ tokensRetrieved: 0,
4296
+ tokens: []
4269
4297
  };
4270
4298
  }
4271
- const nftsToLoad = Math.min(totalBalance, maxNFTs);
4272
- const nftResults = await Promise.allSettled(Array.from({ length: nftsToLoad }, async (_, index) => {
4299
+ // Enumerate through user's tokens
4300
+ const maxTokens = params.maxTokens || userBalance;
4301
+ const tokensToRetrieve = Math.min(maxTokens, userBalance);
4302
+ for (let i = 0; i < tokensToRetrieve; i++) {
4273
4303
  try {
4274
4304
  const tokenId = await this.web3Api.getTokenOfOwnerByIndex({
4275
- contractAddress: token.contractAddress,
4276
- abi: token.abi,
4277
- accountAddress: request.accountAddress,
4278
- tokenIndex: index,
4279
- chainId: token.chainId
4305
+ contractAddress: params.contractAddress,
4306
+ abi: params.abi,
4307
+ accountAddress: params.accountAddress,
4308
+ tokenIndex: i,
4309
+ chainId: params.chainId
4280
4310
  });
4281
- const tokenUri = await this.web3Api.getTokenUri({
4282
- contractAddress: token.contractAddress,
4283
- abi: token.abi,
4311
+ const tokenWithMetadata = await this.getTokenWithMetadata({
4312
+ accountAddress: params.accountAddress,
4313
+ contractAddress: params.contractAddress,
4314
+ abi: params.abi,
4284
4315
  tokenId,
4285
- chainId: token.chainId
4316
+ chainId: params.chainId
4286
4317
  });
4287
- const metadata = await this.fetchMetadata(tokenUri, token.chainId);
4288
- const nftItem = {
4289
- tokenId,
4290
- name: metadata?.name || `Token #${tokenId}`,
4291
- description: metadata?.description || '',
4292
- imageUrl: await this.resolveIPFSUrl(metadata?.image || '', token.chainId),
4293
- rawBalance: 1,
4294
- formattedBalance: '1',
4295
- hasBalance: true,
4296
- metadata,
4297
- tokenIndex: index
4298
- };
4299
- return nftItem;
4318
+ if (tokenWithMetadata.hasBalance) {
4319
+ tokens.push(tokenWithMetadata);
4320
+ }
4300
4321
  }
4301
4322
  catch (error) {
4302
- console.warn(`Failed to load NFT at index ${index} for ${token.symbol}:`, error);
4303
- return null;
4323
+ console.warn(`Error retrieving ERC-721 token at index ${i}:`, error);
4324
+ continue;
4304
4325
  }
4305
- }));
4306
- // ✅ FIXED: Usar tipo específico NFTItem
4307
- const successfulNFTs = nftResults
4308
- .filter((result) => result.status === 'fulfilled' && result.value !== null)
4309
- .map(result => result.value);
4310
- return {
4311
- token,
4312
- totalNFTs: totalBalance,
4313
- nfts: successfulNFTs,
4314
- hasMore: totalBalance > maxNFTs
4315
- };
4326
+ }
4316
4327
  }
4317
- catch (error) {
4318
- console.error(`Failed to load NFT collection for ${token.symbol}:`, error);
4328
+ else {
4329
+ // Unknown standard
4319
4330
  return {
4320
- token,
4321
- totalNFTs: 0,
4322
- nfts: [],
4323
- hasMore: false
4331
+ accountAddress: params.accountAddress,
4332
+ contractAddress: params.contractAddress,
4333
+ totalBalance: 0,
4334
+ tokensRetrieved: 0,
4335
+ tokens: [],
4336
+ note: 'Unsupported token standard for collection retrieval'
4324
4337
  };
4325
4338
  }
4326
- }));
4327
- const totalNFTs = contractResults.reduce((sum, contract) => sum + contract.nfts.length, 0);
4328
- const loadingTime = Date.now() - startTime;
4329
- const response = {
4330
- accountAddress: request.accountAddress,
4331
- contracts: contractResults,
4332
- summary: {
4333
- totalContracts: request.nftContracts.length,
4334
- totalNFTs,
4335
- loadingTime
4339
+ // Calculate total balance based on retrieved tokens
4340
+ let totalBalance = 0;
4341
+ if (contractAnalysis.isERC721) {
4342
+ // For ERC-721, total balance is the number of unique tokens owned
4343
+ totalBalance = tokens.length;
4344
+ }
4345
+ else {
4346
+ // For other standards, sum up individual token balances
4347
+ totalBalance = tokens.reduce((sum, token) => sum + token.balance, 0);
4348
+ }
4349
+ return {
4350
+ accountAddress: params.accountAddress,
4351
+ contractAddress: params.contractAddress,
4352
+ totalBalance,
4353
+ tokensRetrieved: tokens.length,
4354
+ tokens
4355
+ };
4356
+ }
4357
+ catch (error) {
4358
+ console.error('Error getting token collection:', error);
4359
+ return {
4360
+ accountAddress: params.accountAddress,
4361
+ contractAddress: params.contractAddress,
4362
+ totalBalance: 0,
4363
+ tokensRetrieved: 0,
4364
+ tokens: [],
4365
+ note: 'Error retrieving collection'
4366
+ };
4367
+ }
4368
+ }
4369
+ async getTokenMetadata(params) {
4370
+ try {
4371
+ const tokenUri = await this.web3Api.getTokenUri({
4372
+ contractAddress: params.contractAddress,
4373
+ abi: params.abi,
4374
+ tokenId: params.tokenId,
4375
+ chainId: params.chainId
4376
+ });
4377
+ let metadata = null;
4378
+ if (tokenUri) {
4379
+ metadata = await this.metadataService.fetchAndProcessMetadata(tokenUri, params.chainId);
4336
4380
  }
4381
+ return {
4382
+ tokenId: params.tokenId,
4383
+ tokenUri,
4384
+ metadata
4385
+ };
4386
+ }
4387
+ catch (error) {
4388
+ console.error('Error getting token metadata:', error);
4389
+ return {
4390
+ tokenId: params.tokenId,
4391
+ tokenUri: null,
4392
+ metadata: null
4393
+ };
4394
+ }
4395
+ }
4396
+ }
4397
+
4398
+ /**
4399
+ * MetadataDomainService - Clean IPFS metadata resolution
4400
+ */
4401
+ class MetadataDomainService {
4402
+ constructor(ipfsApi) {
4403
+ this.ipfsApi = ipfsApi;
4404
+ }
4405
+ async fetchAndProcessMetadata(tokenUri, chainId) {
4406
+ return this.ipfsApi.fetchAndProcessMetadata(tokenUri, chainId);
4407
+ }
4408
+ async resolveIPFSUrl(url, chainId) {
4409
+ return this.ipfsApi.resolveIPFSUrl(url, chainId);
4410
+ }
4411
+ }
4412
+
4413
+ /**
4414
+ * ContractDomainService - Clean contract analysis without external dependencies
4415
+ */
4416
+ class ContractDomainService {
4417
+ constructor() { }
4418
+ analyzeContract(abi) {
4419
+ const methods = abi.filter(item => item.type === 'function').map(item => item.name);
4420
+ // ERC-721 detection
4421
+ const hasOwnerOf = methods.includes('ownerOf');
4422
+ const hasTokenURI = methods.includes('tokenURI');
4423
+ const hasTransferFrom = methods.includes('transferFrom');
4424
+ const isERC721 = hasOwnerOf && hasTokenURI && hasTransferFrom;
4425
+ // ERC-1155 detection
4426
+ const hasBalanceOfBatch = methods.includes('balanceOfBatch');
4427
+ const hasSafeBatchTransferFrom = methods.includes('safeBatchTransferFrom');
4428
+ const hasURI = methods.includes('uri');
4429
+ const isERC1155 = hasBalanceOfBatch && hasSafeBatchTransferFrom && hasURI;
4430
+ return {
4431
+ hasEnumeration: methods.includes('tokenByIndex') && methods.includes('totalSupply'),
4432
+ hasOwnerOf,
4433
+ hasBalanceOf: methods.includes('balanceOf'),
4434
+ hasTokenURI,
4435
+ hasTransfer: methods.includes('transfer') || methods.includes('transferFrom'),
4436
+ hasApprove: methods.includes('approve'),
4437
+ isERC721,
4438
+ isERC1155
4337
4439
  };
4338
- // ✅ CACHE SET: Store complete collection response
4339
- this.cache.set(cacheKey, response);
4340
- return response;
4341
4440
  }
4342
- // ==========================================
4343
- // HELPER METHODS
4344
- // ==========================================
4345
- formatBalance(rawBalance, decimals) {
4346
- const balance = rawBalance / Math.pow(10, decimals);
4347
- return balance.toLocaleString('en-US', {
4348
- minimumFractionDigits: 0,
4349
- maximumFractionDigits: decimals > 0 ? 2 : 0
4441
+ supportsEnumeration(abi) {
4442
+ return this.analyzeContract(abi).hasEnumeration;
4443
+ }
4444
+ supportsMethod(abi, methodName) {
4445
+ const methods = abi.filter(item => item.type === 'function').map(item => item.name);
4446
+ return methods.includes(methodName);
4447
+ }
4448
+ }
4449
+
4450
+ /**
4451
+ * Web3ApplicationService - Application layer entrance point
4452
+ * Orchestrates domain services and provides clean public interface
4453
+ * Simplified architecture with concrete classes
4454
+ */
4455
+ class Web3ApplicationService {
4456
+ constructor(web3Api, ipfsApi) {
4457
+ // Type-safe metadata conversion methods for ERC-721/ERC-1155 standards
4458
+ this.metadataMapper = {
4459
+ fromERCStandard: (ercMetadata) => ({
4460
+ name: ercMetadata.name || '',
4461
+ description: ercMetadata.description || '',
4462
+ imageUrl: ercMetadata.image || '',
4463
+ externalUrl: ercMetadata.external_url,
4464
+ animationUrl: ercMetadata.animation_url,
4465
+ animationUrlConverted: undefined, // Will be set by IPFS conversion
4466
+ attributes: ercMetadata.attributes || [],
4467
+ ...ercMetadata
4468
+ }),
4469
+ toERCStandard: (metadata) => ({
4470
+ name: metadata.name,
4471
+ description: metadata.description,
4472
+ image: metadata.imageUrl,
4473
+ animation_url: metadata.animationUrl,
4474
+ external_url: metadata.externalUrl,
4475
+ attributes: metadata.attributes,
4476
+ ...Object.fromEntries(Object.entries(metadata).filter(([key]) => !['name', 'description', 'imageUrl', 'animationUrl', 'externalUrl', 'attributes', 'animationUrlConverted'].includes(key)))
4477
+ })
4478
+ };
4479
+ // Create domain services with injected infrastructure dependencies
4480
+ this.contractDomainService = new ContractDomainService();
4481
+ this.metadataDomainService = new MetadataDomainService(ipfsApi);
4482
+ this.tokenDomainService = new TokenDomainService(web3Api, this.metadataDomainService, this.contractDomainService);
4483
+ }
4484
+ /**
4485
+ * Get balance and metadata for a specific token
4486
+ */
4487
+ async getSpecificTokenBalance(request) {
4488
+ if (!request.tokenId) {
4489
+ return this.tokenDomainService.getTokenBalance({
4490
+ accountAddress: request.accountAddress || '',
4491
+ contractAddress: request.contractAddress,
4492
+ abi: request.abi,
4493
+ tokenId: '',
4494
+ chainId: request.chainId
4495
+ });
4496
+ }
4497
+ return this.tokenDomainService.getTokenWithMetadata({
4498
+ accountAddress: request.accountAddress || '',
4499
+ contractAddress: request.contractAddress,
4500
+ abi: request.abi,
4501
+ tokenId: request.tokenId || '',
4502
+ chainId: request.chainId
4503
+ });
4504
+ }
4505
+ /**
4506
+ * Get metadata for a specific token from on-chain
4507
+ */
4508
+ async getTokenMetadata(request) {
4509
+ const domainResult = await this.tokenDomainService.getTokenMetadata({
4510
+ contractAddress: request.contractAddress,
4511
+ abi: request.abi,
4512
+ tokenId: request.tokenId || '',
4513
+ chainId: request.chainId
4514
+ });
4515
+ return domainResult.metadata;
4516
+ }
4517
+ /**
4518
+ * Retrieve entire collection of tokens with balance and metadata
4519
+ */
4520
+ async getTokenCollection(request) {
4521
+ return this.tokenDomainService.getTokenCollection({
4522
+ accountAddress: request.accountAddress || '',
4523
+ contractAddress: request.contractAddress,
4524
+ abi: request.abi,
4525
+ chainId: request.chainId,
4526
+ maxTokens: request.maxTokens,
4527
+ tokenIds: request.tokenIds
4350
4528
  });
4351
4529
  }
4352
- // ✅ FIXED: Update method signature to handle null properly
4353
- findMetadata(metadata, tokenId) {
4354
- if (!metadata || tokenId === null)
4530
+ /**
4531
+ * Resolve IPFS URLs to HTTPS if needed
4532
+ */
4533
+ async resolveIPFSUrl(url, chainId) {
4534
+ return this.metadataDomainService.resolveIPFSUrl(url, chainId);
4535
+ }
4536
+ /**
4537
+ * Fetch and process metadata from URI with IPFS conversion
4538
+ */
4539
+ async fetchAndProcessMetadata(tokenUri, chainId) {
4540
+ const domainMetadata = await this.metadataDomainService.fetchAndProcessMetadata(tokenUri, chainId);
4541
+ if (!domainMetadata)
4355
4542
  return null;
4356
- return metadata.find(m => m.tokenMetadataIncrementalId?.toString() === tokenId) || null;
4543
+ // Convert from ERC token standard to our clean interface
4544
+ const cleanMetadata = this.metadataMapper.fromERCStandard(domainMetadata);
4545
+ // Add IPFS conversion if needed
4546
+ if (cleanMetadata.animationUrl?.startsWith('ipfs://')) {
4547
+ return {
4548
+ ...cleanMetadata,
4549
+ animationUrlConverted: await this.resolveIPFSUrl(cleanMetadata.animationUrl, chainId)
4550
+ };
4551
+ }
4552
+ return cleanMetadata;
4357
4553
  }
4358
- async fetchMetadata(uri, chainId) {
4554
+ }
4555
+
4556
+ /**
4557
+ * Web3InfrastructureApi - Infrastructure implementation for blockchain operations
4558
+ * Uses @explorins/web3-ts for Web3 interactions
4559
+ */
4560
+ class Web3InfrastructureApi {
4561
+ constructor(web3ChainService) {
4562
+ this.web3ChainService = web3ChainService;
4563
+ }
4564
+ async getTokenBalance(request) {
4359
4565
  try {
4360
- const httpUrl = await this.resolveIPFSUrl(uri, chainId);
4361
- const response = await fetch(httpUrl);
4362
- if (!response.ok) {
4363
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
4364
- }
4365
- return await response.json();
4566
+ if (request.tokenId !== null)
4567
+ request.tokenId = request.tokenId.toString();
4568
+ const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
4569
+ const contract = web3Ts.getSmartContractInstance(request.contractAddress, request.abi, web3);
4570
+ return await web3Ts.getAccountTokenBalance(contract, request.accountAddress, request.tokenId);
4366
4571
  }
4367
4572
  catch (error) {
4368
- console.warn('Failed to fetch NFT metadata:', error);
4369
- return null;
4573
+ console.error(`Failed to get token balance for ${request.accountAddress} for ${request.contractAddress} and tokenId ${request.tokenId}, return 0 instead:`, error);
4574
+ return 0;
4370
4575
  }
4371
4576
  }
4577
+ async getTokenUri(request) {
4578
+ try {
4579
+ const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
4580
+ const contract = web3Ts.getSmartContractInstance(request.contractAddress, request.abi, web3);
4581
+ const tokenId = Number(request.tokenId);
4582
+ const tokenUri = await web3Ts.getTokenUri(contract, tokenId);
4583
+ return String(tokenUri);
4584
+ }
4585
+ catch (error) {
4586
+ console.error(`Failed to get token URI for tokenId ${request.tokenId}:`, error);
4587
+ throw error;
4588
+ }
4589
+ }
4590
+ async getTokenOfOwnerByIndex(request) {
4591
+ try {
4592
+ const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
4593
+ const tokenContract = web3Ts.getSmartContractInstance(request.contractAddress, request.abi, web3);
4594
+ const tokenId = await web3Ts.getTokenOfOwnerByIndex(tokenContract, request.accountAddress, request.tokenIndex);
4595
+ return String(tokenId);
4596
+ }
4597
+ catch (error) {
4598
+ console.error(`Failed to get token by index ${request.tokenIndex} for ${request.accountAddress}:`, error);
4599
+ throw error;
4600
+ }
4601
+ }
4602
+ }
4603
+
4604
+ /**
4605
+ * IPFSInfrastructureApi - Infrastructure implementation for IPFS operations
4606
+ * Uses Web3ChainService for IPFS gateway resolution
4607
+ */
4608
+ class IPFSInfrastructureApi {
4609
+ constructor(web3ChainService) {
4610
+ this.web3ChainService = web3ChainService;
4611
+ this.defaultIpfsGatewayDomain = 'pers.mypinata.cloud';
4612
+ }
4372
4613
  async getIpfsGatewayDomain(chainId) {
4373
4614
  try {
4374
4615
  const chainData = await this.web3ChainService.getChainDataWithCache(chainId);
@@ -4380,29 +4621,66 @@ class Web3Service {
4380
4621
  }
4381
4622
  }
4382
4623
  async resolveIPFSUrl(url, chainId) {
4383
- if (!url)
4384
- return '';
4385
4624
  if (url.startsWith('ipfs://')) {
4386
- const gatewayDomain = await this.getIpfsGatewayDomain(chainId);
4387
- return `https://${gatewayDomain}/ipfs/${url.slice(7)}`;
4625
+ const gateway = await this.getIpfsGatewayDomain(chainId);
4626
+ return url.replace('ipfs://', `https://${gateway}/ipfs/`);
4388
4627
  }
4389
4628
  return url;
4390
4629
  }
4630
+ async fetchAndProcessMetadata(tokenUri, chainId) {
4631
+ try {
4632
+ const resolvedUri = await this.resolveIPFSUrl(tokenUri, chainId);
4633
+ const response = await fetch(resolvedUri);
4634
+ if (!response.ok) {
4635
+ throw new Error(`HTTP error! status: ${response.status}`);
4636
+ }
4637
+ const metadata = await response.json();
4638
+ // Process and return clean metadata
4639
+ return {
4640
+ name: metadata.name || '',
4641
+ description: metadata.description || '',
4642
+ image: metadata.image ? await this.resolveIPFSUrl(metadata.image, chainId) : '',
4643
+ attributes: metadata.attributes || [],
4644
+ animation_url: metadata.animation_url ? await this.resolveIPFSUrl(metadata.animation_url, chainId) : undefined,
4645
+ external_url: metadata.external_url || undefined
4646
+ };
4647
+ }
4648
+ catch (error) {
4649
+ console.error('Error fetching metadata:', error);
4650
+ return null;
4651
+ }
4652
+ }
4653
+ async fetchFromUrl(url) {
4654
+ try {
4655
+ const response = await fetch(url);
4656
+ if (!response.ok) {
4657
+ throw new Error(`Failed to fetch from ${url}: ${response.statusText}`);
4658
+ }
4659
+ return await response.json();
4660
+ }
4661
+ catch (error) {
4662
+ console.error(`Error fetching from URL ${url}:`, error);
4663
+ throw error;
4664
+ }
4665
+ }
4391
4666
  }
4392
4667
 
4393
- //import { PublicHttpProviderService } from '../web3-chain/services/public-http-provider.service';
4394
4668
  function createWeb3SDK(apiClient) {
4395
4669
  // TODO: FIX LATER - TEMPORARY CONSTRUCTION
4396
4670
  const web3ProviderService = new Web3ProviderService();
4397
4671
  const web3ChainSDK = createWeb3ChainSDK(apiClient, web3ProviderService);
4398
- const web3Api = new Web3Api(web3ChainSDK.service);
4399
- const web3Service = new Web3Service(web3Api, web3ChainSDK.service);
4672
+ // Create Web3ApplicationService - main entry point for all Web3 operations
4673
+ const web3InfrastructureApi = new Web3InfrastructureApi(web3ChainSDK.service);
4674
+ const ipfsInfrastructureApi = new IPFSInfrastructureApi(web3ChainSDK.service);
4675
+ const web3ApplicationService = new Web3ApplicationService(web3InfrastructureApi, ipfsInfrastructureApi);
4676
+ // Clean SDK - all functions route through Web3ApplicationService
4400
4677
  return {
4401
- getCreditsBalance: (request) => web3Service.getERC20Balance(request),
4402
- getRewardsCollection: (request) => web3Service.getERC1155Collection(request),
4403
- getStampsCollection: (request) => web3Service.getERC721Collection(request),
4404
- api: web3Api,
4405
- service: web3Service
4678
+ getTokenBalance: (request) => web3ApplicationService.getSpecificTokenBalance(request),
4679
+ getTokenMetadata: (request) => web3ApplicationService.getTokenMetadata(request),
4680
+ getTokenCollection: (request) => web3ApplicationService.getTokenCollection(request),
4681
+ resolveIPFSUrl: (url, chainId) => web3ApplicationService.resolveIPFSUrl(url, chainId),
4682
+ fetchAndProcessMetadata: (tokenUri, chainId) => web3ApplicationService.fetchAndProcessMetadata(tokenUri, chainId),
4683
+ applicationService: web3ApplicationService
4406
4684
  };
4407
4685
  }
4408
4686
 
@@ -4419,6 +4697,7 @@ exports.ChainTypes = ChainTypes;
4419
4697
  exports.DEFAULT_PERS_CONFIG = DEFAULT_PERS_CONFIG;
4420
4698
  exports.DonationApi = DonationApi;
4421
4699
  exports.DonationService = DonationService;
4700
+ exports.IPFSInfrastructureApi = IPFSInfrastructureApi;
4422
4701
  exports.PaymentApi = PurchaseApi;
4423
4702
  exports.PaymentService = PaymentService;
4424
4703
  exports.PersApiClient = PersApiClient;
@@ -4426,7 +4705,6 @@ exports.PersApiError = PersApiError;
4426
4705
  exports.PersSDK = PersSDK;
4427
4706
  exports.RedemptionApi = RedemptionApi;
4428
4707
  exports.RedemptionService = RedemptionService;
4429
- exports.SimpleCache = SimpleCache;
4430
4708
  exports.TenantApi = TenantApi;
4431
4709
  exports.TenantService = TenantService;
4432
4710
  exports.TokenApi = TokenApi;
@@ -4438,8 +4716,10 @@ exports.UserApi = UserApi;
4438
4716
  exports.UserService = UserService;
4439
4717
  exports.UserStatusApi = UserStatusApi;
4440
4718
  exports.UserStatusService = UserStatusService;
4719
+ exports.Web3ApplicationService = Web3ApplicationService;
4441
4720
  exports.Web3ChainApi = Web3ChainApi;
4442
4721
  exports.Web3ChainService = Web3ChainService;
4722
+ exports.Web3InfrastructureApi = Web3InfrastructureApi;
4443
4723
  exports.Web3ProviderService = Web3ProviderService;
4444
4724
  exports.buildApiRoot = buildApiRoot;
4445
4725
  exports.createAnalyticsSDK = createAnalyticsSDK;