@explorins/pers-sdk 1.2.6 → 1.3.2

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 (106) hide show
  1. package/README.md +416 -0
  2. package/dist/business/api/business-api.d.ts.map +1 -1
  3. package/dist/business.cjs +6 -8
  4. package/dist/business.cjs.map +1 -1
  5. package/dist/business.js +6 -8
  6. package/dist/business.js.map +1 -1
  7. package/dist/campaign/api/campaign-api.d.ts +19 -65
  8. package/dist/campaign/api/campaign-api.d.ts.map +1 -1
  9. package/dist/campaign.cjs +51 -105
  10. package/dist/campaign.cjs.map +1 -1
  11. package/dist/campaign.js +49 -103
  12. package/dist/campaign.js.map +1 -1
  13. package/dist/chunks/base-token-service-BA81_Ouq.js +532 -0
  14. package/dist/chunks/base-token-service-BA81_Ouq.js.map +1 -0
  15. package/dist/chunks/base-token-service-BQ6uFoki.cjs +537 -0
  16. package/dist/chunks/base-token-service-BQ6uFoki.cjs.map +1 -0
  17. package/dist/chunks/environment-C2AkkLPd.js +46 -0
  18. package/dist/chunks/environment-C2AkkLPd.js.map +1 -0
  19. package/dist/chunks/environment-CRROnwAY.cjs +50 -0
  20. package/dist/chunks/environment-CRROnwAY.cjs.map +1 -0
  21. package/dist/chunks/jwt.function-BYiyl-z_.cjs +25 -0
  22. package/dist/chunks/jwt.function-BYiyl-z_.cjs.map +1 -0
  23. package/dist/chunks/jwt.function-d6jPtBqI.js +23 -0
  24. package/dist/chunks/jwt.function-d6jPtBqI.js.map +1 -0
  25. package/dist/chunks/pers-sdk-Ct_uUMJl.cjs +1424 -0
  26. package/dist/chunks/pers-sdk-Ct_uUMJl.cjs.map +1 -0
  27. package/dist/chunks/pers-sdk-tKHGQr5x.js +1417 -0
  28. package/dist/chunks/pers-sdk-tKHGQr5x.js.map +1 -0
  29. package/dist/core/auth/api/auth-api.d.ts +5 -2
  30. package/dist/core/auth/api/auth-api.d.ts.map +1 -1
  31. package/dist/core/auth/auth-constants.d.ts +33 -0
  32. package/dist/core/auth/auth-constants.d.ts.map +1 -0
  33. package/dist/core/auth/auth-errors.d.ts +8 -0
  34. package/dist/core/auth/auth-errors.d.ts.map +1 -0
  35. package/dist/core/auth/auth-provider.interface.d.ts +49 -3
  36. package/dist/core/auth/auth-provider.interface.d.ts.map +1 -1
  37. package/dist/core/auth/create-auth-provider.d.ts.map +1 -1
  38. package/dist/core/auth/default-auth-provider.d.ts +71 -0
  39. package/dist/core/auth/default-auth-provider.d.ts.map +1 -0
  40. package/dist/core/auth/index.d.ts +1 -22
  41. package/dist/core/auth/index.d.ts.map +1 -1
  42. package/dist/core/auth/services/auth-service.d.ts +10 -1
  43. package/dist/core/auth/services/auth-service.d.ts.map +1 -1
  44. package/dist/core/auth/token-refresh.d.ts +91 -0
  45. package/dist/core/auth/token-refresh.d.ts.map +1 -0
  46. package/dist/core/auth/token-storage.d.ts +74 -0
  47. package/dist/core/auth/token-storage.d.ts.map +1 -0
  48. package/dist/core/environment.d.ts +26 -0
  49. package/dist/core/environment.d.ts.map +1 -0
  50. package/dist/core/errors/index.d.ts +80 -0
  51. package/dist/core/errors/index.d.ts.map +1 -0
  52. package/dist/core/index.d.ts +2 -1
  53. package/dist/core/index.d.ts.map +1 -1
  54. package/dist/core/pers-api-client.d.ts +184 -19
  55. package/dist/core/pers-api-client.d.ts.map +1 -1
  56. package/dist/core/pers-config.d.ts +36 -1
  57. package/dist/core/pers-config.d.ts.map +1 -1
  58. package/dist/core/utils/jwt.function.d.ts.map +1 -1
  59. package/dist/core.cjs +12 -814
  60. package/dist/core.cjs.map +1 -1
  61. package/dist/core.js +3 -803
  62. package/dist/core.js.map +1 -1
  63. package/dist/index.cjs +82 -4912
  64. package/dist/index.cjs.map +1 -1
  65. package/dist/index.d.ts +1 -0
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +21 -4857
  68. package/dist/index.js.map +1 -1
  69. package/dist/package.json +147 -129
  70. package/dist/pers-sdk.d.ts +49 -7
  71. package/dist/pers-sdk.d.ts.map +1 -1
  72. package/dist/redemption/api/redemption-api.d.ts +12 -13
  73. package/dist/redemption/api/redemption-api.d.ts.map +1 -1
  74. package/dist/redemption.cjs +24 -24
  75. package/dist/redemption.cjs.map +1 -1
  76. package/dist/redemption.js +24 -24
  77. package/dist/redemption.js.map +1 -1
  78. package/dist/shared/index.d.ts +5 -0
  79. package/dist/shared/index.d.ts.map +1 -0
  80. package/dist/shared/interfaces/pers-shared-lib.interfaces.d.ts +1 -0
  81. package/dist/shared/interfaces/pers-shared-lib.interfaces.d.ts.map +1 -1
  82. package/dist/tenant/api/tenant-api.d.ts +28 -10
  83. package/dist/tenant/api/tenant-api.d.ts.map +1 -1
  84. package/dist/tenant/index.d.ts +4 -4
  85. package/dist/tenant.cjs +40 -11
  86. package/dist/tenant.cjs.map +1 -1
  87. package/dist/tenant.js +40 -11
  88. package/dist/tenant.js.map +1 -1
  89. package/dist/token.cjs +7 -534
  90. package/dist/token.cjs.map +1 -1
  91. package/dist/token.js +1 -532
  92. package/dist/token.js.map +1 -1
  93. package/dist/web3/index.d.ts.map +1 -1
  94. package/dist/web3-chain/services/getWeb3FCD.service.d.ts +1 -1
  95. package/dist/web3-chain/services/getWeb3FCD.service.d.ts.map +1 -1
  96. package/dist/web3-chain.cjs +12 -152
  97. package/dist/web3-chain.cjs.map +1 -1
  98. package/dist/web3-chain.js +8 -148
  99. package/dist/web3-chain.js.map +1 -1
  100. package/dist/web3.cjs +12 -538
  101. package/dist/web3.cjs.map +1 -1
  102. package/dist/web3.js +10 -536
  103. package/dist/web3.js.map +1 -1
  104. package/package.json +147 -129
  105. package/dist/core/auth/simple-sdk-auth-provider.d.ts +0 -27
  106. package/dist/core/auth/simple-sdk-auth-provider.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -1,4859 +1,23 @@
1
- import { AccountOwnerType, TransactionRole } from '@explorins/pers-shared';
1
+ export { D as DEFAULT_PERS_CONFIG, a as PersApiClient, P as PersSDK, b as buildApiRoot, c as createPersSDK, m as mergeWithDefaults } from './chunks/pers-sdk-tKHGQr5x.js';
2
+ export { d as detectEnvironment, e as environment, w as warnIfProblematicEnvironment } from './chunks/environment-C2AkkLPd.js';
2
3
  export { AccountOwnerType } from '@explorins/pers-shared';
3
- import { jwtDecode } from 'jwt-decode';
4
- import Web3 from 'web3';
5
- import { FetchRequest, JsonRpcProvider } from 'ethers';
6
- import { getSmartContractInstance, getAccountTokenBalance, getTokenUri, getTokenOfOwnerByIndex } from '@explorins/web3-ts';
7
-
8
- /**
9
- * PERS SDK Configuration interfaces
10
- */
11
- /**
12
- * Default configuration values
13
- */
14
- const DEFAULT_PERS_CONFIG = {
15
- environment: 'production',
16
- apiVersion: 'v2',
17
- timeout: 30000,
18
- retries: 3
19
- };
20
- /**
21
- * Internal function to construct API root from environment
22
- * Now defaults to production and v2
23
- */
24
- function buildApiRoot(environment = 'production', version = 'v2') {
25
- const baseUrls = {
26
- development: 'https://explorins-loyalty.ngrok.io',
27
- staging: `https://dev.api.pers.ninja/${version}`,
28
- production: `https://api.pers.ninja/${version}`
29
- };
30
- return `${baseUrls[environment]}`;
31
- }
32
- /**
33
- * Merge user config with defaults
34
- */
35
- function mergeWithDefaults(config) {
36
- return {
37
- ...DEFAULT_PERS_CONFIG,
38
- ...config,
39
- environment: config.environment ?? DEFAULT_PERS_CONFIG.environment,
40
- apiVersion: config.apiVersion ?? DEFAULT_PERS_CONFIG.apiVersion,
41
- timeout: config.timeout ?? DEFAULT_PERS_CONFIG.timeout,
42
- retries: config.retries ?? DEFAULT_PERS_CONFIG.retries
43
- };
44
- }
45
-
46
- /**
47
- * Platform-Agnostic Auth Admin API Client
48
- *
49
- * Handles authentication and authorization admin operations using the PERS backend.
50
- * Uses @explorins/pers-shared DTOs for consistency with backend.
51
- *
52
- * Note: Special header handling (bypass-auth-interceptor) may need to be implemented
53
- * at the PersApiClient level or through a specialized auth client.
54
- */
55
- class AuthApi {
56
- constructor(apiClient) {
57
- this.apiClient = apiClient;
58
- this.basePath = '/auth';
59
- }
60
- // ==========================================
61
- // ADMIN AUTHENTICATION OPERATIONS
62
- // ==========================================
63
- /**
64
- * ADMIN: Login tenant admin with JWT
65
- * Note: JWT handling and auth bypass headers may need special implementation
66
- */
67
- async loginTenantAdmin(jwt) {
68
- const body = {
69
- authToken: jwt,
70
- authType: AccountOwnerType.TENANT
71
- };
72
- return this.apiClient.post(`${this.basePath}/token`, body);
73
- }
74
- async loginUser(jwt) {
75
- const body = {
76
- authToken: jwt,
77
- authType: AccountOwnerType.USER
78
- };
79
- return this.apiClient.post(`${this.basePath}/token`, body);
80
- }
81
- /**
82
- * ADMIN: Refresh access token
83
- * Note: Bypass header handling may need special implementation
84
- */
85
- async refreshAccessToken(refreshToken) {
86
- return this.apiClient.post(`${this.basePath}/refresh`, { refreshToken });
87
- }
88
- }
89
-
90
- /**
91
- * Platform-Agnostic Auth Admin Service
92
- *
93
- * Contains auth admin business logic and operations that work across platforms.
94
- * No framework dependencies - pure TypeScript business logic.
95
- *
96
- * Focuses only on actual backend capabilities.
97
- */
98
- class AuthService {
99
- constructor(authApi, authProvider) {
100
- this.authApi = authApi;
101
- this.authProvider = authProvider;
102
- }
103
- // ==========================================
104
- // ADMIN AUTHENTICATION OPERATIONS
105
- // ==========================================
106
- /**
107
- * ADMIN: Login tenant admin with JWT
108
- * Automatically stores tokens if auth provider supports token storage
109
- */
110
- async loginTenantAdmin(jwt) {
111
- const response = await this.authApi.loginTenantAdmin(jwt);
112
- // Store tokens if auth provider supports it
113
- if (this.authProvider && response.accessToken) {
114
- await this.storeTokens(response.accessToken, response.refreshToken);
115
- }
116
- return response;
117
- }
118
- /**
119
- * ADMIN: Login user with JWT
120
- * Automatically stores tokens if auth provider supports token storage
121
- */
122
- async loginUser(jwt) {
123
- const response = await this.authApi.loginUser(jwt);
124
- // Store tokens if auth provider supports it
125
- if (this.authProvider && response.accessToken) {
126
- await this.storeTokens(response.accessToken, response.refreshToken);
127
- }
128
- return response;
129
- }
130
- /**
131
- * ADMIN: Refresh access token
132
- * Automatically stores new tokens if auth provider supports token storage
133
- */
134
- async refreshAccessToken(refreshToken) {
135
- // Use provided refresh token or get from auth provider
136
- const tokenToUse = refreshToken || (this.authProvider?.getRefreshToken ? await this.authProvider.getRefreshToken() : null);
137
- if (!tokenToUse) {
138
- throw new Error('No refresh token available for token refresh');
139
- }
140
- const response = await this.authApi.refreshAccessToken(tokenToUse);
141
- // Store new tokens if auth provider supports it
142
- if (this.authProvider && response.accessToken) {
143
- await this.storeTokens(response.accessToken, response.refreshToken);
144
- }
145
- return response;
146
- }
147
- /**
148
- * Automatic token refresh using stored refresh token
149
- * Convenience method for 401 error handling
150
- */
151
- async autoRefreshToken() {
152
- return this.refreshAccessToken(); // Uses stored refresh token
153
- }
154
- /**
155
- * Clear stored tokens if auth provider supports it
156
- */
157
- async clearTokens() {
158
- if (this.authProvider?.clearTokens) {
159
- await this.authProvider.clearTokens();
160
- }
161
- }
162
- /**
163
- * Check if we have valid tokens for authentication
164
- */
165
- hasValidAuth() {
166
- return this.authProvider?.hasValidToken?.() ?? false;
167
- }
168
- // ==========================================
169
- // PRIVATE HELPERS
170
- // ==========================================
171
- /**
172
- * Store tokens using auth provider if it supports token storage
173
- */
174
- async storeTokens(accessToken, refreshToken) {
175
- if (!this.authProvider)
176
- return;
177
- try {
178
- // Store access token
179
- if (this.authProvider.setAccessToken) {
180
- await this.authProvider.setAccessToken(accessToken);
181
- }
182
- // Store refresh token if provided and supported
183
- if (refreshToken && this.authProvider.setRefreshToken) {
184
- await this.authProvider.setRefreshToken(refreshToken);
185
- }
186
- }
187
- catch (error) {
188
- console.error('Failed to store tokens in auth provider:', error);
189
- // Don't throw - token storage failure shouldn't break authentication
190
- }
191
- }
192
- }
193
-
194
- /**
195
- * Simple, self-contained authentication provider for SDK
196
- *
197
- * Manages tokens internally without external dependencies.
198
- * Perfect for platform-agnostic usage.
199
- */
200
- class SimpleSdkAuthProvider {
201
- constructor(projectKey) {
202
- this.accessToken = null;
203
- this.refreshToken = null;
204
- this.projectKey = null;
205
- this.authType = 'admin';
206
- this.projectKey = projectKey || null;
207
- // Try to load tokens from localStorage if available
208
- this.loadTokensFromStorage();
209
- }
210
- async getToken() {
211
- // Return stored access token
212
- return this.accessToken;
213
- }
214
- async getProjectKey() {
215
- return this.projectKey;
216
- }
217
- async onTokenExpired() {
218
- console.log('SimpleSdkAuthProvider: Token expired, attempting refresh...');
219
- if (!this.refreshToken) {
220
- console.warn('SimpleSdkAuthProvider: No refresh token available');
221
- throw new Error('No refresh token available for refresh');
222
- }
223
- // Note: Actual refresh logic would be handled by the SDK's AuthService
224
- // This provider just manages token storage
225
- console.warn('SimpleSdkAuthProvider: Token refresh should be handled by SDK AuthService');
226
- }
227
- // Token storage methods
228
- async setAccessToken(token) {
229
- this.accessToken = token;
230
- this.saveTokenToStorage('pers_access_token', token);
231
- }
232
- async setRefreshToken(token) {
233
- this.refreshToken = token;
234
- this.saveTokenToStorage('pers_refresh_token', token);
235
- }
236
- async getRefreshToken() {
237
- return this.refreshToken;
238
- }
239
- async clearTokens() {
240
- this.accessToken = null;
241
- this.refreshToken = null;
242
- // Clear from storage
243
- this.removeTokenFromStorage('pers_access_token');
244
- this.removeTokenFromStorage('pers_refresh_token');
245
- }
246
- // Internal methods for token persistence
247
- loadTokensFromStorage() {
248
- if (typeof localStorage !== 'undefined') {
249
- try {
250
- this.accessToken = localStorage.getItem('pers_access_token');
251
- this.refreshToken = localStorage.getItem('pers_refresh_token');
252
- }
253
- catch (error) {
254
- console.error('Failed to load tokens from localStorage:', error);
255
- }
256
- }
257
- else {
258
- console.warn('localStorage is not available for token persistence');
259
- }
260
- }
261
- saveTokenToStorage(key, value) {
262
- if (typeof localStorage !== 'undefined') {
263
- localStorage.setItem(key, value);
264
- }
265
- }
266
- removeTokenFromStorage(key) {
267
- if (typeof localStorage !== 'undefined') {
268
- localStorage.removeItem(key);
269
- }
270
- }
271
- // Utility methods for external integration
272
- hasValidToken() {
273
- const hasToken = !!this.accessToken;
274
- return hasToken;
275
- }
276
- hasRefreshToken() {
277
- return !!this.refreshToken;
278
- }
279
- }
280
-
281
- // packages/pers-sdk/src/core/pers-api-client.ts
282
- /**
283
- * PERS API Client - Core platform-agnostic client for PERS backend
284
- */
285
- class PersApiClient {
286
- constructor(httpClient, config) {
287
- this.httpClient = httpClient;
288
- this.config = config;
289
- // Merge user config with defaults (production + v2)
290
- this.mergedConfig = mergeWithDefaults(config);
291
- // Auto-create auth provider if none provided
292
- if (!this.mergedConfig.authProvider) {
293
- this.mergedConfig.authProvider = new SimpleSdkAuthProvider(this.mergedConfig.apiProjectKey);
294
- }
295
- // Build API root from merged environment and version
296
- this.apiRoot = buildApiRoot(this.mergedConfig.environment, this.mergedConfig.apiVersion);
297
- // Initialize auth services for direct authentication
298
- this.authApi = new AuthApi(this);
299
- this.authService = new AuthService(this.authApi, this.mergedConfig.authProvider);
300
- }
301
- /**
302
- * Get request headers including auth token and project key
303
- */
304
- async getHeaders() {
305
- const headers = {
306
- 'Content-Type': 'application/json',
307
- };
308
- // Add authentication token
309
- if (this.mergedConfig.authProvider) {
310
- const token = await this.mergedConfig.authProvider.getToken();
311
- if (token) {
312
- headers['Authorization'] = `Bearer ${token}`;
313
- }
314
- }
315
- // Add project key
316
- if (this.mergedConfig.authProvider) {
317
- const projectKey = await this.mergedConfig.authProvider.getProjectKey();
318
- if (projectKey) {
319
- headers['x-project-key'] = projectKey;
320
- }
321
- }
322
- else if (this.mergedConfig.apiProjectKey) {
323
- // Fallback to config project key if no auth provider
324
- headers['x-project-key'] = this.mergedConfig.apiProjectKey;
325
- }
326
- return headers;
327
- }
328
- /**
329
- * Make a request with proper headers, auth, and error handling
330
- */
331
- async request(method, endpoint, body, options) {
332
- const { retryCount = 0, responseType = 'json' } = options || {};
333
- const url = `${this.apiRoot}${endpoint}`;
334
- // ✅ DEBUGGING: Add extensive logging for CSV endpoint
335
- const isCSVEndpoint = endpoint.includes('/export/csv');
336
- const requestOptions = {
337
- headers: await this.getHeaders(),
338
- timeout: this.mergedConfig.timeout,
339
- responseType
340
- };
341
- try {
342
- let result;
343
- switch (method) {
344
- case 'GET':
345
- result = await this.httpClient.get(url, requestOptions);
346
- break;
347
- case 'POST':
348
- result = await this.httpClient.post(url, body, requestOptions);
349
- break;
350
- case 'PUT':
351
- result = await this.httpClient.put(url, body, requestOptions);
352
- break;
353
- case 'DELETE':
354
- result = await this.httpClient.delete(url, requestOptions);
355
- break;
356
- default:
357
- throw new Error(`Unsupported HTTP method: ${method}`);
358
- }
359
- return result;
360
- }
361
- catch (error) {
362
- if (isCSVEndpoint) {
363
- console.error('❌ [PERS API CLIENT] CSV Request failed:', error);
364
- }
365
- // Handle 401 errors with automatic token refresh
366
- const apiError = error;
367
- if (apiError.status === 401 && retryCount === 0 && this.mergedConfig.authProvider?.onTokenExpired) {
368
- try {
369
- await this.mergedConfig.authProvider.onTokenExpired();
370
- // Retry once with refreshed token
371
- return this.request(method, endpoint, body, { ...options, retryCount: 1 });
372
- }
373
- catch (refreshError) {
374
- throw new PersApiError(`Authentication refresh failed: ${refreshError}`, endpoint, method, 401);
375
- }
376
- }
377
- throw new PersApiError(`PERS API request failed: ${apiError.message || error}`, endpoint, method, apiError.status);
378
- }
379
- }
380
- /**
381
- * Generic GET request
382
- */
383
- async get(endpoint, responseType) {
384
- return this.request('GET', endpoint, undefined, { responseType });
385
- }
386
- /**
387
- * Generic POST request
388
- */
389
- async post(endpoint, body) {
390
- return this.request('POST', endpoint, body);
391
- }
392
- /**
393
- * Generic PUT request
394
- */
395
- async put(endpoint, body) {
396
- return this.request('PUT', endpoint, body);
397
- }
398
- /**
399
- * Generic DELETE request
400
- */
401
- async delete(endpoint) {
402
- return this.request('DELETE', endpoint);
403
- }
404
- // ==========================================
405
- // AUTHENTICATION METHODS
406
- // ==========================================
407
- /**
408
- * Login admin user with external JWT (e.g., Firebase)
409
- * Automatically stores tokens in auth provider if available
410
- */
411
- async loginAdmin(externalJwt) {
412
- return this.authService.loginTenantAdmin(externalJwt);
413
- }
414
- /**
415
- * Login regular user with external JWT
416
- * Automatically stores tokens in auth provider if available
417
- */
418
- async loginUser(externalJwt) {
419
- return this.authService.loginUser(externalJwt);
420
- }
421
- /**
422
- * Refresh access token using stored refresh token
423
- */
424
- async refreshToken() {
425
- const refreshToken = await this.mergedConfig.authProvider?.getRefreshToken?.();
426
- if (!refreshToken) {
427
- throw new Error('No refresh token available');
428
- }
429
- return this.authService.refreshAccessToken(refreshToken);
430
- }
431
- /**
432
- * Clear all stored authentication tokens
433
- */
434
- async clearAuth() {
435
- return this.authService.clearTokens();
436
- }
437
- /**
438
- * Check if user has valid authentication token
439
- */
440
- hasValidAuth() {
441
- return this.mergedConfig.authProvider?.hasValidToken?.() || false;
442
- }
443
- /**
444
- * Get current configuration (returns merged config)
445
- */
446
- getConfig() {
447
- return this.mergedConfig;
448
- }
449
- /**
450
- * Get original user configuration
451
- */
452
- getOriginalConfig() {
453
- return this.config;
454
- }
455
- }
456
- class PersApiError extends Error {
457
- constructor(message, endpoint, method, statusCode) {
458
- super(message);
459
- this.endpoint = endpoint;
460
- this.method = method;
461
- this.statusCode = statusCode;
462
- this.name = 'PersApiError';
463
- }
464
- }
465
-
466
- /**
467
- * Memory-based token storage (default)
468
- */
469
- class MemoryTokenStorage {
470
- constructor() {
471
- this.storage = new Map();
472
- }
473
- async setItem(key, value) {
474
- this.storage.set(key, value);
475
- }
476
- async getItem(key) {
477
- return this.storage.get(key) || null;
478
- }
479
- async removeItem(key) {
480
- this.storage.delete(key);
481
- }
482
- }
483
- /**
484
- * localStorage-based token storage (browser only)
485
- */
486
- class LocalStorageTokenStorage {
487
- async setItem(key, value) {
488
- if (typeof localStorage !== 'undefined') {
489
- localStorage.setItem(key, value);
490
- }
491
- else {
492
- throw new Error('localStorage is not available in this environment');
493
- }
494
- }
495
- async getItem(key) {
496
- if (typeof localStorage !== 'undefined') {
497
- return localStorage.getItem(key);
498
- }
499
- return null;
500
- }
501
- async removeItem(key) {
502
- if (typeof localStorage !== 'undefined') {
503
- localStorage.removeItem(key);
504
- }
505
- }
506
- }
507
- /**
508
- * Creates a platform-agnostic AuthProvider from simple configuration
509
- *
510
- * This factory function is completely platform-agnostic and can be used
511
- * across Angular, React, Vue, Node.js, or any other JavaScript environment.
512
- *
513
- * Features:
514
- * - Token caching with refresh support
515
- * - Automatic token refresh on expiration
516
- * - Configurable token providers
517
- * - Token storage (memory, localStorage, custom)
518
- * - Platform-independent
519
- *
520
- * @param config - Simple auth configuration
521
- * @returns AuthProvider implementation
522
- */
523
- function createAuthProvider(config) {
524
- // Initialize token storage
525
- let tokenStorage;
526
- switch (config.tokenStorage) {
527
- case 'localStorage':
528
- tokenStorage = new LocalStorageTokenStorage();
529
- break;
530
- case 'custom':
531
- if (!config.customTokenStorage) {
532
- throw new Error('Custom token storage configuration is required when tokenStorage is "custom"');
533
- }
534
- tokenStorage = config.customTokenStorage;
535
- break;
536
- case 'memory':
537
- default:
538
- tokenStorage = new MemoryTokenStorage();
539
- break;
540
- }
541
- // Token storage keys
542
- const ACCESS_TOKEN_KEY = `pers_access_token_${config.authType || 'user'}`;
543
- const REFRESH_TOKEN_KEY = `pers_refresh_token_${config.authType || 'user'}`;
544
- // Store current token for refresh scenarios and caching
545
- let currentToken = config.token || null;
546
- let isRefreshing = false; // Prevent concurrent refresh attempts
547
- let refreshPromise = null;
548
- return {
549
- authType: config.authType || 'user',
550
- async getToken() {
551
- // If currently refreshing, wait for it to complete
552
- if (isRefreshing && refreshPromise) {
553
- await refreshPromise;
554
- return currentToken;
555
- }
556
- // Use cached current token (updated after refresh)
557
- if (currentToken) {
558
- return currentToken;
559
- }
560
- // Try to get token from storage
561
- try {
562
- const storedToken = await tokenStorage.getItem(ACCESS_TOKEN_KEY);
563
- if (storedToken) {
564
- currentToken = storedToken;
565
- return storedToken;
566
- }
567
- }
568
- catch (error) {
569
- console.warn('Failed to retrieve token from storage:', error);
570
- }
571
- // Custom token provider function (always fresh)
572
- if (config.tokenProvider) {
573
- const token = await config.tokenProvider();
574
- currentToken = token; // Cache for future calls
575
- return token;
576
- }
577
- // No token available
578
- return null;
579
- },
580
- async getProjectKey() {
581
- return config.projectKey || null;
582
- },
583
- // Token storage methods
584
- async setAccessToken(token) {
585
- currentToken = token;
586
- try {
587
- await tokenStorage.setItem(ACCESS_TOKEN_KEY, token);
588
- }
589
- catch (error) {
590
- console.error('Failed to store access token:', error);
591
- throw error;
592
- }
593
- },
594
- async setRefreshToken(token) {
595
- try {
596
- await tokenStorage.setItem(REFRESH_TOKEN_KEY, token);
597
- }
598
- catch (error) {
599
- console.error('Failed to store refresh token:', error);
600
- throw error;
601
- }
602
- },
603
- async getRefreshToken() {
604
- try {
605
- return await tokenStorage.getItem(REFRESH_TOKEN_KEY);
606
- }
607
- catch (error) {
608
- console.warn('Failed to retrieve refresh token from storage:', error);
609
- return null;
610
- }
611
- },
612
- async clearTokens() {
613
- currentToken = null;
614
- try {
615
- await Promise.all([
616
- tokenStorage.removeItem(ACCESS_TOKEN_KEY),
617
- tokenStorage.removeItem(REFRESH_TOKEN_KEY)
618
- ]);
619
- }
620
- catch (error) {
621
- console.error('Failed to clear tokens from storage:', error);
622
- throw error;
623
- }
624
- },
625
- async onTokenExpired() {
626
- // Prevent concurrent refresh attempts
627
- if (isRefreshing) {
628
- if (refreshPromise) {
629
- await refreshPromise;
630
- }
631
- return;
632
- }
633
- // No refresh logic provided
634
- if (!config.onTokenExpired) {
635
- console.warn('Token expired but no refresh logic provided');
636
- currentToken = null;
637
- try {
638
- await tokenStorage.removeItem(ACCESS_TOKEN_KEY);
639
- }
640
- catch (error) {
641
- console.warn('Failed to clear expired token from storage:', error);
642
- }
643
- return;
644
- }
645
- // Start refresh process
646
- isRefreshing = true;
647
- refreshPromise = (async () => {
648
- try {
649
- // Execute refresh logic (should update token source)
650
- await config.onTokenExpired();
651
- // After refresh, get the new token
652
- if (config.tokenProvider) {
653
- const newToken = await config.tokenProvider();
654
- if (newToken && newToken !== currentToken) {
655
- currentToken = newToken;
656
- // Store the new token
657
- try {
658
- await tokenStorage.setItem(ACCESS_TOKEN_KEY, newToken);
659
- }
660
- catch (error) {
661
- console.warn('Failed to store refreshed token:', error);
662
- }
663
- // Notify about successful token refresh
664
- if (config.onTokenRefreshed) {
665
- config.onTokenRefreshed(newToken);
666
- }
667
- }
668
- else {
669
- console.warn('Token refresh completed but no new token received');
670
- currentToken = null;
671
- try {
672
- await tokenStorage.removeItem(ACCESS_TOKEN_KEY);
673
- }
674
- catch (error) {
675
- console.warn('Failed to clear token after failed refresh:', error);
676
- }
677
- }
678
- }
679
- else {
680
- // For static token configs, clear the token since we can't refresh
681
- console.warn('Token expired for static token config - clearing token');
682
- currentToken = null;
683
- try {
684
- await tokenStorage.removeItem(ACCESS_TOKEN_KEY);
685
- }
686
- catch (error) {
687
- console.warn('Failed to clear expired static token:', error);
688
- }
689
- }
690
- }
691
- catch (error) {
692
- console.error('Token refresh failed:', error);
693
- currentToken = null; // Clear token on refresh failure
694
- try {
695
- await tokenStorage.removeItem(ACCESS_TOKEN_KEY);
696
- }
697
- catch (storageError) {
698
- console.warn('Failed to clear token after refresh failure:', storageError);
699
- }
700
- throw error; // Re-throw to let SDK handle the error
701
- }
702
- finally {
703
- isRefreshing = false;
704
- refreshPromise = null;
705
- }
706
- })();
707
- await refreshPromise;
708
- }
709
- };
710
- }
711
- /**
712
- * Platform-specific localStorage token provider for browsers
713
- * This is a convenience function for browser environments
714
- */
715
- /* export function createBrowserTokenProvider(tokenKey: string = 'userJwt'): () => Promise<string | null> {
716
- return async () => {
717
- if (typeof localStorage !== 'undefined') {
718
- return localStorage.getItem(tokenKey);
719
- }
720
- return null;
721
- };
722
- } */
723
- /**
724
- * Platform-specific environment variable token provider for Node.js
725
- * This is a convenience function for Node.js environments
726
- */
727
- /* export function createNodeTokenProvider(envVar: string = 'JWT_TOKEN'): () => Promise<string | null> {
728
- return async () => {
729
- if (typeof process !== 'undefined' && process.env) {
730
- return process.env[envVar] || null;
731
- }
732
- return null;
733
- };
734
- } */
735
-
736
- /**
737
- * @explorins/pers-sdk/core/auth - Consolidated Auth Module
738
- *
739
- * All authentication functionality in one place:
740
- * - Auth provider interfaces and implementations
741
- * - Auth API and service logic
742
- * - Token management
743
- */
744
- // Auth provider interfaces and implementations
745
- /**
746
- * Create a complete Auth SDK instance (for backward compatibility)
747
- * Note: This is now handled directly by PersApiClient
748
- *
749
- * @param apiClient - Configured PERS API client
750
- * @param authProvider - Optional auth provider. If not provided, uses SimpleSdkAuthProvider
751
- * @returns Auth SDK with flattened structure for better DX
752
- */
753
- function createAuthSDK(apiClient, authProvider) {
754
- // Use simple internal auth provider if none provided
755
- const provider = authProvider || new SimpleSdkAuthProvider();
756
- const authApi = new AuthApi(apiClient);
757
- const authService = new AuthService(authApi, provider);
758
- return {
759
- // Direct access to service methods (primary interface)
760
- // Admin authentication methods
761
- loginTenantAdmin: (jwt) => authService.loginTenantAdmin(jwt),
762
- loginUser: (jwt) => authService.loginUser(jwt),
763
- refreshAccessToken: (refreshToken) => authService.refreshAccessToken(refreshToken),
764
- clearTokens: () => authService.clearTokens(),
765
- // Auth provider access for external integration
766
- getAuthProvider: () => provider,
767
- hasValidToken: () => provider.hasValidToken?.() || false,
768
- // Advanced access for edge cases
769
- api: authApi,
770
- service: authService
771
- };
772
- }
773
-
774
- /**
775
- * PERS SDK - Minimal platform-agnostic client with built-in authentication
776
- * Authentication is now handled at the SDK core level for better scalability
777
- */
778
- /**
779
- * Minimal PERS SDK - API client with authentication built-in
780
- * Platform adapters provide auth providers and HTTP clients
781
- */
782
- class PersSDK {
783
- constructor(httpClient, config) {
784
- this.apiClient = new PersApiClient(httpClient, config);
785
- }
786
- /**
787
- * Get the API client for direct PERS API calls
788
- * This is the main interface - keep it simple!
789
- */
790
- api() {
791
- return this.apiClient;
792
- }
793
- /**
794
- * Quick config check
795
- */
796
- isProduction() {
797
- return this.apiClient.getConfig().environment === 'production';
798
- }
799
- }
800
- /**
801
- * Simple factory function
802
- */
803
- function createPersSDK(httpClient, config) {
804
- return new PersSDK(httpClient, config);
805
- }
806
-
807
- /**
808
- * Platform-Agnostic Business API Client
809
- *
810
- * Updated to match the actual RESTful endpoints:
811
- * - /businesses for business operations
812
- * - /business-types for business type operations (separate controller)
813
- */
814
- class BusinessApi {
815
- constructor(apiClient) {
816
- this.apiClient = apiClient;
817
- this.basePath = '/businesses';
818
- this.businessTypesPath = '/business-types'; // ✅ FIX: Separate controller
819
- }
820
- // ==========================================
821
- // 🌐 BUSINESS TYPES MANAGEMENT
822
- // ==========================================
823
- /**
824
- * Get all business types (project key required)
825
- *
826
- * Endpoint: GET /business-types
827
- * Auth: @ApiSecurity('projectKey')
828
- */
829
- async getAllBusinessTypes() {
830
- return this.apiClient.get(this.businessTypesPath); // ✅ FIX: Correct path
831
- }
832
- /**
833
- * ADMIN: Create business type
834
- *
835
- * Endpoint: POST /business-types
836
- * Auth: @TenantAdmin()
837
- */
838
- async createBusinessType(dto) {
839
- return this.apiClient.post(this.businessTypesPath, dto); // ✅ FIX: Correct path
840
- }
841
- /**
842
- * ADMIN: Update business type
843
- *
844
- * Endpoint: PUT /business-types
845
- * Auth: @TenantAdmin()
846
- */
847
- async updateBusinessType(dto) {
848
- return this.apiClient.put(this.businessTypesPath, dto); // ✅ FIX: Correct path
849
- }
850
- /**
851
- * ADMIN: Delete business type
852
- *
853
- * Endpoint: DELETE /business-types/{id}
854
- * Auth: @TenantAdmin()
855
- */
856
- async deleteBusinessType(id) {
857
- return this.apiClient.delete(`${this.businessTypesPath}/${id}`); // ✅ FIX: Correct path
858
- }
859
- // ==========================================
860
- // 🏢 BUSINESS MANAGEMENT
861
- // ==========================================
862
- /**
863
- * Get current business info (business authentication required)
864
- *
865
- * Endpoint: GET /businesses/me
866
- * Auth: @Business()
867
- */
868
- async getCurrentBusiness() {
869
- return this.apiClient.get(`${this.basePath}/me`);
870
- }
871
- /**
872
- * Get all businesses with role-based filtering
873
- *
874
- * Endpoint: GET /businesses?active={boolean}&sanitize={mode}
875
- * Auth: @ApiSecurity('projectKey') (enhanced with role-based filtering)
876
- * Note:
877
- * - Project API Key users: Active businesses only (automatically filtered)
878
- * - Admin JWT users: Full access with all query parameters
879
- */
880
- async getAllBusinesses(options) {
881
- const params = new URLSearchParams();
882
- if (options?.active !== undefined) {
883
- params.append('active', String(options.active));
884
- }
885
- if (options?.sanitize) {
886
- params.append('sanitize', options.sanitize);
887
- }
888
- const queryString = params.toString();
889
- const url = queryString ? `${this.basePath}?${queryString}` : this.basePath;
890
- return this.apiClient.get(url);
891
- }
892
- /**
893
- * Get all active businesses (convenience method)
894
- *
895
- * Endpoint: GET /businesses
896
- * Auth: @ApiSecurity('projectKey')
897
- */
898
- async getActiveBusinesses() {
899
- return this.apiClient.get(this.basePath);
900
- }
901
- // ✅ REMOVED: getAllBusinessesAdmin() - No separate /admin endpoint exists
902
- // The unified endpoint handles role-based access automatically
903
- /**
904
- * Get business by ID
905
- *
906
- * Endpoint: GET /businesses/{id}
907
- * Auth: @ApiSecurity('projectKey')
908
- */
909
- async getBusinessById(businessId) {
910
- return this.apiClient.get(`${this.basePath}/${businessId}`);
911
- }
912
- /**
913
- * Get business by account address
914
- *
915
- * Endpoint: GET /businesses/account/{accountAddress}
916
- * Auth: @ApiSecurity('projectKey')
917
- */
918
- async getBusinessByAccount(accountAddress) {
919
- return this.apiClient.get(`${this.basePath}/account/${accountAddress}`);
920
- }
921
- // ==========================================
922
- // 🔧 ADMIN OPERATIONS
923
- // ==========================================
924
- /**
925
- * ADMIN: Create business
926
- *
927
- * Endpoint: POST /businesses
928
- * Auth: @TenantAdmin()
929
- * Returns: BusinessApiKeyDTO | BusinessTokenBalancesDTO
930
- */
931
- async createBusiness(dto) {
932
- return this.apiClient.post(this.basePath, dto);
933
- }
934
- /**
935
- * ADMIN: Create business by display name (convenience method)
936
- */
937
- async createBusinessByDisplayName(displayName) {
938
- const dto = {
939
- displayName,
940
- // Add other required fields based on BusinessCreateRequestDTO structure
941
- };
942
- return this.createBusiness(dto);
943
- }
944
- /**
945
- * ADMIN: Create businesses from URL
946
- *
947
- * Endpoint: POST /businesses/bulk/url
948
- * Auth: @TenantAdmin()
949
- */
950
- async createBusinessesFromUrl(url) {
951
- return this.apiClient.post(`${this.basePath}/bulk/url`, { url });
952
- }
953
- /**
954
- * ADMIN: Update business
955
- *
956
- * Endpoint: PUT /businesses/{id}
957
- * Auth: @TenantAdmin()
958
- */
959
- async updateBusiness(id, businessData) {
960
- return this.apiClient.put(`${this.basePath}/${id}`, businessData);
961
- }
962
- /**
963
- * ADMIN: Toggle business active status
964
- *
965
- * Endpoint: PUT /businesses/{id}/status
966
- * Auth: @TenantAdmin()
967
- */
968
- async toggleBusinessActive(id, isActive) {
969
- const dto = { isActive };
970
- return this.apiClient.put(`${this.basePath}/${id}/status`, dto); // ✅ FIX: Correct endpoint
971
- }
972
- }
973
-
974
- /**
975
- * Platform-Agnostic Business Service
976
- *
977
- * Contains business logic and operations that work across platforms.
978
- * No framework dependencies - pure TypeScript business logic.
979
- *
980
- * Focuses only on actual backend capabilities.
981
- */
982
- class BusinessService {
983
- constructor(businessApi) {
984
- this.businessApi = businessApi;
985
- }
986
- /**
987
- * Get all active businesses
988
- */
989
- async getActiveBusinesses() {
990
- return this.businessApi.getActiveBusinesses();
991
- }
992
- /**
993
- * Get all business types
994
- */
995
- async getAllBusinessTypes() {
996
- return this.businessApi.getAllBusinessTypes();
997
- }
998
- /**
999
- * Get business by ID
1000
- */
1001
- async getBusinessById(businessId) {
1002
- return this.businessApi.getBusinessById(businessId);
1003
- }
1004
- /**
1005
- * Get business by account address
1006
- */
1007
- async getBusinessByAccount(accountAddress) {
1008
- return this.businessApi.getBusinessByAccount(accountAddress);
1009
- }
1010
- /**
1011
- * Get businesses by type (client-side filtering)
1012
- */
1013
- async getBusinessesByType(typeId) {
1014
- const businesses = await this.getActiveBusinesses();
1015
- return businesses.filter(business => business.businessType && business.businessType.id === parseInt(typeId));
1016
- }
1017
- // ==========================================
1018
- // ADMIN OPERATIONS
1019
- // ==========================================
1020
- /**
1021
- * ADMIN: Get all businesses (active and inactive)
1022
- */
1023
- async getAllBusinesses() {
1024
- return this.businessApi.getAllBusinesses();
1025
- }
1026
- /**
1027
- * ADMIN: Create business by display name
1028
- */
1029
- async createBusinessByDisplayName(displayName) {
1030
- return this.businessApi.createBusinessByDisplayName(displayName);
1031
- }
1032
- /**
1033
- * ADMIN: Update business
1034
- */
1035
- async updateBusiness(id, businessData) {
1036
- return this.businessApi.updateBusiness(id, businessData);
1037
- }
1038
- /**
1039
- * ADMIN: Toggle business active status
1040
- */
1041
- async toggleBusinessActive(id, isActive) {
1042
- return this.businessApi.toggleBusinessActive(id, isActive);
1043
- }
1044
- }
1045
-
1046
- /**
1047
- * @explorins/pers-sdk-business
1048
- *
1049
- * Platform-agnostic Business Domain SDK for PERS ecosystem
1050
- * Focuses on non-admin business operations
1051
- */
1052
- // API Layer
1053
- /**
1054
- * Create a complete Business SDK instance
1055
- *
1056
- * @param apiClient - Configured PERS API client
1057
- * @returns Business SDK with flattened structure for better DX
1058
- */
1059
- function createBusinessSDK(apiClient) {
1060
- const businessApi = new BusinessApi(apiClient);
1061
- const businessService = new BusinessService(businessApi);
1062
- return {
1063
- // Direct access to service methods (primary interface)
1064
- getActiveBusinesses: () => businessService.getActiveBusinesses(),
1065
- getAllBusinessTypes: () => businessService.getAllBusinessTypes(),
1066
- getBusinessById: (businessId) => businessService.getBusinessById(businessId),
1067
- getBusinessByAccount: (accountAddress) => businessService.getBusinessByAccount(accountAddress),
1068
- getBusinessesByType: (typeId) => businessService.getBusinessesByType(typeId),
1069
- // Admin methods
1070
- getAllBusinesses: () => businessService.getAllBusinesses(),
1071
- createBusinessByDisplayName: (displayName) => businessService.createBusinessByDisplayName(displayName),
1072
- updateBusiness: (id, businessData) => businessService.updateBusiness(id, businessData),
1073
- toggleBusinessActive: (id, isActive) => businessService.toggleBusinessActive(id, isActive),
1074
- // Advanced access for edge cases
1075
- api: businessApi,
1076
- service: businessService
1077
- };
1078
- }
1079
-
1080
- /**
1081
- * Platform-Agnostic Transaction API Client (UPDATED FOR NEW RESTful ENDPOINTS)
1082
- *
1083
- * Handles transaction operations using the PERS backend.
1084
- * Uses @explorins/pers-shared DTOs for consistency with backend.
1085
- *
1086
- * MIGRATION NOTES:
1087
- * - All endpoints changed from /transaction to /transactions
1088
- * - Role-based paths removed (no more /auth, /admin, /business in URLs)
1089
- * - New RESTful resource-based structure
1090
- * - Added new client-side transaction flow methods
1091
- * - Enhanced admin query capabilities
1092
- */
1093
- class TransactionApi {
1094
- constructor(apiClient) {
1095
- this.apiClient = apiClient;
1096
- this.basePath = '/transactions';
1097
- }
1098
- /**
1099
- * Get transaction by ID (public endpoint)
1100
- *
1101
- * UPDATED: /transaction/{id} → /transactions/{id}
1102
- */
1103
- async getTransactionById(transactionId) {
1104
- return this.apiClient.get(`${this.basePath}/${transactionId}`);
1105
- }
1106
- /**
1107
- * Unique method to create a transaction
1108
- * @param request
1109
- * @returns
1110
- */
1111
- async createTransaction(request) {
1112
- return this.apiClient.post(`${this.basePath}`, request);
1113
- // return this.apiClient.post<TransactionDTO>(`${this.basePath}/system`, request);
1114
- }
1115
- // ==========================================
1116
- // AUTHENTICATED USER OPERATIONS
1117
- // ==========================================
1118
- /**
1119
- * AUTH: Create authenticated user transaction
1120
- *
1121
- * UPDATED: /transaction/auth/transaction → /transactions/user
1122
- */
1123
- /* async createAuthTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
1124
- return this.apiClient.post<TransactionRequestResponseDTO>(`${this.basePath}`, request);
1125
- } */
1126
- /**
1127
- * AUTH: Get user's sent transactions
1128
- *
1129
- * UPDATED: /transaction/auth/sender → /transactions/me/sent
1130
- */
1131
- async getUserSentTransactions() {
1132
- const params = new URLSearchParams({
1133
- timestamp: Date.now().toString()
1134
- });
1135
- return this.apiClient.get(`${this.basePath}/me/sent?${params.toString()}`);
1136
- }
1137
- /**
1138
- * AUTH: Get user's received transactions
1139
- *
1140
- * UPDATED: /transaction/auth/recipient → /transactions/me/received
1141
- */
1142
- async getUserReceivedTransactions() {
1143
- const params = new URLSearchParams({
1144
- timestamp: Date.now().toString()
1145
- });
1146
- return this.apiClient.get(`${this.basePath}/me/received?${params.toString()}`);
1147
- }
1148
- /**
1149
- * AUTH: Get user transaction history by type (backwards compatibility)
1150
- *
1151
- * UPDATED: Maps to appropriate /transactions/me/* endpoints
1152
- */
1153
- async getUserTransactionHistory(type) {
1154
- const params = new URLSearchParams({
1155
- timestamp: Date.now().toString()
1156
- });
1157
- // Map legacy type parameter to new endpoints
1158
- switch (type.toLowerCase()) {
1159
- case 'sender':
1160
- case 'sent':
1161
- return this.apiClient.get(`${this.basePath}/me/sent?${params.toString()}`);
1162
- case 'recipient':
1163
- case 'received':
1164
- return this.apiClient.get(`${this.basePath}/me/received?${params.toString()}`);
1165
- default:
1166
- // Default to sent transactions for backwards compatibility
1167
- return this.apiClient.get(`${this.basePath}/me/sent?${params.toString()}`);
1168
- }
1169
- }
1170
- /**
1171
- * AUTH: Prepare existing transaction for client-side signing
1172
- *
1173
- * NEW ENDPOINT: GET /transactions/{id}/prepare
1174
- */
1175
- async prepareExistingTransaction(transactionId) {
1176
- return this.apiClient.get(`${this.basePath}/${transactionId}/prepare`);
1177
- }
1178
- /**
1179
- * AUTH: Submit client-side signed transaction
1180
- *
1181
- * NEW ENDPOINT: POST /transactions/{id}/submit
1182
- */
1183
- async submitSignedTransaction(signedTxData) {
1184
- return this.apiClient.post(`${this.basePath}/submit`, signedTxData);
1185
- }
1186
- /**
1187
- * AUTH: Burn user tokens
1188
- *
1189
- * UPDATED: Uses new user transaction endpoint with burn-specific parameters
1190
- * Note: This might need backend confirmation on burn functionality implementation
1191
- */
1192
- /* async burnUserTokens(request: UserBurnTokenRequestDTO): Promise<TransactionRequestResponseDTO> {
1193
- // Map burn request to TransactionRequestDTO format for new endpoint
1194
- const transactionRequest: TransactionRequestDTO = {
1195
- ...request,
1196
- // Add any specific burn transaction parameters here
1197
- } as any;
1198
-
1199
- return this.apiClient.post<TransactionRequestResponseDTO>(`${this.basePath}`, transactionRequest);
1200
- } */
1201
- // ==========================================
1202
- // BUSINESS OPERATIONS
1203
- // ==========================================
1204
- /**
1205
- * BUSINESS: Create business transaction
1206
- *
1207
- * UPDATED: /transaction/business/transaction → /transactions/business
1208
- */
1209
- /* async createBusinessTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
1210
- return this.apiClient.post<TransactionRequestResponseDTO>(`${this.basePath}`, request);
1211
- } */
1212
- // ==========================================
1213
- // ADMIN OPERATIONS
1214
- // ==========================================
1215
- /**
1216
- * ADMIN: Create admin transaction
1217
- *
1218
- * UPDATED: /transaction/admin/transaction → /transactions/admin
1219
- */
1220
- /* async createAdminTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
1221
- // return this.apiClient.post<TransactionRequestResponseDTO>(`${this.basePath}`, request);
1222
- return this.apiClient.post<TransactionDTO>(`${this.basePath}/system`, request);
1223
- } */
1224
- /**
1225
- * AUTH: Prepare client signed transaction
1226
- *
1227
- * UPDATED: /transaction/auth/prepare-signing → /transactions/prepare
1228
- */
1229
- async prepareClientSignedTransaction(request) {
1230
- return this.apiClient.post(`${this.basePath}`, request);
1231
- }
1232
- /**
1233
- * ADMIN: Get all tenant transactions
1234
- *
1235
- * UPDATED: /transaction/admin → /transactions
1236
- */
1237
- async getTenantTransactions() {
1238
- const result = await this.apiClient.get(`${this.basePath}`);
1239
- // If the new endpoint returns paginated response, extract the data array
1240
- if ('data' in result) {
1241
- return result.data;
1242
- }
1243
- // Fallback for direct array response
1244
- return result;
1245
- }
1246
- /**
1247
- * ADMIN: Get paginated transactions with filtering and sorting
1248
- *
1249
- * UPDATED: /transaction/admin → /transactions (same endpoint, better structure)
1250
- */
1251
- async getPaginatedTransactions(params) {
1252
- // Build query parameters
1253
- const queryParams = {
1254
- page: params.page.toString(),
1255
- limit: params.limit.toString()
1256
- };
1257
- // Add sorting parameters if provided
1258
- if (params.sortBy) {
1259
- queryParams['sortBy'] = params.sortBy;
1260
- }
1261
- if (params.sortOrder) {
1262
- queryParams['sortOrder'] = params.sortOrder;
1263
- }
1264
- // Add user-specific filtering if provided
1265
- if (params.participantId) {
1266
- queryParams['participantId'] = params.participantId;
1267
- }
1268
- // Add status filtering if provided
1269
- if (params.status) {
1270
- queryParams['status'] = params.status;
1271
- }
1272
- // Add additional filters if provided
1273
- if (params.filters) {
1274
- if (params.filters.startDate) {
1275
- queryParams['startDate'] = params.filters.startDate;
1276
- }
1277
- if (params.filters.endDate) {
1278
- queryParams['endDate'] = params.filters.endDate;
1279
- }
1280
- if (params.filters.type && params.filters.type.length > 0) {
1281
- queryParams['type'] = params.filters.type.join(',');
1282
- }
1283
- if (params.filters.tokenType && params.filters.tokenType.length > 0) {
1284
- queryParams['tokenType'] = params.filters.tokenType.join(',');
1285
- }
1286
- }
1287
- // Build query string
1288
- const queryString = Object.entries(queryParams)
1289
- .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
1290
- .join('&');
1291
- return this.apiClient.get(`${this.basePath}?${queryString}`);
1292
- }
1293
- /**
1294
- * ADMIN: Export transactions to CSV
1295
- *
1296
- * UPDATED: /transaction/admin/export/csv → /transactions/export/csv
1297
- */
1298
- async exportTransactionsCSV() {
1299
- return this.apiClient.get(`${this.basePath}/export/csv`, 'blob');
1300
- }
1301
- // ==========================================
1302
- // NEW ADMIN QUERY METHODS
1303
- // ==========================================
1304
- /**
1305
- * ADMIN: Query transactions by sender
1306
- *
1307
- * NEW ENDPOINT: POST /transactions/query-sender
1308
- */
1309
- /**
1310
- * Query transactions by sender using unified endpoint
1311
- */
1312
- async queryTransactionsBySender(accountSelector) {
1313
- // Build query parameters safely
1314
- const queryParams = {};
1315
- if (accountSelector.accountId) {
1316
- queryParams['participantId'] = accountSelector.accountId;
1317
- }
1318
- queryParams['role'] = TransactionRole.SENDER.toString();
1319
- const params = new URLSearchParams(queryParams);
1320
- return this.apiClient.get(`${this.basePath}?${params.toString()}`).then(response => response); // Extract items from paginated response
1321
- }
1322
- /**
1323
- * Query transactions by recipient using unified endpoint
1324
- */
1325
- async queryTransactionsByRecipient(accountSelector) {
1326
- // Build query parameters safely
1327
- const queryParams = {};
1328
- if (accountSelector.accountId) {
1329
- queryParams['participantId'] = accountSelector.accountId;
1330
- }
1331
- queryParams['role'] = TransactionRole.RECIPIENT.toString();
1332
- const params = new URLSearchParams(queryParams);
1333
- return this.apiClient.get(`${this.basePath}?${params.toString()}`).then(response => response); // Extract items from paginated response
1334
- }
1335
- /**
1336
- * ADMIN: Get transaction analytics
1337
- *
1338
- * NEW ENDPOINT: POST /transactions/analytics
1339
- */
1340
- async getTransactionAnalytics(analyticsRequest) {
1341
- return this.apiClient.post(`${this.basePath}/analytics`, analyticsRequest);
1342
- }
1343
- // ==========================================
1344
- // CONVENIENCE METHODS (BACKWARDS COMPATIBILITY)
1345
- // ==========================================
1346
- /**
1347
- * Convenience method: Get user sent transactions (alias)
1348
- */
1349
- async getUserSenderTransactions() {
1350
- return this.getUserSentTransactions();
1351
- }
1352
- /**
1353
- * Convenience method: Get user received transactions (alias)
1354
- */
1355
- async getUserRecipientTransactions() {
1356
- return this.getUserReceivedTransactions();
1357
- }
1358
- }
1359
-
1360
- /**
1361
- * Platform-Agnostic Transaction Service
1362
- *
1363
- * Contains transaction business logic and operations that work across platforms.
1364
- * No framework dependencies - pure TypeScript business logic.
1365
- *
1366
- * Focuses only on actual backend capabilities.
1367
- */
1368
- class TransactionService {
1369
- constructor(transactionApi) {
1370
- this.transactionApi = transactionApi;
1371
- }
1372
- /**
1373
- * Get transaction by ID
1374
- */
1375
- async getTransactionById(transactionId) {
1376
- return this.transactionApi.getTransactionById(transactionId);
1377
- }
1378
- // ==========================================
1379
- // AUTHENTICATED OPERATIONS
1380
- // ==========================================
1381
- /**
1382
- * AUTH: Create authenticated transaction
1383
- */
1384
- /* async createAuthTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
1385
- return this.transactionApi.createAuthTransaction(request);
1386
- } */
1387
- async createTransaction(request) {
1388
- return this.transactionApi.createTransaction(request);
1389
- }
1390
- async submitSignedTransaction(signedTxData) {
1391
- return this.transactionApi.submitSignedTransaction(signedTxData);
1392
- }
1393
- /**
1394
- * AUTH: Get user transaction history by type
1395
- */
1396
- async getUserTransactionHistory(type) {
1397
- return this.transactionApi.getUserTransactionHistory(type);
1398
- }
1399
- /**
1400
- * AUTH: Prepare client signed transaction
1401
- */
1402
- /* async prepareClientSignedTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
1403
- return this.transactionApi.prepareClientSignedTransaction(request);
1404
- } */
1405
- /**
1406
- * AUTH: Burn user tokens
1407
- */
1408
- /* async burnUserTokens(request: UserBurnTokenRequestDTO): Promise<TransactionRequestResponseDTO> {
1409
- return this.transactionApi.burnUserTokens(request);
1410
- } */
1411
- // ==========================================
1412
- // BUSINESS OPERATIONS
1413
- // ==========================================
1414
- /**
1415
- * BUSINESS: Create business transaction
1416
- */
1417
- /* async createBusinessTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
1418
- return this.transactionApi.createBusinessTransaction(request);
1419
- } */
1420
- // ==========================================
1421
- // ADMIN OPERATIONS
1422
- // ==========================================
1423
- /**
1424
- * ADMIN: Create admin transaction
1425
- */
1426
- /* async createAdminTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
1427
- return this.transactionApi.createAdminTransaction(request);
1428
- } */
1429
- /**
1430
- * ADMIN: Get all tenant transactions
1431
- */
1432
- async getTenantTransactions() {
1433
- return this.transactionApi.getTenantTransactions();
1434
- }
1435
- /**
1436
- * ADMIN: Get paginated transactions with filtering and sorting
1437
- */
1438
- async getPaginatedTransactions(params) {
1439
- return this.transactionApi.getPaginatedTransactions(params);
1440
- }
1441
- /**
1442
- * ADMIN: Export transactions to CSV
1443
- */
1444
- async exportTransactionsCSV() {
1445
- return this.transactionApi.exportTransactionsCSV();
1446
- }
1447
- }
1448
-
1449
- /**
1450
- * Transaction Domain Models
1451
- *
1452
- * Re-exports from @explorins/pers-shared for consistency with backend
1453
- * and to provide a single import source for transaction-related types.
1454
- */
1455
- // Transaction account types (domain-specific enum)
1456
- var TransactionAccountType;
1457
- (function (TransactionAccountType) {
1458
- // Add specific transaction account types as needed
1459
- // This should match the enum used in the infrastructure layer
1460
- })(TransactionAccountType || (TransactionAccountType = {}));
1461
-
1462
- /**
1463
- * @explorins/pers-sdk-transaction
1464
- *
1465
- * Platform-agnostic Transaction Domain SDK for PERS ecosystem
1466
- * Handles transaction operations across different authorization levels
1467
- */
1468
- // API Layer
1469
- /**
1470
- * Create a complete Transaction SDK instance
1471
- *
1472
- * @param apiClient - Configured PERS API client
1473
- * @returns Transaction SDK with flattened structure for better DX
1474
- */
1475
- function createTransactionSDK(apiClient) {
1476
- const transactionApi = new TransactionApi(apiClient);
1477
- const transactionService = new TransactionService(transactionApi);
1478
- return {
1479
- // Direct access to service methods (primary interface)
1480
- // Public methods
1481
- getTransactionById: (transactionId) => transactionService.getTransactionById(transactionId),
1482
- createTransaction: (request) => transactionService.createTransaction(request),
1483
- // Auth methods
1484
- // createAuthTransaction: (request: TransactionRequestDTO) => transactionService.createAuthTransaction(request),
1485
- getUserTransactionHistory: (type) => transactionService.getUserTransactionHistory(type),
1486
- //prepareClientSignedTransaction: (request: TransactionRequestDTO) => transactionService.prepareClientSignedTransaction(request),
1487
- // burnUserTokens: (request: UserBurnTokenRequestDTO) => transactionService.burnUserTokens(request),
1488
- // Business methods
1489
- // createBusinessTransaction: (request: TransactionRequestDTO) => transactionService.createBusinessTransaction(request),
1490
- // Admin methods
1491
- // createAdminTransaction: (request: TransactionRequestDTO) => transactionService.createAdminTransaction(request),
1492
- getTenantTransactions: () => transactionService.getTenantTransactions(),
1493
- getPaginatedTransactions: (params) => transactionService.getPaginatedTransactions(params),
1494
- exportTransactionsCSV: () => transactionService.exportTransactionsCSV(),
1495
- // Advanced access for edge cases
1496
- api: transactionApi,
1497
- service: transactionService
1498
- };
1499
- }
1500
-
1501
- /**
1502
- * Platform-Agnostic Analytics API Client
1503
- *
1504
- * Handles analytics operations using the PERS backend.
1505
- * Uses @explorins/pers-shared DTOs for consistency with backend.
1506
- */
1507
- class AnalyticsApi {
1508
- constructor(apiClient) {
1509
- this.apiClient = apiClient;
1510
- }
1511
- // ==========================================
1512
- // ADMIN OPERATIONS
1513
- // ==========================================
1514
- /**
1515
- * ADMIN: Get transaction analytics with filtering and aggregation
1516
- */
1517
- async getTransactionAnalytics(request) {
1518
- return this.apiClient.post('/transactions/analytics', request);
1519
- }
1520
- }
1521
-
1522
- /**
1523
- * Platform-Agnostic Analytics Service
1524
- *
1525
- * Contains analytics business logic and operations that work across platforms.
1526
- * No framework dependencies - pure TypeScript business logic.
1527
- *
1528
- * Focuses only on actual backend capabilities.
1529
- */
1530
- class AnalyticsService {
1531
- constructor(analyticsApi) {
1532
- this.analyticsApi = analyticsApi;
1533
- }
1534
- // ==========================================
1535
- // ADMIN OPERATIONS
1536
- // ==========================================
1537
- /**
1538
- * ADMIN: Get transaction analytics with filtering and aggregation
1539
- */
1540
- async getTransactionAnalytics(request) {
1541
- return this.analyticsApi.getTransactionAnalytics(request);
1542
- }
1543
- }
1544
-
1545
- /**
1546
- * @explorins/pers-sdk-analytics
1547
- *
1548
- * Platform-agnostic Analytics Domain SDK for PERS ecosystem
1549
- * Handles analytics operations and data aggregation
1550
- */
1551
- // API Layer
1552
- /**
1553
- * Create a complete Analytics SDK instance
1554
- *
1555
- * @param apiClient - Configured PERS API client
1556
- * @returns Analytics SDK with flattened structure for better DX
1557
- */
1558
- function createAnalyticsSDK(apiClient) {
1559
- const analyticsApi = new AnalyticsApi(apiClient);
1560
- const analyticsService = new AnalyticsService(analyticsApi);
1561
- return {
1562
- // Direct access to service methods (primary interface)
1563
- // Admin methods
1564
- getTransactionAnalytics: (request) => analyticsService.getTransactionAnalytics(request),
1565
- // Advanced access for edge cases
1566
- api: analyticsApi,
1567
- service: analyticsService
1568
- };
1569
- }
1570
-
1571
- /**
1572
- * Platform-Agnostic Campaign API Client (NEW - RESTful Design)
1573
- *
1574
- * Updated to use the new microservice-ready campaign controllers:
1575
- * - CampaignsController: Core campaign operations
1576
- * - CampaignTagsController: Tag management
1577
- * - CampaignTokensController: Token unit operations
1578
- * - CampaignTriggersController: Trigger system
1579
- * - CampaignEngagementsController: Business relationships
1580
- * - CampaignClaimsController: Claims processing
1581
- *
1582
- * Uses @explorins/pers-shared DTOs for consistency with backend.
1583
- * All endpoints updated to new RESTful patterns without role revelation.
1584
- */
1585
- class CampaignApi {
1586
- constructor(apiClient) {
1587
- this.apiClient = apiClient;
1588
- }
1589
- // ==========================================
1590
- // CORE CAMPAIGN OPERATIONS (/campaigns)
1591
- // ==========================================
1592
- /**
1593
- * PUBLIC: Get all active campaigns
1594
- * NEW: /campaigns (intelligent access detection)
1595
- */
1596
- async getActiveCampaigns() {
1597
- return this.apiClient.get('/campaigns');
1598
- }
1599
- /**
1600
- * ADMIN: Get campaigns with filtering options
1601
- * NEW: /campaigns with query parameters (admin access detected automatically)
1602
- */
1603
- async getCampaigns(options) {
1604
- let url = '/campaigns';
1605
- const params = [];
1606
- if (options) {
1607
- if (options.active !== undefined)
1608
- params.push(`active=${options.active}`);
1609
- if (options.tag)
1610
- params.push(`tag=${encodeURIComponent(options.tag)}`);
1611
- if (options.limit)
1612
- params.push(`limit=${options.limit}`);
1613
- if (options.offset)
1614
- params.push(`offset=${options.offset}`);
1615
- if (options.sort)
1616
- params.push(`sort=${options.sort}`);
1617
- if (options.order)
1618
- params.push(`order=${options.order}`);
1619
- }
1620
- if (params.length > 0) {
1621
- url += `?${params.join('&')}`;
1622
- }
1623
- return this.apiClient.get(url);
1624
- }
1625
- /**
1626
- * PUBLIC: Get campaign by ID
1627
- * NEW: /campaigns/{id}
1628
- */
1629
- async getCampaignById(id) {
1630
- return this.apiClient.get(`/campaigns/${id}`);
1631
- }
1632
- /**
1633
- * ADMIN: Create campaign
1634
- * NEW: POST /campaigns
1635
- */
1636
- async createCampaign(campaign) {
1637
- return this.apiClient.post('/campaigns', campaign);
1638
- }
1639
- /**
1640
- * ADMIN: Update campaign
1641
- * NEW: PUT /campaigns/{id}
1642
- */
1643
- async updateCampaign(campaignId, campaign) {
1644
- return this.apiClient.put(`/campaigns/${campaignId}`, campaign);
1645
- }
1646
- /**
1647
- * ADMIN: Toggle campaign active status
1648
- * NEW: PUT /campaigns/{id}/status
1649
- */
1650
- async toggleCampaignActive(campaignId) {
1651
- return this.apiClient.put(`/campaigns/${campaignId}/status`, {});
1652
- }
1653
- /**
1654
- * ADMIN: Toggle campaign testnet environment
1655
- * NEW: PUT /campaigns/{id}/environment
1656
- */
1657
- async toggleCampaignTestnet(campaignId) {
1658
- return this.apiClient.put(`/campaigns/${campaignId}/environment`, {});
1659
- }
1660
- /**
1661
- * ADMIN: Delete campaign
1662
- * NEW: DELETE /campaigns/{id}
1663
- */
1664
- async deleteCampaign(campaignId) {
1665
- return this.apiClient.delete(`/campaigns/${campaignId}`);
1666
- }
1667
- // ==========================================
1668
- // TAG MANAGEMENT (/campaign-tags)
1669
- // ==========================================
1670
- /**
1671
- * ADMIN: Get all unique campaign tags
1672
- * NEW: GET /campaign-tags
1673
- */
1674
- async getAllUniqueTags() {
1675
- return this.apiClient.get('/campaign-tags');
1676
- }
1677
- /**
1678
- * ADMIN: Update campaign tags (replace all)
1679
- * NEW: PUT /campaign-tags/{id}
1680
- */
1681
- async updateCampaignTags(campaignId, tags) {
1682
- return this.apiClient.put(`/campaign-tags/${campaignId}`, { tags });
1683
- }
1684
- /**
1685
- * ADMIN: Add tags to campaign
1686
- * NEW: POST /campaign-tags/{id}
1687
- */
1688
- async addTagsToCampaign(campaignId, tags) {
1689
- return this.apiClient.post(`/campaign-tags/${campaignId}`, { tags });
1690
- }
1691
- /**
1692
- * ADMIN: Remove tag from campaign
1693
- * NEW: DELETE /campaign-tags/{id}/{tag}
1694
- */
1695
- async removeTagFromCampaign(campaignId, tag) {
1696
- return this.apiClient.delete(`/campaign-tags/${campaignId}/${encodeURIComponent(tag)}`);
1697
- }
1698
- // ==========================================
1699
- // TOKEN MANAGEMENT (/campaign-tokens)
1700
- // ==========================================
1701
- /**
1702
- * ADMIN: Create campaign token unit
1703
- * NEW: POST /campaign-tokens/{id}
1704
- */
1705
- async createCampaignTokenUnit(campaignId, campaignTokenUnit) {
1706
- return this.apiClient.post(`/campaign-tokens/${campaignId}`, campaignTokenUnit);
1707
- }
1708
- /**
1709
- * ADMIN: Update campaign token unit
1710
- * NEW: PUT /campaign-tokens/{id}/{tokenUnitId}
1711
- */
1712
- async updateCampaignTokenUnit(campaignId, tokenUnitId, campaignTokenUnit) {
1713
- return this.apiClient.put(`/campaign-tokens/${campaignId}/${tokenUnitId}`, campaignTokenUnit);
1714
- }
1715
- /**
1716
- * ADMIN: Delete campaign token unit
1717
- * NEW: DELETE /campaign-tokens/{id}/{tokenUnitId}
1718
- */
1719
- async deleteCampaignTokenUnit(campaignId, campaignTokenUnitId) {
1720
- return this.apiClient.delete(`/campaign-tokens/${campaignId}/${campaignTokenUnitId}`);
1721
- }
1722
- // ==========================================
1723
- // TRIGGER SYSTEM (/campaign-triggers)
1724
- // ==========================================
1725
- /**
1726
- * PUBLIC: Get campaign triggers catalog
1727
- * NEW: GET /campaign-triggers
1728
- */
1729
- async getCampaignTriggers() {
1730
- return this.apiClient.get('/campaign-triggers');
1731
- }
1732
- /**
1733
- * ADMIN: Create campaign trigger
1734
- * NEW: POST /campaign-triggers
1735
- */
1736
- async createCampaignTrigger(trigger) {
1737
- return this.apiClient.post('/campaign-triggers', trigger);
1738
- }
1739
- /**
1740
- * ADMIN: Update campaign trigger
1741
- * NEW: PUT /campaign-triggers/{id}
1742
- */
1743
- async updateCampaignTrigger(triggerId, trigger) {
1744
- return this.apiClient.put(`/campaign-triggers/${triggerId}`, trigger);
1745
- }
1746
- /**
1747
- * ADMIN: Delete campaign trigger
1748
- * NEW: DELETE /campaign-triggers/{id}
1749
- */
1750
- async deleteCampaignTrigger(triggerId) {
1751
- return this.apiClient.delete(`/campaign-triggers/${triggerId}`);
1752
- }
1753
- /**
1754
- * ADMIN: Set campaign trigger
1755
- * NEW: PUT /campaign-triggers/campaigns/{id}/trigger/{triggerId}
1756
- */
1757
- async setCampaignTrigger(campaignId, triggerId) {
1758
- return this.apiClient.put(`/campaign-triggers/campaigns/${campaignId}/trigger/${triggerId}`, {});
1759
- }
1760
- /**
1761
- * ADMIN: Create trigger condition
1762
- * NEW: POST /campaign-triggers/conditions
1763
- */
1764
- async createTriggerCondition(condition) {
1765
- return this.apiClient.post('/campaign-triggers/conditions', condition);
1766
- }
1767
- /**
1768
- * ADMIN: Update trigger condition
1769
- * NEW: PUT /campaign-triggers/conditions/{id}
1770
- */
1771
- async updateTriggerCondition(conditionId, condition) {
1772
- return this.apiClient.put(`/campaign-triggers/conditions/${conditionId}`, condition);
1773
- }
1774
- /**
1775
- * ADMIN: Add/Remove condition to trigger
1776
- * NEW: PUT /campaign-triggers/{triggerId}/condition/{conditionId}
1777
- */
1778
- async addOrRemoveConditionToTrigger(triggerId, conditionId) {
1779
- return this.apiClient.put(`/campaign-triggers/${triggerId}/condition/${conditionId}`, {});
1780
- }
1781
- // ==========================================
1782
- // BUSINESS ENGAGEMENTS (/campaign-engagements)
1783
- // ==========================================
1784
- /**
1785
- * ADMIN: Add business engagement to campaign
1786
- * NEW: POST /campaign-engagements/{id}
1787
- */
1788
- async addBusinessEngagementToCampaign(campaignId, campaignBusinessEngagement) {
1789
- return this.apiClient.post(`/campaign-engagements/${campaignId}`, campaignBusinessEngagement);
1790
- }
1791
- /**
1792
- * ADMIN: Update campaign business engagement
1793
- * NEW: PUT /campaign-engagements/{id}/{businessEngagementId}
1794
- */
1795
- async updateCampaignBusinessEngagement(campaignId, businessEngagementId, campaignBusinessEngagement) {
1796
- return this.apiClient.put(`/campaign-engagements/${campaignId}/${businessEngagementId}`, campaignBusinessEngagement);
1797
- }
1798
- /**
1799
- * ADMIN: Delete campaign business engagement
1800
- * NEW: DELETE /campaign-engagements/{id}/{businessEngagementId}
1801
- */
1802
- async deleteCampaignBusinessEngagement(campaignId, businessEngagementId) {
1803
- return this.apiClient.delete(`/campaign-engagements/${campaignId}/${businessEngagementId}`);
1804
- }
1805
- // ==========================================
1806
- // CLAIMS PROCESSING (/campaign-claims)
1807
- // ==========================================
1808
- /**
1809
- * USER: Claim campaign reward
1810
- * NEW: POST /campaign-claims/user
1811
- */
1812
- async claimCampaign(request) {
1813
- return this.apiClient.post('/campaign-claims', request);
1814
- }
1815
- /**
1816
- * USER: Get claims for logged user
1817
- * NEW: GET /campaign-claims/users/me
1818
- */
1819
- async getClaimsForLoggedUser() {
1820
- return this.apiClient.get('/campaign-claims/me');
1821
- }
1822
- /**
1823
- * ADMIN: Get all campaign claims
1824
- * Updated to use unified endpoint
1825
- */
1826
- async getCampaignClaims() {
1827
- // Admin context - no parameters needed for all claims
1828
- return this.apiClient.get('/campaign-claims');
1829
- }
1830
- /**
1831
- * ADMIN: Get campaign claims by campaign ID
1832
- * Updated to use query parameters
1833
- */
1834
- async getCampaignClaimsByCampaignId(campaignId) {
1835
- return this.apiClient.get(`/campaign-claims?campaignId=${campaignId}`);
1836
- }
1837
- /**
1838
- * ADMIN: Get campaign claims by user ID
1839
- * Updated to use query parameters
1840
- */
1841
- async getCampaignClaimsByUserId(userId) {
1842
- return this.apiClient.get(`/campaign-claims?userId=${userId}`);
1843
- }
1844
- /**
1845
- * ADMIN: Get campaign claims by business ID
1846
- * Updated to use query parameters
1847
- */
1848
- async getCampaignClaimsByBusinessId(businessId) {
1849
- return this.apiClient.get(`/campaign-claims?businessId=${businessId}`);
1850
- }
1851
- /**
1852
- * ADMIN: Get campaign claims by user ID for specific campaign
1853
- * Combined filtering using query parameters
1854
- */
1855
- async getCampaignClaimsByUserAndCampaign(userId, campaignId) {
1856
- return this.apiClient.get(`/campaign-claims?userId=${userId}&campaignId=${campaignId}`);
1857
- }
1858
- /**
1859
- * ADMIN: Get campaign claims by business ID for specific campaign
1860
- * Combined filtering using query parameters
1861
- */
1862
- async getCampaignClaimsByBusinessAndCampaign(businessId, campaignId) {
1863
- return this.apiClient.get(`/campaign-claims?businessId=${businessId}&campaignId=${campaignId}`);
1864
- }
1865
- /**
1866
- * USER: Get user's own claims (all campaigns)
1867
- * Use convenience endpoint
1868
- */
1869
- async getUserClaims() {
1870
- return this.apiClient.get('/campaign-claims/me');
1871
- }
1872
- /**
1873
- * USER: Get user's claims for specific campaign
1874
- * Use convenience endpoint with query parameter
1875
- */
1876
- async getUserClaimsForCampaign(campaignId) {
1877
- return this.apiClient.get(`/campaign-claims/me?campaignId=${campaignId}`);
1878
- }
1879
- /**
1880
- * BUSINESS: Get business claims (all campaigns)
1881
- * Uses unified endpoint with business context
1882
- */
1883
- async getBusinessClaims() {
1884
- return this.apiClient.get('/campaign-claims');
1885
- }
1886
- /**
1887
- * BUSINESS: Get business claims for specific campaign
1888
- * Uses unified endpoint with business context and campaign filter
1889
- */
1890
- async getBusinessClaimsForCampaign(campaignId) {
1891
- return this.apiClient.get(`/campaign-claims?campaignId=${campaignId}`);
1892
- }
1893
- /**
1894
- * Helper: Build query string from parameters
1895
- */
1896
- buildQueryString(params) {
1897
- const validParams = Object.entries(params)
1898
- .filter(([_, value]) => value !== undefined)
1899
- .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
1900
- .join('&');
1901
- return validParams ? `?${validParams}` : '';
1902
- }
1903
- /**
1904
- * Flexible admin claims query with multiple filters
1905
- */
1906
- async getAdminClaims(filters) {
1907
- const queryString = this.buildQueryString(filters || {});
1908
- return this.apiClient.get(`/campaign-claims${queryString}`);
1909
- }
1910
- }
1911
-
1912
- /**
1913
- * Platform-Agnostic Campaign Service
1914
- *
1915
- * Contains campaign business logic and operations that work across platforms.
1916
- * No framework dependencies - pure TypeScript business logic.
1917
- *
1918
- * Focuses only on actual backend capabilities.
1919
- */
1920
- class CampaignService {
1921
- constructor(campaignApi) {
1922
- this.campaignApi = campaignApi;
1923
- }
1924
- // ==========================================
1925
- // PUBLIC OPERATIONS
1926
- // ==========================================
1927
- /**
1928
- * PUBLIC: Get all active campaigns
1929
- */
1930
- async getActiveCampaigns() {
1931
- return this.campaignApi.getActiveCampaigns();
1932
- }
1933
- /**
1934
- * PUBLIC: Get campaign by ID
1935
- */
1936
- async getCampaignById(id) {
1937
- return this.campaignApi.getCampaignById(id);
1938
- }
1939
- // ==========================================
1940
- // AUTHENTICATED OPERATIONS
1941
- // ==========================================
1942
- /**
1943
- * AUTH: Claim campaign
1944
- */
1945
- async claimCampaign(request) {
1946
- return this.campaignApi.claimCampaign(request);
1947
- }
1948
- /**
1949
- * AUTH: Get claims for logged user
1950
- */
1951
- async getClaimsForLoggedUser() {
1952
- return this.campaignApi.getClaimsForLoggedUser();
1953
- }
1954
- // ==========================================
1955
- // ADMIN OPERATIONS
1956
- // ==========================================
1957
- /**
1958
- * ADMIN: Get campaigns with optional active filter
1959
- */
1960
- async getCampaigns(active) {
1961
- return this.campaignApi.getCampaigns(active !== undefined ? { active } : undefined);
1962
- }
1963
- /**
1964
- * ADMIN: Get campaign triggers
1965
- */
1966
- async getCampaignTriggers() {
1967
- return this.campaignApi.getCampaignTriggers();
1968
- }
1969
- /**
1970
- * ADMIN: Toggle campaign active status
1971
- */
1972
- async toggleCampaignActive(campaignId) {
1973
- return this.campaignApi.toggleCampaignActive(campaignId);
1974
- }
1975
- /**
1976
- * ADMIN: Toggle campaign testnet environment
1977
- */
1978
- async toggleCampaignTestnet(campaignId) {
1979
- return this.campaignApi.toggleCampaignTestnet(campaignId);
1980
- }
1981
- /**
1982
- * ADMIN: Create campaign
1983
- */
1984
- async createCampaign(campaign) {
1985
- return this.campaignApi.createCampaign(campaign);
1986
- }
1987
- /**
1988
- * ADMIN: Set campaign trigger
1989
- */
1990
- async setCampaignTrigger(campaignId, triggerId) {
1991
- return this.campaignApi.setCampaignTrigger(campaignId, triggerId);
1992
- }
1993
- /**
1994
- * ADMIN: Update campaign
1995
- */
1996
- async updateCampaign(campaignId, campaign) {
1997
- return this.campaignApi.updateCampaign(campaignId, campaign);
1998
- }
1999
- /**
2000
- * ADMIN: Create campaign token unit
2001
- */
2002
- async createCampaignTokenUnit(campaignId, campaignTokenUnit) {
2003
- return this.campaignApi.createCampaignTokenUnit(campaignId, campaignTokenUnit);
2004
- }
2005
- /**
2006
- * ADMIN: Delete campaign token unit
2007
- */
2008
- async deleteCampaignTokenUnit(campaignId, campaignTokenUnitId) {
2009
- return this.campaignApi.deleteCampaignTokenUnit(campaignId, campaignTokenUnitId);
2010
- }
2011
- /**
2012
- * ADMIN: Add business engagement to campaign
2013
- */
2014
- async addBusinessEngagementToCampaign(campaignId, campaignBusinessEngagement) {
2015
- return this.campaignApi.addBusinessEngagementToCampaign(campaignId, campaignBusinessEngagement);
2016
- }
2017
- /**
2018
- * ADMIN: Update campaign business engagement
2019
- */
2020
- async updateCampaignBusinessEngagement(campaignId, businessEngagementId, campaignBusinessEngagement) {
2021
- return this.campaignApi.updateCampaignBusinessEngagement(campaignId, businessEngagementId, campaignBusinessEngagement);
2022
- }
2023
- async deleteCampaignBusinessEngagement(campaignId, businessEngagementId) {
2024
- return this.campaignApi.deleteCampaignBusinessEngagement(campaignId, businessEngagementId);
2025
- }
2026
- /**
2027
- * ADMIN: Get all campaign claims
2028
- */
2029
- async getCampaignClaims() {
2030
- return this.campaignApi.getCampaignClaims();
2031
- }
2032
- /**
2033
- * ADMIN: Get campaign claims by user ID
2034
- */
2035
- async getCampaignClaimsByUserId(userId) {
2036
- return this.campaignApi.getCampaignClaimsByUserId(userId);
2037
- }
2038
- /**
2039
- * ADMIN: Get campaign claims by business ID
2040
- */
2041
- async getCampaignClaimsByBusinessId(businessId) {
2042
- return this.campaignApi.getCampaignClaimsByBusinessId(businessId);
2043
- }
2044
- }
2045
-
2046
- /**
2047
- * @explorins/pers-sdk-campaign
2048
- *
2049
- * Platform-agnostic Campaign Domain SDK for PERS ecosystem
2050
- * Handles campaign operations across different authorization levels
2051
- */
2052
- // API Layer
2053
- /**
2054
- * Create a complete Campaign SDK instance
2055
- *
2056
- * @param apiClient - Configured PERS API client
2057
- * @returns Campaign SDK with flattened structure for better DX
2058
- */
2059
- function createCampaignSDK(apiClient) {
2060
- const campaignApi = new CampaignApi(apiClient);
2061
- const campaignService = new CampaignService(campaignApi);
2062
- return {
2063
- // Direct access to service methods (primary interface)
2064
- // Public methods
2065
- getActiveCampaigns: () => campaignService.getActiveCampaigns(),
2066
- getCampaignById: (id) => campaignService.getCampaignById(id),
2067
- // Auth methods
2068
- claimCampaign: (request) => campaignService.claimCampaign(request),
2069
- getClaimsForLoggedUser: () => campaignService.getClaimsForLoggedUser(),
2070
- // Admin methods
2071
- getCampaigns: (active) => campaignService.getCampaigns(active),
2072
- getCampaignTriggers: () => campaignService.getCampaignTriggers(),
2073
- toggleCampaignActive: (campaignId) => campaignService.toggleCampaignActive(campaignId),
2074
- toggleCampaignTestnet: (campaignId) => campaignService.toggleCampaignTestnet(campaignId),
2075
- createCampaign: (campaign) => campaignService.createCampaign(campaign),
2076
- setCampaignTrigger: (campaignId, triggerId) => campaignService.setCampaignTrigger(campaignId, triggerId),
2077
- updateCampaign: (campaignId, campaign) => campaignService.updateCampaign(campaignId, campaign),
2078
- createCampaignTokenUnit: (campaignId, campaignTokenUnit) => campaignService.createCampaignTokenUnit(campaignId, campaignTokenUnit),
2079
- deleteCampaignTokenUnit: (campaignId, campaignTokenUnitId) => campaignService.deleteCampaignTokenUnit(campaignId, campaignTokenUnitId),
2080
- addBusinessEngagementToCampaign: (campaignId, campaignBusinessEngagement) => campaignService.addBusinessEngagementToCampaign(campaignId, campaignBusinessEngagement),
2081
- updateCampaignBusinessEngagement: (campaignId, businessEngagementId, campaignBusinessEngagement) => campaignService.updateCampaignBusinessEngagement(campaignId, businessEngagementId, campaignBusinessEngagement),
2082
- deleteCampaignBusinessEngagement: (campaignId, businessEngagementId) => campaignService.deleteCampaignBusinessEngagement(campaignId, businessEngagementId),
2083
- getCampaignClaims: () => campaignService.getCampaignClaims(),
2084
- getCampaignClaimsByUserId: (userId) => campaignService.getCampaignClaimsByUserId(userId),
2085
- getCampaignClaimsByBusinessId: (businessId) => campaignService.getCampaignClaimsByBusinessId(businessId),
2086
- // Advanced access for edge cases
2087
- api: campaignApi,
2088
- service: campaignService
2089
- };
2090
- }
2091
-
2092
- /**
2093
- * Platform-Agnostic Donation API Client
2094
- *
2095
- * Handles donation operations using the PERS backend.
2096
- * Matches framework DonationApiService methods exactly.
2097
- */
2098
- class DonationApi {
2099
- constructor(apiClient) {
2100
- this.apiClient = apiClient;
2101
- }
2102
- // ==========================================
2103
- // PUBLIC OPERATIONS
2104
- // ==========================================
2105
- /**
2106
- * PUBLIC: Get all donation types
2107
- * ✅ ONLY method actually used by framework
2108
- */
2109
- async getAllDonationTypes() {
2110
- return this.apiClient.get('/purchases/donation-types');
2111
- }
2112
- }
2113
-
2114
- /**
2115
- * Platform-Agnostic Donation Service
2116
- *
2117
- * Contains donation business logic and operations that work across platforms.
2118
- * No framework dependencies - pure TypeScript business logic.
2119
- * Matches framework DonationApiService capabilities exactly.
2120
- */
2121
- class DonationService {
2122
- constructor(donationApi) {
2123
- this.donationApi = donationApi;
2124
- }
2125
- // ==========================================
2126
- // PUBLIC OPERATIONS
2127
- // ==========================================
2128
- /**
2129
- * PUBLIC: Get all donation types
2130
- * ✅ ONLY method actually used by framework
2131
- */
2132
- async getAllDonationTypes() {
2133
- return this.donationApi.getAllDonationTypes();
2134
- }
2135
- }
2136
-
2137
- /**
2138
- * @explorins/pers-sdk-donation
2139
- *
2140
- * Platform-agnostic Donation Domain SDK for PERS ecosystem
2141
- * Handles donation type retrieval for purchase flow integration
2142
- */
2143
- // API Layer
2144
- /**
2145
- * Create a complete Donation SDK instance
2146
- *
2147
- * @param apiClient - Configured PERS API client
2148
- * @returns Donation SDK with flattened structure for better DX
2149
- */
2150
- function createDonationSDK(apiClient) {
2151
- const donationApi = new DonationApi(apiClient);
2152
- const donationService = new DonationService(donationApi);
2153
- return {
2154
- // Direct access to service methods (primary interface)
2155
- // ✅ FRAMEWORK ALIGNED: Only method actually used by framework
2156
- // Public methods
2157
- getAllDonationTypes: () => donationService.getAllDonationTypes(),
2158
- // Advanced access for edge cases
2159
- api: donationApi,
2160
- service: donationService
2161
- };
2162
- }
2163
-
2164
- /**
2165
- * Platform-Agnostic Purchase API Client (RESTful Architecture)
2166
- *
2167
- * Handles purchase and payment operations using the PERS backend's new RESTful endpoints.
2168
- * Uses @explorins/pers-shared DTOs for consistency with backend.
2169
- *
2170
- * Migration Status: Updated to match /purchases controller (replaces /purchase endpoints)
2171
- *
2172
- * Available Access Levels:
2173
- * - PUBLIC: Project key authentication for catalog browsing and payment operations
2174
- * - USER: Requires user authentication JWT (purchase creation, history access)
2175
- * - ADMIN: Requires tenant admin privileges (not implemented in this client)
2176
- *
2177
- * Note: This SDK focuses on backend purchase operations only.
2178
- * Payment provider integrations (Stripe, etc.) should remain in infrastructure layer.
2179
- */
2180
- class PurchaseApi {
2181
- constructor(apiClient) {
2182
- this.apiClient = apiClient;
2183
- this.basePath = '/purchases';
2184
- }
2185
- // ==========================================
2186
- // PUBLIC OPERATIONS (Project Key)
2187
- // ==========================================
2188
- /**
2189
- * PUBLIC: Get purchase tokens (Intelligent Access)
2190
- *
2191
- * RESTful endpoint: GET /purchases/tokens
2192
- * Replaces: GET /purchase/token
2193
- *
2194
- * INTELLIGENT ACCESS:
2195
- * - PUBLIC (Project Key): Returns active tokens only (active parameter ignored)
2196
- * - ADMIN (Tenant Admin JWT): Returns filtered results based on active parameter
2197
- */
2198
- async getPurchaseTokens(active) {
2199
- let url = `${this.basePath}/tokens`;
2200
- if (active !== undefined) {
2201
- url += `?active=${active}`;
2202
- }
2203
- return this.apiClient.get(url);
2204
- }
2205
- /**
2206
- * PUBLIC: Get donation types
2207
- *
2208
- * RESTful endpoint: GET /purchases/donation-types
2209
- * Replaces: GET /purchase/donation/type
2210
- */
2211
- async getDonationTypes() {
2212
- return this.apiClient.get(`${this.basePath}/donation-types`);
2213
- }
2214
- // ==========================================
2215
- // PAYMENT OPERATIONS (FINANCIAL - CRITICAL)
2216
- // ==========================================
2217
- /**
2218
- * PUBLIC: Create payment intent (FINANCIAL OPERATION)
2219
- *
2220
- * RESTful endpoint: POST /purchases/payment-intents
2221
- * Replaces: POST /purchase/payment-intent
2222
- *
2223
- * CRITICAL: Handles real money operations - tenant context required
2224
- */
2225
- async createPaymentIntent(amount, currency, receiptEmail, description) {
2226
- const body = {
2227
- amount,
2228
- currency,
2229
- receiptEmail,
2230
- description
2231
- };
2232
- return this.apiClient.post(`${this.basePath}/payment-intents`, body);
2233
- }
2234
- /**
2235
- * PUBLIC: Update payment intent (FINANCIAL OPERATION)
2236
- *
2237
- * RESTful endpoint: PUT /purchases/payment-intents/{paymentIntentId}
2238
- * Replaces: PUT /purchase/payment-intent/{paymentIntentId}
2239
- *
2240
- * CRITICAL: Handles real money operations - tenant context required
2241
- */
2242
- async updatePaymentIntent(paymentIntentId, amount, currency, receiptEmail, description) {
2243
- const body = {
2244
- amount,
2245
- currency,
2246
- receiptEmail,
2247
- description
2248
- };
2249
- return this.apiClient.put(`${this.basePath}/payment-intents/${paymentIntentId}`, body);
2250
- }
2251
- /**
2252
- * PUBLIC: Cancel payment intent (FINANCIAL OPERATION)
2253
- *
2254
- * RESTful endpoint: DELETE /purchases/payment-intents/{paymentIntentId}
2255
- * Replaces: DELETE /purchase/payment-intent/{paymentIntentId}
2256
- *
2257
- * CRITICAL: Handles real money operations - tenant context required
2258
- */
2259
- async cancelPaymentIntent(paymentIntentId) {
2260
- return this.apiClient.delete(`${this.basePath}/payment-intents/${paymentIntentId}`);
2261
- }
2262
- // ==========================================
2263
- // USER OPERATIONS (JWT + Project Key)
2264
- // ==========================================
2265
- /**
2266
- * USER: Create purchase (BUSINESS CRITICAL - FINANCIAL TRANSACTION)
2267
- *
2268
- * RESTful endpoint: POST /purchases
2269
- * Replaces: POST /purchase/auth
2270
- *
2271
- * USER-ONLY: Requires user authentication JWT for purchase creation
2272
- * CRITICAL: Real financial transaction with Stripe integration
2273
- */
2274
- async createUserPurchase(paymentIntentId, amount, purchaseTokenId, donationTypeId, donationAccountAddress) {
2275
- const body = {
2276
- quantity: amount,
2277
- purchaseTokenId: purchaseTokenId || '',
2278
- donationTypeId,
2279
- donationAccountAddress,
2280
- paymentIntentId
2281
- };
2282
- return this.apiClient.post(`${this.basePath}`, body);
2283
- }
2284
- /**
2285
- * USER: Get user purchase history
2286
- *
2287
- * RESTful endpoint: GET /purchases/me/history
2288
- * Replaces: GET /purchase/auth
2289
- *
2290
- * USER-ONLY: Get authenticated user's purchase history
2291
- * FINANCIAL RECORDS: User attribution critical for compliance
2292
- */
2293
- async getUserPurchaseHistory() {
2294
- return this.apiClient.get(`${this.basePath}/me/history`);
2295
- }
2296
- // ==========================================
2297
- // CONVENIENCE METHODS (Backward Compatibility)
2298
- // ==========================================
2299
- /**
2300
- * @deprecated Use getPurchaseTokens() instead
2301
- * Backward compatibility alias for getActivePurchaseTokens
2302
- */
2303
- async getActivePurchaseTokens(active = true) {
2304
- return this.getPurchaseTokens(active);
2305
- }
2306
- /**
2307
- * @deprecated Use createUserPurchase() instead
2308
- * Backward compatibility alias for createPurchase
2309
- */
2310
- async createPurchase(paymentIntentId, amount, purchaseTokenId, donationTypeId, donationAccountAddress) {
2311
- return this.createUserPurchase(paymentIntentId, amount, purchaseTokenId, donationTypeId, donationAccountAddress);
2312
- }
2313
- /**
2314
- * @deprecated Use getUserPurchaseHistory() instead
2315
- * Backward compatibility alias for getAllUserPurchases
2316
- */
2317
- async getAllUserPurchases() {
2318
- return this.getUserPurchaseHistory();
2319
- }
2320
- }
2321
-
2322
- /**
2323
- * Platform-Agnostic Payment Service
2324
- *
2325
- * Contains payment business logic and operations that work across platforms.
2326
- * No framework dependencies - pure TypeScript business logic.
2327
- *
2328
- * Focuses only on actual backend capabilities.
2329
- * Payment provider logic (Stripe, etc.) should remain in infrastructure layer.
2330
- */
2331
- class PaymentService {
2332
- constructor(paymentApi) {
2333
- this.paymentApi = paymentApi;
2334
- }
2335
- // ==========================================
2336
- // PUBLIC OPERATIONS
2337
- // ==========================================
2338
- /**
2339
- * PUBLIC: Get active purchase tokens
2340
- */
2341
- async getActivePurchaseTokens(active = true) {
2342
- return this.paymentApi.getActivePurchaseTokens(active);
2343
- }
2344
- /**
2345
- * PUBLIC: Create payment intent
2346
- */
2347
- async createPaymentIntent(amount, currency, receiptEmail, description) {
2348
- return this.paymentApi.createPaymentIntent(amount, currency, receiptEmail, description);
2349
- }
2350
- /**
2351
- * PUBLIC: Update payment intent
2352
- */
2353
- async updatePaymentIntent(paymentIntentId, amount, currency, receiptEmail, description) {
2354
- return this.paymentApi.updatePaymentIntent(paymentIntentId, amount, currency, receiptEmail, description);
2355
- }
2356
- /**
2357
- * PUBLIC: Cancel payment intent
2358
- */
2359
- async cancelPaymentIntent(paymentIntentId) {
2360
- return this.paymentApi.cancelPaymentIntent(paymentIntentId);
2361
- }
2362
- // ==========================================
2363
- // AUTHENTICATED OPERATIONS
2364
- // ==========================================
2365
- /**
2366
- * AUTH: Create purchase
2367
- */
2368
- async createPurchase(paymentIntentId, amount, purchaseTokenId, donationTypeId, donationAccountAddress) {
2369
- return this.paymentApi.createPurchase(paymentIntentId, amount, purchaseTokenId, donationTypeId, donationAccountAddress);
2370
- }
2371
- /**
2372
- * AUTH: Get all user purchases
2373
- */
2374
- async getAllUserPurchases() {
2375
- return this.paymentApi.getAllUserPurchases();
2376
- }
2377
- }
2378
-
2379
- /**
2380
- * @explorins/pers-sdk-payment
2381
- *
2382
- * Platform-agnostic Payment Domain SDK for PERS ecosystem
2383
- * Handles payment intents, purchases, and purchase tokens
2384
- *
2385
- * Note: Payment provider integrations (Stripe, etc.) are kept separate
2386
- * in the infrastructure layer to maintain platform-agnostic principles.
2387
- */
2388
- // API Layer
2389
- /**
2390
- * Create a complete Payment SDK instance
2391
- *
2392
- * @param apiClient - Configured PERS API client
2393
- * @returns Payment SDK with flattened structure for better DX
2394
- */
2395
- function createPaymentSDK(apiClient) {
2396
- const paymentApi = new PurchaseApi(apiClient);
2397
- const paymentService = new PaymentService(paymentApi);
2398
- return {
2399
- // Direct access to service methods (primary interface)
2400
- // Public methods
2401
- getActivePurchaseTokens: (active) => paymentService.getActivePurchaseTokens(active),
2402
- // ✅ FIXED: Proper type instead of any
2403
- createPaymentIntent: (amount, currency, receiptEmail, description) => paymentService.createPaymentIntent(amount, currency, receiptEmail, description),
2404
- // ✅ FIXED: Proper type instead of any
2405
- updatePaymentIntent: (paymentIntentId, amount, currency, receiptEmail, description) => paymentService.updatePaymentIntent(paymentIntentId, amount, currency, receiptEmail, description),
2406
- cancelPaymentIntent: (paymentIntentId) => paymentService.cancelPaymentIntent(paymentIntentId),
2407
- // Auth methods
2408
- createPurchase: (paymentIntentId, amount, purchaseTokenId, donationTypeId, donationAccountAddress) => paymentService.createPurchase(paymentIntentId, amount, purchaseTokenId, donationTypeId, donationAccountAddress),
2409
- getAllUserPurchases: () => paymentService.getAllUserPurchases(),
2410
- // Advanced access for edge cases
2411
- api: paymentApi,
2412
- service: paymentService
2413
- };
2414
- }
2415
-
2416
- /**
2417
- * Platform-Agnostic Redemption API Client (UPDATED - RESTful Design)
2418
- *
2419
- * Updated to work with the new RESTful /redemptions and /redemption-redeems endpoints.
2420
- * Handles redemption operations using the PERS backend with intelligent access detection.
2421
- * Uses @explorins/pers-shared DTOs for consistency with backend.
2422
- *
2423
- * Migration Update: Updated all endpoints for unified controller pattern
2424
- * - Removed role revelation from URLs (no more /admin, /auth paths)
2425
- * - Added intelligent access detection for unified endpoints
2426
- * - Added new /redemption-redeems endpoints for redeem processing
2427
- * - Enhanced redemption process with role-based access control
2428
- */
2429
- class RedemptionApi {
2430
- constructor(apiClient) {
2431
- this.apiClient = apiClient;
2432
- this.basePath = '/redemptions';
2433
- this.redeemsPath = '/redemption-redeems';
2434
- }
2435
- // ==========================================
2436
- // PUBLIC OPERATIONS (Project Key)
2437
- // ==========================================
2438
- /**
2439
- * UNIFIED: Get redemptions with intelligent access control
2440
- *
2441
- * Intelligent endpoint that adapts based on authentication:
2442
- * - Public users: Get active redemptions only
2443
- * - Admin users: Get all redemptions with optional filtering
2444
- *
2445
- * @param options.active - Filter by active status (undefined = all for admins/active for public)
2446
- * @param options.adminAccess - Force admin access (requires admin auth)
2447
- */
2448
- async getRedemptions(options) {
2449
- let url = `${this.basePath}`;
2450
- if (options?.active !== undefined) {
2451
- url += `?active=${options.active}`;
2452
- }
2453
- return this.apiClient.get(url);
2454
- }
2455
- /**
2456
- * PUBLIC: Get redemption types
2457
- *
2458
- * Updated: /redemption/type → /redemptions/types
2459
- */
2460
- async getRedemptionTypes() {
2461
- return this.apiClient.get(`/redemption-types`);
2462
- }
2463
- /**
2464
- * PUBLIC: Get redemption by ID
2465
- *
2466
- * Updated: /redemption/:id → /redemptions/:id
2467
- */
2468
- async getRedemptionById(id) {
2469
- return this.apiClient.get(`${this.basePath}/${id}`);
2470
- }
2471
- /**
2472
- * PUBLIC: Get available supply for redemption
2473
- *
2474
- * Updated: /redemption/:id/available-supply → /redemptions/:id/supply
2475
- */
2476
- async getRedemptionAvailableSupply(id) {
2477
- return this.apiClient.get(`${this.basePath}/${id}/supply`);
2478
- }
2479
- // ==========================================
2480
- // REDEMPTION EXECUTION (NEW UNIFIED ENDPOINT)
2481
- // ==========================================
2482
- /**
2483
- * Execute redemption (unified endpoint)
2484
- *
2485
- * NEW: POST /redemption-redeems - Role-based processing
2486
- * - USER: Direct user redemption processing
2487
- * - ADMIN: Can process redemptions for any account type
2488
- * - BUSINESS: Process redemptions for customers
2489
- */
2490
- async redeemRedemption(redemptionId) {
2491
- const body = {
2492
- redemptionId: redemptionId,
2493
- };
2494
- return this.apiClient.post(this.redeemsPath, body);
2495
- }
2496
- // ==========================================
2497
- // REDEMPTION REDEEMS QUERIES (NEW ENDPOINTS)
2498
- // ==========================================
2499
- /**
2500
- * UNIFIED: Get redemption redeems with filtering and intelligent access
2501
- *
2502
- * Role-based access with unified filtering:
2503
- * - Users: See only their own redeems (userId/businessId filters ignored)
2504
- * - Admins: Can filter by userId, businessId, or redemptionId
2505
- *
2506
- * @param filters.redemptionId - Filter by specific redemption
2507
- * @param filters.userId - Admin only: Filter by user ID
2508
- * @param filters.businessId - Admin only: Filter by business ID
2509
- * @param filters.myRedeems - Force user's own redeems (uses /me endpoint)
2510
- */
2511
- async getRedemptionRedeems(filters) {
2512
- // Use convenience endpoint for user's own redeems
2513
- if (filters?.myRedeems) {
2514
- let url = `${this.redeemsPath}/me`;
2515
- if (filters.redemptionId) {
2516
- url += `?redemptionId=${filters.redemptionId}`;
2517
- }
2518
- return this.apiClient.get(url);
2519
- }
2520
- // Use admin endpoint with filtering
2521
- let url = this.redeemsPath;
2522
- const params = new URLSearchParams();
2523
- if (filters?.redemptionId)
2524
- params.append('redemptionId', filters.redemptionId);
2525
- if (filters?.userId)
2526
- params.append('userId', filters.userId);
2527
- if (filters?.businessId)
2528
- params.append('businessId', filters.businessId);
2529
- const queryString = params.toString();
2530
- if (queryString) {
2531
- url += `?${queryString}`;
2532
- }
2533
- return this.apiClient.get(url);
2534
- }
2535
- /**
2536
- * UNIFIED: Get specific redemption redeem by ID
2537
- */
2538
- async getRedemptionRedeemById(id) {
2539
- return this.apiClient.get(`${this.redeemsPath}/${id}`);
2540
- }
2541
- // ==========================================
2542
- // USER OPERATIONS (JWT + Project Key)
2543
- // ==========================================
2544
- /**
2545
- * UNIFIED: Get user redemption history
2546
- *
2547
- * Uses convenience endpoint /redemption-redeems/me with optional filtering
2548
- * @param redemptionId - Optional filter by specific redemption
2549
- */
2550
- async getUserRedeems(redemptionId) {
2551
- return this.getRedemptionRedeems({ myRedeems: true, redemptionId });
2552
- }
2553
- // ==========================================
2554
- // ADMIN OPERATIONS (Tenant Admin JWT)
2555
- // ==========================================
2556
- /**
2557
- * ADMIN: Get redemptions with filtering (using intelligent endpoint)
2558
- *
2559
- * Updated: /redemption/admin → /redemptions (intelligent access detection)
2560
- * The unified endpoint will detect admin privileges and allow filtering
2561
- */
2562
- async getRedemptionsAsAdmin(active) {
2563
- return this.getRedemptions({ active, adminAccess: true });
2564
- }
2565
- /**
2566
- * ADMIN: Create redemption
2567
- *
2568
- * Updated: /redemption/admin → /redemptions
2569
- */
2570
- async createRedemption(redemption) {
2571
- return this.apiClient.post(`${this.basePath}`, redemption);
2572
- }
2573
- /**
2574
- * ADMIN: Update redemption
2575
- *
2576
- * Updated: /redemption/admin/:id → /redemptions/:id
2577
- */
2578
- async updateRedemption(id, redemptionCreateRequest) {
2579
- return this.apiClient.put(`${this.basePath}/${id}`, redemptionCreateRequest);
2580
- }
2581
- /**
2582
- * UNIFIED: Toggle redemption active status
2583
- *
2584
- * Updated: /redemption/admin/:id/toggle-active → /redemptions/:id/status
2585
- * Following standard /status pattern used across domains
2586
- */
2587
- async toggleRedemptionActive(redemptionId) {
2588
- return this.apiClient.put(`${this.basePath}/${redemptionId}/status`, {});
2589
- }
2590
- /**
2591
- * ADMIN: Delete redemption
2592
- *
2593
- * Updated: /redemption/admin/:id → /redemptions/:id
2594
- */
2595
- async deleteRedemption(id) {
2596
- return this.apiClient.delete(`${this.basePath}/${id}`);
2597
- }
2598
- /**
2599
- * ADMIN: Create redemption type
2600
- *
2601
- * Updated: /redemption/admin/type → /redemptions/types
2602
- */
2603
- async createRedemptionType(redemptionType) {
2604
- return this.apiClient.post(`${this.basePath}/redemption-types`, redemptionType);
2605
- }
2606
- // ==========================================
2607
- // TOKEN UNIT MANAGEMENT (Admin)
2608
- // ==========================================
2609
- /**
2610
- * ADMIN: Create redemption token unit
2611
- *
2612
- * Updated: /redemption/admin/:id/token-units → /redemptions/:id/token-units
2613
- */
2614
- async createRedemptionTokenUnit(redemptionId, redemptionTokenUnit) {
2615
- return this.apiClient.post(`${this.basePath}/${redemptionId}/token-units`, redemptionTokenUnit);
2616
- }
2617
- /**
2618
- * ADMIN: Update redemption token unit
2619
- *
2620
- * Updated: /redemption/admin/:id/token-units/:tokenUnitId → /redemptions/:id/token-units/:tokenUnitId
2621
- */
2622
- async updateRedemptionTokenUnit(redemptionId, tokenUnitId, redemptionTokenUnit) {
2623
- return this.apiClient.put(`${this.basePath}/${redemptionId}/token-units/${tokenUnitId}`, redemptionTokenUnit);
2624
- }
2625
- /**
2626
- * ADMIN: Delete redemption token unit
2627
- *
2628
- * Updated: /redemption/admin/:id/token-units/:tokenUnitId → /redemptions/:id/token-units/:tokenUnitId
2629
- */
2630
- async deleteRedemptionTokenUnit(redemptionId, redemptionTokenUnitId) {
2631
- return this.apiClient.delete(`${this.basePath}/${redemptionId}/token-units/${redemptionTokenUnitId}`);
2632
- }
2633
- // ==========================================
2634
- // CONVENIENCE METHODS (Legacy Support)
2635
- // ==========================================
2636
- /**
2637
- * Convenience: Get active redemptions (public access)
2638
- */
2639
- async getActiveRedemptions() {
2640
- return this.getRedemptions({ active: true });
2641
- }
2642
- }
2643
-
2644
- /**
2645
- * Platform-Agnostic Redemption Service
2646
- *
2647
- * Contains redemption business logic and operations that work across platforms.
2648
- * No framework dependencies - pure TypeScript business logic.
2649
- *
2650
- * Focuses only on actual backend capabilities.
2651
- */
2652
- class RedemptionService {
2653
- constructor(redemptionApi) {
2654
- this.redemptionApi = redemptionApi;
2655
- }
2656
- // ==========================================
2657
- // PUBLIC OPERATIONS
2658
- // ==========================================
2659
- /**
2660
- * UNIFIED: Get redemptions with intelligent access control
2661
- * @param options.active - Filter by active status
2662
- * @param options.adminAccess - Force admin access
2663
- */
2664
- async getRedemptions(options) {
2665
- return this.redemptionApi.getRedemptions(options);
2666
- }
2667
- /**
2668
- * Convenience: Get active redemptions (public)
2669
- */
2670
- async getActiveRedemptions() {
2671
- return this.redemptionApi.getActiveRedemptions();
2672
- }
2673
- /**
2674
- * PUBLIC: Get redemption types
2675
- */
2676
- async getRedemptionTypes() {
2677
- return this.redemptionApi.getRedemptionTypes();
2678
- }
2679
- // ==========================================
2680
- // AUTHENTICATED OPERATIONS
2681
- // ==========================================
2682
- /**
2683
- * AUTH: Redeem a redemption
2684
- */
2685
- async redeemRedemption(redemptionId) {
2686
- return this.redemptionApi.redeemRedemption(redemptionId);
2687
- }
2688
- /**
2689
- * UNIFIED: Get redemption redeems with filtering
2690
- */
2691
- async getRedemptionRedeems(filters) {
2692
- return this.redemptionApi.getRedemptionRedeems(filters);
2693
- }
2694
- /**
2695
- * Convenience: Get user redemptions
2696
- */
2697
- async getUserRedeems() {
2698
- return this.redemptionApi.getUserRedeems();
2699
- }
2700
- // ==========================================
2701
- // ADMIN OPERATIONS
2702
- // ==========================================
2703
- /**
2704
- * Convenience: Get redemptions as admin
2705
- */
2706
- async getRedemptionsAsAdmin(active) {
2707
- return this.redemptionApi.getRedemptionsAsAdmin(active);
2708
- }
2709
- /**
2710
- * ADMIN: Create redemption
2711
- */
2712
- async createRedemption(redemption) {
2713
- return this.redemptionApi.createRedemption(redemption);
2714
- }
2715
- /**
2716
- * ADMIN: Update redemption
2717
- */
2718
- async updateRedemption(id, redemptionCreateRequest) {
2719
- return this.redemptionApi.updateRedemption(id, redemptionCreateRequest); // ✅ CORRECTED: Fixed parameter
2720
- }
2721
- /**
2722
- * ADMIN: Toggle redemption active status
2723
- */
2724
- async toggleRedemptionActive(redemptionId) {
2725
- return this.redemptionApi.toggleRedemptionActive(redemptionId);
2726
- }
2727
- /**
2728
- * ADMIN: Create redemption token unit
2729
- */
2730
- async createRedemptionTokenUnit(redemptionId, redemptionTokenUnit) {
2731
- return this.redemptionApi.createRedemptionTokenUnit(redemptionId, redemptionTokenUnit);
2732
- }
2733
- /**
2734
- * ADMIN: Delete redemption token unit
2735
- */
2736
- async deleteRedemptionTokenUnit(redemptionId, redemptionTokenUnitId) {
2737
- return this.redemptionApi.deleteRedemptionTokenUnit(redemptionId, redemptionTokenUnitId);
2738
- }
2739
- }
2740
-
2741
- /**
2742
- * @explorins/pers-sdk-redemption
2743
- *
2744
- * Platform-agnostic Redemption Domain SDK for PERS ecosystem
2745
- * Handles redemption operations across different authorization levels
2746
- */
2747
- // API Layer
2748
- /**
2749
- * Create a complete Redemption SDK instance
2750
- *
2751
- * @param apiClient - Configured PERS API client
2752
- * @returns Redemption SDK with flattened structure for better DX
2753
- */
2754
- function createRedemptionSDK(apiClient) {
2755
- const redemptionApi = new RedemptionApi(apiClient);
2756
- const redemptionService = new RedemptionService(redemptionApi);
2757
- return {
2758
- // Direct access to service methods (primary interface)
2759
- // Public methods
2760
- getActiveRedemptions: () => redemptionService.getActiveRedemptions(),
2761
- getRedemptionTypes: () => redemptionService.getRedemptionTypes(),
2762
- // Auth methods
2763
- redeemRedemption: (redemptionId) => redemptionService.redeemRedemption(redemptionId),
2764
- getUserRedeems: () => redemptionService.getUserRedeems(),
2765
- // Admin methods
2766
- getRedemptionsAsAdmin: (active) => redemptionService.getRedemptionsAsAdmin(active),
2767
- createRedemption: (redemption) => redemptionService.createRedemption(redemption),
2768
- updateRedemption: (id, redemptionCreateRequest) => redemptionService.updateRedemption(id, redemptionCreateRequest),
2769
- toggleRedemptionActive: (redemptionId) => redemptionService.toggleRedemptionActive(redemptionId),
2770
- createRedemptionTokenUnit: (redemptionId, redemptionTokenUnit) => redemptionService.createRedemptionTokenUnit(redemptionId, redemptionTokenUnit),
2771
- deleteRedemptionTokenUnit: (redemptionId, redemptionTokenUnitId) => redemptionService.deleteRedemptionTokenUnit(redemptionId, redemptionTokenUnitId),
2772
- // Advanced access for edge cases
2773
- api: redemptionApi,
2774
- service: redemptionService
2775
- };
2776
- }
2777
-
2778
- /**
2779
- * Platform-Agnostic Tenant API Client
2780
- *
2781
- * Handles tenant and admin operations using the PERS backend.
2782
- * Matches framework TenantApiService methods exactly.
2783
- *
2784
- * Note: Special header handling (bypass-auth-interceptor) should be handled by PersApiClient internally
2785
- * or through endpoint-specific configuration.
2786
- */
2787
- class TenantApi {
2788
- constructor(apiClient) {
2789
- this.apiClient = apiClient;
2790
- this.basePath = '/tenants';
2791
- this.adminPath = '/admins';
2792
- }
2793
- // ==========================================
2794
- // PUBLIC OPERATIONS
2795
- // ==========================================
2796
- /**
2797
- * PUBLIC: Get tenant public information
2798
- * ✅ FIXED: Matches framework cache busting pattern exactly
2799
- */
2800
- async getRemoteTenant() {
2801
- const timestamp = Date.now().toString();
2802
- const url = `${this.basePath}/public?date=${timestamp}`;
2803
- return this.apiClient.get(url);
2804
- }
2805
- /**
2806
- * PUBLIC: Get remote login token
2807
- */
2808
- async getRemoteLoginToken() {
2809
- return this.apiClient.get(`${this.basePath}/login-token`);
2810
- }
2811
- /**
2812
- * PUBLIC: Get remote client configuration
2813
- * ✅ FIXED: Removed second parameter - PersApiClient handles bypass auth internally
2814
- * Note: The /tenants/client-config endpoint should be configured to bypass auth at the API client level
2815
- */
2816
- async getRemoteClientConfig() {
2817
- return this.apiClient.get(`${this.basePath}/client-config`);
2818
- }
2819
- // ==========================================
2820
- // ADMIN OPERATIONS
2821
- // ==========================================
2822
- /**
2823
- * ADMIN: Update tenant information
2824
- * ✅ FIXED: Uses TenantPublicDTO directly like framework
2825
- */
2826
- async updateRemoteTenant(tenantData) {
2827
- return this.apiClient.put(`${this.basePath}`, tenantData);
2828
- }
2829
- /**
2830
- * ADMIN: Get all tenant admins
2831
- */
2832
- async getAdmins() {
2833
- return this.apiClient.get(`${this.adminPath}`);
2834
- }
2835
- /**
2836
- * ADMIN: Create new admin
2837
- * ✅ FIXED: Renamed to match framework postAdmin method
2838
- */
2839
- async postAdmin(adminData) {
2840
- return this.apiClient.post(`${this.adminPath}`, adminData);
2841
- }
2842
- /**
2843
- * ADMIN: Update admin (toggle tenant association)
2844
- * ✅ FIXED: Renamed to match framework putAdmin method
2845
- */
2846
- async putAdmin(adminId, adminData) {
2847
- return this.apiClient.put(`${this.adminPath}/${adminId}/tenant`, adminData);
2848
- }
2849
- }
2850
-
2851
- /**
2852
- * Platform-Agnostic Tenant Service
2853
- *
2854
- * Contains tenant business logic and operations that work across platforms.
2855
- * No framework dependencies - pure TypeScript business logic.
2856
- * Matches framework TenantApiService capabilities exactly.
2857
- */
2858
- class TenantService {
2859
- constructor(tenantApi) {
2860
- this.tenantApi = tenantApi;
2861
- }
2862
- // ==========================================
2863
- // PUBLIC OPERATIONS
2864
- // ==========================================
2865
- /**
2866
- * PUBLIC: Get tenant public information
2867
- */
2868
- async getRemoteTenant() {
2869
- return this.tenantApi.getRemoteTenant();
2870
- }
2871
- /**
2872
- * PUBLIC: Get remote login token
2873
- */
2874
- async getRemoteLoginToken() {
2875
- return this.tenantApi.getRemoteLoginToken();
2876
- }
2877
- /**
2878
- * PUBLIC: Get remote client configuration
2879
- */
2880
- async getRemoteClientConfig() {
2881
- return this.tenantApi.getRemoteClientConfig();
2882
- }
2883
- // ==========================================
2884
- // ADMIN OPERATIONS
2885
- // ==========================================
2886
- /**
2887
- * ADMIN: Update tenant information
2888
- * ✅ FIXED: Uses TenantPublicDTO directly like framework
2889
- */
2890
- async updateRemoteTenant(tenantData) {
2891
- return this.tenantApi.updateRemoteTenant(tenantData);
2892
- }
2893
- /**
2894
- * ADMIN: Get all tenant admins
2895
- */
2896
- async getAdmins() {
2897
- return this.tenantApi.getAdmins();
2898
- }
2899
- /**
2900
- * ADMIN: Create new admin
2901
- * ✅ FIXED: Renamed to match framework postAdmin method
2902
- */
2903
- async postAdmin(adminData) {
2904
- return this.tenantApi.postAdmin(adminData);
2905
- }
2906
- /**
2907
- * ADMIN: Update admin (toggle tenant association)
2908
- * ✅ FIXED: Renamed to match framework putAdmin method
2909
- */
2910
- async putAdmin(adminId, adminData) {
2911
- return this.tenantApi.putAdmin(adminId, adminData);
2912
- }
2913
- }
2914
-
2915
- /**
2916
- * @explorins/pers-sdk-tenant
2917
- *
2918
- * Platform-agnostic Tenant Domain SDK for PERS ecosystem
2919
- * Handles tenant management and admin operations for multi-tenant architecture
2920
- */
2921
- // API Layer
2922
- /**
2923
- * Create a complete Tenant SDK instance
2924
- *
2925
- * @param apiClient - Configured PERS API client
2926
- * @returns Tenant SDK with flattened structure for better DX
2927
- */
2928
- function createTenantSDK(apiClient) {
2929
- const tenantApi = new TenantApi(apiClient);
2930
- const tenantService = new TenantService(tenantApi);
2931
- return {
2932
- // Direct access to service methods (primary interface)
2933
- // ✅ FRAMEWORK ALIGNED: Only methods actually used by framework
2934
- // Public methods
2935
- getRemoteTenant: () => tenantService.getRemoteTenant(),
2936
- getRemoteLoginToken: () => tenantService.getRemoteLoginToken(),
2937
- getRemoteClientConfig: () => tenantService.getRemoteClientConfig(),
2938
- // Admin methods - ✅ FIXED: Matches framework method names exactly
2939
- updateRemoteTenant: (tenantData) => tenantService.updateRemoteTenant(tenantData),
2940
- getAdmins: () => tenantService.getAdmins(),
2941
- postAdmin: (adminData) => tenantService.postAdmin(adminData),
2942
- putAdmin: (adminId, adminData) => tenantService.putAdmin(adminId, adminData),
2943
- // Advanced access for edge cases
2944
- api: tenantApi,
2945
- service: tenantService
2946
- };
2947
- }
2948
-
2949
- class TokenApi {
2950
- constructor(apiClient) {
2951
- this.apiClient = apiClient;
2952
- this.basePath = '/tokens';
2953
- }
2954
- // ==========================================
2955
- // PUBLIC OPERATIONS
2956
- // ==========================================
2957
- /**
2958
- * PUBLIC: Get all remote tokens
2959
- * ENHANCED: Added admin filtering capability
2960
- */
2961
- async getRemoteTokens(includeInactive = false) {
2962
- const url = includeInactive ? `${this.basePath}?active=false` : `${this.basePath}`;
2963
- return this.apiClient.get(url);
2964
- }
2965
- /**
2966
- * PUBLIC: Get all remote token types
2967
- */
2968
- async getRemoteTokenTypes() {
2969
- return this.apiClient.get(`${this.basePath}/types`);
2970
- }
2971
- /**
2972
- * PUBLIC: Get active point token (was credit token)
2973
- */
2974
- async getRemoteActiveCreditToken() {
2975
- return this.apiClient.get(`${this.basePath}/points`);
2976
- }
2977
- /**
2978
- * PUBLIC: Get reward tokens
2979
- * ENHANCED: Added admin filtering capability
2980
- */
2981
- async getRemoteRewardTokens(includeInactive = false) {
2982
- const url = includeInactive ? `${this.basePath}/rewards?active=false` : `${this.basePath}/rewards`;
2983
- return this.apiClient.get(url);
2984
- }
2985
- /**
2986
- * PUBLIC: Get stamp tokens (was status tokens)
2987
- * ENHANCED: Added admin filtering capability
2988
- */
2989
- async getRemoteStatusTokens(includeInactive = false) {
2990
- const url = includeInactive ? `${this.basePath}/stamps?active=false` : `${this.basePath}/stamps`;
2991
- return this.apiClient.get(url);
2992
- }
2993
- /**
2994
- * PUBLIC: Get token by contract address
2995
- */
2996
- async getTokenByContractAddress(contractAddress, contractTokenId) {
2997
- let url = `${this.basePath}/address/${contractAddress}`;
2998
- if (contractTokenId) {
2999
- url += `?contractTokenId=${contractTokenId}`;
3000
- }
3001
- return this.apiClient.get(url);
3002
- }
3003
- // ==========================================
3004
- // ADMIN OPERATIONS
3005
- // ==========================================
3006
- /**
3007
- * ADMIN: Create new token
3008
- */
3009
- async createToken(tokenData) {
3010
- return this.apiClient.post(`${this.basePath}`, tokenData);
3011
- }
3012
- /**
3013
- * ADMIN: Update token
3014
- */
3015
- async updateToken(tokenId, tokenData) {
3016
- return this.apiClient.put(`${this.basePath}/${tokenId}`, tokenData);
3017
- }
3018
- /**
3019
- * ADMIN: Toggle token active status
3020
- * FIXED: Now calls correct endpoint
3021
- */
3022
- async toggleTokenActive(tokenId) {
3023
- return this.apiClient.put(`${this.basePath}/${tokenId}/status`, {});
3024
- }
3025
- /**
3026
- * ADMIN: Set mainnet contract address
3027
- */
3028
- async setMainnetContract(tokenId, contractAddress, chainId) {
3029
- return this.apiClient.put(`${this.basePath}/${tokenId}/mainnet`, {
3030
- contractAddress,
3031
- chainId
3032
- });
3033
- }
3034
- /**
3035
- * ADMIN: Create token metadata
3036
- */
3037
- async createTokenMetadata(tokenId, tokenData) {
3038
- return this.apiClient.post(`${this.basePath}/${tokenId}/metadata`, tokenData);
3039
- }
3040
- /**
3041
- * ADMIN: Toggle token metadata status (separate from token status)
3042
- */
3043
- async toggleTokenMetadataStatus(metadataId) {
3044
- return this.apiClient.put(`${this.basePath}/metadata/${metadataId}/status`, {});
3045
- }
3046
- /**
3047
- * ADMIN: Create token type
3048
- */
3049
- async createTokenType(tokenType) {
3050
- return this.apiClient.post(`${this.basePath}/types`, tokenType);
3051
- }
3052
- }
3053
-
3054
- /**
3055
- * Platform-Agnostic Token Service
3056
- *
3057
- * Contains token business logic and operations that work across platforms.
3058
- * No framework dependencies - pure TypeScript business logic.
3059
- * Matches framework TokenApiService capabilities exactly.
3060
- */
3061
- class TokenService {
3062
- constructor(tokenApi) {
3063
- this.tokenApi = tokenApi;
3064
- }
3065
- // ==========================================
3066
- // PUBLIC OPERATIONS
3067
- // ==========================================
3068
- /**
3069
- * PUBLIC: Get all remote tokens
3070
- */
3071
- async getRemoteTokens() {
3072
- return this.tokenApi.getRemoteTokens();
3073
- }
3074
- /**
3075
- * PUBLIC: Get all remote token types
3076
- */
3077
- async getRemoteTokenTypes() {
3078
- return this.tokenApi.getRemoteTokenTypes();
3079
- }
3080
- /**
3081
- * PUBLIC: Get active credit token
3082
- */
3083
- async getRemoteActiveCreditToken() {
3084
- return this.tokenApi.getRemoteActiveCreditToken();
3085
- }
3086
- /**
3087
- * PUBLIC: Get reward tokens
3088
- */
3089
- async getRemoteRewardTokens() {
3090
- return this.tokenApi.getRemoteRewardTokens();
3091
- }
3092
- /**
3093
- * PUBLIC: Get status tokens
3094
- */
3095
- async getRemoteStatusTokens() {
3096
- return this.tokenApi.getRemoteStatusTokens();
3097
- }
3098
- /**
3099
- * PUBLIC: Get token by contract address
3100
- * ✅ FIXED: Matches framework parameter types exactly
3101
- */
3102
- async getTokenByContractAddress(contractAddress, contractTokenId) {
3103
- return this.tokenApi.getTokenByContractAddress(contractAddress, contractTokenId);
3104
- }
3105
- // ==========================================
3106
- // ADMIN OPERATIONS
3107
- // ==========================================
3108
- /**
3109
- * ADMIN: Create token metadata
3110
- */
3111
- async createTokenMetadata(tokenId, tokenData) {
3112
- return this.tokenApi.createTokenMetadata(tokenId, tokenData);
3113
- }
3114
- /**
3115
- * ADMIN: Toggle token active status
3116
- */
3117
- async toggleTokenActive(tokenId) {
3118
- return this.tokenApi.toggleTokenActive(tokenId);
3119
- }
3120
- /**
3121
- * ADMIN: Create new token
3122
- */
3123
- async createToken(tokenData) {
3124
- return this.tokenApi.createToken(tokenData);
3125
- }
3126
- /**
3127
- * ADMIN: Update token
3128
- */
3129
- async updateToken(tokenId, tokenData) {
3130
- return this.tokenApi.updateToken(tokenId, tokenData);
3131
- }
3132
- /**
3133
- * ADMIN: Set mainnet contract address
3134
- */
3135
- async setMainnetContract(tokenId, contractAddress, chainId) {
3136
- return this.tokenApi.setMainnetContract(tokenId, contractAddress, chainId);
3137
- }
3138
- /**
3139
- * ADMIN: Toggle token metadata status
3140
- */
3141
- async toggleTokenMetadataStatus(metadataId) {
3142
- return this.tokenApi.toggleTokenMetadataStatus(metadataId);
3143
- }
3144
- /**
3145
- * ADMIN: Create token type
3146
- */
3147
- async createTokenType(tokenType) {
3148
- return this.tokenApi.createTokenType(tokenType);
3149
- }
3150
- }
3151
-
3152
- /**
3153
- * Token SDK - Class-based Promise SDK for Token Operations
3154
- *
3155
- * Modern, performant SDK with direct method access and excellent TypeScript support.
3156
- * Optimized for bundle size, performance, and developer experience.
3157
- *
3158
- * Usage:
3159
- * const tokenSDK = new TokenSDK(apiClient);
3160
- * const tokens = await tokenSDK.getTokens();
3161
- * const creditToken = await tokenSDK.getActiveCreditToken();
3162
- */
3163
- class TokenSDK {
3164
- constructor(apiClient) {
3165
- this.tokenApi = new TokenApi(apiClient);
3166
- this.tokenService = new TokenService(this.tokenApi);
3167
- }
3168
- // ==========================================
3169
- // CONVENIENCE METHODS - Direct Promise API
3170
- // ==========================================
3171
- // Simplified method names for better developer experience
3172
- /**
3173
- * Get all tokens
3174
- * @returns Promise with all available tokens
3175
- */
3176
- async getTokens() {
3177
- return this.tokenService.getRemoteTokens();
3178
- }
3179
- /**
3180
- * Get all token types
3181
- * @returns Promise with all available token types
3182
- */
3183
- async getTokenTypes() {
3184
- return this.tokenService.getRemoteTokenTypes();
3185
- }
3186
- /**
3187
- * Get the active credit token
3188
- * @returns Promise with the current active credit token
3189
- */
3190
- async getActiveCreditToken() {
3191
- return this.tokenService.getRemoteActiveCreditToken();
3192
- }
3193
- /**
3194
- * Get all reward tokens
3195
- * @returns Promise with all reward tokens
3196
- */
3197
- async getRewardTokens() {
3198
- return this.tokenService.getRemoteRewardTokens();
3199
- }
3200
- /**
3201
- * Get all status tokens
3202
- * @returns Promise with all status tokens
3203
- */
3204
- async getStatusTokens() {
3205
- return this.tokenService.getRemoteStatusTokens();
3206
- }
3207
- /**
3208
- * Get token by contract address
3209
- * @param contractAddress - The contract address to search for
3210
- * @param contractTokenId - Optional contract token ID
3211
- * @returns Promise with the matching token
3212
- */
3213
- async getTokenByContract(contractAddress, contractTokenId = null) {
3214
- return this.tokenService.getTokenByContractAddress(contractAddress, contractTokenId);
3215
- }
3216
- // ==========================================
3217
- // ADMIN METHODS - Token Management
3218
- // ==========================================
3219
- /**
3220
- * Create token metadata
3221
- * @param tokenId - The token ID
3222
- * @param tokenData - The token storage data
3223
- * @returns Promise with the updated token
3224
- */
3225
- async createTokenMetadata(tokenId, tokenData) {
3226
- return this.tokenService.createTokenMetadata(tokenId, tokenData);
3227
- }
3228
- /**
3229
- * Toggle token active status
3230
- * @param tokenId - The token ID to toggle
3231
- * @returns Promise with the updated token
3232
- */
3233
- async toggleTokenActive(tokenId) {
3234
- return this.tokenService.toggleTokenActive(tokenId);
3235
- }
3236
- /**
3237
- * Create a new token
3238
- * @param tokenData - The token creation data
3239
- * @returns Promise with the created token
3240
- */
3241
- async createToken(tokenData) {
3242
- return this.tokenService.createToken(tokenData);
3243
- }
3244
- /**
3245
- * Update an existing token
3246
- * @param tokenId - The token ID to update
3247
- * @param tokenData - The token update data
3248
- * @returns Promise with the updated token
3249
- */
3250
- async updateToken(tokenId, tokenData) {
3251
- return this.tokenService.updateToken(tokenId, tokenData);
3252
- }
3253
- /**
3254
- * Set mainnet contract address for a token
3255
- * @param tokenId - The token ID
3256
- * @param contractAddress - The contract address
3257
- * @param chainId - The blockchain chain ID
3258
- * @returns Promise with the updated token
3259
- */
3260
- async setMainnetContract(tokenId, contractAddress, chainId) {
3261
- return this.tokenService.setMainnetContract(tokenId, contractAddress, chainId);
3262
- }
3263
- /**
3264
- * Toggle token metadata status
3265
- * @param metadataId - The metadata ID to toggle
3266
- * @returns Promise with the updated metadata
3267
- */
3268
- async toggleTokenMetadataStatus(metadataId) {
3269
- return this.tokenService.toggleTokenMetadataStatus(metadataId);
3270
- }
3271
- /**
3272
- * Create a new token type
3273
- * @param tokenType - The token type data
3274
- * @returns Promise with the created token type
3275
- */
3276
- async createTokenType(tokenType) {
3277
- return this.tokenService.createTokenType(tokenType);
3278
- }
3279
- // ==========================================
3280
- // ADVANCED ACCESS - For Complex Operations
3281
- // ==========================================
3282
- /**
3283
- * Get direct access to the token service for advanced operations
3284
- * @returns The underlying TokenService instance
3285
- */
3286
- getTokenService() {
3287
- return this.tokenService;
3288
- }
3289
- /**
3290
- * Get direct access to the token API for low-level operations
3291
- * @returns The underlying TokenApi instance
3292
- */
3293
- getTokenApi() {
3294
- return this.tokenApi;
3295
- }
3296
- // ==========================================
3297
- // FRAMEWORK COMPATIBILITY METHODS
3298
- // ==========================================
3299
- // These maintain compatibility with existing framework method names
3300
- /**
3301
- * @deprecated Use getTokens() instead
3302
- * Framework compatibility method
3303
- */
3304
- async getRemoteTokens() {
3305
- return this.getTokens();
3306
- }
3307
- /**
3308
- * @deprecated Use getTokenTypes() instead
3309
- * Framework compatibility method
3310
- */
3311
- async getRemoteTokenTypes() {
3312
- return this.getTokenTypes();
3313
- }
3314
- /**
3315
- * @deprecated Use getActiveCreditToken() instead
3316
- * Framework compatibility method
3317
- */
3318
- async getRemoteActiveCreditToken() {
3319
- return this.getActiveCreditToken();
3320
- }
3321
- /**
3322
- * @deprecated Use getRewardTokens() instead
3323
- * Framework compatibility method
3324
- */
3325
- async getRemoteRewardTokens() {
3326
- return this.getRewardTokens();
3327
- }
3328
- /**
3329
- * @deprecated Use getStatusTokens() instead
3330
- * Framework compatibility method
3331
- */
3332
- async getRemoteStatusTokens() {
3333
- return this.getStatusTokens();
3334
- }
3335
- /**
3336
- * @deprecated Use getTokenByContract() instead
3337
- * Framework compatibility method
3338
- */
3339
- async getTokenByContractAddress(contractAddress, contractTokenId) {
3340
- return this.getTokenByContract(contractAddress, contractTokenId);
3341
- }
3342
- }
3343
-
3344
- /**
3345
- * Abstract Base Token Service - Explicit Initialization Pattern
3346
- *
3347
- * Platform-agnostic token operations with Promise-based API.
3348
- * Framework services extend this and control initialization lifecycle.
3349
- *
3350
- * Benefits:
3351
- * - Explicit initialization control
3352
- * - Better error boundaries
3353
- * - Clear lifecycle management
3354
- * - Testable initialization state
3355
- * - Zero framework dependencies
3356
- */
3357
- class BaseTokenService {
3358
- constructor() {
3359
- this._isInitialized = false;
3360
- }
3361
- // ==========================================
3362
- // INITIALIZATION LIFECYCLE
3363
- // ==========================================
3364
- /**
3365
- * LIFECYCLE: Initialize token service with API client
3366
- * Must be called before using any token operations
3367
- */
3368
- initializeTokenService(apiClient) {
3369
- if (!apiClient) {
3370
- throw new Error('Cannot initialize TokenService: apiClient is null or undefined');
3371
- }
3372
- if (!this._isInitialized) {
3373
- this._tokenApi = new TokenApi(apiClient);
3374
- this._tokenBusinessService = new TokenService(this._tokenApi);
3375
- this._isInitialized = true;
3376
- }
3377
- }
3378
- /**
3379
- * LIFECYCLE: Check if token service is initialized
3380
- */
3381
- get isTokenServiceInitialized() {
3382
- return this._isInitialized;
3383
- }
3384
- /**
3385
- * INTERNAL: Get token business service (throws if not initialized)
3386
- */
3387
- get tokenBusinessService() {
3388
- if (!this._tokenBusinessService) {
3389
- throw new Error('TokenService not initialized. Call initializeTokenService(apiClient) first.');
3390
- }
3391
- return this._tokenBusinessService;
3392
- }
3393
- // ==========================================
3394
- // PUBLIC OPERATIONS
3395
- // ==========================================
3396
- /**
3397
- * PUBLIC: Get all remote tokens
3398
- */
3399
- getRemoteTokens() {
3400
- return this.tokenBusinessService.getRemoteTokens();
3401
- }
3402
- /**
3403
- * PUBLIC: Get all remote token types
3404
- */
3405
- getRemoteTokenTypes() {
3406
- return this.tokenBusinessService.getRemoteTokenTypes();
3407
- }
3408
- /**
3409
- * PUBLIC: Get active credit token
3410
- */
3411
- getRemoteActiveCreditToken() {
3412
- return this.tokenBusinessService.getRemoteActiveCreditToken();
3413
- }
3414
- /**
3415
- * PUBLIC: Get reward tokens
3416
- */
3417
- getRemoteRewardTokens() {
3418
- return this.tokenBusinessService.getRemoteRewardTokens();
3419
- }
3420
- /**
3421
- * PUBLIC: Get status tokens
3422
- */
3423
- getRemoteStatusTokens() {
3424
- return this.tokenBusinessService.getRemoteStatusTokens();
3425
- }
3426
- /**
3427
- * PUBLIC: Get token by contract address
3428
- */
3429
- getTokenByContractAddress(contractAddress, contractTokenId) {
3430
- return this.tokenBusinessService.getTokenByContractAddress(contractAddress, contractTokenId);
3431
- }
3432
- // ==========================================
3433
- // ADMIN OPERATIONS
3434
- // ==========================================
3435
- /**
3436
- * ADMIN: Create token metadata
3437
- */
3438
- createTokenMetadata(tokenId, tokenData) {
3439
- return this.tokenBusinessService.createTokenMetadata(tokenId, tokenData);
3440
- }
3441
- /**
3442
- * ADMIN: Toggle token active status
3443
- */
3444
- toggleTokenActive(tokenId) {
3445
- return this.tokenBusinessService.toggleTokenActive(tokenId);
3446
- }
3447
- /**
3448
- * ADMIN: Create new token
3449
- */
3450
- createToken(tokenData) {
3451
- return this.tokenBusinessService.createToken(tokenData);
3452
- }
3453
- /**
3454
- * ADMIN: Update token
3455
- */
3456
- updateToken(tokenId, tokenData) {
3457
- return this.tokenBusinessService.updateToken(tokenId, tokenData);
3458
- }
3459
- /**
3460
- * ADMIN: Set mainnet contract address
3461
- */
3462
- setMainnetContract(tokenId, contractAddress, chainId) {
3463
- return this.tokenBusinessService.setMainnetContract(tokenId, contractAddress, chainId);
3464
- }
3465
- /**
3466
- * ADMIN: Toggle token metadata status
3467
- */
3468
- toggleTokenMetadataStatus(metadataId) {
3469
- return this.tokenBusinessService.toggleTokenMetadataStatus(metadataId);
3470
- }
3471
- /**
3472
- * ADMIN: Create token type
3473
- */
3474
- createTokenType(tokenType) {
3475
- return this.tokenBusinessService.createTokenType(tokenType);
3476
- }
3477
- }
3478
-
3479
- /**
3480
- * Platform-Agnostic User API Client
3481
- *
3482
- * Handles user operations using the PERS backend RESTful API.
3483
- * Updated to use new /users endpoints with enhanced security and consistency.
3484
- * Maintains framework UserApiService method compatibility.
3485
- */
3486
- class UserApi {
3487
- constructor(apiClient) {
3488
- this.apiClient = apiClient;
3489
- this.basePath = '/users';
3490
- }
3491
- // ==========================================
3492
- // PUBLIC OPERATIONS
3493
- // ==========================================
3494
- /**
3495
- * PUBLIC: Get all users public profiles with optional filtering
3496
- * ✅ UPDATED: Uses new RESTful /users/public endpoint
3497
- */
3498
- async getAllUsersPublicProfiles(filter = null) {
3499
- let url = `${this.basePath}/public`;
3500
- if (filter) {
3501
- // ✅ MAINTAINED: Same parameter pattern for compatibility
3502
- const params = new URLSearchParams();
3503
- params.set('filterKey', filter.key);
3504
- params.set('filterValue', filter.value);
3505
- url += `?${params.toString()}`;
3506
- }
3507
- return this.apiClient.get(url);
3508
- }
3509
- // ==========================================
3510
- // AUTHENTICATED OPERATIONS
3511
- // ==========================================
3512
- /**
3513
- * AUTH: Get current authenticated user
3514
- * ✅ UPDATED: Uses new RESTful /users/me endpoint
3515
- */
3516
- async getRemoteUser() {
3517
- return this.apiClient.get(`${this.basePath}/me`);
3518
- }
3519
- /**
3520
- * AUTH: Update current authenticated user
3521
- * ✅ UPDATED: Uses new RESTful /users/me endpoint
3522
- */
3523
- async updateRemoteUser(updateRequest) {
3524
- return this.apiClient.put(`${this.basePath}/me`, updateRequest);
3525
- }
3526
- // ==========================================
3527
- // ADMIN OPERATIONS
3528
- // ==========================================
3529
- /**
3530
- * ADMIN: Get all remote users with query parameters
3531
- * ✅ UPDATED: Uses new RESTful /users endpoint with role-based access
3532
- * Note: Admin users get full data, non-admin users get public profiles only
3533
- */
3534
- async getAllRemoteUsers() {
3535
- // ✅ MAINTAINED: Same merge=soft parameter for compatibility
3536
- const url = `${this.basePath}?merge=soft`;
3537
- return this.apiClient.get(url);
3538
- }
3539
- /**
3540
- * ADMIN: Update user as admin
3541
- * ✅ UPDATED: Uses new RESTful /users/{id} endpoint
3542
- */
3543
- async updateUserAsAdmin(id, userData) {
3544
- return this.apiClient.put(`${this.basePath}/${id}`, userData);
3545
- }
3546
- /**
3547
- * ADMIN: Toggle user active status
3548
- * ✅ UPDATED: Uses new consistent /users/{id}/status endpoint
3549
- * Enhanced: Follows RESTful status management pattern across all domains
3550
- */
3551
- async toggleUserActiveStatusByUser(user) {
3552
- return this.apiClient.put(`${this.basePath}/${user.id}/status`, {});
3553
- }
3554
- /**
3555
- * ADMIN: Get user by unique identifier
3556
- * ✅ UPDATED: Uses new RESTful /users/{id} endpoint
3557
- */
3558
- async getUserByUniqueIdentifier(id) {
3559
- return this.apiClient.get(`${this.basePath}/${id}`);
3560
- }
3561
- }
3562
-
3563
- /**
3564
- * Platform-Agnostic User Service
3565
- *
3566
- * Contains user business logic and operations that work across platforms.
3567
- * No framework dependencies - pure TypeScript business logic.
3568
- * Matches framework UserApiService capabilities exactly.
3569
- */
3570
- class UserService {
3571
- constructor(userApi) {
3572
- this.userApi = userApi;
3573
- }
3574
- // ==========================================
3575
- // PUBLIC OPERATIONS
3576
- // ==========================================
3577
- /**
3578
- * PUBLIC: Get all users public profiles with optional filtering
3579
- * ✅ FIXED: Uses framework-compatible inline filter type
3580
- */
3581
- async getAllUsersPublicProfiles(filter = null) {
3582
- return this.userApi.getAllUsersPublicProfiles(filter);
3583
- }
3584
- // ==========================================
3585
- // AUTHENTICATED OPERATIONS
3586
- // ==========================================
3587
- /**
3588
- * AUTH: Get current authenticated user
3589
- */
3590
- async getRemoteUser() {
3591
- return this.userApi.getRemoteUser();
3592
- }
3593
- /**
3594
- * AUTH: Update current authenticated user
3595
- */
3596
- async updateRemoteUser(updateRequest) {
3597
- return this.userApi.updateRemoteUser(updateRequest);
3598
- }
3599
- // ==========================================
3600
- // ADMIN OPERATIONS
3601
- // ==========================================
3602
- /**
3603
- * ADMIN: Get all remote users
3604
- * ✅ FIXED: Matches API method signature (no parameters needed)
3605
- */
3606
- async getAllRemoteUsers() {
3607
- return this.userApi.getAllRemoteUsers();
3608
- }
3609
- /**
3610
- * ADMIN: Update user as admin
3611
- */
3612
- async updateUserAsAdmin(id, userData) {
3613
- return this.userApi.updateUserAsAdmin(id, userData);
3614
- }
3615
- async getUserByUniqueIdentifier(id) {
3616
- return this.userApi.getUserByUniqueIdentifier(id);
3617
- }
3618
- /**
3619
- * ADMIN: Toggle user active status by user object
3620
- * ✅ FIXED: Matches API method signature exactly
3621
- */
3622
- async toggleUserActiveStatusByUser(user) {
3623
- return this.userApi.toggleUserActiveStatusByUser(user);
3624
- }
3625
- }
3626
-
3627
- /**
3628
- * @explorins/pers-sdk-user
3629
- *
3630
- * Platform-agnostic User Domain SDK for PERS ecosystem
3631
- * Handles user management, profiles, and authentication operations
3632
- */
3633
- // API Layer
3634
- /**
3635
- * Create a complete User SDK instance
3636
- *
3637
- * @param apiClient - Configured PERS API client
3638
- * @returns User SDK with flattened structure for better DX
3639
- */
3640
- function createUserSDK(apiClient) {
3641
- const userApi = new UserApi(apiClient);
3642
- const userService = new UserService(userApi);
3643
- return {
3644
- // Direct access to service methods (primary interface)
3645
- // Public methods - matches framework exactly
3646
- getAllUsersPublicProfiles: (filter = null) => userService.getAllUsersPublicProfiles(filter),
3647
- // Auth methods - matches framework exactly
3648
- getRemoteUser: () => userService.getRemoteUser(),
3649
- updateRemoteUser: (updateRequest) => userService.updateRemoteUser(updateRequest),
3650
- // Admin methods - matches framework exactly
3651
- getAllRemoteUsers: () => userService.getAllRemoteUsers(),
3652
- updateUserAsAdmin: (id, userData) => userService.updateUserAsAdmin(id, userData),
3653
- toggleUserActiveStatusByUser: (user) => userService.toggleUserActiveStatusByUser(user),
3654
- getUserByUniqueIdentifier: (id) => userService.getUserByUniqueIdentifier(id),
3655
- // Advanced access for edge cases
3656
- api: userApi,
3657
- service: userService
3658
- };
3659
- }
3660
-
3661
- /**
3662
- * Platform-Agnostic User Status API Client
3663
- *
3664
- * Handles user status operations using the PERS backend.
3665
- * Matches framework UserStatusApiService methods exactly.
3666
- *
3667
- * ✅ UPDATED: All endpoints updated to new RESTful /users patterns
3668
- *
3669
- * Error handling patterns follow framework implementation:
3670
- * - getRemoteEarnedUserStatus() uses silent fallback (empty array)
3671
- * - Other operations throw errors for proper error handling
3672
- */
3673
- class UserStatusApi {
3674
- constructor(apiClient) {
3675
- this.apiClient = apiClient;
3676
- this.basePath = '/users';
3677
- }
3678
- // ==========================================
3679
- // PUBLIC OPERATIONS
3680
- // ==========================================
3681
- /**
3682
- * PUBLIC: Get remote user status types
3683
- * ✅ UPDATED: /user/status-type → /users/status-types
3684
- */
3685
- async getRemoteUserStatusTypes() {
3686
- try {
3687
- return await this.apiClient.get(`${this.basePath}/status-types`);
3688
- }
3689
- catch (error) {
3690
- console.error('Error getting user status types', error);
3691
- throw error;
3692
- }
3693
- }
3694
- // ==========================================
3695
- // AUTHENTICATED OPERATIONS
3696
- // ==========================================
3697
- /**
3698
- * AUTH: Get earned user status for authenticated user
3699
- * ✅ UPDATED: /user/auth/status → /users/me/status
3700
- * ✅ FIXED: Returns UserStatusTypeDTO[] to match framework exactly
3701
- * Note: Uses silent fallback pattern from framework - returns empty array on error
3702
- */
3703
- async getRemoteEarnedUserStatus() {
3704
- try {
3705
- return await this.apiClient.get(`${this.basePath}/me/status`);
3706
- }
3707
- catch (error) {
3708
- console.error('Error getting user status', error);
3709
- // ✅ FIXED: Silent fallback pattern from framework implementation
3710
- return [];
3711
- }
3712
- }
3713
- // ==========================================
3714
- // ADMIN OPERATIONS
3715
- // ==========================================
3716
- /**
3717
- * ADMIN: Create user status type
3718
- * ✅ UPDATED: /user/admin/status-type → /users/status-types
3719
- */
3720
- async createUserStatusType(userStatusType) {
3721
- try {
3722
- return await this.apiClient.post(`${this.basePath}/status-types`, userStatusType);
3723
- }
3724
- catch (error) {
3725
- console.error('Error creating user status type', error);
3726
- throw error;
3727
- }
3728
- }
3729
- }
3730
-
3731
- /**
3732
- * Platform-Agnostic User Status Service
3733
- *
3734
- * Contains user status business logic and operations that work across platforms.
3735
- * No framework dependencies - pure TypeScript business logic.
3736
- * Matches framework UserStatusApiService capabilities exactly.
3737
- */
3738
- class UserStatusService {
3739
- constructor(userStatusApi) {
3740
- this.userStatusApi = userStatusApi;
3741
- }
3742
- // ==========================================
3743
- // PUBLIC OPERATIONS
3744
- // ==========================================
3745
- /**
3746
- * PUBLIC: Get remote user status types
3747
- */
3748
- async getRemoteUserStatusTypes() {
3749
- return this.userStatusApi.getRemoteUserStatusTypes();
3750
- }
3751
- // ==========================================
3752
- // AUTHENTICATED OPERATIONS
3753
- // ==========================================
3754
- /**
3755
- * AUTH: Get earned user status for authenticated user
3756
- */
3757
- async getRemoteEarnedUserStatus() {
3758
- return this.userStatusApi.getRemoteEarnedUserStatus();
3759
- }
3760
- // ==========================================
3761
- // ADMIN OPERATIONS
3762
- // ==========================================
3763
- /**
3764
- * ADMIN: Create user status type
3765
- */
3766
- async createUserStatusType(userStatusType) {
3767
- return this.userStatusApi.createUserStatusType(userStatusType);
3768
- }
3769
- }
3770
-
3771
- /**
3772
- * @explorins/pers-sdk-user-status
3773
- *
3774
- * Platform-agnostic User Status Domain SDK for PERS ecosystem
3775
- * Handles user status management and type operations
3776
- */
3777
- // API Layer
3778
- /**
3779
- * Create a complete User Status SDK instance
3780
- *
3781
- * @param apiClient - Configured PERS API client
3782
- * @returns User Status SDK with flattened structure for better DX
3783
- */
3784
- function createUserStatusSDK(apiClient) {
3785
- const userStatusApi = new UserStatusApi(apiClient);
3786
- const userStatusService = new UserStatusService(userStatusApi);
3787
- return {
3788
- // Direct access to service methods (primary interface)
3789
- // ✅ FRAMEWORK ALIGNED: Only methods actually used by framework
3790
- // Public methods
3791
- getRemoteUserStatusTypes: () => userStatusService.getRemoteUserStatusTypes(),
3792
- // Auth methods
3793
- getRemoteEarnedUserStatus: () => userStatusService.getRemoteEarnedUserStatus(),
3794
- // Admin methods
3795
- createUserStatusType: (userStatusType) => userStatusService.createUserStatusType(userStatusType),
3796
- // Advanced access for edge cases
3797
- api: userStatusApi,
3798
- service: userStatusService
3799
- };
3800
- }
3801
-
3802
- /**
3803
- * Platform-Agnostic Web3 Chain API Client
3804
- *
3805
- * Handles blockchain chain operations using the PERS backend.
3806
- * Uses @explorins/web3-ts types for perfect framework compatibility.
3807
- */
3808
- class Web3ChainApi {
3809
- constructor(apiClient) {
3810
- this.apiClient = apiClient;
3811
- this.basePath = '/chains';
3812
- }
3813
- // ==========================================
3814
- // PUBLIC OPERATIONS
3815
- // ==========================================
3816
- /**
3817
- * PUBLIC: Get chain data by chain ID
3818
- * ✅ Returns ChainData exactly as framework expects from @explorins/web3-ts
3819
- */
3820
- async getChainData(chainId) {
3821
- try {
3822
- console.log('🔍 [Web3ChainApi] Fetching chain data for chainId:', chainId);
3823
- const response = await this.apiClient.get(`${this.basePath}/${chainId}`);
3824
- if (!response) {
3825
- throw new Error(`No chain data received for chainId: ${chainId}`);
3826
- }
3827
- return response;
3828
- }
3829
- catch (error) {
3830
- console.error('❌ [Web3ChainApi] Failed to get chain data:', {
3831
- chainId,
3832
- error: error instanceof Error ? error.message : String(error)
3833
- });
3834
- throw error;
3835
- }
3836
- }
3837
- }
3838
-
3839
- const isTokenExpired = (token, margin = 60) => {
3840
- // ✅ SANITIZE: Remove any words (Bearer etc) if exists and get the token
3841
- const cleanToken = token.split(' ')[1] || token;
3842
- // ✅ VALIDATION: Check if token is jwt
3843
- if (!cleanToken || cleanToken.split('.').length !== 3) {
3844
- return true; // Consider invalid tokens as expired
3845
- }
3846
- try {
3847
- // ✅ TYPE-SAFE: Decode with proper typing
3848
- const decoded = jwtDecode(cleanToken);
3849
- const currentTime = Math.floor(Date.now() / 1000);
3850
- // ✅ CONFIGURABLE: Use provided margin (default 60 seconds)
3851
- return decoded.exp < (currentTime + margin);
3852
- }
3853
- catch (error) {
3854
- console.error('[SDK JWT Utils] Error decoding JWT token:', error);
3855
- return true; // Consider unparseable tokens as expired
3856
- }
3857
- };
3858
-
3859
- class Web3ChainService {
3860
- constructor(web3ChainApi, providerService) {
3861
- this.web3ChainApi = web3ChainApi;
3862
- this.providerService = providerService;
3863
- this.web3InstanceCache = new Map();
3864
- }
3865
- async getWeb3ByChainId(chainId) {
3866
- const cached = this.web3InstanceCache.get(chainId);
3867
- // ✅ SMART CACHE: Check if cache is valid based on token expiration
3868
- if (cached && !this.checkIsTokenExpired(cached.chainData.authHeader)) {
3869
- console.log(`♻️ [Web3ChainService] Using cached Web3 instance for chain ${chainId}`);
3870
- return cached.web3Instance;
3871
- }
3872
- // ✅ CREATE WITH ERROR RECOVERY: Handle auth errors gracefully
3873
- try {
3874
- console.log(`🔧 [Web3ChainService] Creating new Web3 instance for chain ${chainId}`);
3875
- const { web3, chainData } = await this.createWeb3Instance(chainId);
3876
- // ✅ CACHE NEW INSTANCE
3877
- this.web3InstanceCache.set(chainId, {
3878
- web3Instance: web3,
3879
- chainData: chainData,
3880
- createdAt: Date.now(),
3881
- chainId
3882
- });
3883
- return web3;
3884
- }
3885
- catch (error) {
3886
- // ✅ AUTH ERROR RECOVERY: Clear cache and retry once
3887
- if (this.isAuthError(error)) {
3888
- console.warn(`🔄 [Web3ChainService] Auth error detected, clearing cache and retrying...`);
3889
- this.web3InstanceCache.delete(chainId);
3890
- // Retry once with fresh instance
3891
- const { web3, chainData } = await this.createWeb3Instance(chainId);
3892
- this.web3InstanceCache.set(chainId, {
3893
- web3Instance: web3,
3894
- chainData: chainData,
3895
- createdAt: Date.now(),
3896
- chainId
3897
- });
3898
- return web3;
3899
- }
3900
- throw error;
3901
- }
3902
- }
3903
- async getChainDataWithCache(chainId) {
3904
- const cached = this.web3InstanceCache.get(chainId);
3905
- //const now = Date.now();
3906
- if (cached && !this.checkIsTokenExpired(cached.chainData.authHeader)) {
3907
- console.log(`♻️ [Web3ChainService] Using cached ChainData for chain ${chainId}`);
3908
- return cached.chainData;
3909
- }
3910
- // If not cached, fetch fresh data
3911
- const chainData = await this.getChainDataById(chainId);
3912
- if (!chainData) {
3913
- throw new Error(`Chain data not found for chainId: ${chainId}`);
3914
- }
3915
- return chainData;
3916
- }
3917
- checkIsTokenExpired(authHeader) {
3918
- // ✅ NULL CHECK: Handle undefined case
3919
- if (!authHeader) {
3920
- return false; // No token means no expiration (public chains)
3921
- }
3922
- // ✅ FUNCTION CALL: Use imported function, not method
3923
- return isTokenExpired(authHeader);
3924
- }
3925
- async createWeb3Instance(chainId) {
3926
- const chainData = await this.getChainDataById(chainId);
3927
- if (!chainData) {
3928
- throw new Error(`Chain data not found for chainId: ${chainId}`);
3929
- }
3930
- // ✅ CRITICAL CHECK: Ensure authHeader is present for private chains
3931
- if (chainData.chainType === 'PRIVATE' && !chainData.authHeader) {
3932
- console.error('❌ [Web3ChainService] CRITICAL: Private chain missing authHeader!');
3933
- throw new Error(`Private chain ${chainId} missing authentication header`);
3934
- }
3935
- const web3 = await this.providerService.getWeb3(chainId, chainData.chainType || 'PUBLIC', chainData);
3936
- return { web3, chainData };
3937
- }
3938
- // ✅ HELPER: Type-safe error checking
3939
- isAuthError(error) {
3940
- const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
3941
- return (message.includes('unauthorized') ||
3942
- message.includes('401') ||
3943
- message.includes('token expired') ||
3944
- message.includes('invalid token'));
3945
- }
3946
- async getChainDataById(chainId) {
3947
- try {
3948
- return await this.web3ChainApi.getChainData(chainId);
3949
- }
3950
- catch (error) {
3951
- console.error('❌ [SDK Web3ChainService] Error getting chain data for chainId:', chainId, error);
3952
- return null;
3953
- }
3954
- }
3955
- }
3956
-
3957
- // ✅ REVERT: Función síncrona como el código comentado que funciona
3958
- const getWeb3ProviderFromChainData = (chainData, timeout = 15000, customUserAgentName = '', tokenRefresher) => {
3959
- console.log(`🔧 [getWeb3FCD] Creating provider for chain ${chainData.chainId || 'unknown'}`);
3960
- let ethersProvider;
3961
- if (chainData.authHeader) {
3962
- // ✅ AUTHENTICATED: For private chains
3963
- const fetchRequest = new FetchRequest(chainData.rpcUrl);
3964
- fetchRequest.timeout = timeout;
3965
- // ✅ IMPROVED AUTH HEADER: Better handling
3966
- const authValue = chainData.authHeader.startsWith('Bearer ')
3967
- ? chainData.authHeader
3968
- : `Bearer ${chainData.authHeader}`;
3969
- fetchRequest.setHeader('Authorization', authValue);
3970
- fetchRequest.setHeader('Content-Type', 'application/json');
3971
- fetchRequest.setHeader('Accept', 'application/json');
3972
- if (customUserAgentName) {
3973
- fetchRequest.setHeader('User-Agent', customUserAgentName);
3974
- }
3975
- ethersProvider = new JsonRpcProvider(fetchRequest, undefined, {
3976
- staticNetwork: false,
3977
- polling: false,
3978
- batchMaxCount: 1, // ✅ DISABLE BATCHING: Better for private chains
3979
- });
3980
- }
3981
- else {
3982
- // ✅ PUBLIC: For public chains
3983
- ethersProvider = new JsonRpcProvider(chainData.rpcUrl, undefined, {
3984
- staticNetwork: false,
3985
- polling: false,
3986
- });
3987
- }
3988
- console.log(`✅ [getWeb3FCD] Provider created successfully`);
3989
- return {
3990
- web3Provider: null,
3991
- ethersProvider: ethersProvider,
3992
- isAuthenticated: !!chainData.authHeader,
3993
- };
3994
- };
3995
- // ✅ NEW: Async wrapper with retry for higher-level usage
3996
- const getWeb3ProviderWithRetry = async (chainData, timeout = 15000, customUserAgentName = '', tokenRefresher, retryConfig = { maxAttempts: 3, baseDelay: 1000, maxDelay: 8000 }) => {
3997
- let lastError = null;
3998
- for (let attempt = 1; attempt <= retryConfig.maxAttempts; attempt++) {
3999
- try {
4000
- console.log(`🔄 [Web3Provider] Attempt ${attempt}/${retryConfig.maxAttempts} for chain ${chainData.chainId || 'unknown'}`);
4001
- // ✅ SYNC CALL: Use the original sync function
4002
- const provider = getWeb3ProviderFromChainData(chainData, timeout, customUserAgentName, tokenRefresher);
4003
- await validateChainConnection(provider.ethersProvider, chainData.authHeader ? 'private' : 'public');
4004
- console.log(`✅ [Web3Provider] Successfully connected on attempt ${attempt}`);
4005
- return provider;
4006
- }
4007
- catch (error) {
4008
- lastError = error instanceof Error ? error : new Error(String(error));
4009
- console.warn(`⚠️ [Web3Provider] Attempt ${attempt} failed:`, lastError.message);
4010
- // ✅ NO RETRY: if auth error, no retry
4011
- if (isAuthError(lastError) && chainData.authHeader) {
4012
- console.error(`❌ [Web3Provider] Auth error, stopping retries`);
4013
- break;
4014
- }
4015
- if (attempt === retryConfig.maxAttempts)
4016
- break;
4017
- const delay = Math.min(retryConfig.baseDelay * Math.pow(2, attempt - 1), retryConfig.maxDelay);
4018
- console.log(`⏳ [Web3Provider] Retrying in ${delay}ms...`);
4019
- await sleep(delay);
4020
- }
4021
- }
4022
- throw new Error(`Failed to create Web3 provider after ${retryConfig.maxAttempts} attempts. Last error: ${lastError?.message}`);
4023
- };
4024
- async function validateChainConnection(provider, chainType) {
4025
- try {
4026
- console.log(`🔍 [Validation] Testing ${chainType} chain connection...`);
4027
- // ✅ LIGHTWEIGHT TEST: Use eth_chainId (works for both public and private)
4028
- const timeoutPromise = new Promise((_, reject) => {
4029
- setTimeout(() => reject(new Error(`${chainType} chain validation timeout`)), 3000);
4030
- });
4031
- // Try chainId first (fast, lightweight, universal)
4032
- const chainIdPromise = provider.send('eth_chainId', []);
4033
- const result = await Promise.race([chainIdPromise, timeoutPromise]);
4034
- console.log(`✅ [Validation] ${chainType} chain connection validated - Chain ID: ${result}`);
4035
- }
4036
- catch (error) {
4037
- // ✅ FALLBACK: Try net_version if chainId fails
4038
- try {
4039
- console.log(`🔄 [Validation] Trying fallback validation for ${chainType} chain...`);
4040
- const timeoutPromise = new Promise((_, reject) => {
4041
- setTimeout(() => reject(new Error(`${chainType} chain fallback validation timeout`)), 3000);
4042
- });
4043
- const versionPromise = provider.send('net_version', []);
4044
- const result = await Promise.race([versionPromise, timeoutPromise]);
4045
- console.log(`✅ [Validation] ${chainType} chain connection validated via fallback - Network Version: ${result}`);
4046
- }
4047
- catch (fallbackError) {
4048
- throw new Error(`${chainType} chain validation failed: ${error instanceof Error ? error.message : String(error)}`);
4049
- }
4050
- }
4051
- }
4052
- // ✅ HELPER: Auth error detection
4053
- function isAuthError(error) {
4054
- const message = error.message.toLowerCase();
4055
- return (message.includes('unauthorized') ||
4056
- message.includes('401') ||
4057
- message.includes('token expired') ||
4058
- message.includes('-40100'));
4059
- }
4060
- // ✅ HELPER: Sleep utility
4061
- function sleep(ms) {
4062
- return new Promise(resolve => setTimeout(resolve, ms));
4063
- }
4064
- /*
4065
- //IMPORTANT//
4066
- //This function is temporary so we install ethers just to make it work, once we delete this function we must uninstall Ethers
4067
-
4068
- import { ChainData } from "@explorins/web3-ts";
4069
- import { FetchRequest, JsonRpcProvider } from "ethers";
4070
-
4071
- export const getWeb3ProviderFromChainData = (
4072
- chainData: ChainData,
4073
- timeout = 15000,
4074
- customUserAgentName = '',
4075
- tokenRefresher?: () => Promise<string>
4076
- ) => {
4077
-
4078
- // Fixed ethers provider setup for authenticated requests
4079
- let ethersProvider: JsonRpcProvider;
4080
-
4081
- if (chainData.authHeader) {
4082
- // For authenticated requests, create a custom FetchRequest
4083
- const fetchRequest = new FetchRequest(chainData.rpcUrl);
4084
- fetchRequest.timeout = timeout;
4085
- fetchRequest.setHeader('Authorization', chainData.authHeader);
4086
- fetchRequest.setHeader('Content-Type', 'application/json');
4087
-
4088
- if (customUserAgentName) {
4089
- fetchRequest.setHeader('User-Agent', customUserAgentName);
4090
- }
4091
-
4092
- // Create provider with the configured FetchRequest
4093
- ethersProvider = new JsonRpcProvider(fetchRequest, undefined, {
4094
- staticNetwork: false,
4095
- polling: false, // Disable polling for better Lambda performance
4096
- });
4097
- } else {
4098
- // For public chains, use simple URL-based provider
4099
- ethersProvider = new JsonRpcProvider(chainData.rpcUrl, undefined, {
4100
- staticNetwork: false,
4101
- polling: false,
4102
- });
4103
- }
4104
-
4105
- return {
4106
- web3Provider: null,
4107
- ethersProvider: ethersProvider,
4108
- isAuthenticated: !!chainData.authHeader,
4109
- };
4110
- }; */
4111
-
4112
- class Web3ProviderService {
4113
- constructor() {
4114
- this._web3 = null;
4115
- this._currentChainId = null;
4116
- this._creationPromise = null;
4117
- }
4118
- async getWeb3(chainId, chainType, chainData) {
4119
- // ✅ EARLY RETURN: Reuse existing provider
4120
- if (this._web3 && this._currentChainId === chainId) {
4121
- return this._web3;
4122
- }
4123
- // ✅ PREVENT RACE CONDITION: Wait for ongoing creation
4124
- if (this._creationPromise) {
4125
- return await this._creationPromise;
4126
- }
4127
- if (!chainId)
4128
- throw new Error('ChainId not found');
4129
- if (!chainData)
4130
- throw new Error('ChainData not found');
4131
- // ✅ CREATE AND CACHE: Single promise for concurrent calls
4132
- this._creationPromise = this.createProvider(chainId, chainType, chainData);
4133
- try {
4134
- const web3Instance = await this._creationPromise;
4135
- this._web3 = web3Instance;
4136
- this._currentChainId = chainId;
4137
- return web3Instance;
4138
- }
4139
- finally {
4140
- // ✅ CLEANUP: Always reset promise after completion
4141
- this._creationPromise = null;
4142
- }
4143
- }
4144
- async createProvider(chainId, chainType, chainData) {
4145
- const provider = await getWeb3ProviderWithRetry(chainData);
4146
- return this.convertToWeb3(provider);
4147
- }
4148
- convertToWeb3(provider) {
4149
- if (provider instanceof Web3) {
4150
- return provider;
4151
- }
4152
- if (provider && typeof provider === 'object' && 'web3Provider' in provider) {
4153
- const providerObj = provider;
4154
- // If we want to user the web3Provider directly:
4155
- /*if (providerObj.web3Provider) {
4156
- return new Web3(providerObj.web3Provider as never);
4157
- }*/
4158
- if (providerObj.ethersProvider) {
4159
- const url = this.extractUrlFromEthersProvider(providerObj.ethersProvider);
4160
- const headers = this.extractHeadersFromEthersProvider(providerObj.ethersProvider);
4161
- const web3 = new Web3(url);
4162
- const currentProvider = web3.currentProvider;
4163
- if (currentProvider) {
4164
- currentProvider['url'] = url;
4165
- if (headers && Object.keys(headers).length > 0) {
4166
- currentProvider['request'] = async (payload) => {
4167
- const response = await fetch(url, {
4168
- method: 'POST',
4169
- headers: {
4170
- 'Content-Type': 'application/json',
4171
- ...headers
4172
- },
4173
- body: JSON.stringify(payload)
4174
- });
4175
- if (!response.ok) {
4176
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
4177
- }
4178
- return await response.json();
4179
- };
4180
- }
4181
- }
4182
- return web3;
4183
- }
4184
- }
4185
- return new Web3(provider);
4186
- }
4187
- extractUrlFromEthersProvider(ethersProvider) {
4188
- return ethersProvider.connection?.url ||
4189
- ethersProvider._getConnection?.()?.url ||
4190
- ethersProvider.url ||
4191
- '';
4192
- }
4193
- extractHeadersFromEthersProvider(ethersProvider) {
4194
- return ethersProvider.connection?.headers ||
4195
- ethersProvider._getConnection?.()?.headers ||
4196
- {};
4197
- }
4198
- }
4199
- /* import Web3 from "web3";
4200
- import { ChainData, ChainType, ChainTypes } from "@explorins/web3-ts";
4201
- import { PublicHttpProviderService } from "./public-http-provider.service";
4202
- import { getWeb3ProviderFromChainData } from "./getWeb3FCD.service";
4203
-
4204
-
4205
- export class Web3ProviderService {
4206
-
4207
- private _web3: Web3 | null = null;
4208
- private _currentChainId: number | null = null;
4209
-
4210
- constructor(
4211
- private readonly publicHttpProviderService: PublicHttpProviderService,
4212
- ) {
4213
- }
4214
-
4215
- public async getWeb3(chainId: number, chainType: ChainType, privateChainData: ChainData | null = null) {
4216
- if (!this._web3 || this._currentChainId !== chainId) {
4217
-
4218
- if(!chainId) throw new Error('ChainId not found')
4219
-
4220
- try {
4221
- this._currentChainId = chainId;
4222
- const provider = await this.getWeb3ByChainId(chainId, chainType, privateChainData);
4223
- this._web3 = this.convertToWeb3(provider);
4224
- } catch (error) {
4225
- console.error('Error getting web3 connection from chain id ' + chainId , error)
4226
- throw new Error('Error getting web3 connection from chain id ' + chainId)
4227
- }
4228
- }
4229
- return this._web3 as Web3;
4230
- }
4231
-
4232
- // Keep return type as 'any' to avoid TypeScript errors while still being adapted later
4233
- private getWeb3ByChainId(chainId: number, chainType: ChainType, privateChainData: ChainData | null = null): any {
4234
- // Rest of the method remains the same
4235
- if(chainType === ChainTypes.PRIVATE && privateChainData) {
4236
- //const privateProvider = this.privateChainProviderService.getProviderFromChainData(privateChainData)
4237
- const privateProvider = getWeb3ProviderFromChainData(privateChainData);
4238
-
4239
- if(!privateProvider || privateProvider instanceof Error) throw new Error('Error getting web3 provider');
4240
-
4241
-
4242
- return privateProvider;
4243
-
4244
- } else {
4245
-
4246
- const publicProvider = this.publicHttpProviderService.getProvider(chainId)
4247
- if(!publicProvider || publicProvider instanceof Error) throw new Error('Error getting web3 provider');
4248
-
4249
- return publicProvider;
4250
- }
4251
- }
4252
-
4253
- private convertToWeb3(provider: unknown): Web3 {
4254
- if (provider instanceof Web3) {
4255
- return provider as Web3;
4256
- }
4257
-
4258
- if (provider && typeof provider === 'object' && 'web3Provider' in provider) {
4259
- const providerObj = provider as {
4260
- web3Provider?: unknown;
4261
- ethersProvider?: any;
4262
- isAuthenticated?: boolean;
4263
- };
4264
-
4265
- // If we want to user the web3Provider directly:
4266
- /*if (providerObj.web3Provider) {
4267
- return new Web3(providerObj.web3Provider as never);
4268
- }*/
4269
- /*if (providerObj.ethersProvider) {
4270
-
4271
- const url = this.extractUrlFromEthersProvider(providerObj.ethersProvider);
4272
- const headers = this.extractHeadersFromEthersProvider(providerObj.ethersProvider);
4273
-
4274
- const web3 = new Web3(url);
4275
- const currentProvider = web3.currentProvider as unknown as Record<string, unknown>;
4276
-
4277
- if (currentProvider) {
4278
- currentProvider['url'] = url;
4279
-
4280
- if (headers && Object.keys(headers).length > 0) {
4281
- currentProvider['request'] = async (payload: Record<string, unknown>): Promise<Record<string, unknown>> => {
4282
- const response = await fetch(url, {
4283
- method: 'POST',
4284
- headers: {
4285
- 'Content-Type': 'application/json',
4286
- ...headers
4287
- },
4288
- body: JSON.stringify(payload)
4289
- });
4290
-
4291
- if (!response.ok) {
4292
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
4293
- }
4294
-
4295
- return await response.json() as Record<string, unknown>;
4296
- };
4297
- }
4298
- }
4299
-
4300
- return web3;
4301
- }
4302
- }
4303
-
4304
- return new Web3(provider as never);
4305
- }
4306
-
4307
-
4308
- private extractUrlFromEthersProvider(ethersProvider: any): string {
4309
- return ethersProvider.connection?.url ||
4310
- ethersProvider._getConnection?.()?.url ||
4311
- ethersProvider.url ||
4312
- '';
4313
- }
4314
-
4315
- private extractHeadersFromEthersProvider(ethersProvider: any): Record<string, string> {
4316
- return ethersProvider.connection?.headers ||
4317
- ethersProvider._getConnection?.()?.headers ||
4318
- {};
4319
- }
4320
- } */
4321
-
4322
- /**
4323
- * Web3 Chain Domain Models
4324
- *
4325
- * Minimal interface definitions matching framework usage exactly.
4326
- * Local ChainData interface to avoid external dependency issues.
4327
- */
4328
- const ChainTypes = {
4329
- PUBLIC: 'PUBLIC',
4330
- PRIVATE: 'PRIVATE'
4331
- };
4332
-
4333
- function createWeb3ChainSDK(apiClient, providerService) {
4334
- const web3ChainApi = new Web3ChainApi(apiClient);
4335
- const web3ChainService = new Web3ChainService(web3ChainApi, providerService); // ✅ DIRECT INJECTION
4336
- return {
4337
- // ✅ REPLICA: Same methods as framework
4338
- getChainDataById: (chainId) => web3ChainService.getChainDataById(chainId),
4339
- getWeb3ByChainId: (chainId) => web3ChainService.getWeb3ByChainId(chainId),
4340
- api: web3ChainApi,
4341
- service: web3ChainService
4342
- };
4343
- }
4344
-
4345
- /**
4346
- * TokenDomainService - Domain service for token operations
4347
- * Implements business logic for token balance, metadata, and collection operations
4348
- */
4349
- class TokenDomainService {
4350
- constructor(web3Api, metadataService, contractService) {
4351
- this.web3Api = web3Api;
4352
- this.metadataService = metadataService;
4353
- this.contractService = contractService;
4354
- }
4355
- async getTokenBalance(request) {
4356
- const balance = await this.web3Api.getTokenBalance({
4357
- accountAddress: request.accountAddress,
4358
- contractAddress: request.contractAddress,
4359
- abi: request.abi,
4360
- tokenId: request.tokenId,
4361
- chainId: request.chainId
4362
- });
4363
- return {
4364
- tokenId: request.tokenId,
4365
- balance,
4366
- hasBalance: balance > 0,
4367
- metadata: null
4368
- };
4369
- }
4370
- async getTokenWithMetadata(params) {
4371
- try {
4372
- const balance = await this.web3Api.getTokenBalance({
4373
- accountAddress: params.accountAddress,
4374
- contractAddress: params.contractAddress,
4375
- abi: params.abi,
4376
- tokenId: params.tokenId,
4377
- chainId: params.chainId
4378
- });
4379
- let metadata = null;
4380
- if (balance > 0) {
4381
- const tokenUri = await this.web3Api.getTokenUri({
4382
- contractAddress: params.contractAddress,
4383
- abi: params.abi,
4384
- tokenId: params.tokenId,
4385
- chainId: params.chainId
4386
- });
4387
- if (tokenUri) {
4388
- metadata = await this.metadataService.fetchAndProcessMetadata(tokenUri, params.chainId);
4389
- }
4390
- }
4391
- return {
4392
- tokenId: params.tokenId,
4393
- balance,
4394
- hasBalance: balance > 0,
4395
- metadata
4396
- };
4397
- }
4398
- catch (error) {
4399
- console.error('Error getting token with metadata:', error);
4400
- return {
4401
- tokenId: params.tokenId,
4402
- balance: 0,
4403
- hasBalance: false,
4404
- metadata: null
4405
- };
4406
- }
4407
- }
4408
- async getTokenCollection(params) {
4409
- try {
4410
- const contractAnalysis = this.contractService.analyzeContract(params.abi);
4411
- const tokens = [];
4412
- if (!contractAnalysis.hasEnumeration && !contractAnalysis.isERC1155) {
4413
- console.warn('Contract does not support enumeration, cannot retrieve full collection');
4414
- return {
4415
- accountAddress: params.accountAddress,
4416
- contractAddress: params.contractAddress,
4417
- totalBalance: 0,
4418
- tokensRetrieved: 0,
4419
- tokens: [],
4420
- note: 'Contract does not support enumeration'
4421
- };
4422
- }
4423
- else if (contractAnalysis.isERC1155) {
4424
- const tokenIdsToProcess = params.tokenIds || [];
4425
- if (tokenIdsToProcess.length > 0) {
4426
- for (const tokenId of tokenIdsToProcess) {
4427
- const tokenBalance = await this.getTokenWithMetadata({
4428
- accountAddress: params.accountAddress,
4429
- contractAddress: params.contractAddress,
4430
- abi: params.abi,
4431
- tokenId,
4432
- chainId: params.chainId
4433
- });
4434
- tokens.push(tokenBalance);
4435
- }
4436
- }
4437
- console.log('ERC-1155 User balances:', tokens);
4438
- // ERC-1155: Cannot enumerate without knowing token IDs
4439
- // Would need to use events or provide specific token IDs
4440
- console.warn('ERC-1155 collection retrieval requires specific token IDs or event analysis');
4441
- return {
4442
- accountAddress: params.accountAddress,
4443
- contractAddress: params.contractAddress,
4444
- totalBalance: 0,
4445
- tokensRetrieved: 0,
4446
- tokens: tokens,
4447
- note: 'ERC-1155 collection retrieval requires specific token IDs. Use getTokenWithMetadata() for individual tokens.'
4448
- };
4449
- }
4450
- // Handle different token standards
4451
- if (contractAnalysis.isERC721) {
4452
- // ERC-721: Get user's total balance and enumerate through tokens
4453
- const userBalance = await this.web3Api.getTokenBalance({
4454
- accountAddress: params.accountAddress,
4455
- contractAddress: params.contractAddress,
4456
- abi: params.abi,
4457
- tokenId: null, // null for ERC-721 total balance
4458
- chainId: params.chainId
4459
- });
4460
- console.log(`ERC-721 User balance for ${params.accountAddress}:`, userBalance);
4461
- if (userBalance === 0) {
4462
- return {
4463
- accountAddress: params.accountAddress,
4464
- contractAddress: params.contractAddress,
4465
- totalBalance: 0,
4466
- tokensRetrieved: 0,
4467
- tokens: []
4468
- };
4469
- }
4470
- // Enumerate through user's tokens
4471
- const maxTokens = params.maxTokens || userBalance;
4472
- const tokensToRetrieve = Math.min(maxTokens, userBalance);
4473
- for (let i = 0; i < tokensToRetrieve; i++) {
4474
- try {
4475
- const tokenId = await this.web3Api.getTokenOfOwnerByIndex({
4476
- contractAddress: params.contractAddress,
4477
- abi: params.abi,
4478
- accountAddress: params.accountAddress,
4479
- tokenIndex: i,
4480
- chainId: params.chainId
4481
- });
4482
- const tokenWithMetadata = await this.getTokenWithMetadata({
4483
- accountAddress: params.accountAddress,
4484
- contractAddress: params.contractAddress,
4485
- abi: params.abi,
4486
- tokenId,
4487
- chainId: params.chainId
4488
- });
4489
- if (tokenWithMetadata.hasBalance) {
4490
- tokens.push(tokenWithMetadata);
4491
- }
4492
- }
4493
- catch (error) {
4494
- console.warn(`Error retrieving ERC-721 token at index ${i}:`, error);
4495
- continue;
4496
- }
4497
- }
4498
- }
4499
- else {
4500
- // Unknown standard
4501
- return {
4502
- accountAddress: params.accountAddress,
4503
- contractAddress: params.contractAddress,
4504
- totalBalance: 0,
4505
- tokensRetrieved: 0,
4506
- tokens: [],
4507
- note: 'Unsupported token standard for collection retrieval'
4508
- };
4509
- }
4510
- // Calculate total balance based on retrieved tokens
4511
- let totalBalance = 0;
4512
- if (contractAnalysis.isERC721) {
4513
- // For ERC-721, total balance is the number of unique tokens owned
4514
- totalBalance = tokens.length;
4515
- }
4516
- else {
4517
- // For other standards, sum up individual token balances
4518
- totalBalance = tokens.reduce((sum, token) => sum + token.balance, 0);
4519
- }
4520
- return {
4521
- accountAddress: params.accountAddress,
4522
- contractAddress: params.contractAddress,
4523
- totalBalance,
4524
- tokensRetrieved: tokens.length,
4525
- tokens
4526
- };
4527
- }
4528
- catch (error) {
4529
- console.error('Error getting token collection:', error);
4530
- return {
4531
- accountAddress: params.accountAddress,
4532
- contractAddress: params.contractAddress,
4533
- totalBalance: 0,
4534
- tokensRetrieved: 0,
4535
- tokens: [],
4536
- note: 'Error retrieving collection'
4537
- };
4538
- }
4539
- }
4540
- async getTokenMetadata(params) {
4541
- try {
4542
- const tokenUri = await this.web3Api.getTokenUri({
4543
- contractAddress: params.contractAddress,
4544
- abi: params.abi,
4545
- tokenId: params.tokenId,
4546
- chainId: params.chainId
4547
- });
4548
- let metadata = null;
4549
- if (tokenUri) {
4550
- metadata = await this.metadataService.fetchAndProcessMetadata(tokenUri, params.chainId);
4551
- }
4552
- return {
4553
- tokenId: params.tokenId,
4554
- tokenUri,
4555
- metadata
4556
- };
4557
- }
4558
- catch (error) {
4559
- console.error('Error getting token metadata:', error);
4560
- return {
4561
- tokenId: params.tokenId,
4562
- tokenUri: null,
4563
- metadata: null
4564
- };
4565
- }
4566
- }
4567
- }
4568
-
4569
- /**
4570
- * MetadataDomainService - Clean IPFS metadata resolution
4571
- */
4572
- class MetadataDomainService {
4573
- constructor(ipfsApi) {
4574
- this.ipfsApi = ipfsApi;
4575
- }
4576
- async fetchAndProcessMetadata(tokenUri, chainId) {
4577
- return this.ipfsApi.fetchAndProcessMetadata(tokenUri, chainId);
4578
- }
4579
- async resolveIPFSUrl(url, chainId) {
4580
- return this.ipfsApi.resolveIPFSUrl(url, chainId);
4581
- }
4582
- }
4583
-
4584
- /**
4585
- * ContractDomainService - Clean contract analysis without external dependencies
4586
- */
4587
- class ContractDomainService {
4588
- constructor() { }
4589
- analyzeContract(abi) {
4590
- const methods = abi.filter(item => item.type === 'function').map(item => item.name);
4591
- // ERC-721 detection
4592
- const hasOwnerOf = methods.includes('ownerOf');
4593
- const hasTokenURI = methods.includes('tokenURI');
4594
- const hasTransferFrom = methods.includes('transferFrom');
4595
- const isERC721 = hasOwnerOf && hasTokenURI && hasTransferFrom;
4596
- // ERC-1155 detection
4597
- const hasBalanceOfBatch = methods.includes('balanceOfBatch');
4598
- const hasSafeBatchTransferFrom = methods.includes('safeBatchTransferFrom');
4599
- const hasURI = methods.includes('uri');
4600
- const isERC1155 = hasBalanceOfBatch && hasSafeBatchTransferFrom && hasURI;
4601
- return {
4602
- hasEnumeration: methods.includes('tokenByIndex') && methods.includes('totalSupply'),
4603
- hasOwnerOf,
4604
- hasBalanceOf: methods.includes('balanceOf'),
4605
- hasTokenURI,
4606
- hasTransfer: methods.includes('transfer') || methods.includes('transferFrom'),
4607
- hasApprove: methods.includes('approve'),
4608
- isERC721,
4609
- isERC1155
4610
- };
4611
- }
4612
- supportsEnumeration(abi) {
4613
- return this.analyzeContract(abi).hasEnumeration;
4614
- }
4615
- supportsMethod(abi, methodName) {
4616
- const methods = abi.filter(item => item.type === 'function').map(item => item.name);
4617
- return methods.includes(methodName);
4618
- }
4619
- }
4620
-
4621
- /**
4622
- * Web3ApplicationService - Application layer entrance point
4623
- * Orchestrates domain services and provides clean public interface
4624
- * Simplified architecture with concrete classes
4625
- */
4626
- class Web3ApplicationService {
4627
- constructor(web3Api, ipfsApi) {
4628
- // Type-safe metadata conversion methods for ERC-721/ERC-1155 standards
4629
- this.metadataMapper = {
4630
- fromERCStandard: (ercMetadata) => ({
4631
- name: ercMetadata.name || '',
4632
- description: ercMetadata.description || '',
4633
- imageUrl: ercMetadata.image || '',
4634
- externalUrl: ercMetadata.external_url,
4635
- animationUrl: ercMetadata.animation_url,
4636
- animationUrlConverted: undefined, // Will be set by IPFS conversion
4637
- attributes: ercMetadata.attributes || [],
4638
- ...ercMetadata
4639
- }),
4640
- toERCStandard: (metadata) => ({
4641
- name: metadata.name,
4642
- description: metadata.description,
4643
- image: metadata.imageUrl,
4644
- animation_url: metadata.animationUrl,
4645
- external_url: metadata.externalUrl,
4646
- attributes: metadata.attributes,
4647
- ...Object.fromEntries(Object.entries(metadata).filter(([key]) => !['name', 'description', 'imageUrl', 'animationUrl', 'externalUrl', 'attributes', 'animationUrlConverted'].includes(key)))
4648
- })
4649
- };
4650
- // Create domain services with injected infrastructure dependencies
4651
- this.contractDomainService = new ContractDomainService();
4652
- this.metadataDomainService = new MetadataDomainService(ipfsApi);
4653
- this.tokenDomainService = new TokenDomainService(web3Api, this.metadataDomainService, this.contractDomainService);
4654
- }
4655
- /**
4656
- * Get balance and metadata for a specific token
4657
- */
4658
- async getSpecificTokenBalance(request) {
4659
- if (!request.tokenId) {
4660
- return this.tokenDomainService.getTokenBalance({
4661
- accountAddress: request.accountAddress || '',
4662
- contractAddress: request.contractAddress,
4663
- abi: request.abi,
4664
- tokenId: '',
4665
- chainId: request.chainId
4666
- });
4667
- }
4668
- return this.tokenDomainService.getTokenWithMetadata({
4669
- accountAddress: request.accountAddress || '',
4670
- contractAddress: request.contractAddress,
4671
- abi: request.abi,
4672
- tokenId: request.tokenId || '',
4673
- chainId: request.chainId
4674
- });
4675
- }
4676
- /**
4677
- * Get metadata for a specific token from on-chain
4678
- */
4679
- async getTokenMetadata(request) {
4680
- const domainResult = await this.tokenDomainService.getTokenMetadata({
4681
- contractAddress: request.contractAddress,
4682
- abi: request.abi,
4683
- tokenId: request.tokenId || '',
4684
- chainId: request.chainId
4685
- });
4686
- return domainResult.metadata;
4687
- }
4688
- /**
4689
- * Retrieve entire collection of tokens with balance and metadata
4690
- */
4691
- async getTokenCollection(request) {
4692
- return this.tokenDomainService.getTokenCollection({
4693
- accountAddress: request.accountAddress || '',
4694
- contractAddress: request.contractAddress,
4695
- abi: request.abi,
4696
- chainId: request.chainId,
4697
- maxTokens: request.maxTokens,
4698
- tokenIds: request.tokenIds
4699
- });
4700
- }
4701
- /**
4702
- * Resolve IPFS URLs to HTTPS if needed
4703
- */
4704
- async resolveIPFSUrl(url, chainId) {
4705
- return this.metadataDomainService.resolveIPFSUrl(url, chainId);
4706
- }
4707
- /**
4708
- * Fetch and process metadata from URI with IPFS conversion
4709
- */
4710
- async fetchAndProcessMetadata(tokenUri, chainId) {
4711
- const domainMetadata = await this.metadataDomainService.fetchAndProcessMetadata(tokenUri, chainId);
4712
- if (!domainMetadata)
4713
- return null;
4714
- // Convert from ERC token standard to our clean interface
4715
- const cleanMetadata = this.metadataMapper.fromERCStandard(domainMetadata);
4716
- // Add IPFS conversion if needed
4717
- if (cleanMetadata.animationUrl?.startsWith('ipfs://')) {
4718
- return {
4719
- ...cleanMetadata,
4720
- animationUrlConverted: await this.resolveIPFSUrl(cleanMetadata.animationUrl, chainId)
4721
- };
4722
- }
4723
- return cleanMetadata;
4724
- }
4725
- }
4726
-
4727
- /**
4728
- * Web3InfrastructureApi - Infrastructure implementation for blockchain operations
4729
- * Uses @explorins/web3-ts for Web3 interactions
4730
- */
4731
- class Web3InfrastructureApi {
4732
- constructor(web3ChainService) {
4733
- this.web3ChainService = web3ChainService;
4734
- }
4735
- async getTokenBalance(request) {
4736
- try {
4737
- if (request.tokenId !== null)
4738
- request.tokenId = request.tokenId.toString();
4739
- const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
4740
- const contract = getSmartContractInstance(request.contractAddress, request.abi, web3);
4741
- return await getAccountTokenBalance(contract, request.accountAddress, request.tokenId);
4742
- }
4743
- catch (error) {
4744
- console.error(`Failed to get token balance for ${request.accountAddress} for ${request.contractAddress} and tokenId ${request.tokenId}, return 0 instead:`, error);
4745
- return 0;
4746
- }
4747
- }
4748
- async getTokenUri(request) {
4749
- try {
4750
- const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
4751
- const contract = getSmartContractInstance(request.contractAddress, request.abi, web3);
4752
- const tokenId = Number(request.tokenId);
4753
- const tokenUri = await getTokenUri(contract, tokenId);
4754
- return String(tokenUri);
4755
- }
4756
- catch (error) {
4757
- console.error(`Failed to get token URI for tokenId ${request.tokenId}:`, error);
4758
- throw error;
4759
- }
4760
- }
4761
- async getTokenOfOwnerByIndex(request) {
4762
- try {
4763
- const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
4764
- const tokenContract = getSmartContractInstance(request.contractAddress, request.abi, web3);
4765
- const tokenId = await getTokenOfOwnerByIndex(tokenContract, request.accountAddress, request.tokenIndex);
4766
- return String(tokenId);
4767
- }
4768
- catch (error) {
4769
- console.error(`Failed to get token by index ${request.tokenIndex} for ${request.accountAddress}:`, error);
4770
- throw error;
4771
- }
4772
- }
4773
- }
4774
-
4775
- /**
4776
- * IPFSInfrastructureApi - Infrastructure implementation for IPFS operations
4777
- * Uses Web3ChainService for IPFS gateway resolution
4778
- */
4779
- class IPFSInfrastructureApi {
4780
- constructor(web3ChainService) {
4781
- this.web3ChainService = web3ChainService;
4782
- this.defaultIpfsGatewayDomain = 'pers.mypinata.cloud';
4783
- }
4784
- async getIpfsGatewayDomain(chainId) {
4785
- try {
4786
- const chainData = await this.web3ChainService.getChainDataWithCache(chainId);
4787
- return chainData.ipfsGatewayDomain || this.defaultIpfsGatewayDomain;
4788
- }
4789
- catch (error) {
4790
- console.warn(`Failed to get chain data for chainId ${chainId}, using default IPFS gateway:`, error);
4791
- return this.defaultIpfsGatewayDomain;
4792
- }
4793
- }
4794
- async resolveIPFSUrl(url, chainId) {
4795
- if (url.startsWith('ipfs://')) {
4796
- const gateway = await this.getIpfsGatewayDomain(chainId);
4797
- return url.replace('ipfs://', `https://${gateway}/ipfs/`);
4798
- }
4799
- return url;
4800
- }
4801
- async fetchAndProcessMetadata(tokenUri, chainId) {
4802
- try {
4803
- const resolvedUri = await this.resolveIPFSUrl(tokenUri, chainId);
4804
- const response = await fetch(resolvedUri);
4805
- if (!response.ok) {
4806
- throw new Error(`HTTP error! status: ${response.status}`);
4807
- }
4808
- const metadata = await response.json();
4809
- // Process and return clean metadata
4810
- return {
4811
- name: metadata.name || '',
4812
- description: metadata.description || '',
4813
- image: metadata.image ? await this.resolveIPFSUrl(metadata.image, chainId) : '',
4814
- attributes: metadata.attributes || [],
4815
- animation_url: metadata.animation_url ? await this.resolveIPFSUrl(metadata.animation_url, chainId) : undefined,
4816
- external_url: metadata.external_url || undefined
4817
- };
4818
- }
4819
- catch (error) {
4820
- console.error('Error fetching metadata:', error);
4821
- return null;
4822
- }
4823
- }
4824
- async fetchFromUrl(url) {
4825
- try {
4826
- const response = await fetch(url);
4827
- if (!response.ok) {
4828
- throw new Error(`Failed to fetch from ${url}: ${response.statusText}`);
4829
- }
4830
- return await response.json();
4831
- }
4832
- catch (error) {
4833
- console.error(`Error fetching from URL ${url}:`, error);
4834
- throw error;
4835
- }
4836
- }
4837
- }
4838
-
4839
- function createWeb3SDK(apiClient) {
4840
- // TODO: FIX LATER - TEMPORARY CONSTRUCTION
4841
- const web3ProviderService = new Web3ProviderService();
4842
- const web3ChainSDK = createWeb3ChainSDK(apiClient, web3ProviderService);
4843
- // Create Web3ApplicationService - main entry point for all Web3 operations
4844
- const web3InfrastructureApi = new Web3InfrastructureApi(web3ChainSDK.service);
4845
- const ipfsInfrastructureApi = new IPFSInfrastructureApi(web3ChainSDK.service);
4846
- const web3ApplicationService = new Web3ApplicationService(web3InfrastructureApi, ipfsInfrastructureApi);
4847
- // Clean SDK - all functions route through Web3ApplicationService
4848
- return {
4849
- getTokenBalance: (request) => web3ApplicationService.getSpecificTokenBalance(request),
4850
- getTokenMetadata: (request) => web3ApplicationService.getTokenMetadata(request),
4851
- getTokenCollection: (request) => web3ApplicationService.getTokenCollection(request),
4852
- resolveIPFSUrl: (url, chainId) => web3ApplicationService.resolveIPFSUrl(url, chainId),
4853
- fetchAndProcessMetadata: (tokenUri, chainId) => web3ApplicationService.fetchAndProcessMetadata(tokenUri, chainId),
4854
- applicationService: web3ApplicationService
4855
- };
4856
- }
4857
-
4858
- export { AnalyticsApi, AnalyticsService, AuthApi, AuthService, BaseTokenService, BusinessApi, BusinessService, CampaignApi, CampaignService, ChainTypes, DEFAULT_PERS_CONFIG, DonationApi, DonationService, IPFSInfrastructureApi, PurchaseApi as PaymentApi, PaymentService, PersApiClient, PersApiError, PersSDK, RedemptionApi, RedemptionService, SimpleSdkAuthProvider, TenantApi, TenantService, TokenApi, TokenSDK, TokenService, TransactionAccountType, TransactionApi, TransactionService, UserApi, UserService, UserStatusApi, UserStatusService, Web3ApplicationService, Web3ChainApi, Web3ChainService, Web3InfrastructureApi, Web3ProviderService, buildApiRoot, createAnalyticsSDK, createAuthProvider, createAuthSDK, createBusinessSDK, createCampaignSDK, createDonationSDK, createPaymentSDK, createPersSDK, createRedemptionSDK, createTenantSDK, createTransactionSDK, createUserSDK, createUserStatusSDK, createWeb3ChainSDK, createWeb3SDK, mergeWithDefaults };
4
+ export { BusinessApi, BusinessService, createBusinessSDK } from './business.js';
5
+ export { TransactionAccountType, TransactionApi, TransactionService, createTransactionSDK } from './transaction.js';
6
+ export { AnalyticsApi, AnalyticsService, createAnalyticsSDK } from './analytics.js';
7
+ export { CampaignApi, CampaignService, createCampaignSDK } from './campaign.js';
8
+ export { DonationApi, DonationService, createDonationSDK } from './donation.js';
9
+ export { PaymentApi, PaymentService, createPaymentSDK } from './payment.js';
10
+ export { RedemptionApi, RedemptionService, createRedemptionSDK } from './redemption.js';
11
+ export { TenantApi, TenantService, createTenantSDK } from './tenant.js';
12
+ export { B as BaseTokenService, a as TokenApi, T as TokenSDK, b as TokenService } from './chunks/base-token-service-BA81_Ouq.js';
13
+ export { UserApi, UserService, createUserSDK } from './user.js';
14
+ export { UserStatusApi, UserStatusService, createUserStatusSDK } from './user-status.js';
15
+ export { ChainTypes, Web3ChainApi, Web3ChainService, Web3ProviderService, createWeb3ChainSDK } from './web3-chain.js';
16
+ export { IPFSInfrastructureApi, Web3ApplicationService, Web3InfrastructureApi, createWeb3SDK } from './web3.js';
17
+ import './chunks/jwt.function-d6jPtBqI.js';
18
+ import 'jwt-decode';
19
+ import 'web3';
20
+ import 'ethers/providers';
21
+ import 'ethers/utils';
22
+ import '@explorins/web3-ts';
4859
23
  //# sourceMappingURL=index.js.map