@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/core.cjs CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ var persShared = require('@explorins/pers-shared');
4
+
3
5
  /**
4
6
  * PERS SDK Configuration interfaces
5
7
  */
@@ -38,6 +40,241 @@ function mergeWithDefaults(config) {
38
40
  };
39
41
  }
40
42
 
43
+ /**
44
+ * Platform-Agnostic Auth Admin API Client
45
+ *
46
+ * Handles authentication and authorization admin operations using the PERS backend.
47
+ * Uses @explorins/pers-shared DTOs for consistency with backend.
48
+ *
49
+ * Note: Special header handling (bypass-auth-interceptor) may need to be implemented
50
+ * at the PersApiClient level or through a specialized auth client.
51
+ */
52
+ class AuthApi {
53
+ constructor(apiClient) {
54
+ this.apiClient = apiClient;
55
+ this.basePath = '/auth';
56
+ }
57
+ // ==========================================
58
+ // ADMIN AUTHENTICATION OPERATIONS
59
+ // ==========================================
60
+ /**
61
+ * ADMIN: Login tenant admin with JWT
62
+ * Note: JWT handling and auth bypass headers may need special implementation
63
+ */
64
+ async loginTenantAdmin(jwt) {
65
+ const body = {
66
+ authToken: jwt,
67
+ authType: persShared.AccountOwnerType.TENANT
68
+ };
69
+ return this.apiClient.post(`${this.basePath}/token`, body);
70
+ }
71
+ async loginUser(jwt) {
72
+ const body = {
73
+ authToken: jwt,
74
+ authType: persShared.AccountOwnerType.USER
75
+ };
76
+ return this.apiClient.post(`${this.basePath}/token`, body);
77
+ }
78
+ /**
79
+ * ADMIN: Refresh access token
80
+ * Note: Bypass header handling may need special implementation
81
+ */
82
+ async refreshAccessToken(refreshToken) {
83
+ return this.apiClient.post(`${this.basePath}/refresh`, { refreshToken });
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Platform-Agnostic Auth Admin Service
89
+ *
90
+ * Contains auth admin business logic and operations that work across platforms.
91
+ * No framework dependencies - pure TypeScript business logic.
92
+ *
93
+ * Focuses only on actual backend capabilities.
94
+ */
95
+ class AuthService {
96
+ constructor(authApi, authProvider) {
97
+ this.authApi = authApi;
98
+ this.authProvider = authProvider;
99
+ }
100
+ // ==========================================
101
+ // ADMIN AUTHENTICATION OPERATIONS
102
+ // ==========================================
103
+ /**
104
+ * ADMIN: Login tenant admin with JWT
105
+ * Automatically stores tokens if auth provider supports token storage
106
+ */
107
+ async loginTenantAdmin(jwt) {
108
+ const response = await this.authApi.loginTenantAdmin(jwt);
109
+ // Store tokens if auth provider supports it
110
+ if (this.authProvider && response.accessToken) {
111
+ await this.storeTokens(response.accessToken, response.refreshToken);
112
+ }
113
+ return response;
114
+ }
115
+ /**
116
+ * ADMIN: Login user with JWT
117
+ * Automatically stores tokens if auth provider supports token storage
118
+ */
119
+ async loginUser(jwt) {
120
+ const response = await this.authApi.loginUser(jwt);
121
+ // Store tokens if auth provider supports it
122
+ if (this.authProvider && response.accessToken) {
123
+ await this.storeTokens(response.accessToken, response.refreshToken);
124
+ }
125
+ return response;
126
+ }
127
+ /**
128
+ * ADMIN: Refresh access token
129
+ * Automatically stores new tokens if auth provider supports token storage
130
+ */
131
+ async refreshAccessToken(refreshToken) {
132
+ // Use provided refresh token or get from auth provider
133
+ const tokenToUse = refreshToken || (this.authProvider?.getRefreshToken ? await this.authProvider.getRefreshToken() : null);
134
+ if (!tokenToUse) {
135
+ throw new Error('No refresh token available for token refresh');
136
+ }
137
+ const response = await this.authApi.refreshAccessToken(tokenToUse);
138
+ // Store new tokens if auth provider supports it
139
+ if (this.authProvider && response.accessToken) {
140
+ await this.storeTokens(response.accessToken, response.refreshToken);
141
+ }
142
+ return response;
143
+ }
144
+ /**
145
+ * Automatic token refresh using stored refresh token
146
+ * Convenience method for 401 error handling
147
+ */
148
+ async autoRefreshToken() {
149
+ return this.refreshAccessToken(); // Uses stored refresh token
150
+ }
151
+ /**
152
+ * Clear stored tokens if auth provider supports it
153
+ */
154
+ async clearTokens() {
155
+ if (this.authProvider?.clearTokens) {
156
+ await this.authProvider.clearTokens();
157
+ }
158
+ }
159
+ /**
160
+ * Check if we have valid tokens for authentication
161
+ */
162
+ hasValidAuth() {
163
+ return this.authProvider?.hasValidToken?.() ?? false;
164
+ }
165
+ // ==========================================
166
+ // PRIVATE HELPERS
167
+ // ==========================================
168
+ /**
169
+ * Store tokens using auth provider if it supports token storage
170
+ */
171
+ async storeTokens(accessToken, refreshToken) {
172
+ if (!this.authProvider)
173
+ return;
174
+ try {
175
+ // Store access token
176
+ if (this.authProvider.setAccessToken) {
177
+ await this.authProvider.setAccessToken(accessToken);
178
+ }
179
+ // Store refresh token if provided and supported
180
+ if (refreshToken && this.authProvider.setRefreshToken) {
181
+ await this.authProvider.setRefreshToken(refreshToken);
182
+ }
183
+ }
184
+ catch (error) {
185
+ console.error('Failed to store tokens in auth provider:', error);
186
+ // Don't throw - token storage failure shouldn't break authentication
187
+ }
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Simple, self-contained authentication provider for SDK
193
+ *
194
+ * Manages tokens internally without external dependencies.
195
+ * Perfect for platform-agnostic usage.
196
+ */
197
+ class SimpleSdkAuthProvider {
198
+ constructor(projectKey) {
199
+ this.accessToken = null;
200
+ this.refreshToken = null;
201
+ this.projectKey = null;
202
+ this.authType = 'admin';
203
+ this.projectKey = projectKey || null;
204
+ // Try to load tokens from localStorage if available
205
+ this.loadTokensFromStorage();
206
+ }
207
+ async getToken() {
208
+ // Return stored access token
209
+ return this.accessToken;
210
+ }
211
+ async getProjectKey() {
212
+ return this.projectKey;
213
+ }
214
+ async onTokenExpired() {
215
+ console.log('SimpleSdkAuthProvider: Token expired, attempting refresh...');
216
+ if (!this.refreshToken) {
217
+ console.warn('SimpleSdkAuthProvider: No refresh token available');
218
+ throw new Error('No refresh token available for refresh');
219
+ }
220
+ // Note: Actual refresh logic would be handled by the SDK's AuthService
221
+ // This provider just manages token storage
222
+ console.warn('SimpleSdkAuthProvider: Token refresh should be handled by SDK AuthService');
223
+ }
224
+ // Token storage methods
225
+ async setAccessToken(token) {
226
+ this.accessToken = token;
227
+ this.saveTokenToStorage('pers_access_token', token);
228
+ }
229
+ async setRefreshToken(token) {
230
+ this.refreshToken = token;
231
+ this.saveTokenToStorage('pers_refresh_token', token);
232
+ }
233
+ async getRefreshToken() {
234
+ return this.refreshToken;
235
+ }
236
+ async clearTokens() {
237
+ this.accessToken = null;
238
+ this.refreshToken = null;
239
+ // Clear from storage
240
+ this.removeTokenFromStorage('pers_access_token');
241
+ this.removeTokenFromStorage('pers_refresh_token');
242
+ }
243
+ // Internal methods for token persistence
244
+ loadTokensFromStorage() {
245
+ if (typeof localStorage !== 'undefined') {
246
+ try {
247
+ this.accessToken = localStorage.getItem('pers_access_token');
248
+ this.refreshToken = localStorage.getItem('pers_refresh_token');
249
+ }
250
+ catch (error) {
251
+ console.error('Failed to load tokens from localStorage:', error);
252
+ }
253
+ }
254
+ else {
255
+ console.warn('localStorage is not available for token persistence');
256
+ }
257
+ }
258
+ saveTokenToStorage(key, value) {
259
+ if (typeof localStorage !== 'undefined') {
260
+ localStorage.setItem(key, value);
261
+ }
262
+ }
263
+ removeTokenFromStorage(key) {
264
+ if (typeof localStorage !== 'undefined') {
265
+ localStorage.removeItem(key);
266
+ }
267
+ }
268
+ // Utility methods for external integration
269
+ hasValidToken() {
270
+ const hasToken = !!this.accessToken;
271
+ return hasToken;
272
+ }
273
+ hasRefreshToken() {
274
+ return !!this.refreshToken;
275
+ }
276
+ }
277
+
41
278
  // packages/pers-sdk/src/core/pers-api-client.ts
42
279
  /**
43
280
  * PERS API Client - Core platform-agnostic client for PERS backend
@@ -48,8 +285,15 @@ class PersApiClient {
48
285
  this.config = config;
49
286
  // Merge user config with defaults (production + v2)
50
287
  this.mergedConfig = mergeWithDefaults(config);
288
+ // Auto-create auth provider if none provided
289
+ if (!this.mergedConfig.authProvider) {
290
+ this.mergedConfig.authProvider = new SimpleSdkAuthProvider(this.mergedConfig.apiProjectKey);
291
+ }
51
292
  // Build API root from merged environment and version
52
293
  this.apiRoot = buildApiRoot(this.mergedConfig.environment, this.mergedConfig.apiVersion);
294
+ // Initialize auth services for direct authentication
295
+ this.authApi = new AuthApi(this);
296
+ this.authService = new AuthService(this.authApi, this.mergedConfig.authProvider);
53
297
  }
54
298
  /**
55
299
  * Get request headers including auth token and project key
@@ -154,6 +398,45 @@ class PersApiClient {
154
398
  async delete(endpoint) {
155
399
  return this.request('DELETE', endpoint);
156
400
  }
401
+ // ==========================================
402
+ // AUTHENTICATION METHODS
403
+ // ==========================================
404
+ /**
405
+ * Login admin user with external JWT (e.g., Firebase)
406
+ * Automatically stores tokens in auth provider if available
407
+ */
408
+ async loginAdmin(externalJwt) {
409
+ return this.authService.loginTenantAdmin(externalJwt);
410
+ }
411
+ /**
412
+ * Login regular user with external JWT
413
+ * Automatically stores tokens in auth provider if available
414
+ */
415
+ async loginUser(externalJwt) {
416
+ return this.authService.loginUser(externalJwt);
417
+ }
418
+ /**
419
+ * Refresh access token using stored refresh token
420
+ */
421
+ async refreshToken() {
422
+ const refreshToken = await this.mergedConfig.authProvider?.getRefreshToken?.();
423
+ if (!refreshToken) {
424
+ throw new Error('No refresh token available');
425
+ }
426
+ return this.authService.refreshAccessToken(refreshToken);
427
+ }
428
+ /**
429
+ * Clear all stored authentication tokens
430
+ */
431
+ async clearAuth() {
432
+ return this.authService.clearTokens();
433
+ }
434
+ /**
435
+ * Check if user has valid authentication token
436
+ */
437
+ hasValidAuth() {
438
+ return this.mergedConfig.authProvider?.hasValidToken?.() || false;
439
+ }
157
440
  /**
158
441
  * Get current configuration (returns merged config)
159
442
  */
@@ -176,168 +459,48 @@ class PersApiError extends Error {
176
459
  this.name = 'PersApiError';
177
460
  }
178
461
  }
179
- /**
180
- * PERS API Client - Core platform-agnostic client for PERS backend
181
- */
182
- /*import { HttpClient, RequestOptions } from './abstractions/http-client';
183
- import { PersConfig, buildApiRoot, mergeWithDefaults } from './pers-config';
184
-
185
- export class PersApiClient {
186
- private readonly apiRoot: string;
187
- private readonly mergedConfig: ReturnType<typeof mergeWithDefaults>;
188
-
189
- constructor(
190
- private httpClient: HttpClient,
191
- private config: PersConfig
192
- ) {
193
- // Merge user config with defaults (production + v2)
194
- this.mergedConfig = mergeWithDefaults(config);
195
-
196
- // Build API root from merged environment and version
197
- this.apiRoot = buildApiRoot(this.mergedConfig.environment, this.mergedConfig.apiVersion);
198
- }
199
-
200
- /**
201
- * Get request headers including auth token and project key
202
- */
203
- /*private async getHeaders(): Promise<Record<string, string>> {
204
- const headers: Record<string, string> = {
205
- 'Content-Type': 'application/json',
206
- };
207
-
208
- // Add authentication token
209
- if (this.mergedConfig.authProvider) {
210
- const token = await this.mergedConfig.authProvider.getToken();
211
- if (token) {
212
- headers['Authorization'] = `Bearer ${token}`;
213
- }
214
- }
215
-
216
- // Add project key
217
- if (this.mergedConfig.authProvider) {
218
- const projectKey = await this.mergedConfig.authProvider.getProjectKey();
219
- if (projectKey) {
220
- headers['x-project-key'] = projectKey;
221
- }
222
- } else if(this.mergedConfig.apiProjectKey) {
223
- // Fallback to config project key if no auth provider
224
- headers['x-project-key'] = this.mergedConfig.apiProjectKey;
225
- }
226
-
227
- return headers;
228
- }
229
462
 
230
463
  /**
231
- * Make a request with proper headers, auth, and error handling
464
+ * Memory-based token storage (default)
232
465
  */
233
- /*private async request<T>(
234
- method: 'GET' | 'POST' | 'PUT' | 'DELETE',
235
- endpoint: string,
236
- body?: any,
237
- options?: { retryCount?: number }
238
- ): Promise<T> {
239
- const { retryCount = 0 } = options || {};
240
- const url = `${this.apiRoot}${endpoint}`;
241
-
242
- const requestOptions: RequestOptions = {
243
- headers: await this.getHeaders(),
244
- timeout: this.mergedConfig.timeout,
245
- };
246
-
247
- try {
248
- switch (method) {
249
- case 'GET':
250
- return await this.httpClient.get<T>(url, requestOptions);
251
- case 'POST':
252
- return await this.httpClient.post<T>(url, body, requestOptions);
253
- case 'PUT':
254
- return await this.httpClient.put<T>(url, body, requestOptions);
255
- case 'DELETE':
256
- return await this.httpClient.delete<T>(url, requestOptions);
257
- default:
258
- throw new Error(`Unsupported HTTP method: ${method}`);
259
- }
260
- } catch (error: any) {
261
- // Handle 401 errors with automatic token refresh
262
- if (error.status === 401 && retryCount === 0 && this.mergedConfig.authProvider?.onTokenExpired) {
263
- try {
264
- await this.mergedConfig.authProvider.onTokenExpired();
265
- // Retry once with refreshed token
266
- return this.request<T>(method, endpoint, body, { ...options, retryCount: 1 });
267
- } catch (refreshError) {
268
- throw new PersApiError(
269
- `Authentication refresh failed: ${refreshError}`,
270
- endpoint,
271
- method,
272
- 401
273
- );
274
- }
466
+ class MemoryTokenStorage {
467
+ constructor() {
468
+ this.storage = new Map();
469
+ }
470
+ async setItem(key, value) {
471
+ this.storage.set(key, value);
472
+ }
473
+ async getItem(key) {
474
+ return this.storage.get(key) || null;
475
+ }
476
+ async removeItem(key) {
477
+ this.storage.delete(key);
275
478
  }
276
-
277
- throw new PersApiError(
278
- `PERS API request failed: ${error.message || error}`,
279
- endpoint,
280
- method,
281
- error.status
282
- );
283
- }
284
- }
285
-
286
- /**
287
- * Generic GET request
288
- */
289
- /*async get<T>(endpoint: string): Promise<T> {
290
- return this.request<T>('GET', endpoint);
291
- }
292
-
293
- /**
294
- * Generic POST request
295
- */
296
- /*async post<T>(endpoint: string, body?: any): Promise<T> {
297
- return this.request<T>('POST', endpoint, body);
298
- }
299
-
300
- /**
301
- * Generic PUT request
302
- */
303
- /*async put<T>(endpoint: string, body?: any): Promise<T> {
304
- return this.request<T>('PUT', endpoint, body);
305
- }
306
-
307
- /**
308
- * Generic DELETE request
309
- */
310
- /*async delete<T>(endpoint: string): Promise<T> {
311
- return this.request<T>('DELETE', endpoint);
312
- }
313
-
314
- /**
315
- * Get current configuration (returns merged config)
316
- */
317
- /*getConfig(): ReturnType<typeof mergeWithDefaults> {
318
- return this.mergedConfig;
319
479
  }
320
-
321
480
  /**
322
- * Get original user configuration
481
+ * localStorage-based token storage (browser only)
323
482
  */
324
- /*getOriginalConfig(): PersConfig {
325
- return this.config;
326
- }
327
- }
328
-
329
- export class PersApiError extends Error {
330
- constructor(
331
- message: string,
332
- public endpoint: string,
333
- public method: string,
334
- public statusCode?: number
335
- ) {
336
- super(message);
337
- this.name = 'PersApiError';
483
+ class LocalStorageTokenStorage {
484
+ async setItem(key, value) {
485
+ if (typeof localStorage !== 'undefined') {
486
+ localStorage.setItem(key, value);
487
+ }
488
+ else {
489
+ throw new Error('localStorage is not available in this environment');
490
+ }
491
+ }
492
+ async getItem(key) {
493
+ if (typeof localStorage !== 'undefined') {
494
+ return localStorage.getItem(key);
495
+ }
496
+ return null;
497
+ }
498
+ async removeItem(key) {
499
+ if (typeof localStorage !== 'undefined') {
500
+ localStorage.removeItem(key);
501
+ }
502
+ }
338
503
  }
339
- }*/
340
-
341
504
  /**
342
505
  * Creates a platform-agnostic AuthProvider from simple configuration
343
506
  *
@@ -348,12 +511,33 @@ constructor(
348
511
  * - Token caching with refresh support
349
512
  * - Automatic token refresh on expiration
350
513
  * - Configurable token providers
351
- * - Platform-independent (no localStorage assumptions)
514
+ * - Token storage (memory, localStorage, custom)
515
+ * - Platform-independent
352
516
  *
353
517
  * @param config - Simple auth configuration
354
518
  * @returns AuthProvider implementation
355
519
  */
356
520
  function createAuthProvider(config) {
521
+ // Initialize token storage
522
+ let tokenStorage;
523
+ switch (config.tokenStorage) {
524
+ case 'localStorage':
525
+ tokenStorage = new LocalStorageTokenStorage();
526
+ break;
527
+ case 'custom':
528
+ if (!config.customTokenStorage) {
529
+ throw new Error('Custom token storage configuration is required when tokenStorage is "custom"');
530
+ }
531
+ tokenStorage = config.customTokenStorage;
532
+ break;
533
+ case 'memory':
534
+ default:
535
+ tokenStorage = new MemoryTokenStorage();
536
+ break;
537
+ }
538
+ // Token storage keys
539
+ const ACCESS_TOKEN_KEY = `pers_access_token_${config.authType || 'user'}`;
540
+ const REFRESH_TOKEN_KEY = `pers_refresh_token_${config.authType || 'user'}`;
357
541
  // Store current token for refresh scenarios and caching
358
542
  let currentToken = config.token || null;
359
543
  let isRefreshing = false; // Prevent concurrent refresh attempts
@@ -370,6 +554,17 @@ function createAuthProvider(config) {
370
554
  if (currentToken) {
371
555
  return currentToken;
372
556
  }
557
+ // Try to get token from storage
558
+ try {
559
+ const storedToken = await tokenStorage.getItem(ACCESS_TOKEN_KEY);
560
+ if (storedToken) {
561
+ currentToken = storedToken;
562
+ return storedToken;
563
+ }
564
+ }
565
+ catch (error) {
566
+ console.warn('Failed to retrieve token from storage:', error);
567
+ }
373
568
  // Custom token provider function (always fresh)
374
569
  if (config.tokenProvider) {
375
570
  const token = await config.tokenProvider();
@@ -382,6 +577,48 @@ function createAuthProvider(config) {
382
577
  async getProjectKey() {
383
578
  return config.projectKey || null;
384
579
  },
580
+ // Token storage methods
581
+ async setAccessToken(token) {
582
+ currentToken = token;
583
+ try {
584
+ await tokenStorage.setItem(ACCESS_TOKEN_KEY, token);
585
+ }
586
+ catch (error) {
587
+ console.error('Failed to store access token:', error);
588
+ throw error;
589
+ }
590
+ },
591
+ async setRefreshToken(token) {
592
+ try {
593
+ await tokenStorage.setItem(REFRESH_TOKEN_KEY, token);
594
+ }
595
+ catch (error) {
596
+ console.error('Failed to store refresh token:', error);
597
+ throw error;
598
+ }
599
+ },
600
+ async getRefreshToken() {
601
+ try {
602
+ return await tokenStorage.getItem(REFRESH_TOKEN_KEY);
603
+ }
604
+ catch (error) {
605
+ console.warn('Failed to retrieve refresh token from storage:', error);
606
+ return null;
607
+ }
608
+ },
609
+ async clearTokens() {
610
+ currentToken = null;
611
+ try {
612
+ await Promise.all([
613
+ tokenStorage.removeItem(ACCESS_TOKEN_KEY),
614
+ tokenStorage.removeItem(REFRESH_TOKEN_KEY)
615
+ ]);
616
+ }
617
+ catch (error) {
618
+ console.error('Failed to clear tokens from storage:', error);
619
+ throw error;
620
+ }
621
+ },
385
622
  async onTokenExpired() {
386
623
  // Prevent concurrent refresh attempts
387
624
  if (isRefreshing) {
@@ -393,7 +630,13 @@ function createAuthProvider(config) {
393
630
  // No refresh logic provided
394
631
  if (!config.onTokenExpired) {
395
632
  console.warn('Token expired but no refresh logic provided');
396
- currentToken = null; // Clear expired token
633
+ currentToken = null;
634
+ try {
635
+ await tokenStorage.removeItem(ACCESS_TOKEN_KEY);
636
+ }
637
+ catch (error) {
638
+ console.warn('Failed to clear expired token from storage:', error);
639
+ }
397
640
  return;
398
641
  }
399
642
  // Start refresh process
@@ -407,6 +650,13 @@ function createAuthProvider(config) {
407
650
  const newToken = await config.tokenProvider();
408
651
  if (newToken && newToken !== currentToken) {
409
652
  currentToken = newToken;
653
+ // Store the new token
654
+ try {
655
+ await tokenStorage.setItem(ACCESS_TOKEN_KEY, newToken);
656
+ }
657
+ catch (error) {
658
+ console.warn('Failed to store refreshed token:', error);
659
+ }
410
660
  // Notify about successful token refresh
411
661
  if (config.onTokenRefreshed) {
412
662
  config.onTokenRefreshed(newToken);
@@ -415,17 +665,35 @@ function createAuthProvider(config) {
415
665
  else {
416
666
  console.warn('Token refresh completed but no new token received');
417
667
  currentToken = null;
668
+ try {
669
+ await tokenStorage.removeItem(ACCESS_TOKEN_KEY);
670
+ }
671
+ catch (error) {
672
+ console.warn('Failed to clear token after failed refresh:', error);
673
+ }
418
674
  }
419
675
  }
420
676
  else {
421
677
  // For static token configs, clear the token since we can't refresh
422
678
  console.warn('Token expired for static token config - clearing token');
423
679
  currentToken = null;
680
+ try {
681
+ await tokenStorage.removeItem(ACCESS_TOKEN_KEY);
682
+ }
683
+ catch (error) {
684
+ console.warn('Failed to clear expired static token:', error);
685
+ }
424
686
  }
425
687
  }
426
688
  catch (error) {
427
689
  console.error('Token refresh failed:', error);
428
690
  currentToken = null; // Clear token on refresh failure
691
+ try {
692
+ await tokenStorage.removeItem(ACCESS_TOKEN_KEY);
693
+ }
694
+ catch (storageError) {
695
+ console.warn('Failed to clear token after refresh failure:', storageError);
696
+ }
429
697
  throw error; // Re-throw to let SDK handle the error
430
698
  }
431
699
  finally {
@@ -462,6 +730,44 @@ function createAuthProvider(config) {
462
730
  };
463
731
  } */
464
732
 
733
+ /**
734
+ * @explorins/pers-sdk/core/auth - Consolidated Auth Module
735
+ *
736
+ * All authentication functionality in one place:
737
+ * - Auth provider interfaces and implementations
738
+ * - Auth API and service logic
739
+ * - Token management
740
+ */
741
+ // Auth provider interfaces and implementations
742
+ /**
743
+ * Create a complete Auth SDK instance (for backward compatibility)
744
+ * Note: This is now handled directly by PersApiClient
745
+ *
746
+ * @param apiClient - Configured PERS API client
747
+ * @param authProvider - Optional auth provider. If not provided, uses SimpleSdkAuthProvider
748
+ * @returns Auth SDK with flattened structure for better DX
749
+ */
750
+ function createAuthSDK(apiClient, authProvider) {
751
+ // Use simple internal auth provider if none provided
752
+ const provider = authProvider || new SimpleSdkAuthProvider();
753
+ const authApi = new AuthApi(apiClient);
754
+ const authService = new AuthService(authApi, provider);
755
+ return {
756
+ // Direct access to service methods (primary interface)
757
+ // Admin authentication methods
758
+ loginTenantAdmin: (jwt) => authService.loginTenantAdmin(jwt),
759
+ loginUser: (jwt) => authService.loginUser(jwt),
760
+ refreshAccessToken: (refreshToken) => authService.refreshAccessToken(refreshToken),
761
+ clearTokens: () => authService.clearTokens(),
762
+ // Auth provider access for external integration
763
+ getAuthProvider: () => provider,
764
+ hasValidToken: () => provider.hasValidToken?.() || false,
765
+ // Advanced access for edge cases
766
+ api: authApi,
767
+ service: authService
768
+ };
769
+ }
770
+
465
771
  /**
466
772
  * PERS SDK - Minimal platform-agnostic client with built-in authentication
467
773
  * Authentication is now handled at the SDK core level for better scalability
@@ -495,12 +801,20 @@ function createPersSDK(httpClient, config) {
495
801
  return new PersSDK(httpClient, config);
496
802
  }
497
803
 
804
+ Object.defineProperty(exports, "AccountOwnerType", {
805
+ enumerable: true,
806
+ get: function () { return persShared.AccountOwnerType; }
807
+ });
808
+ exports.AuthApi = AuthApi;
809
+ exports.AuthService = AuthService;
498
810
  exports.DEFAULT_PERS_CONFIG = DEFAULT_PERS_CONFIG;
499
811
  exports.PersApiClient = PersApiClient;
500
812
  exports.PersApiError = PersApiError;
501
813
  exports.PersSDK = PersSDK;
814
+ exports.SimpleSdkAuthProvider = SimpleSdkAuthProvider;
502
815
  exports.buildApiRoot = buildApiRoot;
503
816
  exports.createAuthProvider = createAuthProvider;
817
+ exports.createAuthSDK = createAuthSDK;
504
818
  exports.createPersSDK = createPersSDK;
505
819
  exports.mergeWithDefaults = mergeWithDefaults;
506
820
  //# sourceMappingURL=core.cjs.map