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