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