@a-cube-io/ereceipts-js-sdk 2.0.9 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -2112,7 +2112,7 @@ function formatDecimal(value, decimals = 2) {
2112
2112
  return num.toFixed(decimals);
2113
2113
  }
2114
2114
 
2115
- const log$h = createPrefixedLogger('AUTH-SERVICE');
2115
+ const log$b = createPrefixedLogger('AUTH-SERVICE');
2116
2116
  class AuthenticationService {
2117
2117
  get user$() {
2118
2118
  return this.userSubject.asObservable();
@@ -2134,7 +2134,7 @@ class AuthenticationService {
2134
2134
  }
2135
2135
  async login(credentials) {
2136
2136
  this.authStateSubject.next('authenticating');
2137
- log$h.info('Login attempt', {
2137
+ log$b.info('Login attempt', {
2138
2138
  authUrl: this.config.authUrl,
2139
2139
  email: credentials.email,
2140
2140
  });
@@ -2145,7 +2145,7 @@ class AuthenticationService {
2145
2145
  });
2146
2146
  const jwtPayload = parseJwt(response.data.token);
2147
2147
  const expiresAt = jwtPayload.exp * 1000;
2148
- log$h.info('Login successful', {
2148
+ log$b.info('Login successful', {
2149
2149
  authUrl: this.config.authUrl,
2150
2150
  tokenPrefix: response.data.token.substring(0, 30) + '...',
2151
2151
  expiresAt: new Date(expiresAt).toISOString(),
@@ -2174,21 +2174,21 @@ class AuthenticationService {
2174
2174
  const token = await this.tokenStorage.getAccessToken();
2175
2175
  if (!token) {
2176
2176
  // No token - clear any stale user state
2177
- log$h.debug('getCurrentUser: No token in storage');
2177
+ log$b.debug('getCurrentUser: No token in storage');
2178
2178
  if (this.userSubject.value) {
2179
2179
  this.userSubject.next(null);
2180
2180
  this.authStateSubject.next('idle');
2181
2181
  }
2182
2182
  return null;
2183
2183
  }
2184
- log$h.debug('getCurrentUser: Token found', {
2184
+ log$b.debug('getCurrentUser: Token found', {
2185
2185
  tokenPrefix: token.substring(0, 30) + '...',
2186
2186
  tokenLength: token.length,
2187
2187
  });
2188
2188
  const jwtPayload = parseJwt(token);
2189
2189
  if (isTokenExpired(jwtPayload)) {
2190
2190
  // Token expired - clear everything
2191
- log$h.warn('getCurrentUser: Token expired');
2191
+ log$b.warn('getCurrentUser: Token expired');
2192
2192
  await this.tokenStorage.clearTokens();
2193
2193
  this.userSubject.next(null);
2194
2194
  this.authStateSubject.next('idle');
@@ -2198,7 +2198,7 @@ class AuthenticationService {
2198
2198
  // Token is valid - return cached user if available
2199
2199
  const currentUser = this.userSubject.value;
2200
2200
  if (currentUser) {
2201
- log$h.debug('getCurrentUser: Returning cached user', {
2201
+ log$b.debug('getCurrentUser: Returning cached user', {
2202
2202
  email: currentUser.email,
2203
2203
  roles: currentUser.roles,
2204
2204
  });
@@ -2221,12 +2221,12 @@ class AuthenticationService {
2221
2221
  async isAuthenticated() {
2222
2222
  const token = await this.tokenStorage.getAccessToken();
2223
2223
  if (!token) {
2224
- log$h.debug('isAuthenticated: No token in storage');
2224
+ log$b.debug('isAuthenticated: No token in storage');
2225
2225
  return false;
2226
2226
  }
2227
2227
  const jwtPayload = parseJwt(token);
2228
2228
  const expired = isTokenExpired(jwtPayload);
2229
- log$h.debug('isAuthenticated: Token check', {
2229
+ log$b.debug('isAuthenticated: Token check', {
2230
2230
  hasToken: true,
2231
2231
  expired,
2232
2232
  expiresAt: new Date(jwtPayload.exp * 1000).toISOString(),
@@ -2898,7 +2898,7 @@ class ACubeSDKError extends Error {
2898
2898
  }
2899
2899
  }
2900
2900
 
2901
- const log$g = createPrefixedLogger('AUTH-STRATEGY');
2901
+ const log$a = createPrefixedLogger('AUTH-STRATEGY');
2902
2902
  class AuthStrategy {
2903
2903
  constructor(jwtHandler, mtlsHandler, userProvider, mtlsAdapter) {
2904
2904
  this.jwtHandler = jwtHandler;
@@ -2913,7 +2913,7 @@ class AuthStrategy {
2913
2913
  const platform = this.detectPlatform();
2914
2914
  const userRole = await this.getUserRole();
2915
2915
  const isReceiptEndpoint = this.isReceiptEndpoint(url);
2916
- log$g.debug('Determining auth config', {
2916
+ log$a.debug('Determining auth config', {
2917
2917
  url,
2918
2918
  method,
2919
2919
  platform,
@@ -3044,7 +3044,7 @@ class JwtAuthHandler {
3044
3044
  }
3045
3045
  }
3046
3046
 
3047
- const log$f = createPrefixedLogger('MTLS-HANDLER');
3047
+ const log$9 = createPrefixedLogger('MTLS-HANDLER');
3048
3048
  class MtlsAuthHandler {
3049
3049
  constructor(mtlsAdapter, certificatePort) {
3050
3050
  this.mtlsAdapter = mtlsAdapter;
@@ -3086,7 +3086,7 @@ class MtlsAuthHandler {
3086
3086
  async makeRequest(url, config, jwtToken) {
3087
3087
  const requestKey = this.generateRequestKey(url, config, jwtToken);
3088
3088
  if (this.pendingRequests.has(requestKey)) {
3089
- log$f.debug('Deduplicating concurrent request:', url);
3089
+ log$9.debug('Deduplicating concurrent request:', url);
3090
3090
  return this.pendingRequests.get(requestKey);
3091
3091
  }
3092
3092
  const requestPromise = this.executeRequest(url, config, jwtToken, false);
@@ -3110,10 +3110,10 @@ class MtlsAuthHandler {
3110
3110
  };
3111
3111
  if (jwtToken) {
3112
3112
  headers['Authorization'] = `Bearer ${jwtToken}`;
3113
- log$f.debug('JWT token present:', jwtToken.substring(0, 20) + '...');
3113
+ log$9.debug('JWT token present:', jwtToken.substring(0, 20) + '...');
3114
3114
  }
3115
3115
  else {
3116
- log$f.warn('No JWT token provided for mTLS request');
3116
+ log$9.warn('No JWT token provided for mTLS request');
3117
3117
  }
3118
3118
  const fullUrl = this.constructMtlsUrl(url);
3119
3119
  const mtlsConfig = {
@@ -3124,25 +3124,25 @@ class MtlsAuthHandler {
3124
3124
  timeout: config.timeout,
3125
3125
  responseType: config.responseType,
3126
3126
  };
3127
- log$f.debug('header-mtls', headers);
3128
- log$f.debug(`${config.method} ${fullUrl}`);
3127
+ log$9.debug('header-mtls', headers);
3128
+ log$9.debug(`${config.method} ${fullUrl}`);
3129
3129
  if (config.data) {
3130
- log$f.debug('Request body:', config.data);
3130
+ log$9.debug('Request body:', config.data);
3131
3131
  }
3132
3132
  try {
3133
3133
  const response = await this.mtlsAdapter.request(mtlsConfig);
3134
- log$f.debug(`Response ${response.status} from ${fullUrl}`);
3134
+ log$9.debug(`Response ${response.status} from ${fullUrl}`);
3135
3135
  if (response.data) {
3136
- log$f.debug('Response body:', response.data);
3136
+ log$9.debug('Response body:', response.data);
3137
3137
  }
3138
3138
  return response.data;
3139
3139
  }
3140
3140
  catch (error) {
3141
- log$f.error(`Response error from ${fullUrl}:`, error);
3141
+ log$9.error(`Response error from ${fullUrl}:`, error);
3142
3142
  if (error && typeof error === 'object' && 'response' in error) {
3143
3143
  const axiosError = error;
3144
3144
  if (axiosError.response?.data) {
3145
- log$f.error('Response body:', axiosError.response.data);
3145
+ log$9.error('Response body:', axiosError.response.data);
3146
3146
  }
3147
3147
  }
3148
3148
  if (isRetryAttempt) {
@@ -3152,7 +3152,7 @@ class MtlsAuthHandler {
3152
3152
  if (!shouldRetry) {
3153
3153
  throw error;
3154
3154
  }
3155
- log$f.debug('Request failed, reconfiguring certificate and retrying...');
3155
+ log$9.debug('Request failed, reconfiguring certificate and retrying...');
3156
3156
  try {
3157
3157
  await this.configureCertificate(certificate);
3158
3158
  return await this.executeRequest(url, config, jwtToken, true);
@@ -3260,1902 +3260,6 @@ class MtlsAuthHandler {
3260
3260
  }
3261
3261
  }
3262
3262
 
3263
- const DEFAULT_QUEUE_CONFIG = {
3264
- maxRetries: 3,
3265
- retryDelay: 1000,
3266
- maxRetryDelay: 30000,
3267
- backoffMultiplier: 2,
3268
- maxQueueSize: 1000,
3269
- batchSize: 10,
3270
- syncInterval: 30000,
3271
- };
3272
-
3273
- class OperationQueue {
3274
- constructor(storage, config = DEFAULT_QUEUE_CONFIG, events = {}) {
3275
- this.storage = storage;
3276
- this.config = config;
3277
- this.events = events;
3278
- this.queue = [];
3279
- this.processing = false;
3280
- this.config = { ...DEFAULT_QUEUE_CONFIG, ...config };
3281
- this.loadQueue();
3282
- if (this.config.syncInterval > 0) {
3283
- this.startAutoSync();
3284
- }
3285
- }
3286
- async addOperation(type, resource, endpoint, method, data, priority = 1) {
3287
- if (this.queue.length >= this.config.maxQueueSize) {
3288
- const lowPriorityIndex = this.queue.findIndex((op) => op.priority === 1);
3289
- if (lowPriorityIndex !== -1) {
3290
- this.queue.splice(lowPriorityIndex, 1);
3291
- }
3292
- else {
3293
- throw new Error('Queue is full');
3294
- }
3295
- }
3296
- const operation = {
3297
- id: this.generateId(),
3298
- type,
3299
- resource,
3300
- endpoint,
3301
- method,
3302
- data,
3303
- status: 'pending',
3304
- createdAt: Date.now(),
3305
- updatedAt: Date.now(),
3306
- retryCount: 0,
3307
- maxRetries: this.config.maxRetries,
3308
- priority,
3309
- };
3310
- const insertIndex = this.queue.findIndex((op) => op.priority < priority);
3311
- if (insertIndex === -1) {
3312
- this.queue.push(operation);
3313
- }
3314
- else {
3315
- this.queue.splice(insertIndex, 0, operation);
3316
- }
3317
- await this.saveQueue();
3318
- this.events.onOperationAdded?.(operation);
3319
- return operation.id;
3320
- }
3321
- getPendingOperations() {
3322
- return this.queue.filter((op) => op.status === 'pending' || op.status === 'failed');
3323
- }
3324
- getOperation(id) {
3325
- return this.queue.find((op) => op.id === id);
3326
- }
3327
- async removeOperation(id) {
3328
- const index = this.queue.findIndex((op) => op.id === id);
3329
- if (index === -1)
3330
- return false;
3331
- this.queue.splice(index, 1);
3332
- await this.saveQueue();
3333
- return true;
3334
- }
3335
- async updateOperation(id, updates) {
3336
- const operation = this.queue.find((op) => op.id === id);
3337
- if (!operation)
3338
- return false;
3339
- Object.assign(operation, { ...updates, updatedAt: Date.now() });
3340
- await this.saveQueue();
3341
- return true;
3342
- }
3343
- getStats() {
3344
- return {
3345
- total: this.queue.length,
3346
- pending: this.queue.filter((op) => op.status === 'pending').length,
3347
- processing: this.queue.filter((op) => op.status === 'processing').length,
3348
- completed: this.queue.filter((op) => op.status === 'completed').length,
3349
- failed: this.queue.filter((op) => op.status === 'failed').length,
3350
- };
3351
- }
3352
- async clearQueue() {
3353
- this.queue = [];
3354
- await this.saveQueue();
3355
- }
3356
- async clearCompleted() {
3357
- this.queue = this.queue.filter((op) => op.status !== 'completed');
3358
- await this.saveQueue();
3359
- }
3360
- async clearFailed() {
3361
- this.queue = this.queue.filter((op) => op.status !== 'failed');
3362
- await this.saveQueue();
3363
- }
3364
- async retryFailed() {
3365
- for (const operation of this.queue.filter((op) => op.status === 'failed')) {
3366
- if (operation.retryCount < operation.maxRetries) {
3367
- operation.status = 'pending';
3368
- operation.retryCount++;
3369
- operation.updatedAt = Date.now();
3370
- delete operation.error;
3371
- }
3372
- }
3373
- await this.saveQueue();
3374
- }
3375
- getNextBatch() {
3376
- return this.queue
3377
- .filter((op) => op.status === 'pending')
3378
- .sort((a, b) => b.priority - a.priority || a.createdAt - b.createdAt)
3379
- .slice(0, this.config.batchSize);
3380
- }
3381
- isEmpty() {
3382
- return this.getPendingOperations().length === 0;
3383
- }
3384
- startAutoSync() {
3385
- if (this.syncIntervalId)
3386
- return;
3387
- this.syncIntervalId = setInterval(() => {
3388
- if (!this.isEmpty() && !this.processing) {
3389
- this.events.onQueueEmpty?.();
3390
- }
3391
- }, this.config.syncInterval);
3392
- }
3393
- stopAutoSync() {
3394
- if (this.syncIntervalId) {
3395
- clearInterval(this.syncIntervalId);
3396
- this.syncIntervalId = undefined;
3397
- }
3398
- }
3399
- setProcessing(value) {
3400
- this.processing = value;
3401
- }
3402
- isCurrentlyProcessing() {
3403
- return this.processing;
3404
- }
3405
- async loadQueue() {
3406
- try {
3407
- const queueData = await this.storage.get(OperationQueue.QUEUE_KEY);
3408
- if (queueData) {
3409
- this.queue = JSON.parse(queueData);
3410
- this.queue.forEach((op) => {
3411
- if (op.status === 'processing') {
3412
- op.status = 'pending';
3413
- }
3414
- });
3415
- }
3416
- }
3417
- catch {
3418
- this.queue = [];
3419
- }
3420
- }
3421
- async saveQueue() {
3422
- try {
3423
- await this.storage.set(OperationQueue.QUEUE_KEY, JSON.stringify(this.queue));
3424
- }
3425
- catch (error) {
3426
- this.events.onError?.(new Error(`Failed to save queue: ${error}`));
3427
- }
3428
- }
3429
- generateId() {
3430
- return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
3431
- }
3432
- destroy() {
3433
- this.stopAutoSync();
3434
- }
3435
- }
3436
- OperationQueue.QUEUE_KEY = 'acube_operation_queue';
3437
-
3438
- class SyncManager {
3439
- constructor(queue, httpPort, networkMonitor, config, events = {}) {
3440
- this.queue = queue;
3441
- this.httpPort = httpPort;
3442
- this.networkMonitor = networkMonitor;
3443
- this.config = config;
3444
- this.events = events;
3445
- this.isOnline = true;
3446
- this.destroy$ = new Subject();
3447
- this.setupNetworkMonitoring();
3448
- }
3449
- setupNetworkMonitoring() {
3450
- // Subscribe to online$ to track current state
3451
- this.networkSubscription = this.networkMonitor.online$
3452
- .pipe(startWith(true), // Assume online initially
3453
- pairwise(), filter(([wasOnline, isNowOnline]) => !wasOnline && isNowOnline), takeUntil(this.destroy$))
3454
- .subscribe(() => {
3455
- // Offline → Online transition detected
3456
- this.syncPendingOperations();
3457
- });
3458
- // Track current online state
3459
- this.networkMonitor.online$.pipe(takeUntil(this.destroy$)).subscribe((online) => {
3460
- this.isOnline = online;
3461
- });
3462
- }
3463
- async syncPendingOperations() {
3464
- if (!this.isOnline) {
3465
- throw new Error('Cannot sync while offline');
3466
- }
3467
- if (this.queue.isCurrentlyProcessing()) {
3468
- throw new Error('Sync already in progress');
3469
- }
3470
- this.queue.setProcessing(true);
3471
- try {
3472
- const results = [];
3473
- let successCount = 0;
3474
- let failureCount = 0;
3475
- while (!this.queue.isEmpty()) {
3476
- const batch = this.queue.getNextBatch();
3477
- if (batch.length === 0)
3478
- break;
3479
- const batchPromises = batch.map((operation) => this.processOperation(operation));
3480
- const batchResults = await Promise.allSettled(batchPromises);
3481
- batchResults.forEach((result, index) => {
3482
- const operation = batch[index];
3483
- if (!operation)
3484
- return;
3485
- if (result.status === 'fulfilled') {
3486
- const syncResult = result.value;
3487
- results.push(syncResult);
3488
- if (syncResult.success) {
3489
- successCount++;
3490
- this.events.onOperationCompleted?.(syncResult);
3491
- }
3492
- else {
3493
- failureCount++;
3494
- this.events.onOperationFailed?.(syncResult);
3495
- }
3496
- }
3497
- else {
3498
- const syncResult = {
3499
- operation,
3500
- success: false,
3501
- error: result.reason?.message || 'Unknown error',
3502
- };
3503
- results.push(syncResult);
3504
- failureCount++;
3505
- this.events.onOperationFailed?.(syncResult);
3506
- this.queue.updateOperation(operation.id, {
3507
- status: 'failed',
3508
- error: syncResult.error,
3509
- });
3510
- }
3511
- });
3512
- if (!this.queue.isEmpty()) {
3513
- await this.delay(500);
3514
- }
3515
- }
3516
- const batchResult = {
3517
- totalOperations: results.length,
3518
- successCount,
3519
- failureCount,
3520
- results,
3521
- };
3522
- this.events.onBatchSyncCompleted?.(batchResult);
3523
- if (this.queue.isEmpty()) {
3524
- this.events.onQueueEmpty?.();
3525
- }
3526
- return batchResult;
3527
- }
3528
- finally {
3529
- this.queue.setProcessing(false);
3530
- }
3531
- }
3532
- async processOperation(operation) {
3533
- await this.queue.updateOperation(operation.id, { status: 'processing' });
3534
- try {
3535
- const response = await this.executeOperation(operation);
3536
- await this.queue.updateOperation(operation.id, { status: 'completed' });
3537
- return { operation, success: true, response };
3538
- }
3539
- catch (error) {
3540
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
3541
- if (operation.retryCount < operation.maxRetries && this.isRetryableError(error)) {
3542
- const delay = this.calculateRetryDelay(operation.retryCount);
3543
- await this.queue.updateOperation(operation.id, {
3544
- status: 'pending',
3545
- retryCount: operation.retryCount + 1,
3546
- error: errorMessage,
3547
- });
3548
- setTimeout(() => {
3549
- if (this.isOnline && !this.queue.isCurrentlyProcessing()) {
3550
- this.syncPendingOperations();
3551
- }
3552
- }, delay);
3553
- return { operation, success: false, error: `Retrying: ${errorMessage}` };
3554
- }
3555
- else {
3556
- await this.queue.updateOperation(operation.id, {
3557
- status: 'failed',
3558
- error: errorMessage,
3559
- });
3560
- return { operation, success: false, error: errorMessage };
3561
- }
3562
- }
3563
- }
3564
- async executeOperation(operation) {
3565
- const { method, endpoint, data, headers } = operation;
3566
- const config = headers ? { headers } : undefined;
3567
- switch (method) {
3568
- case 'GET':
3569
- return (await this.httpPort.get(endpoint, config)).data;
3570
- case 'POST':
3571
- return (await this.httpPort.post(endpoint, data, config)).data;
3572
- case 'PUT':
3573
- return (await this.httpPort.put(endpoint, data, config)).data;
3574
- case 'PATCH':
3575
- return (await this.httpPort.patch(endpoint, data, config)).data;
3576
- case 'DELETE':
3577
- return (await this.httpPort.delete(endpoint, config)).data;
3578
- default:
3579
- throw new Error(`Unsupported HTTP method: ${method}`);
3580
- }
3581
- }
3582
- isRetryableError(error) {
3583
- const errorObj = error;
3584
- if (errorObj.code === 'NETWORK_ERROR')
3585
- return true;
3586
- if (errorObj.statusCode && errorObj.statusCode >= 500)
3587
- return true;
3588
- if (errorObj.statusCode === 429)
3589
- return true;
3590
- const errorMessage = error?.message;
3591
- if (errorObj.code === 'ECONNABORTED' || errorMessage?.includes('timeout'))
3592
- return true;
3593
- return false;
3594
- }
3595
- calculateRetryDelay(retryCount) {
3596
- const delay = this.config.retryDelay * Math.pow(this.config.backoffMultiplier, retryCount);
3597
- return Math.min(delay, this.config.maxRetryDelay);
3598
- }
3599
- delay(ms) {
3600
- return new Promise((resolve) => setTimeout(resolve, ms));
3601
- }
3602
- isCurrentlyOnline() {
3603
- return this.isOnline;
3604
- }
3605
- async triggerSync() {
3606
- if (!this.isOnline)
3607
- return null;
3608
- if (this.queue.isEmpty()) {
3609
- return { totalOperations: 0, successCount: 0, failureCount: 0, results: [] };
3610
- }
3611
- return await this.syncPendingOperations();
3612
- }
3613
- getSyncStatus() {
3614
- return {
3615
- isOnline: this.isOnline,
3616
- isProcessing: this.queue.isCurrentlyProcessing(),
3617
- queueStats: this.queue.getStats(),
3618
- };
3619
- }
3620
- destroy() {
3621
- this.destroy$.next();
3622
- this.destroy$.complete();
3623
- this.networkSubscription?.unsubscribe();
3624
- }
3625
- }
3626
-
3627
- class OfflineManager {
3628
- get queue$() {
3629
- return this.queueSubject.asObservable();
3630
- }
3631
- get syncStatus$() {
3632
- return this.syncStatusSubject.asObservable();
3633
- }
3634
- constructor(storage, httpPort, networkMonitor, config = {}, events = {}, _cache) {
3635
- this.queueSubject = new BehaviorSubject([]);
3636
- this.syncStatusSubject = new BehaviorSubject({
3637
- isOnline: true,
3638
- isProcessing: false,
3639
- queueStats: { total: 0, pending: 0, processing: 0, completed: 0, failed: 0 },
3640
- });
3641
- this.destroy$ = new Subject();
3642
- const finalConfig = { ...DEFAULT_QUEUE_CONFIG, ...config };
3643
- const wrappedEvents = {
3644
- ...events,
3645
- onOperationAdded: (op) => {
3646
- this.updateQueueState();
3647
- events.onOperationAdded?.(op);
3648
- },
3649
- onOperationCompleted: (result) => {
3650
- this.updateQueueState();
3651
- events.onOperationCompleted?.(result);
3652
- },
3653
- onOperationFailed: (result) => {
3654
- this.updateQueueState();
3655
- events.onOperationFailed?.(result);
3656
- },
3657
- onBatchSyncCompleted: (result) => {
3658
- this.updateQueueState();
3659
- events.onBatchSyncCompleted?.(result);
3660
- },
3661
- };
3662
- this.queue = new OperationQueue(storage, finalConfig, wrappedEvents);
3663
- this.syncManager = new SyncManager(this.queue, httpPort, networkMonitor, finalConfig, wrappedEvents);
3664
- this.updateQueueState();
3665
- }
3666
- updateQueueState() {
3667
- this.queueSubject.next(this.queue.getPendingOperations());
3668
- this.syncStatusSubject.next(this.syncManager.getSyncStatus());
3669
- }
3670
- async queueOperation(type, resource, endpoint, method, data, priority = 1) {
3671
- const id = await this.queue.addOperation(type, resource, endpoint, method, data, priority);
3672
- this.updateQueueState();
3673
- return id;
3674
- }
3675
- async queueReceiptCreation(receiptData, priority = 2) {
3676
- return await this.queueOperation('CREATE', 'receipt', '/mf1/receipts', 'POST', receiptData, priority);
3677
- }
3678
- async queueReceiptVoid(voidData, priority = 3) {
3679
- return await this.queueOperation('DELETE', 'receipt', '/mf1/receipts', 'DELETE', voidData, priority);
3680
- }
3681
- async queueReceiptReturn(returnData, priority = 3) {
3682
- return await this.queueOperation('CREATE', 'receipt', '/mf1/receipts/return', 'POST', returnData, priority);
3683
- }
3684
- async queueCashierCreation(cashierData, priority = 1) {
3685
- return await this.queueOperation('CREATE', 'cashier', '/mf1/cashiers', 'POST', cashierData, priority);
3686
- }
3687
- isOnline() {
3688
- return this.syncManager.isCurrentlyOnline();
3689
- }
3690
- getStatus() {
3691
- return this.syncManager.getSyncStatus();
3692
- }
3693
- getPendingCount() {
3694
- return this.queue.getPendingOperations().length;
3695
- }
3696
- isEmpty() {
3697
- return this.queue.isEmpty();
3698
- }
3699
- async sync() {
3700
- const result = await this.syncManager.triggerSync();
3701
- this.updateQueueState();
3702
- return result;
3703
- }
3704
- async retryFailed() {
3705
- await this.queue.retryFailed();
3706
- this.updateQueueState();
3707
- if (this.isOnline()) {
3708
- await this.sync();
3709
- }
3710
- }
3711
- async clearCompleted() {
3712
- await this.queue.clearCompleted();
3713
- this.updateQueueState();
3714
- }
3715
- async clearFailed() {
3716
- await this.queue.clearFailed();
3717
- this.updateQueueState();
3718
- }
3719
- async clearAll() {
3720
- await this.queue.clearQueue();
3721
- this.updateQueueState();
3722
- }
3723
- getOperation(id) {
3724
- return this.queue.getOperation(id);
3725
- }
3726
- async removeOperation(id) {
3727
- const result = await this.queue.removeOperation(id);
3728
- this.updateQueueState();
3729
- return result;
3730
- }
3731
- getQueueStats() {
3732
- return this.queue.getStats();
3733
- }
3734
- startAutoSync() {
3735
- this.queue.startAutoSync();
3736
- }
3737
- stopAutoSync() {
3738
- this.queue.stopAutoSync();
3739
- }
3740
- destroy() {
3741
- this.destroy$.next();
3742
- this.destroy$.complete();
3743
- this.queue.destroy();
3744
- this.syncManager.destroy();
3745
- }
3746
- }
3747
-
3748
- class CompressionAdapter {
3749
- compress(data, threshold = 1024) {
3750
- const originalSize = data.length * 2;
3751
- if (originalSize < threshold) {
3752
- return {
3753
- data,
3754
- compressed: false,
3755
- originalSize,
3756
- compressedSize: originalSize,
3757
- };
3758
- }
3759
- try {
3760
- const compressed = this.compressString(data);
3761
- const compressedSize = compressed.length * 2;
3762
- if (compressedSize < originalSize) {
3763
- return {
3764
- data: compressed,
3765
- compressed: true,
3766
- originalSize,
3767
- compressedSize,
3768
- };
3769
- }
3770
- return {
3771
- data,
3772
- compressed: false,
3773
- originalSize,
3774
- compressedSize: originalSize,
3775
- };
3776
- }
3777
- catch {
3778
- return {
3779
- data,
3780
- compressed: false,
3781
- originalSize,
3782
- compressedSize: originalSize,
3783
- };
3784
- }
3785
- }
3786
- decompress(data, compressed) {
3787
- if (!compressed) {
3788
- return { data, wasCompressed: false };
3789
- }
3790
- try {
3791
- const decompressed = this.decompressString(data);
3792
- return { data: decompressed, wasCompressed: true };
3793
- }
3794
- catch {
3795
- return { data, wasCompressed: false };
3796
- }
3797
- }
3798
- estimateSavings(data) {
3799
- const repeated = data.match(/(.)\1{3,}/g);
3800
- if (!repeated)
3801
- return 0;
3802
- let savings = 0;
3803
- for (const match of repeated) {
3804
- const originalBytes = match.length * 2;
3805
- const compressedBytes = 6;
3806
- if (originalBytes > compressedBytes) {
3807
- savings += originalBytes - compressedBytes;
3808
- }
3809
- }
3810
- return Math.min(savings, data.length * 2 * 0.5);
3811
- }
3812
- compressString(input) {
3813
- let compressed = '';
3814
- let i = 0;
3815
- while (i < input.length) {
3816
- let count = 1;
3817
- const char = input[i];
3818
- while (i + count < input.length && input[i + count] === char && count < 255) {
3819
- count++;
3820
- }
3821
- if (count > 3) {
3822
- compressed += `~${count}${char}`;
3823
- }
3824
- else {
3825
- for (let j = 0; j < count; j++) {
3826
- compressed += char;
3827
- }
3828
- }
3829
- i += count;
3830
- }
3831
- return `COMP:${btoa(compressed)}`;
3832
- }
3833
- decompressString(input) {
3834
- if (!input.startsWith('COMP:')) {
3835
- return input;
3836
- }
3837
- const encodedData = input.substring(5);
3838
- if (!encodedData) {
3839
- return input;
3840
- }
3841
- const compressed = atob(encodedData);
3842
- let decompressed = '';
3843
- let i = 0;
3844
- while (i < compressed.length) {
3845
- if (compressed[i] === '~' && i + 2 < compressed.length) {
3846
- let countStr = '';
3847
- i++;
3848
- while (i < compressed.length) {
3849
- const char = compressed[i];
3850
- if (char && /\d/.test(char)) {
3851
- countStr += char;
3852
- i++;
3853
- }
3854
- else {
3855
- break;
3856
- }
3857
- }
3858
- if (countStr && i < compressed.length) {
3859
- const count = parseInt(countStr, 10);
3860
- const char = compressed[i];
3861
- for (let j = 0; j < count; j++) {
3862
- decompressed += char;
3863
- }
3864
- i++;
3865
- }
3866
- }
3867
- else {
3868
- decompressed += compressed[i];
3869
- i++;
3870
- }
3871
- }
3872
- return decompressed;
3873
- }
3874
- }
3875
- function compressData(data, threshold = 1024) {
3876
- return new CompressionAdapter().compress(data, threshold);
3877
- }
3878
- function decompressData(data, compressed) {
3879
- return new CompressionAdapter().decompress(data, compressed);
3880
- }
3881
-
3882
- const log$e = createPrefixedLogger('CACHE-RN');
3883
- /**
3884
- * React Native cache adapter using SQLite (Expo or react-native-sqlite-storage)
3885
- * Cache never expires - data persists until explicitly invalidated
3886
- */
3887
- class ReactNativeCacheAdapter {
3888
- constructor(options = {}) {
3889
- this.db = null;
3890
- this.initPromise = null;
3891
- this.isExpo = false;
3892
- this.hasCompressedColumn = false;
3893
- this.options = {
3894
- maxSize: 50 * 1024 * 1024, // 50MB
3895
- maxEntries: 10000,
3896
- compression: false,
3897
- compressionThreshold: 1024,
3898
- ...options,
3899
- };
3900
- this.initPromise = this.initialize();
3901
- }
3902
- normalizeResults(results) {
3903
- if (this.isExpo) {
3904
- const expoResults = results;
3905
- if (Array.isArray(expoResults)) {
3906
- return expoResults;
3907
- }
3908
- return expoResults.results || [];
3909
- }
3910
- else {
3911
- const rnResults = results;
3912
- const rows = rnResults.rows;
3913
- if (!rows || rows.length === 0)
3914
- return [];
3915
- const normalizedRows = [];
3916
- for (let i = 0; i < rows.length; i++) {
3917
- normalizedRows.push(rows.item(i));
3918
- }
3919
- return normalizedRows;
3920
- }
3921
- }
3922
- async initialize() {
3923
- if (this.db)
3924
- return;
3925
- try {
3926
- // Try Expo SQLite first
3927
- const ExpoSQLite = require('expo-sqlite');
3928
- this.db = await ExpoSQLite.openDatabaseAsync(ReactNativeCacheAdapter.DB_NAME);
3929
- this.isExpo = true;
3930
- await this.createTables();
3931
- }
3932
- catch (expoError) {
3933
- try {
3934
- // Fallback to react-native-sqlite-storage
3935
- const SQLite = require('react-native-sqlite-storage');
3936
- this.db = await new Promise((resolve, reject) => {
3937
- SQLite.openDatabase({
3938
- name: ReactNativeCacheAdapter.DB_NAME,
3939
- location: 'default',
3940
- }, resolve, reject);
3941
- });
3942
- this.isExpo = false;
3943
- await this.createTables();
3944
- }
3945
- catch (rnError) {
3946
- throw new Error(`Failed to initialize SQLite: Expo error: ${expoError}, RN error: ${rnError}`);
3947
- }
3948
- }
3949
- }
3950
- async createTables() {
3951
- // Create table with simplified schema (no TTL)
3952
- const createTableSQL = `
3953
- CREATE TABLE IF NOT EXISTS ${ReactNativeCacheAdapter.TABLE_NAME} (
3954
- cache_key TEXT PRIMARY KEY,
3955
- data TEXT NOT NULL,
3956
- timestamp INTEGER NOT NULL
3957
- );
3958
-
3959
- CREATE INDEX IF NOT EXISTS idx_timestamp ON ${ReactNativeCacheAdapter.TABLE_NAME}(timestamp);
3960
- `;
3961
- await this.executeSql(createTableSQL);
3962
- // Then, run migrations to add new columns if they don't exist
3963
- await this.runMigrations();
3964
- }
3965
- async runMigrations() {
3966
- log$e.debug('Running database migrations...');
3967
- try {
3968
- // Check if compressed column exists
3969
- this.hasCompressedColumn = await this.checkColumnExists('compressed');
3970
- if (!this.hasCompressedColumn) {
3971
- log$e.debug('Adding compressed column to cache table');
3972
- const addColumnSQL = `ALTER TABLE ${ReactNativeCacheAdapter.TABLE_NAME} ADD COLUMN compressed INTEGER DEFAULT 0`;
3973
- await this.executeSql(addColumnSQL);
3974
- this.hasCompressedColumn = true;
3975
- log$e.debug('Successfully added compressed column');
3976
- }
3977
- else {
3978
- log$e.debug('Compressed column already exists');
3979
- }
3980
- log$e.debug('Database migrations completed', {
3981
- hasCompressedColumn: this.hasCompressedColumn,
3982
- });
3983
- }
3984
- catch (error) {
3985
- log$e.debug('Migration failed, disabling compression features', error);
3986
- this.hasCompressedColumn = false;
3987
- // Don't throw - allow the app to continue even if migration fails
3988
- // The compressed feature will just be disabled
3989
- }
3990
- }
3991
- async checkColumnExists(columnName) {
3992
- try {
3993
- const pragmaSQL = `PRAGMA table_info(${ReactNativeCacheAdapter.TABLE_NAME})`;
3994
- const results = await this.executeSql(pragmaSQL);
3995
- const columns = this.normalizeResults(results);
3996
- log$e.debug('Table columns found', { columns: columns.map((c) => c.name) });
3997
- return columns.some((column) => column.name === columnName);
3998
- }
3999
- catch (error) {
4000
- log$e.debug('Error checking column existence', error);
4001
- return false;
4002
- }
4003
- }
4004
- async get(key) {
4005
- await this.ensureInitialized();
4006
- const sql = `SELECT * FROM ${ReactNativeCacheAdapter.TABLE_NAME} WHERE cache_key = ?`;
4007
- log$e.debug('Executing get query', { sql, key });
4008
- const results = await this.executeSql(sql, [key]);
4009
- log$e.debug('Get query results', { key, hasResults: !!results });
4010
- // Normalize results from different SQLite implementations
4011
- const rows = this.normalizeResults(results);
4012
- if (!rows || rows.length === 0) {
4013
- return null;
4014
- }
4015
- const row = rows[0];
4016
- if (!row) {
4017
- return null;
4018
- }
4019
- const isCompressed = this.hasCompressedColumn ? !!row.compressed : false;
4020
- const rawData = isCompressed ? decompressData(row.data, true).data : row.data;
4021
- return {
4022
- data: JSON.parse(rawData),
4023
- timestamp: row.timestamp,
4024
- compressed: isCompressed,
4025
- };
4026
- }
4027
- async set(key, data) {
4028
- const item = {
4029
- data,
4030
- timestamp: Date.now(),
4031
- };
4032
- log$e.debug('Setting cache item', { key });
4033
- return this.setItem(key, item);
4034
- }
4035
- async setItem(key, item) {
4036
- await this.ensureInitialized();
4037
- // Handle compression if enabled and compressed column is available
4038
- const serializedData = JSON.stringify(item.data);
4039
- let finalData = serializedData;
4040
- let isCompressed = false;
4041
- if (this.options.compression && this.options.compressionThreshold && this.hasCompressedColumn) {
4042
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4043
- finalData = compressionResult.data;
4044
- isCompressed = compressionResult.compressed;
4045
- log$e.debug('Compression result', {
4046
- key,
4047
- originalSize: compressionResult.originalSize,
4048
- compressedSize: compressionResult.compressedSize,
4049
- compressed: isCompressed,
4050
- savings: compressionResult.originalSize - compressionResult.compressedSize,
4051
- });
4052
- }
4053
- log$e.debug('Setting item with metadata', {
4054
- key,
4055
- timestamp: item.timestamp,
4056
- compressed: isCompressed,
4057
- hasCompressedColumn: this.hasCompressedColumn,
4058
- });
4059
- // Build SQL and parameters based on available columns
4060
- let sql;
4061
- let params;
4062
- if (this.hasCompressedColumn) {
4063
- sql = `
4064
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4065
- (cache_key, data, timestamp, compressed)
4066
- VALUES (?, ?, ?, ?)
4067
- `;
4068
- params = [key, finalData, item.timestamp, isCompressed ? 1 : 0];
4069
- }
4070
- else {
4071
- // Fallback for databases without compressed column
4072
- sql = `
4073
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4074
- (cache_key, data, timestamp)
4075
- VALUES (?, ?, ?)
4076
- `;
4077
- params = [key, finalData, item.timestamp];
4078
- }
4079
- log$e.debug('Executing setItem SQL', { key, paramsCount: params.length });
4080
- await this.executeSql(sql, params);
4081
- }
4082
- async setBatch(items) {
4083
- if (items.length === 0)
4084
- return;
4085
- await this.ensureInitialized();
4086
- log$e.debug('Batch setting items', { count: items.length });
4087
- if (this.isExpo) {
4088
- await this.db.withTransactionAsync(async () => {
4089
- for (const [key, item] of items) {
4090
- await this.setBatchItem(key, item);
4091
- }
4092
- });
4093
- }
4094
- else {
4095
- return new Promise((resolve, reject) => {
4096
- this.db.transaction((tx) => {
4097
- const promises = items.map(([key, item]) => this.setBatchItemRN(tx, key, item));
4098
- Promise.all(promises)
4099
- .then(() => resolve())
4100
- .catch(reject);
4101
- }, reject, () => resolve());
4102
- });
4103
- }
4104
- log$e.debug('Batch operation completed', { count: items.length });
4105
- }
4106
- async setBatchItem(key, item) {
4107
- // Handle compression if enabled and compressed column is available
4108
- const serializedData = JSON.stringify(item.data);
4109
- let finalData = serializedData;
4110
- let isCompressed = false;
4111
- if (this.options.compression && this.options.compressionThreshold && this.hasCompressedColumn) {
4112
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4113
- finalData = compressionResult.data;
4114
- isCompressed = compressionResult.compressed;
4115
- }
4116
- // Build SQL and parameters based on available columns
4117
- let sql;
4118
- let params;
4119
- if (this.hasCompressedColumn) {
4120
- sql = `
4121
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4122
- (cache_key, data, timestamp, compressed)
4123
- VALUES (?, ?, ?, ?)
4124
- `;
4125
- params = [key, finalData, item.timestamp, isCompressed ? 1 : 0];
4126
- }
4127
- else {
4128
- sql = `
4129
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4130
- (cache_key, data, timestamp)
4131
- VALUES (?, ?, ?)
4132
- `;
4133
- params = [key, finalData, item.timestamp];
4134
- }
4135
- await this.db.runAsync(sql, params);
4136
- }
4137
- async setBatchItemRN(tx, key, item) {
4138
- // Handle compression if enabled and compressed column is available
4139
- const serializedData = JSON.stringify(item.data);
4140
- let finalData = serializedData;
4141
- let isCompressed = false;
4142
- if (this.options.compression && this.options.compressionThreshold && this.hasCompressedColumn) {
4143
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4144
- finalData = compressionResult.data;
4145
- isCompressed = compressionResult.compressed;
4146
- }
4147
- // Build SQL and parameters based on available columns
4148
- let sql;
4149
- let params;
4150
- if (this.hasCompressedColumn) {
4151
- sql = `
4152
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4153
- (cache_key, data, timestamp, compressed)
4154
- VALUES (?, ?, ?, ?)
4155
- `;
4156
- params = [key, finalData, item.timestamp, isCompressed ? 1 : 0];
4157
- }
4158
- else {
4159
- sql = `
4160
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4161
- (cache_key, data, timestamp)
4162
- VALUES (?, ?, ?)
4163
- `;
4164
- params = [key, finalData, item.timestamp];
4165
- }
4166
- return new Promise((resolve, reject) => {
4167
- tx.executeSql(sql, params, () => resolve(), (_, error) => {
4168
- reject(error);
4169
- return false;
4170
- });
4171
- });
4172
- }
4173
- async invalidate(pattern) {
4174
- await this.ensureInitialized();
4175
- const keys = await this.getKeys(pattern);
4176
- if (keys.length === 0)
4177
- return;
4178
- const placeholders = keys.map(() => '?').join(',');
4179
- const sql = `DELETE FROM ${ReactNativeCacheAdapter.TABLE_NAME} WHERE cache_key IN (${placeholders})`;
4180
- await this.executeSql(sql, keys);
4181
- }
4182
- async clear() {
4183
- await this.ensureInitialized();
4184
- const sql = `DELETE FROM ${ReactNativeCacheAdapter.TABLE_NAME}`;
4185
- await this.executeSql(sql);
4186
- }
4187
- async getSize() {
4188
- await this.ensureInitialized();
4189
- const sql = `
4190
- SELECT
4191
- COUNT(*) as entries,
4192
- SUM(LENGTH(data)) as bytes
4193
- FROM ${ReactNativeCacheAdapter.TABLE_NAME}
4194
- `;
4195
- const results = await this.executeSql(sql);
4196
- const rows = this.normalizeResults(results);
4197
- const row = rows[0] || { entries: 0, bytes: 0 };
4198
- return {
4199
- entries: row.entries || 0,
4200
- bytes: (row.bytes || 0) * 2,
4201
- lastCleanup: Date.now(),
4202
- };
4203
- }
4204
- async cleanup() {
4205
- // No cleanup needed - cache never expires
4206
- return 0;
4207
- }
4208
- async getKeys(pattern) {
4209
- await this.ensureInitialized();
4210
- let sql = `SELECT cache_key FROM ${ReactNativeCacheAdapter.TABLE_NAME}`;
4211
- const params = [];
4212
- if (pattern) {
4213
- // Simple pattern matching with LIKE
4214
- const likePattern = pattern.replace(/\*/g, '%').replace(/\?/g, '_');
4215
- sql += ' WHERE cache_key LIKE ?';
4216
- params.push(likePattern);
4217
- }
4218
- const results = await this.executeSql(sql, params);
4219
- const keys = [];
4220
- const rows = this.normalizeResults(results);
4221
- for (const row of rows) {
4222
- keys.push(row.cache_key);
4223
- }
4224
- return keys;
4225
- }
4226
- async executeSql(sql, params = []) {
4227
- if (this.isExpo) {
4228
- const expoDB = this.db;
4229
- if (sql.toLowerCase().includes('select') || sql.toLowerCase().includes('pragma')) {
4230
- const result = await expoDB.getAllAsync(sql, params);
4231
- return Array.isArray(result) ? { results: result } : result;
4232
- }
4233
- else {
4234
- return await expoDB.runAsync(sql, params);
4235
- }
4236
- }
4237
- else {
4238
- // react-native-sqlite-storage
4239
- return new Promise((resolve, reject) => {
4240
- this.db.transaction((tx) => {
4241
- tx.executeSql(sql, params, (_, results) => resolve(results), (_, error) => {
4242
- reject(error);
4243
- return false;
4244
- });
4245
- });
4246
- });
4247
- }
4248
- }
4249
- async ensureInitialized() {
4250
- if (!this.initPromise) {
4251
- this.initPromise = this.initialize();
4252
- }
4253
- await this.initPromise;
4254
- }
4255
- }
4256
- ReactNativeCacheAdapter.DB_NAME = 'acube_cache.db';
4257
- ReactNativeCacheAdapter.TABLE_NAME = 'cache_entries';
4258
- /**
4259
- * Memory-based fallback cache adapter for environments without SQLite
4260
- * Cache never expires - data persists until explicitly invalidated
4261
- */
4262
- class MemoryCacheAdapter {
4263
- constructor(options = {}) {
4264
- this.cache = new Map();
4265
- this.totalBytes = 0;
4266
- this.options = {
4267
- maxEntries: 1000,
4268
- ...options,
4269
- };
4270
- }
4271
- calculateItemSize(key, item) {
4272
- // Calculate rough size estimation for memory usage
4273
- const keySize = key.length * 2; // UTF-16 estimation
4274
- const itemSize = JSON.stringify(item).length * 2; // UTF-16 estimation
4275
- return keySize + itemSize;
4276
- }
4277
- async get(key) {
4278
- log$e.debug('Getting cache item', { key });
4279
- const item = this.cache.get(key);
4280
- if (!item) {
4281
- log$e.debug('Cache miss', { key });
4282
- return null;
4283
- }
4284
- // Handle decompression if needed
4285
- const isCompressed = !!item.compressed;
4286
- let finalData = item.data;
4287
- if (isCompressed) {
4288
- const decompressed = decompressData(item.data, true);
4289
- finalData = JSON.parse(decompressed.data);
4290
- }
4291
- log$e.debug('Cache hit', { key, compressed: isCompressed });
4292
- return {
4293
- ...item,
4294
- data: finalData,
4295
- compressed: isCompressed,
4296
- };
4297
- }
4298
- async set(key, data) {
4299
- log$e.debug('Setting cache item', { key });
4300
- // Handle compression if enabled
4301
- let finalData = data;
4302
- let isCompressed = false;
4303
- if (this.options.compression && this.options.compressionThreshold) {
4304
- const serializedData = JSON.stringify(data);
4305
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4306
- if (compressionResult.compressed) {
4307
- finalData = compressionResult.data;
4308
- isCompressed = true;
4309
- log$e.debug('Compression result', {
4310
- key,
4311
- originalSize: compressionResult.originalSize,
4312
- compressedSize: compressionResult.compressedSize,
4313
- savings: compressionResult.originalSize - compressionResult.compressedSize,
4314
- });
4315
- }
4316
- }
4317
- const item = {
4318
- data: finalData,
4319
- timestamp: Date.now(),
4320
- compressed: isCompressed,
4321
- };
4322
- return this.setItem(key, item);
4323
- }
4324
- async setItem(key, item) {
4325
- // Calculate size of new item
4326
- const newItemSize = this.calculateItemSize(key, item);
4327
- // If item already exists, subtract old size
4328
- if (this.cache.has(key)) {
4329
- const oldItem = this.cache.get(key);
4330
- const oldItemSize = this.calculateItemSize(key, oldItem);
4331
- this.totalBytes -= oldItemSize;
4332
- }
4333
- // Enforce max entries limit
4334
- if (this.cache.size >= (this.options.maxEntries || 1000) && !this.cache.has(key)) {
4335
- const oldestKey = this.cache.keys().next().value;
4336
- if (oldestKey) {
4337
- const oldestItem = this.cache.get(oldestKey);
4338
- const oldestItemSize = this.calculateItemSize(oldestKey, oldestItem);
4339
- this.totalBytes -= oldestItemSize;
4340
- this.cache.delete(oldestKey);
4341
- log$e.debug('Removed oldest item for capacity', { oldestKey, freedBytes: oldestItemSize });
4342
- }
4343
- }
4344
- // Set new item and update total size
4345
- this.cache.set(key, item);
4346
- this.totalBytes += newItemSize;
4347
- log$e.debug('Updated cache size', {
4348
- entries: this.cache.size,
4349
- totalBytes: this.totalBytes,
4350
- newItemSize,
4351
- });
4352
- }
4353
- async setBatch(items) {
4354
- if (items.length === 0)
4355
- return;
4356
- log$e.debug('Batch setting items', { count: items.length });
4357
- let totalNewBytes = 0;
4358
- let totalOldBytes = 0;
4359
- const itemsToRemove = [];
4360
- // First pass: calculate size changes and identify capacity issues
4361
- for (const [key, item] of items) {
4362
- const newItemSize = this.calculateItemSize(key, item);
4363
- totalNewBytes += newItemSize;
4364
- // If item already exists, track old size for removal
4365
- if (this.cache.has(key)) {
4366
- const oldItem = this.cache.get(key);
4367
- const oldItemSize = this.calculateItemSize(key, oldItem);
4368
- totalOldBytes += oldItemSize;
4369
- }
4370
- }
4371
- // Handle capacity limits - remove oldest items if needed
4372
- const projectedEntries = this.cache.size + items.filter(([key]) => !this.cache.has(key)).length;
4373
- const maxEntries = this.options.maxEntries || 1000;
4374
- if (projectedEntries > maxEntries) {
4375
- const entriesToRemove = projectedEntries - maxEntries;
4376
- const oldestKeys = Array.from(this.cache.keys()).slice(0, entriesToRemove);
4377
- for (const oldKey of oldestKeys) {
4378
- const oldItem = this.cache.get(oldKey);
4379
- const oldItemSize = this.calculateItemSize(oldKey, oldItem);
4380
- this.totalBytes -= oldItemSize;
4381
- this.cache.delete(oldKey);
4382
- itemsToRemove.push(oldKey);
4383
- }
4384
- if (itemsToRemove.length > 0) {
4385
- log$e.debug('Removed items for batch capacity', {
4386
- removedCount: itemsToRemove.length,
4387
- removedKeys: itemsToRemove,
4388
- });
4389
- }
4390
- }
4391
- // Update total bytes accounting
4392
- this.totalBytes = this.totalBytes - totalOldBytes + totalNewBytes;
4393
- // Second pass: set all items
4394
- for (const [key, item] of items) {
4395
- this.cache.set(key, item);
4396
- }
4397
- log$e.debug('Batch operation completed', {
4398
- count: items.length,
4399
- totalBytes: this.totalBytes,
4400
- entries: this.cache.size,
4401
- bytesAdded: totalNewBytes - totalOldBytes,
4402
- });
4403
- }
4404
- async invalidate(pattern) {
4405
- const regex = this.patternToRegex(pattern);
4406
- let removed = 0;
4407
- let bytesFreed = 0;
4408
- for (const key of this.cache.keys()) {
4409
- if (regex.test(key)) {
4410
- const item = this.cache.get(key);
4411
- const itemSize = this.calculateItemSize(key, item);
4412
- this.cache.delete(key);
4413
- this.totalBytes -= itemSize;
4414
- bytesFreed += itemSize;
4415
- removed++;
4416
- }
4417
- }
4418
- if (removed > 0) {
4419
- log$e.debug('Invalidation completed', {
4420
- pattern,
4421
- entriesRemoved: removed,
4422
- bytesFreed,
4423
- remainingEntries: this.cache.size,
4424
- remainingBytes: this.totalBytes,
4425
- });
4426
- }
4427
- }
4428
- async clear() {
4429
- this.cache.clear();
4430
- this.totalBytes = 0;
4431
- log$e.debug('Cache cleared', { entries: 0, bytes: 0 });
4432
- }
4433
- async getSize() {
4434
- return {
4435
- entries: this.cache.size,
4436
- bytes: this.totalBytes,
4437
- lastCleanup: Date.now(),
4438
- };
4439
- }
4440
- async cleanup() {
4441
- // No cleanup needed - cache never expires
4442
- return 0;
4443
- }
4444
- async getKeys(pattern) {
4445
- const keys = Array.from(this.cache.keys());
4446
- if (!pattern)
4447
- return keys;
4448
- const regex = this.patternToRegex(pattern);
4449
- return keys.filter((key) => regex.test(key));
4450
- }
4451
- patternToRegex(pattern) {
4452
- const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&');
4453
- const regexPattern = escaped.replace(/\\\*/g, '.*').replace(/\\\?/g, '.');
4454
- return new RegExp(`^${regexPattern}$`);
4455
- }
4456
- }
4457
-
4458
- const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);
4459
-
4460
- let idbProxyableTypes;
4461
- let cursorAdvanceMethods;
4462
- // This is a function to prevent it throwing up in node environments.
4463
- function getIdbProxyableTypes() {
4464
- return (idbProxyableTypes ||
4465
- (idbProxyableTypes = [
4466
- IDBDatabase,
4467
- IDBObjectStore,
4468
- IDBIndex,
4469
- IDBCursor,
4470
- IDBTransaction,
4471
- ]));
4472
- }
4473
- // This is a function to prevent it throwing up in node environments.
4474
- function getCursorAdvanceMethods() {
4475
- return (cursorAdvanceMethods ||
4476
- (cursorAdvanceMethods = [
4477
- IDBCursor.prototype.advance,
4478
- IDBCursor.prototype.continue,
4479
- IDBCursor.prototype.continuePrimaryKey,
4480
- ]));
4481
- }
4482
- const transactionDoneMap = new WeakMap();
4483
- const transformCache = new WeakMap();
4484
- const reverseTransformCache = new WeakMap();
4485
- function promisifyRequest(request) {
4486
- const promise = new Promise((resolve, reject) => {
4487
- const unlisten = () => {
4488
- request.removeEventListener('success', success);
4489
- request.removeEventListener('error', error);
4490
- };
4491
- const success = () => {
4492
- resolve(wrap(request.result));
4493
- unlisten();
4494
- };
4495
- const error = () => {
4496
- reject(request.error);
4497
- unlisten();
4498
- };
4499
- request.addEventListener('success', success);
4500
- request.addEventListener('error', error);
4501
- });
4502
- // This mapping exists in reverseTransformCache but doesn't exist in transformCache. This
4503
- // is because we create many promises from a single IDBRequest.
4504
- reverseTransformCache.set(promise, request);
4505
- return promise;
4506
- }
4507
- function cacheDonePromiseForTransaction(tx) {
4508
- // Early bail if we've already created a done promise for this transaction.
4509
- if (transactionDoneMap.has(tx))
4510
- return;
4511
- const done = new Promise((resolve, reject) => {
4512
- const unlisten = () => {
4513
- tx.removeEventListener('complete', complete);
4514
- tx.removeEventListener('error', error);
4515
- tx.removeEventListener('abort', error);
4516
- };
4517
- const complete = () => {
4518
- resolve();
4519
- unlisten();
4520
- };
4521
- const error = () => {
4522
- reject(tx.error || new DOMException('AbortError', 'AbortError'));
4523
- unlisten();
4524
- };
4525
- tx.addEventListener('complete', complete);
4526
- tx.addEventListener('error', error);
4527
- tx.addEventListener('abort', error);
4528
- });
4529
- // Cache it for later retrieval.
4530
- transactionDoneMap.set(tx, done);
4531
- }
4532
- let idbProxyTraps = {
4533
- get(target, prop, receiver) {
4534
- if (target instanceof IDBTransaction) {
4535
- // Special handling for transaction.done.
4536
- if (prop === 'done')
4537
- return transactionDoneMap.get(target);
4538
- // Make tx.store return the only store in the transaction, or undefined if there are many.
4539
- if (prop === 'store') {
4540
- return receiver.objectStoreNames[1]
4541
- ? undefined
4542
- : receiver.objectStore(receiver.objectStoreNames[0]);
4543
- }
4544
- }
4545
- // Else transform whatever we get back.
4546
- return wrap(target[prop]);
4547
- },
4548
- set(target, prop, value) {
4549
- target[prop] = value;
4550
- return true;
4551
- },
4552
- has(target, prop) {
4553
- if (target instanceof IDBTransaction &&
4554
- (prop === 'done' || prop === 'store')) {
4555
- return true;
4556
- }
4557
- return prop in target;
4558
- },
4559
- };
4560
- function replaceTraps(callback) {
4561
- idbProxyTraps = callback(idbProxyTraps);
4562
- }
4563
- function wrapFunction(func) {
4564
- // Due to expected object equality (which is enforced by the caching in `wrap`), we
4565
- // only create one new func per func.
4566
- // Cursor methods are special, as the behaviour is a little more different to standard IDB. In
4567
- // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the
4568
- // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense
4569
- // with real promises, so each advance methods returns a new promise for the cursor object, or
4570
- // undefined if the end of the cursor has been reached.
4571
- if (getCursorAdvanceMethods().includes(func)) {
4572
- return function (...args) {
4573
- // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
4574
- // the original object.
4575
- func.apply(unwrap(this), args);
4576
- return wrap(this.request);
4577
- };
4578
- }
4579
- return function (...args) {
4580
- // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
4581
- // the original object.
4582
- return wrap(func.apply(unwrap(this), args));
4583
- };
4584
- }
4585
- function transformCachableValue(value) {
4586
- if (typeof value === 'function')
4587
- return wrapFunction(value);
4588
- // This doesn't return, it just creates a 'done' promise for the transaction,
4589
- // which is later returned for transaction.done (see idbObjectHandler).
4590
- if (value instanceof IDBTransaction)
4591
- cacheDonePromiseForTransaction(value);
4592
- if (instanceOfAny(value, getIdbProxyableTypes()))
4593
- return new Proxy(value, idbProxyTraps);
4594
- // Return the same value back if we're not going to transform it.
4595
- return value;
4596
- }
4597
- function wrap(value) {
4598
- // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because
4599
- // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.
4600
- if (value instanceof IDBRequest)
4601
- return promisifyRequest(value);
4602
- // If we've already transformed this value before, reuse the transformed value.
4603
- // This is faster, but it also provides object equality.
4604
- if (transformCache.has(value))
4605
- return transformCache.get(value);
4606
- const newValue = transformCachableValue(value);
4607
- // Not all types are transformed.
4608
- // These may be primitive types, so they can't be WeakMap keys.
4609
- if (newValue !== value) {
4610
- transformCache.set(value, newValue);
4611
- reverseTransformCache.set(newValue, value);
4612
- }
4613
- return newValue;
4614
- }
4615
- const unwrap = (value) => reverseTransformCache.get(value);
4616
-
4617
- /**
4618
- * Open a database.
4619
- *
4620
- * @param name Name of the database.
4621
- * @param version Schema version.
4622
- * @param callbacks Additional callbacks.
4623
- */
4624
- function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {
4625
- const request = indexedDB.open(name, version);
4626
- const openPromise = wrap(request);
4627
- if (upgrade) {
4628
- request.addEventListener('upgradeneeded', (event) => {
4629
- upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
4630
- });
4631
- }
4632
- if (blocked) {
4633
- request.addEventListener('blocked', (event) => blocked(
4634
- // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
4635
- event.oldVersion, event.newVersion, event));
4636
- }
4637
- openPromise
4638
- .then((db) => {
4639
- if (terminated)
4640
- db.addEventListener('close', () => terminated());
4641
- if (blocking) {
4642
- db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));
4643
- }
4644
- })
4645
- .catch(() => { });
4646
- return openPromise;
4647
- }
4648
- /**
4649
- * Delete a database.
4650
- *
4651
- * @param name Name of the database.
4652
- */
4653
- function deleteDB(name, { blocked } = {}) {
4654
- const request = indexedDB.deleteDatabase(name);
4655
- if (blocked) {
4656
- request.addEventListener('blocked', (event) => blocked(
4657
- // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
4658
- event.oldVersion, event));
4659
- }
4660
- return wrap(request).then(() => undefined);
4661
- }
4662
-
4663
- const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];
4664
- const writeMethods = ['put', 'add', 'delete', 'clear'];
4665
- const cachedMethods = new Map();
4666
- function getMethod(target, prop) {
4667
- if (!(target instanceof IDBDatabase &&
4668
- !(prop in target) &&
4669
- typeof prop === 'string')) {
4670
- return;
4671
- }
4672
- if (cachedMethods.get(prop))
4673
- return cachedMethods.get(prop);
4674
- const targetFuncName = prop.replace(/FromIndex$/, '');
4675
- const useIndex = prop !== targetFuncName;
4676
- const isWrite = writeMethods.includes(targetFuncName);
4677
- if (
4678
- // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.
4679
- !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||
4680
- !(isWrite || readMethods.includes(targetFuncName))) {
4681
- return;
4682
- }
4683
- const method = async function (storeName, ...args) {
4684
- // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(
4685
- const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');
4686
- let target = tx.store;
4687
- if (useIndex)
4688
- target = target.index(args.shift());
4689
- // Must reject if op rejects.
4690
- // If it's a write operation, must reject if tx.done rejects.
4691
- // Must reject with op rejection first.
4692
- // Must resolve with op value.
4693
- // Must handle both promises (no unhandled rejections)
4694
- return (await Promise.all([
4695
- target[targetFuncName](...args),
4696
- isWrite && tx.done,
4697
- ]))[0];
4698
- };
4699
- cachedMethods.set(prop, method);
4700
- return method;
4701
- }
4702
- replaceTraps((oldTraps) => ({
4703
- ...oldTraps,
4704
- get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),
4705
- has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),
4706
- }));
4707
-
4708
- const advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];
4709
- const methodMap = {};
4710
- const advanceResults = new WeakMap();
4711
- const ittrProxiedCursorToOriginalProxy = new WeakMap();
4712
- const cursorIteratorTraps = {
4713
- get(target, prop) {
4714
- if (!advanceMethodProps.includes(prop))
4715
- return target[prop];
4716
- let cachedFunc = methodMap[prop];
4717
- if (!cachedFunc) {
4718
- cachedFunc = methodMap[prop] = function (...args) {
4719
- advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));
4720
- };
4721
- }
4722
- return cachedFunc;
4723
- },
4724
- };
4725
- async function* iterate(...args) {
4726
- // tslint:disable-next-line:no-this-assignment
4727
- let cursor = this;
4728
- if (!(cursor instanceof IDBCursor)) {
4729
- cursor = await cursor.openCursor(...args);
4730
- }
4731
- if (!cursor)
4732
- return;
4733
- cursor = cursor;
4734
- const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
4735
- ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
4736
- // Map this double-proxy back to the original, so other cursor methods work.
4737
- reverseTransformCache.set(proxiedCursor, unwrap(cursor));
4738
- while (cursor) {
4739
- yield proxiedCursor;
4740
- // If one of the advancing methods was not called, call continue().
4741
- cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
4742
- advanceResults.delete(proxiedCursor);
4743
- }
4744
- }
4745
- function isIteratorProp(target, prop) {
4746
- return ((prop === Symbol.asyncIterator &&
4747
- instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||
4748
- (prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore])));
4749
- }
4750
- replaceTraps((oldTraps) => ({
4751
- ...oldTraps,
4752
- get(target, prop, receiver) {
4753
- if (isIteratorProp(target, prop))
4754
- return iterate;
4755
- return oldTraps.get(target, prop, receiver);
4756
- },
4757
- has(target, prop) {
4758
- return isIteratorProp(target, prop) || oldTraps.has(target, prop);
4759
- },
4760
- }));
4761
-
4762
- const log$d = createPrefixedLogger('CACHE-WEB');
4763
- /**
4764
- * Web cache adapter using IndexedDB with automatic error recovery
4765
- * Cache never expires - data persists until explicitly invalidated
4766
- */
4767
- class WebCacheAdapter {
4768
- constructor(options = {}) {
4769
- this.db = null;
4770
- this.initPromise = null;
4771
- this.retryCount = 0;
4772
- this.maxRetries = 3;
4773
- this.options = {
4774
- maxSize: 50 * 1024 * 1024, // 50MB
4775
- maxEntries: 10000,
4776
- compression: false,
4777
- compressionThreshold: 1024,
4778
- ...options,
4779
- };
4780
- this.initPromise = this.initialize();
4781
- }
4782
- async initialize() {
4783
- if (this.db)
4784
- return;
4785
- log$d.debug('Initializing IndexedDB cache', {
4786
- dbName: WebCacheAdapter.DB_NAME,
4787
- version: WebCacheAdapter.DB_VERSION,
4788
- });
4789
- try {
4790
- this.db = await this.openDatabase();
4791
- log$d.debug('IndexedDB cache initialized successfully');
4792
- this.retryCount = 0; // Reset retry count on success
4793
- }
4794
- catch (error) {
4795
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
4796
- log$d.debug('Failed to initialize IndexedDB', { error: errorMessage });
4797
- // Check if this is a version conflict error
4798
- if (this.isVersionConflictError(errorMessage)) {
4799
- await this.handleVersionConflict();
4800
- }
4801
- else {
4802
- throw new Error(`Failed to initialize IndexedDB: ${errorMessage}`);
4803
- }
4804
- }
4805
- }
4806
- async openDatabase() {
4807
- return await openDB(WebCacheAdapter.DB_NAME, WebCacheAdapter.DB_VERSION, {
4808
- upgrade: (db, oldVersion, newVersion, transaction) => {
4809
- log$d.debug('Database upgrade needed', { oldVersion, newVersion });
4810
- this.handleUpgrade(db, oldVersion, newVersion, transaction);
4811
- },
4812
- blocked: () => {
4813
- log$d.debug('Database blocked - another tab may be open');
4814
- },
4815
- blocking: () => {
4816
- log$d.debug('Database blocking - will close connection');
4817
- if (this.db) {
4818
- this.db.close();
4819
- this.db = null;
4820
- }
4821
- },
4822
- terminated: () => {
4823
- log$d.debug('Database connection terminated unexpectedly');
4824
- this.db = null;
4825
- },
4826
- });
4827
- }
4828
- handleUpgrade(db, oldVersion, newVersion, transaction) {
4829
- log$d.debug('Handling database upgrade', { oldVersion, newVersion });
4830
- // Create cache store if it doesn't exist (initial setup)
4831
- if (!db.objectStoreNames.contains(WebCacheAdapter.STORE_NAME)) {
4832
- const store = db.createObjectStore(WebCacheAdapter.STORE_NAME, { keyPath: 'key' });
4833
- store.createIndex('timestamp', 'timestamp', { unique: false });
4834
- log$d.debug('Created cache store and timestamp index');
4835
- }
4836
- // Handle migration from version 1 to 2
4837
- if (oldVersion < 2) {
4838
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
4839
- // Remove unused indexes from simplified cache structure
4840
- const indexesToRemove = ['tags', 'source', 'syncStatus'];
4841
- indexesToRemove.forEach((indexName) => {
4842
- try {
4843
- if (store.indexNames.contains(indexName)) {
4844
- store.deleteIndex(indexName);
4845
- log$d.debug(`Removed unused index: ${indexName}`);
4846
- }
4847
- }
4848
- catch (error) {
4849
- // Ignore errors if indexes don't exist
4850
- log$d.debug(`Warning: Could not remove index ${indexName}`, error);
4851
- }
4852
- });
4853
- }
4854
- log$d.debug('Database upgrade completed');
4855
- }
4856
- isVersionConflictError(errorMessage) {
4857
- return (errorMessage.includes('less than the existing version') ||
4858
- errorMessage.includes('version conflict') ||
4859
- errorMessage.includes('VersionError'));
4860
- }
4861
- async handleVersionConflict() {
4862
- log$d.debug('Handling version conflict, attempting recovery...');
4863
- if (this.retryCount >= this.maxRetries) {
4864
- throw new Error('Failed to resolve IndexedDB version conflict after multiple attempts');
4865
- }
4866
- this.retryCount++;
4867
- try {
4868
- // Close any existing connection
4869
- if (this.db) {
4870
- this.db.close();
4871
- this.db = null;
4872
- }
4873
- // Delete the problematic database
4874
- log$d.debug('Deleting problematic database to resolve version conflict');
4875
- await deleteDB(WebCacheAdapter.DB_NAME);
4876
- // Wait a bit for the deletion to complete
4877
- await new Promise((resolve) => setTimeout(resolve, 200));
4878
- // Try to open the database again
4879
- log$d.debug(`Retrying database initialization (attempt ${this.retryCount}/${this.maxRetries})`);
4880
- this.db = await this.openDatabase();
4881
- log$d.debug('Successfully recovered from version conflict');
4882
- this.retryCount = 0; // Reset retry count on success
4883
- }
4884
- catch (retryError) {
4885
- const retryErrorMessage = retryError instanceof Error ? retryError.message : 'Unknown error';
4886
- log$d.debug('Recovery attempt failed', { attempt: this.retryCount, error: retryErrorMessage });
4887
- if (this.retryCount < this.maxRetries) {
4888
- // Try again
4889
- await this.handleVersionConflict();
4890
- }
4891
- else {
4892
- throw new Error(`Failed to recover from IndexedDB version conflict: ${retryErrorMessage}`);
4893
- }
4894
- }
4895
- }
4896
- async get(key) {
4897
- await this.ensureInitialized();
4898
- log$d.debug('Getting cache item', { key });
4899
- try {
4900
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readonly');
4901
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
4902
- const result = await store.get(key);
4903
- if (!result) {
4904
- return null;
4905
- }
4906
- const item = result;
4907
- // Handle decompression if needed
4908
- const isCompressed = !!item.compressed;
4909
- let finalData;
4910
- if (isCompressed) {
4911
- const decompressed = decompressData(item.data, true);
4912
- finalData = JSON.parse(decompressed.data);
4913
- }
4914
- else {
4915
- finalData = item.data;
4916
- }
4917
- return {
4918
- data: finalData,
4919
- timestamp: item.timestamp,
4920
- compressed: isCompressed,
4921
- };
4922
- }
4923
- catch (error) {
4924
- log$d.debug('Error getting cache item', { key, error });
4925
- return null; // Return null on error instead of throwing
4926
- }
4927
- }
4928
- async set(key, data) {
4929
- const item = {
4930
- data,
4931
- timestamp: Date.now(),
4932
- };
4933
- return this.setItem(key, item);
4934
- }
4935
- async setItem(key, item) {
4936
- await this.ensureInitialized();
4937
- // Handle compression if enabled
4938
- let finalData = item.data;
4939
- let isCompressed = false;
4940
- if (this.options.compression && this.options.compressionThreshold) {
4941
- const serializedData = JSON.stringify(item.data);
4942
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4943
- if (compressionResult.compressed) {
4944
- finalData = compressionResult.data;
4945
- isCompressed = true;
4946
- log$d.debug('Compression result', {
4947
- key,
4948
- originalSize: compressionResult.originalSize,
4949
- compressedSize: compressionResult.compressedSize,
4950
- compressed: isCompressed,
4951
- savings: compressionResult.originalSize - compressionResult.compressedSize,
4952
- });
4953
- }
4954
- }
4955
- log$d.debug('Setting cache item', { key, timestamp: item.timestamp, compressed: isCompressed });
4956
- const storedItem = {
4957
- key,
4958
- data: finalData,
4959
- timestamp: item.timestamp,
4960
- compressed: isCompressed,
4961
- };
4962
- try {
4963
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readwrite');
4964
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
4965
- await store.put(storedItem);
4966
- }
4967
- catch (error) {
4968
- log$d.debug('Error setting cache item', { key, error });
4969
- // Silently fail for cache writes
4970
- }
4971
- }
4972
- async setBatch(items) {
4973
- if (items.length === 0)
4974
- return;
4975
- await this.ensureInitialized();
4976
- log$d.debug('Batch setting items', { count: items.length });
4977
- try {
4978
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readwrite');
4979
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
4980
- // Process all items in the transaction
4981
- const promises = items.map(([key, item]) => {
4982
- const storedItem = this.prepareBatchItem(key, item);
4983
- return store.put(storedItem);
4984
- });
4985
- await Promise.all(promises);
4986
- log$d.debug('Batch operation completed', { count: items.length });
4987
- }
4988
- catch (error) {
4989
- log$d.debug('Error in batch operation', { count: items.length, error });
4990
- // Silently fail for batch writes
4991
- }
4992
- }
4993
- prepareBatchItem(key, item) {
4994
- // Handle compression if enabled (same logic as setItem)
4995
- let finalData = item.data;
4996
- let isCompressed = false;
4997
- if (this.options.compression && this.options.compressionThreshold) {
4998
- const serializedData = JSON.stringify(item.data);
4999
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
5000
- if (compressionResult.compressed) {
5001
- finalData = compressionResult.data;
5002
- isCompressed = true;
5003
- }
5004
- }
5005
- return {
5006
- key,
5007
- data: finalData,
5008
- timestamp: item.timestamp,
5009
- compressed: isCompressed,
5010
- };
5011
- }
5012
- async invalidate(pattern) {
5013
- await this.ensureInitialized();
5014
- const keys = await this.getKeys(pattern);
5015
- const deletePromises = keys.map((key) => this.delete(key));
5016
- await Promise.all(deletePromises);
5017
- }
5018
- async clear() {
5019
- await this.ensureInitialized();
5020
- try {
5021
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readwrite');
5022
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5023
- await store.clear();
5024
- log$d.debug('Cache cleared successfully');
5025
- }
5026
- catch (error) {
5027
- log$d.debug('Error clearing cache', error);
5028
- // Silently fail for cache clear
5029
- }
5030
- }
5031
- async getSize() {
5032
- await this.ensureInitialized();
5033
- try {
5034
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readonly');
5035
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5036
- let entries = 0;
5037
- let bytes = 0;
5038
- // Use cursor for efficient iteration
5039
- let cursor = await store.openCursor();
5040
- while (cursor) {
5041
- entries++;
5042
- // Rough estimation of size
5043
- bytes += JSON.stringify(cursor.value).length * 2; // UTF-16 encoding
5044
- cursor = await cursor.continue();
5045
- }
5046
- return {
5047
- entries,
5048
- bytes,
5049
- lastCleanup: Date.now(),
5050
- };
5051
- }
5052
- catch (error) {
5053
- log$d.debug('Error getting cache size', error);
5054
- return {
5055
- entries: 0,
5056
- bytes: 0,
5057
- lastCleanup: Date.now(),
5058
- };
5059
- }
5060
- }
5061
- async cleanup() {
5062
- // No cleanup needed - cache never expires
5063
- return 0;
5064
- }
5065
- async getKeys(pattern) {
5066
- await this.ensureInitialized();
5067
- try {
5068
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readonly');
5069
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5070
- const allKeys = (await store.getAllKeys());
5071
- if (!pattern) {
5072
- return allKeys;
5073
- }
5074
- const regex = this.patternToRegex(pattern);
5075
- return allKeys.filter((key) => regex.test(key));
5076
- }
5077
- catch (error) {
5078
- log$d.debug('Error getting cache keys', error);
5079
- return [];
5080
- }
5081
- }
5082
- async delete(key) {
5083
- await this.ensureInitialized();
5084
- try {
5085
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readwrite');
5086
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5087
- await store.delete(key);
5088
- return true;
5089
- }
5090
- catch (error) {
5091
- log$d.debug('Error deleting cache item', { key, error });
5092
- return false;
5093
- }
5094
- }
5095
- async ensureInitialized() {
5096
- if (!this.initPromise) {
5097
- this.initPromise = this.initialize();
5098
- }
5099
- try {
5100
- await this.initPromise;
5101
- }
5102
- catch (error) {
5103
- log$d.debug('Failed to ensure initialization', error);
5104
- // Reset and try once more
5105
- this.initPromise = null;
5106
- this.db = null;
5107
- this.initPromise = this.initialize();
5108
- await this.initPromise;
5109
- }
5110
- }
5111
- patternToRegex(pattern) {
5112
- // Convert simple glob patterns to regex
5113
- const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&');
5114
- const regexPattern = escaped.replace(/\\\*/g, '.*').replace(/\\\?/g, '.');
5115
- return new RegExp(`^${regexPattern}$`);
5116
- }
5117
- }
5118
- WebCacheAdapter.DB_NAME = 'acube_cache';
5119
- WebCacheAdapter.DB_VERSION = 2;
5120
- WebCacheAdapter.STORE_NAME = 'cache_entries';
5121
-
5122
- const log$c = createPrefixedLogger('CACHE-LOADER');
5123
- function loadCacheAdapter(platform) {
5124
- try {
5125
- switch (platform) {
5126
- case 'web':
5127
- return new WebCacheAdapter({
5128
- maxSize: 50 * 1024 * 1024,
5129
- maxEntries: 10000,
5130
- compression: false,
5131
- });
5132
- case 'react-native':
5133
- try {
5134
- return new ReactNativeCacheAdapter({
5135
- maxSize: 100 * 1024 * 1024,
5136
- maxEntries: 15000,
5137
- });
5138
- }
5139
- catch {
5140
- return new MemoryCacheAdapter({
5141
- maxSize: 10 * 1024 * 1024,
5142
- maxEntries: 5000,
5143
- });
5144
- }
5145
- case 'node':
5146
- default:
5147
- return new MemoryCacheAdapter({
5148
- maxSize: 10 * 1024 * 1024,
5149
- maxEntries: 5000,
5150
- });
5151
- }
5152
- }
5153
- catch (error) {
5154
- log$c.warn(`Cache adapter not available for platform ${platform}:`, error);
5155
- return undefined;
5156
- }
5157
- }
5158
-
5159
3263
  /**
5160
3264
  * Mixin that adds multiGet, multiSet, multiRemove to any storage adapter
5161
3265
  * Eliminates duplicate code across Node, Web, and React Native adapters
@@ -5208,7 +3312,7 @@ class BaseSecureStorageAdapter {
5208
3312
  }
5209
3313
  }
5210
3314
 
5211
- const log$b = createPrefixedLogger('NETWORK-BASE');
3315
+ const log$8 = createPrefixedLogger('NETWORK-BASE');
5212
3316
  class NetworkBase {
5213
3317
  constructor(initialOnline = true, debounceMs = 300) {
5214
3318
  this.destroy$ = new Subject();
@@ -5228,14 +3332,14 @@ class NetworkBase {
5228
3332
  const current = this.statusSubject.getValue();
5229
3333
  if (current.online !== online) {
5230
3334
  this.statusSubject.next({ online, timestamp: Date.now() });
5231
- log$b.debug(`Network status changed: ${online ? 'online' : 'offline'}`);
3335
+ log$8.debug(`Network status changed: ${online ? 'online' : 'offline'}`);
5232
3336
  }
5233
3337
  }
5234
3338
  destroy() {
5235
3339
  this.destroy$.next();
5236
3340
  this.destroy$.complete();
5237
3341
  this.statusSubject.complete();
5238
- log$b.debug('Network monitor destroyed');
3342
+ log$8.debug('Network monitor destroyed');
5239
3343
  }
5240
3344
  }
5241
3345
 
@@ -5295,7 +3399,7 @@ class NodeSecureStorageAdapter extends BaseSecureStorageAdapter {
5295
3399
  }
5296
3400
  }
5297
3401
 
5298
- const log$a = createPrefixedLogger('RN-STORAGE');
3402
+ const log$7 = createPrefixedLogger('RN-STORAGE');
5299
3403
  /**
5300
3404
  * React Native storage adapter using AsyncStorage
5301
3405
  * Note: Uses native batch operations for better performance (not base class)
@@ -5327,7 +3431,7 @@ class ReactNativeStorageAdapter {
5327
3431
  return await this.AsyncStorage.getItem(key);
5328
3432
  }
5329
3433
  catch (error) {
5330
- log$a.error('Failed to get item from AsyncStorage:', error);
3434
+ log$7.error('Failed to get item from AsyncStorage:', error);
5331
3435
  return null;
5332
3436
  }
5333
3437
  }
@@ -5368,7 +3472,7 @@ class ReactNativeStorageAdapter {
5368
3472
  return await this.AsyncStorage.getAllKeys();
5369
3473
  }
5370
3474
  catch (error) {
5371
- log$a.error('Failed to get all keys:', error);
3475
+ log$7.error('Failed to get all keys:', error);
5372
3476
  return [];
5373
3477
  }
5374
3478
  }
@@ -5385,7 +3489,7 @@ class ReactNativeStorageAdapter {
5385
3489
  return result;
5386
3490
  }
5387
3491
  catch (error) {
5388
- log$a.error('Failed to get multiple items:', error);
3492
+ log$7.error('Failed to get multiple items:', error);
5389
3493
  const result = {};
5390
3494
  keys.forEach((key) => {
5391
3495
  result[key] = null;
@@ -5435,7 +3539,7 @@ class ReactNativeSecureStorageAdapter extends BaseSecureStorageAdapter {
5435
3539
  return;
5436
3540
  }
5437
3541
  catch {
5438
- log$a.debug('expo-secure-store not available, trying react-native-keychain');
3542
+ log$7.debug('expo-secure-store not available, trying react-native-keychain');
5439
3543
  }
5440
3544
  try {
5441
3545
  const Keychain = require('react-native-keychain');
@@ -5444,7 +3548,7 @@ class ReactNativeSecureStorageAdapter extends BaseSecureStorageAdapter {
5444
3548
  return;
5445
3549
  }
5446
3550
  catch {
5447
- log$a.error('react-native-keychain not available');
3551
+ log$7.error('react-native-keychain not available');
5448
3552
  }
5449
3553
  throw new Error('No secure storage available. Please install expo-secure-store or react-native-keychain');
5450
3554
  }
@@ -5462,7 +3566,7 @@ class ReactNativeSecureStorageAdapter extends BaseSecureStorageAdapter {
5462
3566
  }
5463
3567
  }
5464
3568
  catch (error) {
5465
- log$a.error('Failed to get secure item:', error);
3569
+ log$7.error('Failed to get secure item:', error);
5466
3570
  }
5467
3571
  return null;
5468
3572
  }
@@ -5499,10 +3603,10 @@ class ReactNativeSecureStorageAdapter extends BaseSecureStorageAdapter {
5499
3603
  }
5500
3604
  }
5501
3605
  async clear() {
5502
- log$a.warn('Clear all secure items not fully implemented for React Native');
3606
+ log$7.warn('Clear all secure items not fully implemented for React Native');
5503
3607
  }
5504
3608
  async getAllKeys() {
5505
- log$a.warn('Get all secure keys not implemented for React Native');
3609
+ log$7.warn('Get all secure keys not implemented for React Native');
5506
3610
  return [];
5507
3611
  }
5508
3612
  async isAvailable() {
@@ -5720,7 +3824,7 @@ class NodeNetworkMonitor extends NetworkBase {
5720
3824
  }
5721
3825
  }
5722
3826
 
5723
- const log$9 = createPrefixedLogger('RN-NETWORK');
3827
+ const log$6 = createPrefixedLogger('RN-NETWORK');
5724
3828
  /**
5725
3829
  * React Native network monitor using RxJS
5726
3830
  * Supports both @react-native-community/netinfo and expo-network
@@ -5733,7 +3837,7 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5733
3837
  this.moduleReady$ = new Subject();
5734
3838
  this.isExpo = detectPlatform().isExpo;
5735
3839
  this.init().catch((error) => {
5736
- log$9.error('Network monitor initialization failed:', error);
3840
+ log$6.error('Network monitor initialization failed:', error);
5737
3841
  });
5738
3842
  }
5739
3843
  async init() {
@@ -5752,10 +3856,10 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5752
3856
  try {
5753
3857
  const module = require('@react-native-community/netinfo');
5754
3858
  this.netInfoModule = module.default || module;
5755
- log$9.debug('Loaded @react-native-community/netinfo module');
3859
+ log$6.debug('Loaded @react-native-community/netinfo module');
5756
3860
  }
5757
3861
  catch (error) {
5758
- log$9.error('Failed to load React Native NetInfo module:', error);
3862
+ log$6.error('Failed to load React Native NetInfo module:', error);
5759
3863
  this.netInfoModule = null;
5760
3864
  }
5761
3865
  }
@@ -5763,10 +3867,10 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5763
3867
  try {
5764
3868
  const module = require('expo-network');
5765
3869
  this.netInfoModule = module.default || module;
5766
- log$9.debug('Loaded expo-network module');
3870
+ log$6.debug('Loaded expo-network module');
5767
3871
  }
5768
3872
  catch (error) {
5769
- log$9.error('Failed to load Expo Network module:', error);
3873
+ log$6.error('Failed to load Expo Network module:', error);
5770
3874
  this.netInfoModule = null;
5771
3875
  }
5772
3876
  }
@@ -5783,16 +3887,16 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5783
3887
  }
5784
3888
  const online = !!(state.isConnected && state.isInternetReachable !== false);
5785
3889
  this.updateStatus(online);
5786
- log$9.debug('Initial network state:', online ? 'online' : 'offline');
3890
+ log$6.debug('Initial network state:', online ? 'online' : 'offline');
5787
3891
  }
5788
3892
  catch (error) {
5789
- log$9.warn('Could not fetch initial network state:', error);
3893
+ log$6.warn('Could not fetch initial network state:', error);
5790
3894
  }
5791
3895
  }
5792
3896
  subscribeToStateChanges() {
5793
3897
  if (!this.netInfoModule)
5794
3898
  return;
5795
- log$9.debug('Subscribing to network state changes');
3899
+ log$6.debug('Subscribing to network state changes');
5796
3900
  const handleState = (state) => {
5797
3901
  const online = !!(state.isConnected && (state.isInternetReachable ?? true));
5798
3902
  this.updateStatus(online);
@@ -5834,7 +3938,7 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5834
3938
  };
5835
3939
  }
5836
3940
  catch (error) {
5837
- log$9.error('Failed to fetch detailed network info:', error);
3941
+ log$6.error('Failed to fetch detailed network info:', error);
5838
3942
  return null;
5839
3943
  }
5840
3944
  }
@@ -5970,7 +4074,7 @@ class CertificateValidator {
5970
4074
  }
5971
4075
  }
5972
4076
 
5973
- const log$8 = createPrefixedLogger('RN-MTLS');
4077
+ const log$5 = createPrefixedLogger('RN-MTLS');
5974
4078
  /**
5975
4079
  * React Native mTLS Adapter using @a-cube-io/expo-mutual-tls
5976
4080
  */
@@ -5992,7 +4096,7 @@ class ReactNativeMTLSAdapter {
5992
4096
  this.expoMTLS = ExpoMutualTls;
5993
4097
  // Set up debug logging with the correct event signature
5994
4098
  const debugListener = ExpoMutualTls.onDebugLog((event) => {
5995
- log$8.debug(`${event.type}: ${event.message}`, {
4099
+ log$5.debug(`${event.type}: ${event.message}`, {
5996
4100
  method: event.method,
5997
4101
  url: event.url,
5998
4102
  statusCode: event.statusCode,
@@ -6002,28 +4106,28 @@ class ReactNativeMTLSAdapter {
6002
4106
  this.eventListeners.push(debugListener);
6003
4107
  // Set up error logging with the correct event signature
6004
4108
  const errorListener = ExpoMutualTls.onError((event) => {
6005
- log$8.error(event.message, {
4109
+ log$5.error(event.message, {
6006
4110
  code: event.code,
6007
4111
  });
6008
4112
  });
6009
4113
  this.eventListeners.push(errorListener);
6010
4114
  // Set up certificate expiry monitoring with the correct event signature
6011
4115
  const expiryListener = ExpoMutualTls.onCertificateExpiry((event) => {
6012
- log$8.warn(`Certificate ${event.subject} expires at ${new Date(event.expiry)}`, {
4116
+ log$5.warn(`Certificate ${event.subject} expires at ${new Date(event.expiry)}`, {
6013
4117
  alias: event.alias,
6014
4118
  warning: event.warning,
6015
4119
  });
6016
4120
  });
6017
4121
  this.eventListeners.push(expiryListener);
6018
- log$8.debug('Expo mTLS module loaded successfully');
4122
+ log$5.debug('Expo mTLS module loaded successfully');
6019
4123
  }
6020
4124
  catch (error) {
6021
- log$8.warn('@a-cube-io/expo-mutual-tls not available:', error);
4125
+ log$5.warn('@a-cube-io/expo-mutual-tls not available:', error);
6022
4126
  }
6023
4127
  }
6024
4128
  async isMTLSSupported() {
6025
4129
  const supported = this.expoMTLS !== null;
6026
- log$8.debug('mTLS support check:', {
4130
+ log$5.debug('mTLS support check:', {
6027
4131
  supported,
6028
4132
  platform: this.getPlatformInfo().platform,
6029
4133
  moduleAvailable: !!this.expoMTLS,
@@ -6035,7 +4139,7 @@ class ReactNativeMTLSAdapter {
6035
4139
  throw new MTLSError(MTLSErrorType$1.NOT_SUPPORTED, 'Expo mTLS module not available');
6036
4140
  }
6037
4141
  this.config = config;
6038
- log$8.debug('Initialized with config:', {
4142
+ log$5.debug('Initialized with config:', {
6039
4143
  baseUrl: config.baseUrl,
6040
4144
  port: config.port,
6041
4145
  timeout: config.timeout,
@@ -6049,7 +4153,7 @@ class ReactNativeMTLSAdapter {
6049
4153
  if (!this.config) {
6050
4154
  throw new MTLSError(MTLSErrorType$1.CONFIGURATION_ERROR, 'Adapter not initialized. Call initialize() first.');
6051
4155
  }
6052
- log$8.debug('Configuring certificate:', {
4156
+ log$5.debug('Configuring certificate:', {
6053
4157
  format: certificateData.format,
6054
4158
  hasPassword: !!certificateData.password,
6055
4159
  certificateLength: certificateData.certificate.length,
@@ -6066,14 +4170,14 @@ class ReactNativeMTLSAdapter {
6066
4170
  'client-key-service', // keyService
6067
4171
  true // enableLogging - let the native module handle its own debug logging
6068
4172
  );
6069
- log$8.debug('PEM services configured:', configResult);
4173
+ log$5.debug('PEM services configured:', configResult);
6070
4174
  if (!configResult.success) {
6071
4175
  throw new MTLSError(MTLSErrorType$1.CONFIGURATION_ERROR, `PEM configuration failed: ${configResult.state}`);
6072
4176
  }
6073
4177
  // Step 2: Store the actual PEM certificate and private key
6074
4178
  const storeResult = await this.expoMTLS.storePEM(certificateData.certificate, certificateData.privateKey, certificateData.password // passphrase (optional)
6075
4179
  );
6076
- log$8.debug('PEM certificate store result:', storeResult);
4180
+ log$5.debug('PEM certificate store result:', storeResult);
6077
4181
  if (!storeResult) {
6078
4182
  throw new MTLSError(MTLSErrorType$1.CERTIFICATE_INVALID, 'Failed to store PEM certificate');
6079
4183
  }
@@ -6086,14 +4190,14 @@ class ReactNativeMTLSAdapter {
6086
4190
  const configResult = await this.expoMTLS.configureP12('client-p12-service', // keychainService
6087
4191
  true // enableLogging - let the native module handle its own debug logging
6088
4192
  );
6089
- log$8.debug('P12 service configured:', configResult);
4193
+ log$5.debug('P12 service configured:', configResult);
6090
4194
  if (!configResult.success) {
6091
4195
  throw new MTLSError(MTLSErrorType$1.CONFIGURATION_ERROR, `P12 configuration failed: ${configResult.state}`);
6092
4196
  }
6093
4197
  // Step 2: Store the P12 certificate data
6094
4198
  const storeResult = await this.expoMTLS.storeP12(certificateData.certificate, // P12 data in certificate field
6095
4199
  certificateData.password);
6096
- log$8.debug('P12 certificate store result:', storeResult);
4200
+ log$5.debug('P12 certificate store result:', storeResult);
6097
4201
  if (!storeResult) {
6098
4202
  throw new MTLSError(MTLSErrorType$1.CERTIFICATE_INVALID, 'Failed to store P12 certificate');
6099
4203
  }
@@ -6107,7 +4211,7 @@ class ReactNativeMTLSAdapter {
6107
4211
  if (error instanceof MTLSError) {
6108
4212
  throw error;
6109
4213
  }
6110
- log$8.error('Certificate configuration failed:', error);
4214
+ log$5.error('Certificate configuration failed:', error);
6111
4215
  throw new MTLSError(MTLSErrorType$1.CONFIGURATION_ERROR, 'Failed to configure certificate', error);
6112
4216
  }
6113
4217
  }
@@ -6118,38 +4222,38 @@ class ReactNativeMTLSAdapter {
6118
4222
  try {
6119
4223
  // Use static method call
6120
4224
  const hasCert = await this.expoMTLS.hasCertificate();
6121
- log$8.debug('Certificate availability check:', hasCert);
4225
+ log$5.debug('Certificate availability check:', hasCert);
6122
4226
  return hasCert;
6123
4227
  }
6124
4228
  catch (error) {
6125
- log$8.error('Certificate check failed:', error);
4229
+ log$5.error('Certificate check failed:', error);
6126
4230
  return false;
6127
4231
  }
6128
4232
  }
6129
4233
  async getCertificateInfo() {
6130
4234
  if (!this.expoMTLS) {
6131
- log$8.debug('Certificate info requested but module not available');
4235
+ log$5.debug('Certificate info requested but module not available');
6132
4236
  return null;
6133
4237
  }
6134
4238
  try {
6135
4239
  const hasCert = await this.hasCertificate();
6136
4240
  if (!hasCert) {
6137
- log$8.debug('No certificate stored');
4241
+ log$5.debug('No certificate stored');
6138
4242
  return null;
6139
4243
  }
6140
4244
  // Use getCertificatesInfo to retrieve information about stored certificates
6141
4245
  const result = await this.expoMTLS.getCertificatesInfo();
6142
4246
  if (!result || !result.certificates || result.certificates.length === 0) {
6143
- log$8.debug('No certificate information available');
4247
+ log$5.debug('No certificate information available');
6144
4248
  return null;
6145
4249
  }
6146
4250
  // Get the first certificate (primary client certificate)
6147
4251
  const cert = result.certificates[0];
6148
4252
  if (!cert) {
6149
- log$8.debug('Certificate data is empty');
4253
+ log$5.debug('Certificate data is empty');
6150
4254
  return null;
6151
4255
  }
6152
- log$8.debug('Retrieved certificate info:', {
4256
+ log$5.debug('Retrieved certificate info:', {
6153
4257
  subject: cert.subject.commonName,
6154
4258
  issuer: cert.issuer.commonName,
6155
4259
  validFrom: new Date(cert.validFrom),
@@ -6168,7 +4272,7 @@ class ReactNativeMTLSAdapter {
6168
4272
  };
6169
4273
  }
6170
4274
  catch (error) {
6171
- log$8.error('Failed to get certificate info:', error);
4275
+ log$5.error('Failed to get certificate info:', error);
6172
4276
  return null;
6173
4277
  }
6174
4278
  }
@@ -6179,7 +4283,7 @@ class ReactNativeMTLSAdapter {
6179
4283
  */
6180
4284
  async parseCertificateData(certificateData) {
6181
4285
  if (!this.expoMTLS) {
6182
- log$8.debug('Parse certificate: Module not available');
4286
+ log$5.debug('Parse certificate: Module not available');
6183
4287
  return null;
6184
4288
  }
6185
4289
  try {
@@ -6196,14 +4300,14 @@ class ReactNativeMTLSAdapter {
6196
4300
  else {
6197
4301
  throw new MTLSError(MTLSErrorType$1.CERTIFICATE_INVALID, `Unsupported certificate format: ${certificateData.format}`);
6198
4302
  }
6199
- log$8.debug('Certificate parsed successfully:', {
4303
+ log$5.debug('Certificate parsed successfully:', {
6200
4304
  certificateCount: result.certificates.length,
6201
4305
  subjects: result.certificates.map((cert) => cert.subject.commonName),
6202
4306
  });
6203
4307
  return result;
6204
4308
  }
6205
4309
  catch (error) {
6206
- log$8.error('Failed to parse certificate:', error);
4310
+ log$5.error('Failed to parse certificate:', error);
6207
4311
  if (error instanceof MTLSError) {
6208
4312
  throw error;
6209
4313
  }
@@ -6218,7 +4322,7 @@ class ReactNativeMTLSAdapter {
6218
4322
  if (!hasCert) {
6219
4323
  throw new MTLSError(MTLSErrorType$1.CERTIFICATE_NOT_FOUND, 'No certificate configured');
6220
4324
  }
6221
- log$8.debug('Making mTLS request:', {
4325
+ log$5.debug('Making mTLS request:', {
6222
4326
  method: requestConfig.method || 'GET',
6223
4327
  url: requestConfig.url,
6224
4328
  headers: requestConfig.headers,
@@ -6226,7 +4330,7 @@ class ReactNativeMTLSAdapter {
6226
4330
  responseType: requestConfig.responseType,
6227
4331
  });
6228
4332
  if (requestConfig.data) {
6229
- log$8.debug('mTLS request body:', requestConfig.data);
4333
+ log$5.debug('mTLS request body:', requestConfig.data);
6230
4334
  }
6231
4335
  try {
6232
4336
  const response = await this.expoMTLS.request(requestConfig.url, {
@@ -6235,7 +4339,7 @@ class ReactNativeMTLSAdapter {
6235
4339
  body: requestConfig.data ? JSON.stringify(requestConfig.data) : undefined,
6236
4340
  responseType: requestConfig.responseType,
6237
4341
  });
6238
- log$8.debug('mTLS request successful:', response);
4342
+ log$5.debug('mTLS request successful:', response);
6239
4343
  if (!response.success) {
6240
4344
  throw new MTLSError(MTLSErrorType$1.CONNECTION_FAILED, `mTLS request failed: ${response.statusMessage} (${response.statusCode})`, undefined, response.statusCode);
6241
4345
  }
@@ -6247,7 +4351,7 @@ class ReactNativeMTLSAdapter {
6247
4351
  data = JSON.parse(response.body);
6248
4352
  }
6249
4353
  catch (parseError) {
6250
- log$8.warn('Failed to parse JSON response:', parseError);
4354
+ log$5.warn('Failed to parse JSON response:', parseError);
6251
4355
  // If parsing fails, keep raw body
6252
4356
  }
6253
4357
  }
@@ -6264,7 +4368,7 @@ class ReactNativeMTLSAdapter {
6264
4368
  };
6265
4369
  }
6266
4370
  catch (error) {
6267
- log$8.error('mTLS request failed:', error);
4371
+ log$5.error('mTLS request failed:', error);
6268
4372
  throw new MTLSError(MTLSErrorType$1.CONNECTION_FAILED, 'mTLS request failed', error);
6269
4373
  }
6270
4374
  }
@@ -6277,18 +4381,18 @@ class ReactNativeMTLSAdapter {
6277
4381
  */
6278
4382
  async testConnection() {
6279
4383
  if (!this.expoMTLS || !this.config) {
6280
- log$8.debug('Diagnostic test: No mTLS module or config available');
4384
+ log$5.debug('Diagnostic test: No mTLS module or config available');
6281
4385
  return false;
6282
4386
  }
6283
4387
  try {
6284
4388
  const hasCert = await this.hasCertificate();
6285
4389
  if (!hasCert) {
6286
- log$8.debug('Diagnostic test: No certificate configured');
4390
+ log$5.debug('Diagnostic test: No certificate configured');
6287
4391
  return false;
6288
4392
  }
6289
- log$8.debug('Running diagnostic test (may fail even if mTLS works):', this.config.baseUrl);
4393
+ log$5.debug('Running diagnostic test (may fail even if mTLS works):', this.config.baseUrl);
6290
4394
  const result = await this.expoMTLS.testConnection(this.config.baseUrl);
6291
- log$8.debug('Diagnostic test result (NOT validation):', {
4395
+ log$5.debug('Diagnostic test result (NOT validation):', {
6292
4396
  success: result.success,
6293
4397
  statusCode: result.statusCode,
6294
4398
  statusMessage: result.statusMessage,
@@ -6299,13 +4403,13 @@ class ReactNativeMTLSAdapter {
6299
4403
  return result.success;
6300
4404
  }
6301
4405
  catch (error) {
6302
- log$8.warn('Diagnostic test failed (this is expected):', error);
4406
+ log$5.warn('Diagnostic test failed (this is expected):', error);
6303
4407
  return false;
6304
4408
  }
6305
4409
  }
6306
4410
  async removeCertificate() {
6307
4411
  if (!this.expoMTLS) {
6308
- log$8.debug('Remove certificate: Module not available');
4412
+ log$5.debug('Remove certificate: Module not available');
6309
4413
  return;
6310
4414
  }
6311
4415
  try {
@@ -6314,10 +4418,10 @@ class ReactNativeMTLSAdapter {
6314
4418
  this.isConfigured = false;
6315
4419
  // Cleanup event listeners
6316
4420
  this.cleanupEventListeners();
6317
- log$8.debug('Certificate removed successfully');
4421
+ log$5.debug('Certificate removed successfully');
6318
4422
  }
6319
4423
  catch (error) {
6320
- log$8.error('Failed to remove certificate:', error);
4424
+ log$5.error('Failed to remove certificate:', error);
6321
4425
  throw new MTLSError(MTLSErrorType$1.CONFIGURATION_ERROR, 'Failed to remove certificate', error);
6322
4426
  }
6323
4427
  }
@@ -6326,7 +4430,7 @@ class ReactNativeMTLSAdapter {
6326
4430
  */
6327
4431
  cleanupEventListeners() {
6328
4432
  if (this.eventListeners.length > 0) {
6329
- log$8.debug(`Cleaning up ${this.eventListeners.length} event listeners`);
4433
+ log$5.debug(`Cleaning up ${this.eventListeners.length} event listeners`);
6330
4434
  }
6331
4435
  // Remove individual listeners if they have remove methods
6332
4436
  this.eventListeners.forEach((listener) => {
@@ -6363,7 +4467,7 @@ class ReactNativeMTLSAdapter {
6363
4467
  }
6364
4468
  }
6365
4469
 
6366
- const log$7 = createPrefixedLogger('WEB-MTLS');
4470
+ const log$4 = createPrefixedLogger('WEB-MTLS');
6367
4471
  /**
6368
4472
  * Web mTLS Adapter - Graceful fallback for web browsers
6369
4473
  *
@@ -6377,13 +4481,13 @@ const log$7 = createPrefixedLogger('WEB-MTLS');
6377
4481
  */
6378
4482
  class WebMTLSAdapter {
6379
4483
  constructor() {
6380
- log$7.warn('Web browsers do not support programmatic mTLS configuration');
6381
- log$7.info('Use JWT authentication or configure client certificates in browser settings');
4484
+ log$4.warn('Web browsers do not support programmatic mTLS configuration');
4485
+ log$4.info('Use JWT authentication or configure client certificates in browser settings');
6382
4486
  }
6383
4487
  async isMTLSSupported() {
6384
4488
  // mTLS is not supported programmatically in web browsers
6385
4489
  const supported = false;
6386
- log$7.debug('mTLS support check:', {
4490
+ log$4.debug('mTLS support check:', {
6387
4491
  supported,
6388
4492
  platform: this.getPlatformInfo().platform,
6389
4493
  reason: 'Browser security model prevents programmatic certificate configuration',
@@ -6392,14 +4496,14 @@ class WebMTLSAdapter {
6392
4496
  return supported;
6393
4497
  }
6394
4498
  async initialize(config) {
6395
- log$7.warn('Initialized but mTLS not available in web browsers:', {
4499
+ log$4.warn('Initialized but mTLS not available in web browsers:', {
6396
4500
  baseUrl: config.baseUrl,
6397
4501
  port: config.port,
6398
4502
  recommendation: 'Use standard HTTPS with JWT authentication',
6399
4503
  });
6400
4504
  }
6401
4505
  async configureCertificate(certificateData) {
6402
- log$7.error('Certificate configuration attempted:', {
4506
+ log$4.error('Certificate configuration attempted:', {
6403
4507
  format: certificateData.format,
6404
4508
  reason: 'Not supported in web browsers',
6405
4509
  alternatives: [
@@ -6414,15 +4518,15 @@ class WebMTLSAdapter {
6414
4518
  }
6415
4519
  async hasCertificate() {
6416
4520
  // We cannot detect if the browser has certificates configured
6417
- log$7.debug('Certificate availability check: Cannot detect browser certificates programmatically');
4521
+ log$4.debug('Certificate availability check: Cannot detect browser certificates programmatically');
6418
4522
  return false;
6419
4523
  }
6420
4524
  async getCertificateInfo() {
6421
- log$7.debug('Certificate info requested: Not accessible in web browsers');
4525
+ log$4.debug('Certificate info requested: Not accessible in web browsers');
6422
4526
  return null;
6423
4527
  }
6424
4528
  async request(requestConfig) {
6425
- log$7.error('mTLS request attempted:', {
4529
+ log$4.error('mTLS request attempted:', {
6426
4530
  method: requestConfig.method,
6427
4531
  url: requestConfig.url,
6428
4532
  reason: 'Not supported in web browsers',
@@ -6437,11 +4541,11 @@ class WebMTLSAdapter {
6437
4541
  'are properly configured in the browser certificate store.');
6438
4542
  }
6439
4543
  async testConnection() {
6440
- log$7.debug('Connection test: mTLS not available in web browsers');
4544
+ log$4.debug('Connection test: mTLS not available in web browsers');
6441
4545
  return false;
6442
4546
  }
6443
4547
  async removeCertificate() {
6444
- log$7.debug('Remove certificate: No certificates to remove (not supported in web browsers)');
4548
+ log$4.debug('Remove certificate: No certificates to remove (not supported in web browsers)');
6445
4549
  // No-op - cannot remove certificates programmatically in browsers
6446
4550
  }
6447
4551
  /**
@@ -6449,7 +4553,7 @@ class WebMTLSAdapter {
6449
4553
  * Always returns null for web browsers as mTLS is not supported
6450
4554
  */
6451
4555
  getBaseUrl() {
6452
- log$7.debug('Base URL requested: Not supported in web browsers');
4556
+ log$4.debug('Base URL requested: Not supported in web browsers');
6453
4557
  return null;
6454
4558
  }
6455
4559
  getPlatformInfo() {
@@ -6482,7 +4586,7 @@ class WebMTLSAdapter {
6482
4586
  }
6483
4587
  }
6484
4588
 
6485
- const log$6 = createPrefixedLogger('MTLS-LOADER');
4589
+ const log$3 = createPrefixedLogger('MTLS-LOADER');
6486
4590
  function loadMTLSAdapter(platform, config) {
6487
4591
  try {
6488
4592
  let adapter;
@@ -6516,7 +4620,7 @@ function loadMTLSAdapter(platform, config) {
6516
4620
  return adapter;
6517
4621
  }
6518
4622
  catch (error) {
6519
- log$6.warn(`mTLS adapter not available for platform ${platform}:`, error);
4623
+ log$3.warn(`mTLS adapter not available for platform ${platform}:`, error);
6520
4624
  return null;
6521
4625
  }
6522
4626
  }
@@ -6526,7 +4630,7 @@ async function initializeAdapterAsync(adapter, config) {
6526
4630
  if (isSupported) {
6527
4631
  await adapter.initialize(config);
6528
4632
  const platformInfo = adapter.getPlatformInfo();
6529
- log$6.debug('mTLS adapter initialized:', {
4633
+ log$3.debug('mTLS adapter initialized:', {
6530
4634
  platform: platformInfo.platform,
6531
4635
  mtlsSupported: platformInfo.mtlsSupported,
6532
4636
  certificateStorage: platformInfo.certificateStorage,
@@ -6535,31 +4639,28 @@ async function initializeAdapterAsync(adapter, config) {
6535
4639
  }
6536
4640
  }
6537
4641
  catch (error) {
6538
- log$6.warn('Failed to initialize mTLS adapter:', error);
4642
+ log$3.warn('Failed to initialize mTLS adapter:', error);
6539
4643
  }
6540
4644
  }
6541
4645
 
6542
- const log$5 = createPrefixedLogger('ADAPTER-LOADER');
4646
+ const log$2 = createPrefixedLogger('ADAPTER-LOADER');
6543
4647
  function loadPlatformAdapters(options = {}) {
6544
4648
  const { mtlsConfig } = options;
6545
4649
  const { platform } = detectPlatform();
6546
- log$5.debug('Loading adapters for platform:', platform);
4650
+ log$2.debug('Loading adapters for platform:', platform);
6547
4651
  const storageAdapters = loadStorageAdapters(platform);
6548
4652
  const networkMonitor = loadNetworkMonitor(platform);
6549
- const cache = loadCacheAdapter(platform);
6550
4653
  const mtls = loadMTLSAdapter(platform, mtlsConfig);
6551
- log$5.debug('Adapters loaded:', {
4654
+ log$2.debug('Adapters loaded:', {
6552
4655
  platform,
6553
4656
  hasStorage: !!storageAdapters.storage,
6554
4657
  hasSecureStorage: !!storageAdapters.secureStorage,
6555
4658
  hasNetworkMonitor: !!networkMonitor,
6556
- hasCache: !!cache,
6557
4659
  hasMTLS: !!mtls,
6558
4660
  });
6559
4661
  return {
6560
4662
  ...storageAdapters,
6561
4663
  networkMonitor,
6562
- cache,
6563
4664
  mtls: mtls || undefined,
6564
4665
  };
6565
4666
  }
@@ -6576,12 +4677,9 @@ function createACubeMTLSConfig(baseUrl, timeout, autoInitialize = true, forcePor
6576
4677
 
6577
4678
  const DI_TOKENS = {
6578
4679
  HTTP_PORT: Symbol('HTTP_PORT'),
6579
- BASE_HTTP_PORT: Symbol('BASE_HTTP_PORT'),
6580
4680
  STORAGE_PORT: Symbol('STORAGE_PORT'),
6581
4681
  SECURE_STORAGE_PORT: Symbol('SECURE_STORAGE_PORT'),
6582
4682
  NETWORK_PORT: Symbol('NETWORK_PORT'),
6583
- CACHE_PORT: Symbol('CACHE_PORT'),
6584
- CACHE_KEY_GENERATOR: Symbol('CACHE_KEY_GENERATOR'),
6585
4683
  MTLS_PORT: Symbol('MTLS_PORT'),
6586
4684
  TOKEN_STORAGE_PORT: Symbol('TOKEN_STORAGE_PORT'),
6587
4685
  RECEIPT_REPOSITORY: Symbol('RECEIPT_REPOSITORY'),
@@ -6599,7 +4697,6 @@ const DI_TOKENS = {
6599
4697
  AUTH_SERVICE: Symbol('AUTH_SERVICE'),
6600
4698
  AUTHENTICATION_SERVICE: Symbol('AUTHENTICATION_SERVICE'),
6601
4699
  CERTIFICATE_SERVICE: Symbol('CERTIFICATE_SERVICE'),
6602
- OFFLINE_SERVICE: Symbol('OFFLINE_SERVICE'),
6603
4700
  NOTIFICATION_SERVICE: Symbol('NOTIFICATION_SERVICE'),
6604
4701
  TELEMETRY_SERVICE: Symbol('TELEMETRY_SERVICE'),
6605
4702
  };
@@ -7574,468 +5671,6 @@ class TelemetryRepositoryImpl {
7574
5671
  }
7575
5672
  }
7576
5673
 
7577
- const log$4 = createPrefixedLogger('CACHE-KEY');
7578
- const URL_PATTERNS = [
7579
- // Receipt (mf1) - specific patterns first
7580
- {
7581
- pattern: /^\/mf1\/receipts\/([^/]+)\/returnable-items$/,
7582
- resource: 'receipt',
7583
- action: 'returnable',
7584
- },
7585
- {
7586
- pattern: /^\/mf1\/receipts\/([^/]+)\/details$/,
7587
- resource: 'receipt',
7588
- action: 'details',
7589
- },
7590
- { pattern: /^\/mf1\/receipts\/([^/]+)$/, resource: 'receipt' },
7591
- {
7592
- pattern: /^\/mf1\/pems\/([^/]+)\/receipts$/,
7593
- resource: 'receipt',
7594
- parent: 'point-of-sale',
7595
- isList: true,
7596
- },
7597
- { pattern: /^\/mf1\/receipts$/, resource: 'receipt', isList: true },
7598
- // Merchant (mf2)
7599
- { pattern: /^\/mf2\/merchants\/([^/]+)$/, resource: 'merchant' },
7600
- { pattern: /^\/mf2\/merchants$/, resource: 'merchant', isList: true },
7601
- // Cashier (mf1)
7602
- { pattern: /^\/mf1\/cashiers\/me$/, resource: 'cashier', action: 'me' },
7603
- { pattern: /^\/mf1\/cashiers\/([^/]+)$/, resource: 'cashier' },
7604
- { pattern: /^\/mf1\/cashiers$/, resource: 'cashier', isList: true },
7605
- // Cash Register (mf1)
7606
- { pattern: /^\/mf1\/cash-registers\/([^/]+)$/, resource: 'cash-register' },
7607
- { pattern: /^\/mf1\/cash-registers$/, resource: 'cash-register', isList: true },
7608
- // Point of Sale (mf1)
7609
- { pattern: /^\/mf1\/pems\/([^/]+)$/, resource: 'point-of-sale' },
7610
- { pattern: /^\/mf1\/pems$/, resource: 'point-of-sale', isList: true },
7611
- // Nested resources under merchant (mf2)
7612
- {
7613
- pattern: /^\/mf2\/merchants\/([^/]+)\/suppliers\/([^/]+)$/,
7614
- resource: 'supplier',
7615
- parent: 'merchant',
7616
- },
7617
- {
7618
- pattern: /^\/mf2\/merchants\/([^/]+)\/suppliers$/,
7619
- resource: 'supplier',
7620
- parent: 'merchant',
7621
- isList: true,
7622
- },
7623
- {
7624
- pattern: /^\/mf2\/merchants\/([^/]+)\/daily-reports/,
7625
- resource: 'daily-report',
7626
- parent: 'merchant',
7627
- isList: true,
7628
- },
7629
- {
7630
- pattern: /^\/mf2\/merchants\/([^/]+)\/journals/,
7631
- resource: 'journal',
7632
- parent: 'merchant',
7633
- isList: true,
7634
- },
7635
- // PEM (mf2)
7636
- {
7637
- pattern: /^\/mf2\/pems\/([^/]+)\/certificates$/,
7638
- resource: 'pem',
7639
- action: 'certificates',
7640
- },
7641
- { pattern: /^\/mf2\/pems\/([^/]+)$/, resource: 'pem' },
7642
- // Others
7643
- { pattern: /^\/mf1\/notifications/, resource: 'notification', isList: true },
7644
- {
7645
- pattern: /^\/mf1\/pems\/([^/]+)\/telemetry$/,
7646
- resource: 'telemetry',
7647
- },
7648
- ];
7649
- const DEFAULT_TTL_CONFIG = {
7650
- // Data that rarely changes - 30 min TTL for items only
7651
- merchant: { ttlMs: 30 * 60 * 1000, cacheList: false, cacheItem: true },
7652
- 'point-of-sale': { ttlMs: 30 * 60 * 1000, cacheList: false, cacheItem: true },
7653
- 'cash-register': { ttlMs: 30 * 60 * 1000, cacheList: false, cacheItem: true },
7654
- pem: { ttlMs: 30 * 60 * 1000, cacheList: false, cacheItem: false },
7655
- // Data that changes moderately - 10 min TTL for items only
7656
- cashier: { ttlMs: 10 * 60 * 1000, cacheList: false, cacheItem: true },
7657
- supplier: { ttlMs: 10 * 60 * 1000, cacheList: false, cacheItem: true },
7658
- // Data that can change - 5 min TTL for items only
7659
- receipt: { ttlMs: 5 * 60 * 1000, cacheList: false, cacheItem: true },
7660
- 'daily-report': { ttlMs: 5 * 60 * 1000, cacheList: false, cacheItem: true },
7661
- journal: { ttlMs: 5 * 60 * 1000, cacheList: false, cacheItem: true },
7662
- // Real-time data - 1 min TTL
7663
- notification: { ttlMs: 1 * 60 * 1000, cacheList: false, cacheItem: false },
7664
- telemetry: { ttlMs: 1 * 60 * 1000, cacheList: false, cacheItem: false },
7665
- };
7666
- const DEFAULT_TTL = 5 * 60 * 1000; // 5 minutes
7667
- class CacheKeyGenerator {
7668
- constructor(customConfig) {
7669
- this.config = { ...DEFAULT_TTL_CONFIG, ...customConfig };
7670
- log$4.info('CacheKeyGenerator initialized with config:', {
7671
- resources: Object.keys(this.config),
7672
- });
7673
- }
7674
- generate(url, params) {
7675
- const parsed = this.parseUrl(url);
7676
- if (!parsed) {
7677
- // Fallback: use URL as key
7678
- const paramStr = params ? this.serializeParams(params) : '';
7679
- const key = paramStr ? `${url}?${paramStr}` : url;
7680
- log$4.debug('URL not matched, using fallback key:', { url, key });
7681
- return key;
7682
- }
7683
- const { resource, ids, action, isList, parent } = parsed;
7684
- if (isList) {
7685
- const paramStr = params ? this.serializeParams(params) : '';
7686
- const parentPart = parent && ids.length > 0 ? `${parent}=${ids[0]}&` : '';
7687
- const key = `${resource}:list:${parentPart}${paramStr}`;
7688
- log$4.debug('Generated list cache key:', { url, key, resource });
7689
- return key;
7690
- }
7691
- // Single item
7692
- if (ids.length === 0 && action) {
7693
- // Special case for endpoints like /cashiers/me
7694
- const key = `${resource}:${action}`;
7695
- log$4.debug('Generated special action cache key:', { url, key, resource, action });
7696
- return key;
7697
- }
7698
- let key = `${resource}:${ids.join(':')}`;
7699
- if (action) {
7700
- key += `:${action}`;
7701
- }
7702
- log$4.debug('Generated item cache key:', { url, key, resource, ids, action });
7703
- return key;
7704
- }
7705
- parseResource(url) {
7706
- const parsed = this.parseUrl(url);
7707
- return parsed?.resource;
7708
- }
7709
- getTTL(url) {
7710
- const resource = this.parseResource(url);
7711
- if (!resource) {
7712
- log$4.debug('No resource found for URL, using default TTL:', { url, ttl: DEFAULT_TTL });
7713
- return DEFAULT_TTL;
7714
- }
7715
- const ttl = this.config[resource].ttlMs;
7716
- log$4.debug('TTL for resource:', { url, resource, ttlMs: ttl, ttlMin: ttl / 60000 });
7717
- return ttl;
7718
- }
7719
- shouldCache(url) {
7720
- const parsed = this.parseUrl(url);
7721
- if (!parsed) {
7722
- log$4.debug('URL not recognized, should not cache:', { url });
7723
- return false;
7724
- }
7725
- const { resource, isList } = parsed;
7726
- const config = this.config[resource];
7727
- if (isList) {
7728
- log$4.debug('List endpoint cache decision:', {
7729
- url,
7730
- resource,
7731
- isList: true,
7732
- shouldCache: config.cacheList,
7733
- });
7734
- return config.cacheList;
7735
- }
7736
- log$4.debug('Item endpoint cache decision:', {
7737
- url,
7738
- resource,
7739
- isList: false,
7740
- shouldCache: config.cacheItem,
7741
- });
7742
- return config.cacheItem;
7743
- }
7744
- getInvalidationPatterns(url, method) {
7745
- const parsed = this.parseUrl(url);
7746
- if (!parsed) {
7747
- log$4.debug('No patterns to invalidate for URL:', { url, method });
7748
- return [];
7749
- }
7750
- const { resource, ids, parent } = parsed;
7751
- const patterns = [];
7752
- // Always invalidate list on mutations
7753
- if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE') {
7754
- if (parent && ids.length > 0) {
7755
- patterns.push(`${resource}:list:${parent}=${ids[0]}*`);
7756
- }
7757
- patterns.push(`${resource}:list:*`);
7758
- }
7759
- // Invalidate specific item on PUT/PATCH/DELETE
7760
- if (method === 'PUT' || method === 'PATCH' || method === 'DELETE') {
7761
- if (ids.length > 0) {
7762
- patterns.push(`${resource}:${ids.join(':')}*`);
7763
- }
7764
- }
7765
- // Special cases
7766
- if (resource === 'cashier' && (method === 'PUT' || method === 'DELETE')) {
7767
- patterns.push('cashier:me');
7768
- }
7769
- log$4.debug('Invalidation patterns:', { url, method, patterns });
7770
- return patterns;
7771
- }
7772
- parseUrl(url) {
7773
- // Remove query string for pattern matching
7774
- const urlPath = url.split('?')[0];
7775
- for (const pattern of URL_PATTERNS) {
7776
- const match = urlPath?.match(pattern.pattern);
7777
- if (match) {
7778
- // Extract IDs from capture groups
7779
- const ids = match.slice(1).filter(Boolean);
7780
- return {
7781
- resource: pattern.resource,
7782
- ids,
7783
- action: pattern.action,
7784
- isList: pattern.isList,
7785
- parent: pattern.parent,
7786
- };
7787
- }
7788
- }
7789
- return null;
7790
- }
7791
- serializeParams(params) {
7792
- const sortedKeys = Object.keys(params).sort();
7793
- const parts = [];
7794
- for (const key of sortedKeys) {
7795
- const value = params[key];
7796
- if (value !== undefined && value !== null) {
7797
- parts.push(`${key}=${String(value)}`);
7798
- }
7799
- }
7800
- return parts.join('&');
7801
- }
7802
- }
7803
-
7804
- const log$3 = createPrefixedLogger('CACHE');
7805
- class CachingHttpDecorator {
7806
- constructor(http, cache, keyGenerator, networkMonitor, config = {}) {
7807
- this.http = http;
7808
- this.cache = cache;
7809
- this.keyGenerator = keyGenerator;
7810
- this.networkMonitor = networkMonitor;
7811
- this.config = config;
7812
- this.currentOnlineState = true;
7813
- this.authToken = null;
7814
- log$3.info('CachingHttpDecorator initialized', {
7815
- enabled: config.enabled !== false,
7816
- hasNetworkMonitor: !!networkMonitor,
7817
- });
7818
- this.setupNetworkMonitoring();
7819
- }
7820
- setupNetworkMonitoring() {
7821
- if (this.networkMonitor) {
7822
- this.networkSubscription = this.networkMonitor.online$.subscribe((online) => {
7823
- if (this.currentOnlineState !== online) {
7824
- log$3.info('Network state changed:', { online });
7825
- }
7826
- this.currentOnlineState = online;
7827
- });
7828
- }
7829
- }
7830
- isOnline() {
7831
- if (this.networkMonitor) {
7832
- return this.currentOnlineState;
7833
- }
7834
- if (typeof navigator !== 'undefined' && 'onLine' in navigator) {
7835
- return navigator.onLine;
7836
- }
7837
- return true;
7838
- }
7839
- async get(url, config) {
7840
- const startTime = Date.now();
7841
- // Check if caching is disabled globally
7842
- if (this.config.enabled === false) {
7843
- log$3.debug('GET (cache disabled globally):', { url });
7844
- return this.http.get(url, config);
7845
- }
7846
- // Check if this URL should be cached
7847
- const shouldCache = this.keyGenerator.shouldCache(url);
7848
- if (!shouldCache) {
7849
- log$3.debug('GET (not cacheable - likely a list endpoint):', { url });
7850
- return this.http.get(url, config);
7851
- }
7852
- const cacheKey = this.keyGenerator.generate(url, config?.params);
7853
- const ttl = this.keyGenerator.getTTL(url);
7854
- const resource = this.keyGenerator.parseResource(url);
7855
- log$3.info('GET request starting:', {
7856
- url,
7857
- resource,
7858
- cacheKey,
7859
- ttlMs: ttl,
7860
- ttlMin: Math.round(ttl / 60000),
7861
- params: config?.params,
7862
- });
7863
- // Check cache
7864
- let cached = null;
7865
- try {
7866
- cached = await this.cache.get(cacheKey);
7867
- if (cached) {
7868
- log$3.debug('Cache entry found:', {
7869
- cacheKey,
7870
- timestamp: new Date(cached.timestamp).toISOString(),
7871
- ageMs: Date.now() - cached.timestamp,
7872
- });
7873
- }
7874
- else {
7875
- log$3.debug('Cache entry not found:', { cacheKey });
7876
- }
7877
- }
7878
- catch (error) {
7879
- log$3.warn('Cache lookup failed:', {
7880
- cacheKey,
7881
- error: error instanceof Error ? error.message : error,
7882
- });
7883
- }
7884
- if (cached) {
7885
- const age = Date.now() - cached.timestamp;
7886
- const isExpired = age >= ttl;
7887
- log$3.debug('Cache analysis:', {
7888
- cacheKey,
7889
- ageMs: age,
7890
- ageSec: Math.round(age / 1000),
7891
- ttlMs: ttl,
7892
- isExpired,
7893
- isOnline: this.isOnline(),
7894
- });
7895
- // If within TTL, return cached data
7896
- if (!isExpired) {
7897
- const duration = Date.now() - startTime;
7898
- log$3.info('CACHE HIT:', {
7899
- url,
7900
- cacheKey,
7901
- ageMs: age,
7902
- durationMs: duration,
7903
- });
7904
- return {
7905
- data: cached.data,
7906
- status: 200,
7907
- headers: { 'x-cache': 'HIT' },
7908
- };
7909
- }
7910
- // If offline and cache is stale, return stale data
7911
- if (!this.isOnline()) {
7912
- const duration = Date.now() - startTime;
7913
- log$3.info('CACHE STALE (offline):', {
7914
- url,
7915
- cacheKey,
7916
- ageMs: age,
7917
- durationMs: duration,
7918
- });
7919
- return {
7920
- data: cached.data,
7921
- status: 200,
7922
- headers: { 'x-cache': 'STALE' },
7923
- };
7924
- }
7925
- log$3.debug('Cache expired, fetching fresh data:', { cacheKey, ageMs: age, ttlMs: ttl });
7926
- }
7927
- // Fetch fresh data
7928
- try {
7929
- log$3.debug('Fetching from network:', { url });
7930
- const response = await this.http.get(url, config);
7931
- // Cache the response
7932
- try {
7933
- await this.cache.set(cacheKey, response.data);
7934
- log$3.debug('Response cached successfully:', { cacheKey });
7935
- }
7936
- catch (error) {
7937
- log$3.error('Failed to cache response:', {
7938
- cacheKey,
7939
- error: error instanceof Error ? error.message : error,
7940
- });
7941
- }
7942
- const duration = Date.now() - startTime;
7943
- log$3.info('CACHE MISS (fetched fresh):', {
7944
- url,
7945
- cacheKey,
7946
- status: response.status,
7947
- durationMs: duration,
7948
- });
7949
- return {
7950
- ...response,
7951
- headers: { ...response.headers, 'x-cache': 'MISS' },
7952
- };
7953
- }
7954
- catch (error) {
7955
- // On error, return stale cache if available
7956
- if (cached) {
7957
- const duration = Date.now() - startTime;
7958
- log$3.warn('CACHE STALE (network error):', {
7959
- url,
7960
- cacheKey,
7961
- error: error instanceof Error ? error.message : 'Unknown error',
7962
- durationMs: duration,
7963
- });
7964
- return {
7965
- data: cached.data,
7966
- status: 200,
7967
- headers: { 'x-cache': 'STALE' },
7968
- };
7969
- }
7970
- log$3.error('Network error with no cache fallback:', {
7971
- url,
7972
- error: error instanceof Error ? error.message : error,
7973
- });
7974
- throw error;
7975
- }
7976
- }
7977
- async post(url, data, config) {
7978
- log$3.info('POST request:', { url });
7979
- const response = await this.http.post(url, data, config);
7980
- await this.invalidateRelated(url, 'POST');
7981
- return response;
7982
- }
7983
- async put(url, data, config) {
7984
- log$3.info('PUT request:', { url });
7985
- const response = await this.http.put(url, data, config);
7986
- await this.invalidateRelated(url, 'PUT');
7987
- return response;
7988
- }
7989
- async patch(url, data, config) {
7990
- log$3.info('PATCH request:', { url });
7991
- const response = await this.http.patch(url, data, config);
7992
- await this.invalidateRelated(url, 'PATCH');
7993
- return response;
7994
- }
7995
- async delete(url, config) {
7996
- log$3.info('DELETE request:', { url });
7997
- const response = await this.http.delete(url, config);
7998
- await this.invalidateRelated(url, 'DELETE');
7999
- return response;
8000
- }
8001
- setAuthToken(token) {
8002
- log$3.debug('CachingHttpDecorator.setAuthToken called:', {
8003
- hasToken: !!token,
8004
- tokenPrefix: token?.substring(0, 20),
8005
- underlyingHttpType: this.http.constructor.name,
8006
- });
8007
- this.authToken = token;
8008
- this.http.setAuthToken(token);
8009
- }
8010
- getAuthToken() {
8011
- return this.authToken;
8012
- }
8013
- async invalidateRelated(url, method) {
8014
- const patterns = this.keyGenerator.getInvalidationPatterns(url, method);
8015
- if (patterns.length === 0) {
8016
- log$3.debug('No cache patterns to invalidate:', { url, method });
8017
- return;
8018
- }
8019
- log$3.info('Invalidating cache patterns:', { url, method, patterns });
8020
- for (const pattern of patterns) {
8021
- try {
8022
- await this.cache.invalidate(pattern);
8023
- log$3.debug('Cache pattern invalidated:', { pattern });
8024
- }
8025
- catch (error) {
8026
- log$3.error('Failed to invalidate pattern:', {
8027
- pattern,
8028
- error: error instanceof Error ? error.message : error,
8029
- });
8030
- }
8031
- }
8032
- }
8033
- destroy() {
8034
- log$3.debug('CachingHttpDecorator destroyed');
8035
- this.networkSubscription?.unsubscribe();
8036
- }
8037
- }
8038
-
8039
5674
  const logJwt = createPrefixedLogger('HTTP-JWT');
8040
5675
  const logMtls = createPrefixedLogger('HTTP-MTLS');
8041
5676
  class AxiosHttpAdapter {
@@ -8305,7 +5940,6 @@ class SDKFactory {
8305
5940
  baseUrl: config.baseUrl,
8306
5941
  timeout: config.timeout,
8307
5942
  });
8308
- container.register(DI_TOKENS.BASE_HTTP_PORT, httpAdapter);
8309
5943
  container.register(DI_TOKENS.HTTP_PORT, httpAdapter);
8310
5944
  container.registerFactory(DI_TOKENS.RECEIPT_REPOSITORY, () => {
8311
5945
  const http = container.get(DI_TOKENS.HTTP_PORT);
@@ -8353,23 +5987,6 @@ class SDKFactory {
8353
5987
  });
8354
5988
  return container;
8355
5989
  }
8356
- static registerCacheServices(container, cache, network) {
8357
- container.register(DI_TOKENS.CACHE_PORT, cache);
8358
- if (network) {
8359
- container.register(DI_TOKENS.NETWORK_PORT, network);
8360
- }
8361
- const keyGenerator = new CacheKeyGenerator();
8362
- container.register(DI_TOKENS.CACHE_KEY_GENERATOR, keyGenerator);
8363
- const baseHttp = container.get(DI_TOKENS.BASE_HTTP_PORT);
8364
- const cachingHttp = new CachingHttpDecorator(baseHttp, cache, keyGenerator, network);
8365
- container.register(DI_TOKENS.HTTP_PORT, cachingHttp);
8366
- }
8367
- static getCacheKeyGenerator(container) {
8368
- if (container.has(DI_TOKENS.CACHE_KEY_GENERATOR)) {
8369
- return container.get(DI_TOKENS.CACHE_KEY_GENERATOR);
8370
- }
8371
- return undefined;
8372
- }
8373
5990
  static registerAuthServices(container, secureStorage, config) {
8374
5991
  const tokenStorage = new TokenStorageAdapter(secureStorage);
8375
5992
  container.register(DI_TOKENS.TOKEN_STORAGE_PORT, tokenStorage);
@@ -8407,7 +6024,7 @@ class SDKFactory {
8407
6024
  }
8408
6025
  }
8409
6026
 
8410
- const log$2 = createPrefixedLogger('SDK');
6027
+ const log$1 = createPrefixedLogger('SDK');
8411
6028
  class ACubeSDK {
8412
6029
  constructor(config, customAdapters, events = {}) {
8413
6030
  this.events = events;
@@ -8421,23 +6038,22 @@ class ACubeSDK {
8421
6038
  }
8422
6039
  async initialize() {
8423
6040
  if (this.isInitialized) {
8424
- log$2.debug('SDK already initialized, skipping');
6041
+ log$1.debug('SDK already initialized, skipping');
8425
6042
  return;
8426
6043
  }
8427
- log$2.info('Initializing SDK', {
6044
+ log$1.info('Initializing SDK', {
8428
6045
  apiUrl: this.config.getApiUrl(),
8429
6046
  authUrl: this.config.getAuthUrl(),
8430
6047
  debugEnabled: this.config.isDebugEnabled(),
8431
6048
  });
8432
6049
  try {
8433
6050
  if (!this.adapters) {
8434
- log$2.debug('Loading platform adapters');
6051
+ log$1.debug('Loading platform adapters');
8435
6052
  const mtlsConfig = createACubeMTLSConfig(this.config.getApiUrl(), this.config.getTimeout(), true);
8436
6053
  this.adapters = loadPlatformAdapters({
8437
6054
  mtlsConfig,
8438
6055
  });
8439
- log$2.info('Platform adapters loaded', {
8440
- hasCache: !!this.adapters.cache,
6056
+ log$1.info('Platform adapters loaded', {
8441
6057
  hasNetworkMonitor: !!this.adapters.networkMonitor,
8442
6058
  hasMtls: !!this.adapters.mtls,
8443
6059
  hasSecureStorage: !!this.adapters.secureStorage,
@@ -8449,30 +6065,15 @@ class ACubeSDK {
8449
6065
  timeout: this.config.getTimeout(),
8450
6066
  debugEnabled: this.config.isDebugEnabled(),
8451
6067
  };
8452
- log$2.debug('Creating DI container');
6068
+ log$1.debug('Creating DI container');
8453
6069
  this.container = SDKFactory.createContainer(factoryConfig);
8454
- log$2.debug('Registering auth services');
6070
+ log$1.debug('Registering auth services');
8455
6071
  SDKFactory.registerAuthServices(this.container, this.adapters.secureStorage, factoryConfig);
8456
- if (this.adapters.cache) {
8457
- log$2.info('Registering cache services', {
8458
- hasNetworkMonitor: !!this.adapters.networkMonitor,
8459
- });
8460
- SDKFactory.registerCacheServices(this.container, this.adapters.cache, this.adapters.networkMonitor);
8461
- }
8462
- else {
8463
- log$2.debug('No cache adapter available, caching disabled');
8464
- }
8465
- log$2.debug('Initializing certificate service');
6072
+ log$1.debug('Initializing certificate service');
8466
6073
  this.certificateService = new CertificateService(this.adapters.secureStorage);
8467
6074
  const tokenStorage = this.container.get(DI_TOKENS.TOKEN_STORAGE_PORT);
8468
6075
  const httpPort = this.container.get(DI_TOKENS.HTTP_PORT);
8469
- const baseHttpPort = this.container.get(DI_TOKENS.BASE_HTTP_PORT);
8470
- log$2.debug('HTTP ports initialized', {
8471
- httpPortType: httpPort.constructor.name,
8472
- baseHttpPortType: baseHttpPort.constructor.name,
8473
- areSameInstance: httpPort === baseHttpPort,
8474
- });
8475
- log$2.debug('Initializing authentication service');
6076
+ log$1.debug('Initializing authentication service');
8476
6077
  this.authService = new AuthenticationService(httpPort, tokenStorage, {
8477
6078
  authUrl: this.config.getAuthUrl(),
8478
6079
  timeout: this.config.getTimeout(),
@@ -8482,51 +6083,33 @@ class ACubeSDK {
8482
6083
  this.events.onAuthError?.(new ACubeSDKError('AUTH_ERROR', error.message, error));
8483
6084
  },
8484
6085
  });
8485
- log$2.debug('Initializing offline manager');
8486
- const queueEvents = {
8487
- onOperationAdded: (operation) => {
8488
- this.events.onOfflineOperationAdded?.(operation.id);
8489
- },
8490
- onOperationCompleted: (result) => {
8491
- this.events.onOfflineOperationCompleted?.(result.operation.id, result.success);
8492
- },
8493
- onOperationFailed: (result) => {
8494
- this.events.onOfflineOperationCompleted?.(result.operation.id, false);
8495
- },
8496
- };
8497
- this.offlineManager = new OfflineManager(this.adapters.storage, httpPort, this.adapters.networkMonitor, {
8498
- syncInterval: 30000,
8499
- }, queueEvents);
8500
6086
  this.networkSubscription = this.adapters.networkMonitor.online$.subscribe((online) => {
8501
6087
  this.currentOnlineState = online;
8502
6088
  this.events.onNetworkStatusChanged?.(online);
8503
- if (online && this.offlineManager) {
8504
- this.offlineManager.sync().catch(() => { });
8505
- }
8506
6089
  });
8507
6090
  const isAuth = await this.authService.isAuthenticated();
8508
- log$2.debug('Checking authentication status during init', { isAuthenticated: isAuth });
6091
+ log$1.debug('Checking authentication status during init', { isAuthenticated: isAuth });
8509
6092
  if (isAuth) {
8510
6093
  const token = await this.authService.getAccessToken();
8511
- log$2.debug('Token retrieved during init', {
6094
+ log$1.debug('Token retrieved during init', {
8512
6095
  hasToken: !!token,
8513
6096
  tokenPrefix: token?.substring(0, 20),
8514
6097
  });
8515
6098
  if (token) {
8516
6099
  httpPort.setAuthToken(token);
8517
- log$2.info('Auth token set on HTTP port during initialization');
6100
+ log$1.info('Auth token set on HTTP port during initialization');
8518
6101
  }
8519
6102
  }
8520
6103
  else {
8521
- log$2.warn('User not authenticated during SDK init - token will be set after login');
6104
+ log$1.warn('User not authenticated during SDK init - token will be set after login');
8522
6105
  }
8523
- if (this.adapters?.mtls && 'setMTLSAdapter' in baseHttpPort) {
8524
- log$2.debug('Connecting mTLS adapter to HTTP port');
8525
- const httpWithMtls = baseHttpPort;
6106
+ if (this.adapters?.mtls && 'setMTLSAdapter' in httpPort) {
6107
+ log$1.debug('Connecting mTLS adapter to HTTP port');
6108
+ const httpWithMtls = httpPort;
8526
6109
  httpWithMtls.setMTLSAdapter(this.adapters.mtls);
8527
6110
  }
8528
- if ('setAuthStrategy' in baseHttpPort) {
8529
- log$2.debug('Configuring auth strategy');
6111
+ if ('setAuthStrategy' in httpPort) {
6112
+ log$1.debug('Configuring auth strategy');
8530
6113
  const jwtHandler = new JwtAuthHandler(tokenStorage);
8531
6114
  const certificatePort = this.certificateService
8532
6115
  ? {
@@ -8557,7 +6140,7 @@ class ACubeSDK {
8557
6140
  },
8558
6141
  };
8559
6142
  const authStrategy = new AuthStrategy(jwtHandler, mtlsHandler, userProvider, this.adapters?.mtls || null);
8560
- const httpWithStrategy = baseHttpPort;
6143
+ const httpWithStrategy = httpPort;
8561
6144
  httpWithStrategy.setAuthStrategy(authStrategy);
8562
6145
  }
8563
6146
  if (this.adapters?.mtls && this.certificateService) {
@@ -8575,19 +6158,18 @@ class ACubeSDK {
8575
6158
  }
8576
6159
  }
8577
6160
  catch (certError) {
8578
- log$2.warn('Certificate auto-configuration failed, will retry on demand', {
6161
+ log$1.warn('Certificate auto-configuration failed, will retry on demand', {
8579
6162
  error: certError instanceof Error ? certError.message : certError,
8580
6163
  });
8581
6164
  }
8582
6165
  }
8583
6166
  this.isInitialized = true;
8584
- log$2.info('SDK initialized successfully', {
8585
- hasCache: !!this.adapters.cache,
6167
+ log$1.info('SDK initialized successfully', {
8586
6168
  hasMtls: !!this.adapters.mtls,
8587
6169
  });
8588
6170
  }
8589
6171
  catch (error) {
8590
- log$2.error('SDK initialization failed', {
6172
+ log$1.error('SDK initialization failed', {
8591
6173
  error: error instanceof Error ? error.message : error,
8592
6174
  });
8593
6175
  throw new ACubeSDKError('SDK_INITIALIZATION_ERROR', `Failed to initialize SDK: ${error instanceof Error ? error.message : 'Unknown error'}`, error);
@@ -8643,19 +6225,19 @@ class ACubeSDK {
8643
6225
  }
8644
6226
  async login(credentials) {
8645
6227
  this.ensureInitialized();
8646
- log$2.info('Login attempt', { email: credentials.email });
6228
+ log$1.info('Login attempt', { email: credentials.email });
8647
6229
  const user = await this.authService.login(credentials);
8648
- log$2.info('Login successful', { roles: user.roles });
6230
+ log$1.info('Login successful', { roles: user.roles });
8649
6231
  const token = await this.authService.getAccessToken();
8650
6232
  if (token) {
8651
6233
  this.httpPort.setAuthToken(token);
8652
- log$2.debug('Auth token set on HTTP port');
6234
+ log$1.debug('Auth token set on HTTP port');
8653
6235
  }
8654
6236
  return user;
8655
6237
  }
8656
6238
  async logout() {
8657
6239
  this.ensureInitialized();
8658
- log$2.info('Logout');
6240
+ log$1.info('Logout');
8659
6241
  await this.authService.logout();
8660
6242
  this.httpPort.setAuthToken(null);
8661
6243
  }
@@ -8673,10 +6255,6 @@ class ACubeSDK {
8673
6255
  this.ensureInitialized();
8674
6256
  return await this.authService.isAuthenticated();
8675
6257
  }
8676
- getOfflineManager() {
8677
- this.ensureInitialized();
8678
- return this.offlineManager;
8679
- }
8680
6258
  isOnline() {
8681
6259
  this.ensureInitialized();
8682
6260
  return this.currentOnlineState;
@@ -8804,7 +6382,6 @@ class ACubeSDK {
8804
6382
  }
8805
6383
  destroy() {
8806
6384
  this.networkSubscription?.unsubscribe();
8807
- this.offlineManager?.destroy();
8808
6385
  this.container?.clear();
8809
6386
  this.isInitialized = false;
8810
6387
  }
@@ -9090,7 +6667,6 @@ class TelemetryService {
9090
6667
  this.events = events;
9091
6668
  this.stateSubject = new BehaviorSubject({
9092
6669
  data: null,
9093
- isCached: false,
9094
6670
  isLoading: false,
9095
6671
  lastFetchedAt: null,
9096
6672
  });
@@ -9160,7 +6736,6 @@ class TelemetryService {
9160
6736
  const data = await this.repository.getTelemetry(this.currentPemId);
9161
6737
  const newState = {
9162
6738
  data,
9163
- isCached: false,
9164
6739
  isLoading: false,
9165
6740
  lastFetchedAt: Date.now(),
9166
6741
  };
@@ -9185,7 +6760,6 @@ class TelemetryService {
9185
6760
  clearTelemetry() {
9186
6761
  this.stateSubject.next({
9187
6762
  data: null,
9188
- isCached: false,
9189
6763
  isLoading: false,
9190
6764
  lastFetchedAt: null,
9191
6765
  });
@@ -9198,7 +6772,7 @@ class TelemetryService {
9198
6772
  }
9199
6773
  }
9200
6774
 
9201
- const log$1 = createPrefixedLogger('SDK-MANAGER');
6775
+ const log = createPrefixedLogger('SDK-MANAGER');
9202
6776
  /**
9203
6777
  * SDKManager - Singleton wrapper for ACubeSDK with simplified API
9204
6778
  *
@@ -9265,7 +6839,7 @@ class SDKManager {
9265
6839
  if (canPoll && !this.isPollingActive) {
9266
6840
  const hasCert = await this.checkCertificate();
9267
6841
  if (!hasCert) {
9268
- log$1.warn('Certificate missing — polling blocked until certificate is installed');
6842
+ log.warn('Certificate missing — polling blocked until certificate is installed');
9269
6843
  return;
9270
6844
  }
9271
6845
  this.notificationService?.startPolling();
@@ -9367,7 +6941,7 @@ class SDKManager {
9367
6941
  this.isPollingActive = true;
9368
6942
  }
9369
6943
  else {
9370
- log$1.warn('Certificate missing at init — polling blocked until certificate is installed');
6944
+ log.warn('Certificate missing at init — polling blocked until certificate is installed');
9371
6945
  }
9372
6946
  }
9373
6947
  // AppStateService remains active for all users (handles OFFLINE network state)
@@ -9410,7 +6984,7 @@ class SDKManager {
9410
6984
  return this.certificateMissingSubject.asObservable();
9411
6985
  }
9412
6986
  /**
9413
- * Observable stream of telemetry state (data, isLoading, isCached, error)
6987
+ * Observable stream of telemetry state (data, isLoading, error)
9414
6988
  */
9415
6989
  get telemetryState$() {
9416
6990
  this.ensureInitialized();
@@ -9494,7 +7068,7 @@ class SDKManager {
9494
7068
  const user = await sdk.getCurrentUser();
9495
7069
  const canPoll = user && hasAnyRole(user.roles, ['ROLE_MERCHANT', 'ROLE_CASHIER']);
9496
7070
  if (canPoll) {
9497
- log$1.info('Certificate installed — starting polling');
7071
+ log.info('Certificate installed — starting polling');
9498
7072
  this.notificationService?.startPolling();
9499
7073
  await this.startTelemetryPollingAuto();
9500
7074
  this.isPollingActive = true;
@@ -9507,7 +7081,7 @@ class SDKManager {
9507
7081
  this.certificateMissingSubject.next(true);
9508
7082
  // Stop polling since certificate is required
9509
7083
  if (this.isPollingActive) {
9510
- log$1.info('Certificate removed — stopping polling');
7084
+ log.info('Certificate removed — stopping polling');
9511
7085
  this.notificationService?.stopPolling();
9512
7086
  this.telemetryService?.stopPolling();
9513
7087
  this.telemetryService?.clearTelemetry();
@@ -9587,91 +7161,6 @@ const RECEIPT_SENT = 'sent';
9587
7161
  const RECEIPT_SORT_DESCENDING = 'descending';
9588
7162
  const RECEIPT_SORT_ASCENDING = 'ascending';
9589
7163
 
9590
- const log = createPrefixedLogger('CACHE-HANDLER');
9591
- class CacheHandler {
9592
- constructor(cache, networkMonitor) {
9593
- this.cache = cache;
9594
- this.networkMonitor = networkMonitor;
9595
- this.currentOnlineState = true;
9596
- this.setupNetworkMonitoring();
9597
- }
9598
- setupNetworkMonitoring() {
9599
- if (this.networkMonitor) {
9600
- this.networkSubscription = this.networkMonitor.online$.subscribe((online) => {
9601
- this.currentOnlineState = online;
9602
- });
9603
- }
9604
- }
9605
- isOnline() {
9606
- if (this.networkMonitor) {
9607
- return this.currentOnlineState;
9608
- }
9609
- if (typeof navigator !== 'undefined' && 'onLine' in navigator) {
9610
- return navigator.onLine;
9611
- }
9612
- return false;
9613
- }
9614
- async handleCachedRequest(url, requestFn, config) {
9615
- if (!this.cache || config?.useCache === false) {
9616
- const response = await requestFn();
9617
- return response.data;
9618
- }
9619
- const cacheKey = this.generateCacheKey(url);
9620
- const online = this.isOnline();
9621
- log.debug('Request:', { url, cacheKey, online });
9622
- if (online) {
9623
- try {
9624
- const response = await requestFn();
9625
- if (this.cache) {
9626
- await this.cache.set(cacheKey, response.data).catch((error) => {
9627
- log.error('Failed to cache:', error instanceof Error ? error.message : error);
9628
- });
9629
- }
9630
- return response.data;
9631
- }
9632
- catch (error) {
9633
- const cached = await this.cache.get(cacheKey).catch(() => null);
9634
- if (cached) {
9635
- log.debug('Network failed, using cache fallback');
9636
- return cached.data;
9637
- }
9638
- throw error;
9639
- }
9640
- }
9641
- else {
9642
- const cached = await this.cache.get(cacheKey).catch(() => null);
9643
- if (cached) {
9644
- log.debug('Offline, returning cached data');
9645
- return cached.data;
9646
- }
9647
- throw new Error('Offline: No cached data available');
9648
- }
9649
- }
9650
- generateCacheKey(url) {
9651
- return url;
9652
- }
9653
- async invalidateCache(pattern) {
9654
- if (!this.cache)
9655
- return;
9656
- try {
9657
- await this.cache.invalidate(pattern);
9658
- }
9659
- catch (error) {
9660
- log.error('Invalidation failed:', error instanceof Error ? error.message : error);
9661
- }
9662
- }
9663
- getCacheStatus() {
9664
- return {
9665
- available: !!this.cache,
9666
- networkMonitorAvailable: !!this.networkMonitor,
9667
- isOnline: this.isOnline(),
9668
- };
9669
- }
9670
- destroy() {
9671
- this.networkSubscription?.unsubscribe();
9672
- }
9673
- }
9674
-
9675
7164
  function transformError(error) {
9676
7165
  if (axios.isAxiosError(error)) {
9677
7166
  const response = error.response;
@@ -9850,5 +7339,5 @@ class PlatformDetector {
9850
7339
  }
9851
7340
  }
9852
7341
 
9853
- export { ACubeSDK, ACubeSDKError, ActivationRequestSchema, AddressMapper, AddressSchema, AppStateService, AuthStrategy, AuthenticationService, AxiosHttpAdapter, CacheHandler, CashRegisterCreateSchema, CashRegisterMapper, CashRegisterRepositoryImpl, CashierCreateInputSchema, CashierMapper, CashierRepositoryImpl, CertificateService, CertificateValidator, ConfigManager, DAILY_REPORT_STATUS_OPTIONS, DEFAULT_QUEUE_CONFIG, DIContainer, DI_TOKENS, DailyReportMapper, DailyReportRepositoryImpl, DailyReportStatusSchema, DailyReportsParamsSchema, EXEMPT_VAT_CODES, ErrorCategory, GOOD_OR_SERVICE_OPTIONS, GoodOrServiceSchema, JournalCloseInputSchema, JournalMapper, JournalRepositoryImpl, JwtAuthHandler, LotterySchema, LotterySecretRequestSchema, MTLSError, MTLSErrorType$1 as MTLSErrorType, MerchantCreateInputSchema, MerchantMapper, MerchantRepositoryImpl, MerchantUpdateInputSchema, MessageSchema, MtlsAuthHandler, NOTIFICATION_CODES, NOTIFICATION_LEVELS, NOTIFICATION_SCOPES, NOTIFICATION_SOURCES, NOTIFICATION_TYPES, NotificationDataBlockAtSchema, NotificationDataPemStatusSchema, NotificationListResponseSchema, NotificationMapper, NotificationMf2UnreachableSchema, NotificationPemBackOnlineSchema, NotificationPemsBlockedSchema, NotificationRepositoryImpl, NotificationSchema, NotificationScopeSchema, NotificationService, OfflineManager, OperationQueue, PEMStatusOfflineRequestSchema, PEMStatusSchema, PEM_STATUS_OPTIONS, PEM_TYPE_OPTIONS, PemCreateInputSchema, PemDataSchema, PemMapper, PemRepositoryImpl, PemStatusSchema, PendingReceiptsSchema, PlatformDetector, PointOfSaleMapper, PointOfSaleRepositoryImpl, RECEIPT_PROOF_TYPE_OPTIONS, RECEIPT_READY, RECEIPT_SENT, RECEIPT_SORT_ASCENDING, RECEIPT_SORT_DESCENDING, ReceiptInputSchema, ReceiptItemSchema, ReceiptMapper, ReceiptProofTypeSchema, ReceiptRepositoryImpl, ReceiptReturnInputSchema, ReceiptReturnItemSchema, ReceiptReturnOrVoidViaPEMInputSchema, ReceiptReturnOrVoidWithProofInputSchema, SDKFactory, SDKManager, STANDARD_VAT_RATES, SupplierCreateInputSchema, SupplierMapper, SupplierRepositoryImpl, SupplierUpdateInputSchema, SyncManager, TelemetryMapper, TelemetryMerchantSchema, TelemetryRepositoryImpl, TelemetrySchema, TelemetryService, TelemetrySoftwareSchema, TelemetrySoftwareVersionSchema, TelemetrySupplierSchema, TransmissionSchema, VAT_RATE_CODES, VAT_RATE_CODE_OPTIONS, ValidationMessages, VatRateCodeSchema, VoidReceiptInputSchema, classifyError, clearObject, clearObjectShallow, createACubeMTLSConfig, createACubeSDK, createPrefixedLogger, createACubeSDK as default, detectPlatform, extractRoles, formatDecimal, getUserFriendlyMessage, hasAnyRole, hasNonEmptyValues, hasRole, isEmpty, isTokenExpired, loadPlatformAdapters, logger, parseJwt, shouldReconfigureCertificate, shouldRetryRequest, transformError, validateInput };
7342
+ export { ACubeSDK, ACubeSDKError, ActivationRequestSchema, AddressMapper, AddressSchema, AppStateService, AuthStrategy, AuthenticationService, AxiosHttpAdapter, CashRegisterCreateSchema, CashRegisterMapper, CashRegisterRepositoryImpl, CashierCreateInputSchema, CashierMapper, CashierRepositoryImpl, CertificateService, CertificateValidator, ConfigManager, DAILY_REPORT_STATUS_OPTIONS, DIContainer, DI_TOKENS, DailyReportMapper, DailyReportRepositoryImpl, DailyReportStatusSchema, DailyReportsParamsSchema, EXEMPT_VAT_CODES, ErrorCategory, GOOD_OR_SERVICE_OPTIONS, GoodOrServiceSchema, JournalCloseInputSchema, JournalMapper, JournalRepositoryImpl, JwtAuthHandler, LotterySchema, LotterySecretRequestSchema, MTLSError, MTLSErrorType$1 as MTLSErrorType, MerchantCreateInputSchema, MerchantMapper, MerchantRepositoryImpl, MerchantUpdateInputSchema, MessageSchema, MtlsAuthHandler, NOTIFICATION_CODES, NOTIFICATION_LEVELS, NOTIFICATION_SCOPES, NOTIFICATION_SOURCES, NOTIFICATION_TYPES, NotificationDataBlockAtSchema, NotificationDataPemStatusSchema, NotificationListResponseSchema, NotificationMapper, NotificationMf2UnreachableSchema, NotificationPemBackOnlineSchema, NotificationPemsBlockedSchema, NotificationRepositoryImpl, NotificationSchema, NotificationScopeSchema, NotificationService, PEMStatusOfflineRequestSchema, PEMStatusSchema, PEM_STATUS_OPTIONS, PEM_TYPE_OPTIONS, PemCreateInputSchema, PemDataSchema, PemMapper, PemRepositoryImpl, PemStatusSchema, PendingReceiptsSchema, PlatformDetector, PointOfSaleMapper, PointOfSaleRepositoryImpl, RECEIPT_PROOF_TYPE_OPTIONS, RECEIPT_READY, RECEIPT_SENT, RECEIPT_SORT_ASCENDING, RECEIPT_SORT_DESCENDING, ReceiptInputSchema, ReceiptItemSchema, ReceiptMapper, ReceiptProofTypeSchema, ReceiptRepositoryImpl, ReceiptReturnInputSchema, ReceiptReturnItemSchema, ReceiptReturnOrVoidViaPEMInputSchema, ReceiptReturnOrVoidWithProofInputSchema, SDKFactory, SDKManager, STANDARD_VAT_RATES, SupplierCreateInputSchema, SupplierMapper, SupplierRepositoryImpl, SupplierUpdateInputSchema, TelemetryMapper, TelemetryMerchantSchema, TelemetryRepositoryImpl, TelemetrySchema, TelemetryService, TelemetrySoftwareSchema, TelemetrySoftwareVersionSchema, TelemetrySupplierSchema, TransmissionSchema, VAT_RATE_CODES, VAT_RATE_CODE_OPTIONS, ValidationMessages, VatRateCodeSchema, VoidReceiptInputSchema, classifyError, clearObject, clearObjectShallow, createACubeMTLSConfig, createACubeSDK, createPrefixedLogger, createACubeSDK as default, detectPlatform, extractRoles, formatDecimal, getUserFriendlyMessage, hasAnyRole, hasNonEmptyValues, hasRole, isEmpty, isTokenExpired, loadPlatformAdapters, logger, parseJwt, shouldReconfigureCertificate, shouldRetryRequest, transformError, validateInput };
9854
7343
  //# sourceMappingURL=index.esm.js.map