@explorins/pers-sdk 1.2.5 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/analytics.cjs +6 -0
  2. package/dist/analytics.cjs.map +1 -1
  3. package/dist/analytics.js +2 -0
  4. package/dist/analytics.js.map +1 -1
  5. package/dist/business.cjs +6 -0
  6. package/dist/business.cjs.map +1 -1
  7. package/dist/business.js +2 -0
  8. package/dist/business.js.map +1 -1
  9. package/dist/campaign.cjs +6 -0
  10. package/dist/campaign.cjs.map +1 -1
  11. package/dist/campaign.js +2 -0
  12. package/dist/campaign.js.map +1 -1
  13. package/dist/{auth-admin/api/auth-admin-api.d.ts → core/auth/api/auth-api.d.ts} +7 -8
  14. package/dist/core/auth/api/auth-api.d.ts.map +1 -0
  15. package/dist/core/auth/auth-provider.interface.d.ts +25 -1
  16. package/dist/core/auth/auth-provider.interface.d.ts.map +1 -1
  17. package/dist/core/auth/create-auth-provider.d.ts +3 -3
  18. package/dist/core/auth/create-auth-provider.d.ts.map +1 -1
  19. package/dist/core/auth/index.d.ts +38 -0
  20. package/dist/core/auth/index.d.ts.map +1 -0
  21. package/dist/core/auth/services/auth-service.d.ts +49 -0
  22. package/dist/core/auth/services/auth-service.d.ts.map +1 -0
  23. package/dist/core/auth/simple-sdk-auth-provider.d.ts +27 -0
  24. package/dist/core/auth/simple-sdk-auth-provider.d.ts.map +1 -0
  25. package/dist/core/index.d.ts +1 -2
  26. package/dist/core/index.d.ts.map +1 -1
  27. package/dist/core/pers-api-client.d.ts +25 -3
  28. package/dist/core/pers-api-client.d.ts.map +1 -1
  29. package/dist/core.cjs +470 -156
  30. package/dist/core.cjs.map +1 -1
  31. package/dist/core.js +464 -157
  32. package/dist/core.js.map +1 -1
  33. package/dist/donation.cjs +6 -0
  34. package/dist/donation.cjs.map +1 -1
  35. package/dist/donation.js +2 -0
  36. package/dist/donation.js.map +1 -1
  37. package/dist/index.cjs +523 -360
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.d.ts +0 -1
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +518 -359
  42. package/dist/index.js.map +1 -1
  43. package/dist/package.json +5 -5
  44. package/dist/payment.cjs +6 -0
  45. package/dist/payment.cjs.map +1 -1
  46. package/dist/payment.js +2 -0
  47. package/dist/payment.js.map +1 -1
  48. package/dist/redemption/api/redemption-api.d.ts +26 -64
  49. package/dist/redemption/api/redemption-api.d.ts.map +1 -1
  50. package/dist/redemption/services/redemption-service.d.ts +21 -3
  51. package/dist/redemption/services/redemption-service.d.ts.map +1 -1
  52. package/dist/redemption.cjs +61 -94
  53. package/dist/redemption.cjs.map +1 -1
  54. package/dist/redemption.js +57 -94
  55. package/dist/redemption.js.map +1 -1
  56. package/dist/shared/interfaces/pers-shared-lib.interfaces.d.ts +1 -1
  57. package/dist/shared/interfaces/pers-shared-lib.interfaces.d.ts.map +1 -1
  58. package/dist/tenant.cjs +6 -0
  59. package/dist/tenant.cjs.map +1 -1
  60. package/dist/tenant.js +2 -0
  61. package/dist/tenant.js.map +1 -1
  62. package/dist/token.cjs +6 -0
  63. package/dist/token.cjs.map +1 -1
  64. package/dist/token.js +2 -0
  65. package/dist/token.js.map +1 -1
  66. package/dist/transaction.cjs +4 -0
  67. package/dist/transaction.cjs.map +1 -1
  68. package/dist/transaction.js +1 -0
  69. package/dist/transaction.js.map +1 -1
  70. package/dist/user-status.cjs +6 -0
  71. package/dist/user-status.cjs.map +1 -1
  72. package/dist/user-status.js +2 -0
  73. package/dist/user-status.js.map +1 -1
  74. package/dist/user.cjs +6 -0
  75. package/dist/user.cjs.map +1 -1
  76. package/dist/user.js +2 -0
  77. package/dist/user.js.map +1 -1
  78. package/dist/web3-chain.cjs +5 -0
  79. package/dist/web3-chain.cjs.map +1 -1
  80. package/dist/web3-chain.js +1 -0
  81. package/dist/web3-chain.js.map +1 -1
  82. package/dist/web3.cjs +1 -0
  83. package/dist/web3.cjs.map +1 -1
  84. package/dist/web3.js +1 -0
  85. package/dist/web3.js.map +1 -1
  86. package/package.json +5 -5
  87. package/dist/auth-admin/api/auth-admin-api.d.ts.map +0 -1
  88. package/dist/auth-admin/index.d.ts +0 -27
  89. package/dist/auth-admin/index.d.ts.map +0 -1
  90. package/dist/auth-admin/services/auth-admin-service.d.ts +0 -27
  91. package/dist/auth-admin/services/auth-admin-service.d.ts.map +0 -1
  92. package/dist/auth-admin.cjs +0 -115
  93. package/dist/auth-admin.cjs.map +0 -1
  94. package/dist/auth-admin.js +0 -111
  95. package/dist/auth-admin.js.map +0 -1
  96. package/dist/core/auth/simple-auth-config.interface.d.ts +0 -15
  97. package/dist/core/auth/simple-auth-config.interface.d.ts.map +0 -1
package/dist/index.cjs CHANGED
@@ -44,6 +44,241 @@ function mergeWithDefaults(config) {
44
44
  };
45
45
  }
46
46
 
47
+ /**
48
+ * Platform-Agnostic Auth Admin API Client
49
+ *
50
+ * Handles authentication and authorization admin operations using the PERS backend.
51
+ * Uses @explorins/pers-shared DTOs for consistency with backend.
52
+ *
53
+ * Note: Special header handling (bypass-auth-interceptor) may need to be implemented
54
+ * at the PersApiClient level or through a specialized auth client.
55
+ */
56
+ class AuthApi {
57
+ constructor(apiClient) {
58
+ this.apiClient = apiClient;
59
+ this.basePath = '/auth';
60
+ }
61
+ // ==========================================
62
+ // ADMIN AUTHENTICATION OPERATIONS
63
+ // ==========================================
64
+ /**
65
+ * ADMIN: Login tenant admin with JWT
66
+ * Note: JWT handling and auth bypass headers may need special implementation
67
+ */
68
+ async loginTenantAdmin(jwt) {
69
+ const body = {
70
+ authToken: jwt,
71
+ authType: persShared.AccountOwnerType.TENANT
72
+ };
73
+ return this.apiClient.post(`${this.basePath}/token`, body);
74
+ }
75
+ async loginUser(jwt) {
76
+ const body = {
77
+ authToken: jwt,
78
+ authType: persShared.AccountOwnerType.USER
79
+ };
80
+ return this.apiClient.post(`${this.basePath}/token`, body);
81
+ }
82
+ /**
83
+ * ADMIN: Refresh access token
84
+ * Note: Bypass header handling may need special implementation
85
+ */
86
+ async refreshAccessToken(refreshToken) {
87
+ return this.apiClient.post(`${this.basePath}/refresh`, { refreshToken });
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Platform-Agnostic Auth Admin Service
93
+ *
94
+ * Contains auth admin business logic and operations that work across platforms.
95
+ * No framework dependencies - pure TypeScript business logic.
96
+ *
97
+ * Focuses only on actual backend capabilities.
98
+ */
99
+ class AuthService {
100
+ constructor(authApi, authProvider) {
101
+ this.authApi = authApi;
102
+ this.authProvider = authProvider;
103
+ }
104
+ // ==========================================
105
+ // ADMIN AUTHENTICATION OPERATIONS
106
+ // ==========================================
107
+ /**
108
+ * ADMIN: Login tenant admin with JWT
109
+ * Automatically stores tokens if auth provider supports token storage
110
+ */
111
+ async loginTenantAdmin(jwt) {
112
+ const response = await this.authApi.loginTenantAdmin(jwt);
113
+ // Store tokens if auth provider supports it
114
+ if (this.authProvider && response.accessToken) {
115
+ await this.storeTokens(response.accessToken, response.refreshToken);
116
+ }
117
+ return response;
118
+ }
119
+ /**
120
+ * ADMIN: Login user with JWT
121
+ * Automatically stores tokens if auth provider supports token storage
122
+ */
123
+ async loginUser(jwt) {
124
+ const response = await this.authApi.loginUser(jwt);
125
+ // Store tokens if auth provider supports it
126
+ if (this.authProvider && response.accessToken) {
127
+ await this.storeTokens(response.accessToken, response.refreshToken);
128
+ }
129
+ return response;
130
+ }
131
+ /**
132
+ * ADMIN: Refresh access token
133
+ * Automatically stores new tokens if auth provider supports token storage
134
+ */
135
+ async refreshAccessToken(refreshToken) {
136
+ // Use provided refresh token or get from auth provider
137
+ const tokenToUse = refreshToken || (this.authProvider?.getRefreshToken ? await this.authProvider.getRefreshToken() : null);
138
+ if (!tokenToUse) {
139
+ throw new Error('No refresh token available for token refresh');
140
+ }
141
+ const response = await this.authApi.refreshAccessToken(tokenToUse);
142
+ // Store new tokens if auth provider supports it
143
+ if (this.authProvider && response.accessToken) {
144
+ await this.storeTokens(response.accessToken, response.refreshToken);
145
+ }
146
+ return response;
147
+ }
148
+ /**
149
+ * Automatic token refresh using stored refresh token
150
+ * Convenience method for 401 error handling
151
+ */
152
+ async autoRefreshToken() {
153
+ return this.refreshAccessToken(); // Uses stored refresh token
154
+ }
155
+ /**
156
+ * Clear stored tokens if auth provider supports it
157
+ */
158
+ async clearTokens() {
159
+ if (this.authProvider?.clearTokens) {
160
+ await this.authProvider.clearTokens();
161
+ }
162
+ }
163
+ /**
164
+ * Check if we have valid tokens for authentication
165
+ */
166
+ hasValidAuth() {
167
+ return this.authProvider?.hasValidToken?.() ?? false;
168
+ }
169
+ // ==========================================
170
+ // PRIVATE HELPERS
171
+ // ==========================================
172
+ /**
173
+ * Store tokens using auth provider if it supports token storage
174
+ */
175
+ async storeTokens(accessToken, refreshToken) {
176
+ if (!this.authProvider)
177
+ return;
178
+ try {
179
+ // Store access token
180
+ if (this.authProvider.setAccessToken) {
181
+ await this.authProvider.setAccessToken(accessToken);
182
+ }
183
+ // Store refresh token if provided and supported
184
+ if (refreshToken && this.authProvider.setRefreshToken) {
185
+ await this.authProvider.setRefreshToken(refreshToken);
186
+ }
187
+ }
188
+ catch (error) {
189
+ console.error('Failed to store tokens in auth provider:', error);
190
+ // Don't throw - token storage failure shouldn't break authentication
191
+ }
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Simple, self-contained authentication provider for SDK
197
+ *
198
+ * Manages tokens internally without external dependencies.
199
+ * Perfect for platform-agnostic usage.
200
+ */
201
+ class SimpleSdkAuthProvider {
202
+ constructor(projectKey) {
203
+ this.accessToken = null;
204
+ this.refreshToken = null;
205
+ this.projectKey = null;
206
+ this.authType = 'admin';
207
+ this.projectKey = projectKey || null;
208
+ // Try to load tokens from localStorage if available
209
+ this.loadTokensFromStorage();
210
+ }
211
+ async getToken() {
212
+ // Return stored access token
213
+ return this.accessToken;
214
+ }
215
+ async getProjectKey() {
216
+ return this.projectKey;
217
+ }
218
+ async onTokenExpired() {
219
+ console.log('SimpleSdkAuthProvider: Token expired, attempting refresh...');
220
+ if (!this.refreshToken) {
221
+ console.warn('SimpleSdkAuthProvider: No refresh token available');
222
+ throw new Error('No refresh token available for refresh');
223
+ }
224
+ // Note: Actual refresh logic would be handled by the SDK's AuthService
225
+ // This provider just manages token storage
226
+ console.warn('SimpleSdkAuthProvider: Token refresh should be handled by SDK AuthService');
227
+ }
228
+ // Token storage methods
229
+ async setAccessToken(token) {
230
+ this.accessToken = token;
231
+ this.saveTokenToStorage('pers_access_token', token);
232
+ }
233
+ async setRefreshToken(token) {
234
+ this.refreshToken = token;
235
+ this.saveTokenToStorage('pers_refresh_token', token);
236
+ }
237
+ async getRefreshToken() {
238
+ return this.refreshToken;
239
+ }
240
+ async clearTokens() {
241
+ this.accessToken = null;
242
+ this.refreshToken = null;
243
+ // Clear from storage
244
+ this.removeTokenFromStorage('pers_access_token');
245
+ this.removeTokenFromStorage('pers_refresh_token');
246
+ }
247
+ // Internal methods for token persistence
248
+ loadTokensFromStorage() {
249
+ if (typeof localStorage !== 'undefined') {
250
+ try {
251
+ this.accessToken = localStorage.getItem('pers_access_token');
252
+ this.refreshToken = localStorage.getItem('pers_refresh_token');
253
+ }
254
+ catch (error) {
255
+ console.error('Failed to load tokens from localStorage:', error);
256
+ }
257
+ }
258
+ else {
259
+ console.warn('localStorage is not available for token persistence');
260
+ }
261
+ }
262
+ saveTokenToStorage(key, value) {
263
+ if (typeof localStorage !== 'undefined') {
264
+ localStorage.setItem(key, value);
265
+ }
266
+ }
267
+ removeTokenFromStorage(key) {
268
+ if (typeof localStorage !== 'undefined') {
269
+ localStorage.removeItem(key);
270
+ }
271
+ }
272
+ // Utility methods for external integration
273
+ hasValidToken() {
274
+ const hasToken = !!this.accessToken;
275
+ return hasToken;
276
+ }
277
+ hasRefreshToken() {
278
+ return !!this.refreshToken;
279
+ }
280
+ }
281
+
47
282
  // packages/pers-sdk/src/core/pers-api-client.ts
48
283
  /**
49
284
  * PERS API Client - Core platform-agnostic client for PERS backend
@@ -54,8 +289,15 @@ class PersApiClient {
54
289
  this.config = config;
55
290
  // Merge user config with defaults (production + v2)
56
291
  this.mergedConfig = mergeWithDefaults(config);
292
+ // Auto-create auth provider if none provided
293
+ if (!this.mergedConfig.authProvider) {
294
+ this.mergedConfig.authProvider = new SimpleSdkAuthProvider(this.mergedConfig.apiProjectKey);
295
+ }
57
296
  // Build API root from merged environment and version
58
297
  this.apiRoot = buildApiRoot(this.mergedConfig.environment, this.mergedConfig.apiVersion);
298
+ // Initialize auth services for direct authentication
299
+ this.authApi = new AuthApi(this);
300
+ this.authService = new AuthService(this.authApi, this.mergedConfig.authProvider);
59
301
  }
60
302
  /**
61
303
  * Get request headers including auth token and project key
@@ -160,6 +402,45 @@ class PersApiClient {
160
402
  async delete(endpoint) {
161
403
  return this.request('DELETE', endpoint);
162
404
  }
405
+ // ==========================================
406
+ // AUTHENTICATION METHODS
407
+ // ==========================================
408
+ /**
409
+ * Login admin user with external JWT (e.g., Firebase)
410
+ * Automatically stores tokens in auth provider if available
411
+ */
412
+ async loginAdmin(externalJwt) {
413
+ return this.authService.loginTenantAdmin(externalJwt);
414
+ }
415
+ /**
416
+ * Login regular user with external JWT
417
+ * Automatically stores tokens in auth provider if available
418
+ */
419
+ async loginUser(externalJwt) {
420
+ return this.authService.loginUser(externalJwt);
421
+ }
422
+ /**
423
+ * Refresh access token using stored refresh token
424
+ */
425
+ async refreshToken() {
426
+ const refreshToken = await this.mergedConfig.authProvider?.getRefreshToken?.();
427
+ if (!refreshToken) {
428
+ throw new Error('No refresh token available');
429
+ }
430
+ return this.authService.refreshAccessToken(refreshToken);
431
+ }
432
+ /**
433
+ * Clear all stored authentication tokens
434
+ */
435
+ async clearAuth() {
436
+ return this.authService.clearTokens();
437
+ }
438
+ /**
439
+ * Check if user has valid authentication token
440
+ */
441
+ hasValidAuth() {
442
+ return this.mergedConfig.authProvider?.hasValidToken?.() || false;
443
+ }
163
444
  /**
164
445
  * Get current configuration (returns merged config)
165
446
  */
@@ -182,168 +463,48 @@ class PersApiError extends Error {
182
463
  this.name = 'PersApiError';
183
464
  }
184
465
  }
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
466
 
236
467
  /**
237
- * Make a request with proper headers, auth, and error handling
468
+ * Memory-based token storage (default)
238
469
  */
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
- }
470
+ class MemoryTokenStorage {
471
+ constructor() {
472
+ this.storage = new Map();
473
+ }
474
+ async setItem(key, value) {
475
+ this.storage.set(key, value);
476
+ }
477
+ async getItem(key) {
478
+ return this.storage.get(key) || null;
479
+ }
480
+ async removeItem(key) {
481
+ this.storage.delete(key);
281
482
  }
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
483
  }
326
-
327
484
  /**
328
- * Get original user configuration
485
+ * localStorage-based token storage (browser only)
329
486
  */
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';
487
+ class LocalStorageTokenStorage {
488
+ async setItem(key, value) {
489
+ if (typeof localStorage !== 'undefined') {
490
+ localStorage.setItem(key, value);
491
+ }
492
+ else {
493
+ throw new Error('localStorage is not available in this environment');
494
+ }
495
+ }
496
+ async getItem(key) {
497
+ if (typeof localStorage !== 'undefined') {
498
+ return localStorage.getItem(key);
499
+ }
500
+ return null;
501
+ }
502
+ async removeItem(key) {
503
+ if (typeof localStorage !== 'undefined') {
504
+ localStorage.removeItem(key);
505
+ }
506
+ }
344
507
  }
345
- }*/
346
-
347
508
  /**
348
509
  * Creates a platform-agnostic AuthProvider from simple configuration
349
510
  *
@@ -354,12 +515,33 @@ constructor(
354
515
  * - Token caching with refresh support
355
516
  * - Automatic token refresh on expiration
356
517
  * - Configurable token providers
357
- * - Platform-independent (no localStorage assumptions)
518
+ * - Token storage (memory, localStorage, custom)
519
+ * - Platform-independent
358
520
  *
359
521
  * @param config - Simple auth configuration
360
522
  * @returns AuthProvider implementation
361
523
  */
362
524
  function createAuthProvider(config) {
525
+ // Initialize token storage
526
+ let tokenStorage;
527
+ switch (config.tokenStorage) {
528
+ case 'localStorage':
529
+ tokenStorage = new LocalStorageTokenStorage();
530
+ break;
531
+ case 'custom':
532
+ if (!config.customTokenStorage) {
533
+ throw new Error('Custom token storage configuration is required when tokenStorage is "custom"');
534
+ }
535
+ tokenStorage = config.customTokenStorage;
536
+ break;
537
+ case 'memory':
538
+ default:
539
+ tokenStorage = new MemoryTokenStorage();
540
+ break;
541
+ }
542
+ // Token storage keys
543
+ const ACCESS_TOKEN_KEY = `pers_access_token_${config.authType || 'user'}`;
544
+ const REFRESH_TOKEN_KEY = `pers_refresh_token_${config.authType || 'user'}`;
363
545
  // Store current token for refresh scenarios and caching
364
546
  let currentToken = config.token || null;
365
547
  let isRefreshing = false; // Prevent concurrent refresh attempts
@@ -376,6 +558,17 @@ function createAuthProvider(config) {
376
558
  if (currentToken) {
377
559
  return currentToken;
378
560
  }
561
+ // Try to get token from storage
562
+ try {
563
+ const storedToken = await tokenStorage.getItem(ACCESS_TOKEN_KEY);
564
+ if (storedToken) {
565
+ currentToken = storedToken;
566
+ return storedToken;
567
+ }
568
+ }
569
+ catch (error) {
570
+ console.warn('Failed to retrieve token from storage:', error);
571
+ }
379
572
  // Custom token provider function (always fresh)
380
573
  if (config.tokenProvider) {
381
574
  const token = await config.tokenProvider();
@@ -388,6 +581,48 @@ function createAuthProvider(config) {
388
581
  async getProjectKey() {
389
582
  return config.projectKey || null;
390
583
  },
584
+ // Token storage methods
585
+ async setAccessToken(token) {
586
+ currentToken = token;
587
+ try {
588
+ await tokenStorage.setItem(ACCESS_TOKEN_KEY, token);
589
+ }
590
+ catch (error) {
591
+ console.error('Failed to store access token:', error);
592
+ throw error;
593
+ }
594
+ },
595
+ async setRefreshToken(token) {
596
+ try {
597
+ await tokenStorage.setItem(REFRESH_TOKEN_KEY, token);
598
+ }
599
+ catch (error) {
600
+ console.error('Failed to store refresh token:', error);
601
+ throw error;
602
+ }
603
+ },
604
+ async getRefreshToken() {
605
+ try {
606
+ return await tokenStorage.getItem(REFRESH_TOKEN_KEY);
607
+ }
608
+ catch (error) {
609
+ console.warn('Failed to retrieve refresh token from storage:', error);
610
+ return null;
611
+ }
612
+ },
613
+ async clearTokens() {
614
+ currentToken = null;
615
+ try {
616
+ await Promise.all([
617
+ tokenStorage.removeItem(ACCESS_TOKEN_KEY),
618
+ tokenStorage.removeItem(REFRESH_TOKEN_KEY)
619
+ ]);
620
+ }
621
+ catch (error) {
622
+ console.error('Failed to clear tokens from storage:', error);
623
+ throw error;
624
+ }
625
+ },
391
626
  async onTokenExpired() {
392
627
  // Prevent concurrent refresh attempts
393
628
  if (isRefreshing) {
@@ -399,7 +634,13 @@ function createAuthProvider(config) {
399
634
  // No refresh logic provided
400
635
  if (!config.onTokenExpired) {
401
636
  console.warn('Token expired but no refresh logic provided');
402
- currentToken = null; // Clear expired token
637
+ currentToken = null;
638
+ try {
639
+ await tokenStorage.removeItem(ACCESS_TOKEN_KEY);
640
+ }
641
+ catch (error) {
642
+ console.warn('Failed to clear expired token from storage:', error);
643
+ }
403
644
  return;
404
645
  }
405
646
  // Start refresh process
@@ -413,6 +654,13 @@ function createAuthProvider(config) {
413
654
  const newToken = await config.tokenProvider();
414
655
  if (newToken && newToken !== currentToken) {
415
656
  currentToken = newToken;
657
+ // Store the new token
658
+ try {
659
+ await tokenStorage.setItem(ACCESS_TOKEN_KEY, newToken);
660
+ }
661
+ catch (error) {
662
+ console.warn('Failed to store refreshed token:', error);
663
+ }
416
664
  // Notify about successful token refresh
417
665
  if (config.onTokenRefreshed) {
418
666
  config.onTokenRefreshed(newToken);
@@ -421,17 +669,35 @@ function createAuthProvider(config) {
421
669
  else {
422
670
  console.warn('Token refresh completed but no new token received');
423
671
  currentToken = null;
672
+ try {
673
+ await tokenStorage.removeItem(ACCESS_TOKEN_KEY);
674
+ }
675
+ catch (error) {
676
+ console.warn('Failed to clear token after failed refresh:', error);
677
+ }
424
678
  }
425
679
  }
426
680
  else {
427
681
  // For static token configs, clear the token since we can't refresh
428
682
  console.warn('Token expired for static token config - clearing token');
429
683
  currentToken = null;
684
+ try {
685
+ await tokenStorage.removeItem(ACCESS_TOKEN_KEY);
686
+ }
687
+ catch (error) {
688
+ console.warn('Failed to clear expired static token:', error);
689
+ }
430
690
  }
431
691
  }
432
692
  catch (error) {
433
693
  console.error('Token refresh failed:', error);
434
694
  currentToken = null; // Clear token on refresh failure
695
+ try {
696
+ await tokenStorage.removeItem(ACCESS_TOKEN_KEY);
697
+ }
698
+ catch (storageError) {
699
+ console.warn('Failed to clear token after refresh failure:', storageError);
700
+ }
435
701
  throw error; // Re-throw to let SDK handle the error
436
702
  }
437
703
  finally {
@@ -468,6 +734,44 @@ function createAuthProvider(config) {
468
734
  };
469
735
  } */
470
736
 
737
+ /**
738
+ * @explorins/pers-sdk/core/auth - Consolidated Auth Module
739
+ *
740
+ * All authentication functionality in one place:
741
+ * - Auth provider interfaces and implementations
742
+ * - Auth API and service logic
743
+ * - Token management
744
+ */
745
+ // Auth provider interfaces and implementations
746
+ /**
747
+ * Create a complete Auth SDK instance (for backward compatibility)
748
+ * Note: This is now handled directly by PersApiClient
749
+ *
750
+ * @param apiClient - Configured PERS API client
751
+ * @param authProvider - Optional auth provider. If not provided, uses SimpleSdkAuthProvider
752
+ * @returns Auth SDK with flattened structure for better DX
753
+ */
754
+ function createAuthSDK(apiClient, authProvider) {
755
+ // Use simple internal auth provider if none provided
756
+ const provider = authProvider || new SimpleSdkAuthProvider();
757
+ const authApi = new AuthApi(apiClient);
758
+ const authService = new AuthService(authApi, provider);
759
+ return {
760
+ // Direct access to service methods (primary interface)
761
+ // Admin authentication methods
762
+ loginTenantAdmin: (jwt) => authService.loginTenantAdmin(jwt),
763
+ loginUser: (jwt) => authService.loginUser(jwt),
764
+ refreshAccessToken: (refreshToken) => authService.refreshAccessToken(refreshToken),
765
+ clearTokens: () => authService.clearTokens(),
766
+ // Auth provider access for external integration
767
+ getAuthProvider: () => provider,
768
+ hasValidToken: () => provider.hasValidToken?.() || false,
769
+ // Advanced access for edge cases
770
+ api: authApi,
771
+ service: authService
772
+ };
773
+ }
774
+
471
775
  /**
472
776
  * PERS SDK - Minimal platform-agnostic client with built-in authentication
473
777
  * Authentication is now handled at the SDK core level for better scalability
@@ -1265,113 +1569,6 @@ function createAnalyticsSDK(apiClient) {
1265
1569
  };
1266
1570
  }
1267
1571
 
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
1572
  /**
1376
1573
  * Platform-Agnostic Campaign API Client (NEW - RESTful Design)
1377
1574
  *
@@ -2240,29 +2437,22 @@ class RedemptionApi {
2240
2437
  // PUBLIC OPERATIONS (Project Key)
2241
2438
  // ==========================================
2242
2439
  /**
2243
- * PUBLIC: Get redemptions (intelligent access)
2440
+ * UNIFIED: Get redemptions with intelligent access control
2244
2441
  *
2245
- * NEW: Intelligent endpoint that adapts based on authentication
2442
+ * Intelligent endpoint that adapts based on authentication:
2246
2443
  * - Public users: Get active redemptions only
2247
2444
  * - Admin users: Get all redemptions with optional filtering
2248
2445
  *
2249
- * Replaces: getActiveRedemptions() + getRedemptionsAsAdmin()
2446
+ * @param options.active - Filter by active status (undefined = all for admins/active for public)
2447
+ * @param options.adminAccess - Force admin access (requires admin auth)
2250
2448
  */
2251
- async getRedemptions(active) {
2449
+ async getRedemptions(options) {
2252
2450
  let url = `${this.basePath}`;
2253
- if (active !== undefined) {
2254
- url += `?active=${active}`;
2451
+ if (options?.active !== undefined) {
2452
+ url += `?active=${options.active}`;
2255
2453
  }
2256
2454
  return this.apiClient.get(url);
2257
2455
  }
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
2456
  /**
2267
2457
  * PUBLIC: Get redemption types
2268
2458
  *
@@ -2308,12 +2498,27 @@ class RedemptionApi {
2308
2498
  // REDEMPTION REDEEMS QUERIES (NEW ENDPOINTS)
2309
2499
  // ==========================================
2310
2500
  /**
2311
- * Get redemption redeems with filtering (unified endpoint)
2501
+ * UNIFIED: Get redemption redeems with filtering and intelligent access
2312
2502
  *
2313
- * NEW: GET /redemption-redeems with query parameters
2314
- * Role-based access: Users see only their own, admins can filter by userId/businessId
2503
+ * Role-based access with unified filtering:
2504
+ * - Users: See only their own redeems (userId/businessId filters ignored)
2505
+ * - Admins: Can filter by userId, businessId, or redemptionId
2506
+ *
2507
+ * @param filters.redemptionId - Filter by specific redemption
2508
+ * @param filters.userId - Admin only: Filter by user ID
2509
+ * @param filters.businessId - Admin only: Filter by business ID
2510
+ * @param filters.myRedeems - Force user's own redeems (uses /me endpoint)
2315
2511
  */
2316
2512
  async getRedemptionRedeems(filters) {
2513
+ // Use convenience endpoint for user's own redeems
2514
+ if (filters?.myRedeems) {
2515
+ let url = `${this.redeemsPath}/me`;
2516
+ if (filters.redemptionId) {
2517
+ url += `?redemptionId=${filters.redemptionId}`;
2518
+ }
2519
+ return this.apiClient.get(url);
2520
+ }
2521
+ // Use admin endpoint with filtering
2317
2522
  let url = this.redeemsPath;
2318
2523
  const params = new URLSearchParams();
2319
2524
  if (filters?.redemptionId)
@@ -2329,67 +2534,22 @@ class RedemptionApi {
2329
2534
  return this.apiClient.get(url);
2330
2535
  }
2331
2536
  /**
2332
- * Get specific redemption redeem by ID
2333
- *
2334
- * NEW: GET /redemption-redeems/:id
2537
+ * UNIFIED: Get specific redemption redeem by ID
2335
2538
  */
2336
2539
  async getRedemptionRedeemById(id) {
2337
2540
  return this.apiClient.get(`${this.redeemsPath}/${id}`);
2338
2541
  }
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
2542
  // ==========================================
2376
2543
  // USER OPERATIONS (JWT + Project Key)
2377
2544
  // ==========================================
2378
2545
  /**
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)
2546
+ * UNIFIED: Get user redemption history
2388
2547
  *
2389
- * Deprecated: Use getUserRedemptionHistory() instead
2548
+ * Uses convenience endpoint /redemption-redeems/me with optional filtering
2549
+ * @param redemptionId - Optional filter by specific redemption
2390
2550
  */
2391
- async getUserRedeems() {
2392
- return this.getUserRedemptionHistory();
2551
+ async getUserRedeems(redemptionId) {
2552
+ return this.getRedemptionRedeems({ myRedeems: true, redemptionId });
2393
2553
  }
2394
2554
  // ==========================================
2395
2555
  // ADMIN OPERATIONS (Tenant Admin JWT)
@@ -2401,7 +2561,7 @@ class RedemptionApi {
2401
2561
  * The unified endpoint will detect admin privileges and allow filtering
2402
2562
  */
2403
2563
  async getRedemptionsAsAdmin(active) {
2404
- return this.getRedemptions(active); // Uses intelligent endpoint
2564
+ return this.getRedemptions({ active, adminAccess: true });
2405
2565
  }
2406
2566
  /**
2407
2567
  * ADMIN: Create redemption
@@ -2420,21 +2580,13 @@ class RedemptionApi {
2420
2580
  return this.apiClient.put(`${this.basePath}/${id}`, redemptionCreateRequest);
2421
2581
  }
2422
2582
  /**
2423
- * ADMIN: Toggle redemption status
2583
+ * UNIFIED: Toggle redemption active status
2424
2584
  *
2425
2585
  * Updated: /redemption/admin/:id/toggle-active → /redemptions/:id/status
2426
2586
  * Following standard /status pattern used across domains
2427
2587
  */
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
2588
  async toggleRedemptionActive(redemptionId) {
2437
- return this.toggleRedemptionStatus(redemptionId);
2589
+ return this.apiClient.put(`${this.basePath}/${redemptionId}/status`, {});
2438
2590
  }
2439
2591
  /**
2440
2592
  * ADMIN: Delete redemption
@@ -2480,21 +2632,13 @@ class RedemptionApi {
2480
2632
  return this.apiClient.delete(`${this.basePath}/${redemptionId}/token-units/${redemptionTokenUnitId}`);
2481
2633
  }
2482
2634
  // ==========================================
2483
- // BACKWARD COMPATIBILITY METHODS
2635
+ // CONVENIENCE METHODS (Legacy Support)
2484
2636
  // ==========================================
2485
2637
  /**
2486
- * @deprecated Use getRedemptions() instead
2487
- * Backward compatibility for old admin endpoint
2638
+ * Convenience: Get active redemptions (public access)
2488
2639
  */
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);
2640
+ async getActiveRedemptions() {
2641
+ return this.getRedemptions({ active: true });
2498
2642
  }
2499
2643
  }
2500
2644
 
@@ -2514,7 +2658,15 @@ class RedemptionService {
2514
2658
  // PUBLIC OPERATIONS
2515
2659
  // ==========================================
2516
2660
  /**
2517
- * PUBLIC: Get active redemptions
2661
+ * UNIFIED: Get redemptions with intelligent access control
2662
+ * @param options.active - Filter by active status
2663
+ * @param options.adminAccess - Force admin access
2664
+ */
2665
+ async getRedemptions(options) {
2666
+ return this.redemptionApi.getRedemptions(options);
2667
+ }
2668
+ /**
2669
+ * Convenience: Get active redemptions (public)
2518
2670
  */
2519
2671
  async getActiveRedemptions() {
2520
2672
  return this.redemptionApi.getActiveRedemptions();
@@ -2535,7 +2687,13 @@ class RedemptionService {
2535
2687
  return this.redemptionApi.redeemRedemption(redemptionId);
2536
2688
  }
2537
2689
  /**
2538
- * AUTH: Get user redemptions
2690
+ * UNIFIED: Get redemption redeems with filtering
2691
+ */
2692
+ async getRedemptionRedeems(filters) {
2693
+ return this.redemptionApi.getRedemptionRedeems(filters);
2694
+ }
2695
+ /**
2696
+ * Convenience: Get user redemptions
2539
2697
  */
2540
2698
  async getUserRedeems() {
2541
2699
  return this.redemptionApi.getUserRedeems();
@@ -2544,7 +2702,7 @@ class RedemptionService {
2544
2702
  // ADMIN OPERATIONS
2545
2703
  // ==========================================
2546
2704
  /**
2547
- * ADMIN: Get redemptions with optional active filter
2705
+ * Convenience: Get redemptions as admin
2548
2706
  */
2549
2707
  async getRedemptionsAsAdmin(active) {
2550
2708
  return this.redemptionApi.getRedemptionsAsAdmin(active);
@@ -4698,10 +4856,14 @@ function createWeb3SDK(apiClient) {
4698
4856
  };
4699
4857
  }
4700
4858
 
4859
+ Object.defineProperty(exports, "AccountOwnerType", {
4860
+ enumerable: true,
4861
+ get: function () { return persShared.AccountOwnerType; }
4862
+ });
4701
4863
  exports.AnalyticsApi = AnalyticsApi;
4702
4864
  exports.AnalyticsService = AnalyticsService;
4703
- exports.AuthAdminApi = AuthAdminApi;
4704
- exports.AuthAdminService = AuthAdminService;
4865
+ exports.AuthApi = AuthApi;
4866
+ exports.AuthService = AuthService;
4705
4867
  exports.BaseTokenService = BaseTokenService;
4706
4868
  exports.BusinessApi = BusinessApi;
4707
4869
  exports.BusinessService = BusinessService;
@@ -4719,6 +4881,7 @@ exports.PersApiError = PersApiError;
4719
4881
  exports.PersSDK = PersSDK;
4720
4882
  exports.RedemptionApi = RedemptionApi;
4721
4883
  exports.RedemptionService = RedemptionService;
4884
+ exports.SimpleSdkAuthProvider = SimpleSdkAuthProvider;
4722
4885
  exports.TenantApi = TenantApi;
4723
4886
  exports.TenantService = TenantService;
4724
4887
  exports.TokenApi = TokenApi;
@@ -4737,8 +4900,8 @@ exports.Web3InfrastructureApi = Web3InfrastructureApi;
4737
4900
  exports.Web3ProviderService = Web3ProviderService;
4738
4901
  exports.buildApiRoot = buildApiRoot;
4739
4902
  exports.createAnalyticsSDK = createAnalyticsSDK;
4740
- exports.createAuthAdminSDK = createAuthAdminSDK;
4741
4903
  exports.createAuthProvider = createAuthProvider;
4904
+ exports.createAuthSDK = createAuthSDK;
4742
4905
  exports.createBusinessSDK = createBusinessSDK;
4743
4906
  exports.createCampaignSDK = createCampaignSDK;
4744
4907
  exports.createDonationSDK = createDonationSDK;