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