@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.cjs.js CHANGED
@@ -2135,7 +2135,7 @@ function formatDecimal(value, decimals = 2) {
2135
2135
  return num.toFixed(decimals);
2136
2136
  }
2137
2137
 
2138
- const log$h = createPrefixedLogger('AUTH-SERVICE');
2138
+ const log$b = createPrefixedLogger('AUTH-SERVICE');
2139
2139
  class AuthenticationService {
2140
2140
  get user$() {
2141
2141
  return this.userSubject.asObservable();
@@ -2157,7 +2157,7 @@ class AuthenticationService {
2157
2157
  }
2158
2158
  async login(credentials) {
2159
2159
  this.authStateSubject.next('authenticating');
2160
- log$h.info('Login attempt', {
2160
+ log$b.info('Login attempt', {
2161
2161
  authUrl: this.config.authUrl,
2162
2162
  email: credentials.email,
2163
2163
  });
@@ -2168,7 +2168,7 @@ class AuthenticationService {
2168
2168
  });
2169
2169
  const jwtPayload = parseJwt(response.data.token);
2170
2170
  const expiresAt = jwtPayload.exp * 1000;
2171
- log$h.info('Login successful', {
2171
+ log$b.info('Login successful', {
2172
2172
  authUrl: this.config.authUrl,
2173
2173
  tokenPrefix: response.data.token.substring(0, 30) + '...',
2174
2174
  expiresAt: new Date(expiresAt).toISOString(),
@@ -2197,21 +2197,21 @@ class AuthenticationService {
2197
2197
  const token = await this.tokenStorage.getAccessToken();
2198
2198
  if (!token) {
2199
2199
  // No token - clear any stale user state
2200
- log$h.debug('getCurrentUser: No token in storage');
2200
+ log$b.debug('getCurrentUser: No token in storage');
2201
2201
  if (this.userSubject.value) {
2202
2202
  this.userSubject.next(null);
2203
2203
  this.authStateSubject.next('idle');
2204
2204
  }
2205
2205
  return null;
2206
2206
  }
2207
- log$h.debug('getCurrentUser: Token found', {
2207
+ log$b.debug('getCurrentUser: Token found', {
2208
2208
  tokenPrefix: token.substring(0, 30) + '...',
2209
2209
  tokenLength: token.length,
2210
2210
  });
2211
2211
  const jwtPayload = parseJwt(token);
2212
2212
  if (isTokenExpired(jwtPayload)) {
2213
2213
  // Token expired - clear everything
2214
- log$h.warn('getCurrentUser: Token expired');
2214
+ log$b.warn('getCurrentUser: Token expired');
2215
2215
  await this.tokenStorage.clearTokens();
2216
2216
  this.userSubject.next(null);
2217
2217
  this.authStateSubject.next('idle');
@@ -2221,7 +2221,7 @@ class AuthenticationService {
2221
2221
  // Token is valid - return cached user if available
2222
2222
  const currentUser = this.userSubject.value;
2223
2223
  if (currentUser) {
2224
- log$h.debug('getCurrentUser: Returning cached user', {
2224
+ log$b.debug('getCurrentUser: Returning cached user', {
2225
2225
  email: currentUser.email,
2226
2226
  roles: currentUser.roles,
2227
2227
  });
@@ -2244,12 +2244,12 @@ class AuthenticationService {
2244
2244
  async isAuthenticated() {
2245
2245
  const token = await this.tokenStorage.getAccessToken();
2246
2246
  if (!token) {
2247
- log$h.debug('isAuthenticated: No token in storage');
2247
+ log$b.debug('isAuthenticated: No token in storage');
2248
2248
  return false;
2249
2249
  }
2250
2250
  const jwtPayload = parseJwt(token);
2251
2251
  const expired = isTokenExpired(jwtPayload);
2252
- log$h.debug('isAuthenticated: Token check', {
2252
+ log$b.debug('isAuthenticated: Token check', {
2253
2253
  hasToken: true,
2254
2254
  expired,
2255
2255
  expiresAt: new Date(jwtPayload.exp * 1000).toISOString(),
@@ -2921,7 +2921,7 @@ class ACubeSDKError extends Error {
2921
2921
  }
2922
2922
  }
2923
2923
 
2924
- const log$g = createPrefixedLogger('AUTH-STRATEGY');
2924
+ const log$a = createPrefixedLogger('AUTH-STRATEGY');
2925
2925
  class AuthStrategy {
2926
2926
  constructor(jwtHandler, mtlsHandler, userProvider, mtlsAdapter) {
2927
2927
  this.jwtHandler = jwtHandler;
@@ -2936,7 +2936,7 @@ class AuthStrategy {
2936
2936
  const platform = this.detectPlatform();
2937
2937
  const userRole = await this.getUserRole();
2938
2938
  const isReceiptEndpoint = this.isReceiptEndpoint(url);
2939
- log$g.debug('Determining auth config', {
2939
+ log$a.debug('Determining auth config', {
2940
2940
  url,
2941
2941
  method,
2942
2942
  platform,
@@ -3067,7 +3067,7 @@ class JwtAuthHandler {
3067
3067
  }
3068
3068
  }
3069
3069
 
3070
- const log$f = createPrefixedLogger('MTLS-HANDLER');
3070
+ const log$9 = createPrefixedLogger('MTLS-HANDLER');
3071
3071
  class MtlsAuthHandler {
3072
3072
  constructor(mtlsAdapter, certificatePort) {
3073
3073
  this.mtlsAdapter = mtlsAdapter;
@@ -3109,7 +3109,7 @@ class MtlsAuthHandler {
3109
3109
  async makeRequest(url, config, jwtToken) {
3110
3110
  const requestKey = this.generateRequestKey(url, config, jwtToken);
3111
3111
  if (this.pendingRequests.has(requestKey)) {
3112
- log$f.debug('Deduplicating concurrent request:', url);
3112
+ log$9.debug('Deduplicating concurrent request:', url);
3113
3113
  return this.pendingRequests.get(requestKey);
3114
3114
  }
3115
3115
  const requestPromise = this.executeRequest(url, config, jwtToken, false);
@@ -3133,10 +3133,10 @@ class MtlsAuthHandler {
3133
3133
  };
3134
3134
  if (jwtToken) {
3135
3135
  headers['Authorization'] = `Bearer ${jwtToken}`;
3136
- log$f.debug('JWT token present:', jwtToken.substring(0, 20) + '...');
3136
+ log$9.debug('JWT token present:', jwtToken.substring(0, 20) + '...');
3137
3137
  }
3138
3138
  else {
3139
- log$f.warn('No JWT token provided for mTLS request');
3139
+ log$9.warn('No JWT token provided for mTLS request');
3140
3140
  }
3141
3141
  const fullUrl = this.constructMtlsUrl(url);
3142
3142
  const mtlsConfig = {
@@ -3147,25 +3147,25 @@ class MtlsAuthHandler {
3147
3147
  timeout: config.timeout,
3148
3148
  responseType: config.responseType,
3149
3149
  };
3150
- log$f.debug('header-mtls', headers);
3151
- log$f.debug(`${config.method} ${fullUrl}`);
3150
+ log$9.debug('header-mtls', headers);
3151
+ log$9.debug(`${config.method} ${fullUrl}`);
3152
3152
  if (config.data) {
3153
- log$f.debug('Request body:', config.data);
3153
+ log$9.debug('Request body:', config.data);
3154
3154
  }
3155
3155
  try {
3156
3156
  const response = await this.mtlsAdapter.request(mtlsConfig);
3157
- log$f.debug(`Response ${response.status} from ${fullUrl}`);
3157
+ log$9.debug(`Response ${response.status} from ${fullUrl}`);
3158
3158
  if (response.data) {
3159
- log$f.debug('Response body:', response.data);
3159
+ log$9.debug('Response body:', response.data);
3160
3160
  }
3161
3161
  return response.data;
3162
3162
  }
3163
3163
  catch (error) {
3164
- log$f.error(`Response error from ${fullUrl}:`, error);
3164
+ log$9.error(`Response error from ${fullUrl}:`, error);
3165
3165
  if (error && typeof error === 'object' && 'response' in error) {
3166
3166
  const axiosError = error;
3167
3167
  if (axiosError.response?.data) {
3168
- log$f.error('Response body:', axiosError.response.data);
3168
+ log$9.error('Response body:', axiosError.response.data);
3169
3169
  }
3170
3170
  }
3171
3171
  if (isRetryAttempt) {
@@ -3175,7 +3175,7 @@ class MtlsAuthHandler {
3175
3175
  if (!shouldRetry) {
3176
3176
  throw error;
3177
3177
  }
3178
- log$f.debug('Request failed, reconfiguring certificate and retrying...');
3178
+ log$9.debug('Request failed, reconfiguring certificate and retrying...');
3179
3179
  try {
3180
3180
  await this.configureCertificate(certificate);
3181
3181
  return await this.executeRequest(url, config, jwtToken, true);
@@ -3283,1902 +3283,6 @@ class MtlsAuthHandler {
3283
3283
  }
3284
3284
  }
3285
3285
 
3286
- const DEFAULT_QUEUE_CONFIG = {
3287
- maxRetries: 3,
3288
- retryDelay: 1000,
3289
- maxRetryDelay: 30000,
3290
- backoffMultiplier: 2,
3291
- maxQueueSize: 1000,
3292
- batchSize: 10,
3293
- syncInterval: 30000,
3294
- };
3295
-
3296
- class OperationQueue {
3297
- constructor(storage, config = DEFAULT_QUEUE_CONFIG, events = {}) {
3298
- this.storage = storage;
3299
- this.config = config;
3300
- this.events = events;
3301
- this.queue = [];
3302
- this.processing = false;
3303
- this.config = { ...DEFAULT_QUEUE_CONFIG, ...config };
3304
- this.loadQueue();
3305
- if (this.config.syncInterval > 0) {
3306
- this.startAutoSync();
3307
- }
3308
- }
3309
- async addOperation(type, resource, endpoint, method, data, priority = 1) {
3310
- if (this.queue.length >= this.config.maxQueueSize) {
3311
- const lowPriorityIndex = this.queue.findIndex((op) => op.priority === 1);
3312
- if (lowPriorityIndex !== -1) {
3313
- this.queue.splice(lowPriorityIndex, 1);
3314
- }
3315
- else {
3316
- throw new Error('Queue is full');
3317
- }
3318
- }
3319
- const operation = {
3320
- id: this.generateId(),
3321
- type,
3322
- resource,
3323
- endpoint,
3324
- method,
3325
- data,
3326
- status: 'pending',
3327
- createdAt: Date.now(),
3328
- updatedAt: Date.now(),
3329
- retryCount: 0,
3330
- maxRetries: this.config.maxRetries,
3331
- priority,
3332
- };
3333
- const insertIndex = this.queue.findIndex((op) => op.priority < priority);
3334
- if (insertIndex === -1) {
3335
- this.queue.push(operation);
3336
- }
3337
- else {
3338
- this.queue.splice(insertIndex, 0, operation);
3339
- }
3340
- await this.saveQueue();
3341
- this.events.onOperationAdded?.(operation);
3342
- return operation.id;
3343
- }
3344
- getPendingOperations() {
3345
- return this.queue.filter((op) => op.status === 'pending' || op.status === 'failed');
3346
- }
3347
- getOperation(id) {
3348
- return this.queue.find((op) => op.id === id);
3349
- }
3350
- async removeOperation(id) {
3351
- const index = this.queue.findIndex((op) => op.id === id);
3352
- if (index === -1)
3353
- return false;
3354
- this.queue.splice(index, 1);
3355
- await this.saveQueue();
3356
- return true;
3357
- }
3358
- async updateOperation(id, updates) {
3359
- const operation = this.queue.find((op) => op.id === id);
3360
- if (!operation)
3361
- return false;
3362
- Object.assign(operation, { ...updates, updatedAt: Date.now() });
3363
- await this.saveQueue();
3364
- return true;
3365
- }
3366
- getStats() {
3367
- return {
3368
- total: this.queue.length,
3369
- pending: this.queue.filter((op) => op.status === 'pending').length,
3370
- processing: this.queue.filter((op) => op.status === 'processing').length,
3371
- completed: this.queue.filter((op) => op.status === 'completed').length,
3372
- failed: this.queue.filter((op) => op.status === 'failed').length,
3373
- };
3374
- }
3375
- async clearQueue() {
3376
- this.queue = [];
3377
- await this.saveQueue();
3378
- }
3379
- async clearCompleted() {
3380
- this.queue = this.queue.filter((op) => op.status !== 'completed');
3381
- await this.saveQueue();
3382
- }
3383
- async clearFailed() {
3384
- this.queue = this.queue.filter((op) => op.status !== 'failed');
3385
- await this.saveQueue();
3386
- }
3387
- async retryFailed() {
3388
- for (const operation of this.queue.filter((op) => op.status === 'failed')) {
3389
- if (operation.retryCount < operation.maxRetries) {
3390
- operation.status = 'pending';
3391
- operation.retryCount++;
3392
- operation.updatedAt = Date.now();
3393
- delete operation.error;
3394
- }
3395
- }
3396
- await this.saveQueue();
3397
- }
3398
- getNextBatch() {
3399
- return this.queue
3400
- .filter((op) => op.status === 'pending')
3401
- .sort((a, b) => b.priority - a.priority || a.createdAt - b.createdAt)
3402
- .slice(0, this.config.batchSize);
3403
- }
3404
- isEmpty() {
3405
- return this.getPendingOperations().length === 0;
3406
- }
3407
- startAutoSync() {
3408
- if (this.syncIntervalId)
3409
- return;
3410
- this.syncIntervalId = setInterval(() => {
3411
- if (!this.isEmpty() && !this.processing) {
3412
- this.events.onQueueEmpty?.();
3413
- }
3414
- }, this.config.syncInterval);
3415
- }
3416
- stopAutoSync() {
3417
- if (this.syncIntervalId) {
3418
- clearInterval(this.syncIntervalId);
3419
- this.syncIntervalId = undefined;
3420
- }
3421
- }
3422
- setProcessing(value) {
3423
- this.processing = value;
3424
- }
3425
- isCurrentlyProcessing() {
3426
- return this.processing;
3427
- }
3428
- async loadQueue() {
3429
- try {
3430
- const queueData = await this.storage.get(OperationQueue.QUEUE_KEY);
3431
- if (queueData) {
3432
- this.queue = JSON.parse(queueData);
3433
- this.queue.forEach((op) => {
3434
- if (op.status === 'processing') {
3435
- op.status = 'pending';
3436
- }
3437
- });
3438
- }
3439
- }
3440
- catch {
3441
- this.queue = [];
3442
- }
3443
- }
3444
- async saveQueue() {
3445
- try {
3446
- await this.storage.set(OperationQueue.QUEUE_KEY, JSON.stringify(this.queue));
3447
- }
3448
- catch (error) {
3449
- this.events.onError?.(new Error(`Failed to save queue: ${error}`));
3450
- }
3451
- }
3452
- generateId() {
3453
- return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
3454
- }
3455
- destroy() {
3456
- this.stopAutoSync();
3457
- }
3458
- }
3459
- OperationQueue.QUEUE_KEY = 'acube_operation_queue';
3460
-
3461
- class SyncManager {
3462
- constructor(queue, httpPort, networkMonitor, config, events = {}) {
3463
- this.queue = queue;
3464
- this.httpPort = httpPort;
3465
- this.networkMonitor = networkMonitor;
3466
- this.config = config;
3467
- this.events = events;
3468
- this.isOnline = true;
3469
- this.destroy$ = new Subject();
3470
- this.setupNetworkMonitoring();
3471
- }
3472
- setupNetworkMonitoring() {
3473
- // Subscribe to online$ to track current state
3474
- this.networkSubscription = this.networkMonitor.online$
3475
- .pipe(startWith(true), // Assume online initially
3476
- pairwise(), filter(([wasOnline, isNowOnline]) => !wasOnline && isNowOnline), takeUntil(this.destroy$))
3477
- .subscribe(() => {
3478
- // Offline → Online transition detected
3479
- this.syncPendingOperations();
3480
- });
3481
- // Track current online state
3482
- this.networkMonitor.online$.pipe(takeUntil(this.destroy$)).subscribe((online) => {
3483
- this.isOnline = online;
3484
- });
3485
- }
3486
- async syncPendingOperations() {
3487
- if (!this.isOnline) {
3488
- throw new Error('Cannot sync while offline');
3489
- }
3490
- if (this.queue.isCurrentlyProcessing()) {
3491
- throw new Error('Sync already in progress');
3492
- }
3493
- this.queue.setProcessing(true);
3494
- try {
3495
- const results = [];
3496
- let successCount = 0;
3497
- let failureCount = 0;
3498
- while (!this.queue.isEmpty()) {
3499
- const batch = this.queue.getNextBatch();
3500
- if (batch.length === 0)
3501
- break;
3502
- const batchPromises = batch.map((operation) => this.processOperation(operation));
3503
- const batchResults = await Promise.allSettled(batchPromises);
3504
- batchResults.forEach((result, index) => {
3505
- const operation = batch[index];
3506
- if (!operation)
3507
- return;
3508
- if (result.status === 'fulfilled') {
3509
- const syncResult = result.value;
3510
- results.push(syncResult);
3511
- if (syncResult.success) {
3512
- successCount++;
3513
- this.events.onOperationCompleted?.(syncResult);
3514
- }
3515
- else {
3516
- failureCount++;
3517
- this.events.onOperationFailed?.(syncResult);
3518
- }
3519
- }
3520
- else {
3521
- const syncResult = {
3522
- operation,
3523
- success: false,
3524
- error: result.reason?.message || 'Unknown error',
3525
- };
3526
- results.push(syncResult);
3527
- failureCount++;
3528
- this.events.onOperationFailed?.(syncResult);
3529
- this.queue.updateOperation(operation.id, {
3530
- status: 'failed',
3531
- error: syncResult.error,
3532
- });
3533
- }
3534
- });
3535
- if (!this.queue.isEmpty()) {
3536
- await this.delay(500);
3537
- }
3538
- }
3539
- const batchResult = {
3540
- totalOperations: results.length,
3541
- successCount,
3542
- failureCount,
3543
- results,
3544
- };
3545
- this.events.onBatchSyncCompleted?.(batchResult);
3546
- if (this.queue.isEmpty()) {
3547
- this.events.onQueueEmpty?.();
3548
- }
3549
- return batchResult;
3550
- }
3551
- finally {
3552
- this.queue.setProcessing(false);
3553
- }
3554
- }
3555
- async processOperation(operation) {
3556
- await this.queue.updateOperation(operation.id, { status: 'processing' });
3557
- try {
3558
- const response = await this.executeOperation(operation);
3559
- await this.queue.updateOperation(operation.id, { status: 'completed' });
3560
- return { operation, success: true, response };
3561
- }
3562
- catch (error) {
3563
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
3564
- if (operation.retryCount < operation.maxRetries && this.isRetryableError(error)) {
3565
- const delay = this.calculateRetryDelay(operation.retryCount);
3566
- await this.queue.updateOperation(operation.id, {
3567
- status: 'pending',
3568
- retryCount: operation.retryCount + 1,
3569
- error: errorMessage,
3570
- });
3571
- setTimeout(() => {
3572
- if (this.isOnline && !this.queue.isCurrentlyProcessing()) {
3573
- this.syncPendingOperations();
3574
- }
3575
- }, delay);
3576
- return { operation, success: false, error: `Retrying: ${errorMessage}` };
3577
- }
3578
- else {
3579
- await this.queue.updateOperation(operation.id, {
3580
- status: 'failed',
3581
- error: errorMessage,
3582
- });
3583
- return { operation, success: false, error: errorMessage };
3584
- }
3585
- }
3586
- }
3587
- async executeOperation(operation) {
3588
- const { method, endpoint, data, headers } = operation;
3589
- const config = headers ? { headers } : undefined;
3590
- switch (method) {
3591
- case 'GET':
3592
- return (await this.httpPort.get(endpoint, config)).data;
3593
- case 'POST':
3594
- return (await this.httpPort.post(endpoint, data, config)).data;
3595
- case 'PUT':
3596
- return (await this.httpPort.put(endpoint, data, config)).data;
3597
- case 'PATCH':
3598
- return (await this.httpPort.patch(endpoint, data, config)).data;
3599
- case 'DELETE':
3600
- return (await this.httpPort.delete(endpoint, config)).data;
3601
- default:
3602
- throw new Error(`Unsupported HTTP method: ${method}`);
3603
- }
3604
- }
3605
- isRetryableError(error) {
3606
- const errorObj = error;
3607
- if (errorObj.code === 'NETWORK_ERROR')
3608
- return true;
3609
- if (errorObj.statusCode && errorObj.statusCode >= 500)
3610
- return true;
3611
- if (errorObj.statusCode === 429)
3612
- return true;
3613
- const errorMessage = error?.message;
3614
- if (errorObj.code === 'ECONNABORTED' || errorMessage?.includes('timeout'))
3615
- return true;
3616
- return false;
3617
- }
3618
- calculateRetryDelay(retryCount) {
3619
- const delay = this.config.retryDelay * Math.pow(this.config.backoffMultiplier, retryCount);
3620
- return Math.min(delay, this.config.maxRetryDelay);
3621
- }
3622
- delay(ms) {
3623
- return new Promise((resolve) => setTimeout(resolve, ms));
3624
- }
3625
- isCurrentlyOnline() {
3626
- return this.isOnline;
3627
- }
3628
- async triggerSync() {
3629
- if (!this.isOnline)
3630
- return null;
3631
- if (this.queue.isEmpty()) {
3632
- return { totalOperations: 0, successCount: 0, failureCount: 0, results: [] };
3633
- }
3634
- return await this.syncPendingOperations();
3635
- }
3636
- getSyncStatus() {
3637
- return {
3638
- isOnline: this.isOnline,
3639
- isProcessing: this.queue.isCurrentlyProcessing(),
3640
- queueStats: this.queue.getStats(),
3641
- };
3642
- }
3643
- destroy() {
3644
- this.destroy$.next();
3645
- this.destroy$.complete();
3646
- this.networkSubscription?.unsubscribe();
3647
- }
3648
- }
3649
-
3650
- class OfflineManager {
3651
- get queue$() {
3652
- return this.queueSubject.asObservable();
3653
- }
3654
- get syncStatus$() {
3655
- return this.syncStatusSubject.asObservable();
3656
- }
3657
- constructor(storage, httpPort, networkMonitor, config = {}, events = {}, _cache) {
3658
- this.queueSubject = new BehaviorSubject([]);
3659
- this.syncStatusSubject = new BehaviorSubject({
3660
- isOnline: true,
3661
- isProcessing: false,
3662
- queueStats: { total: 0, pending: 0, processing: 0, completed: 0, failed: 0 },
3663
- });
3664
- this.destroy$ = new Subject();
3665
- const finalConfig = { ...DEFAULT_QUEUE_CONFIG, ...config };
3666
- const wrappedEvents = {
3667
- ...events,
3668
- onOperationAdded: (op) => {
3669
- this.updateQueueState();
3670
- events.onOperationAdded?.(op);
3671
- },
3672
- onOperationCompleted: (result) => {
3673
- this.updateQueueState();
3674
- events.onOperationCompleted?.(result);
3675
- },
3676
- onOperationFailed: (result) => {
3677
- this.updateQueueState();
3678
- events.onOperationFailed?.(result);
3679
- },
3680
- onBatchSyncCompleted: (result) => {
3681
- this.updateQueueState();
3682
- events.onBatchSyncCompleted?.(result);
3683
- },
3684
- };
3685
- this.queue = new OperationQueue(storage, finalConfig, wrappedEvents);
3686
- this.syncManager = new SyncManager(this.queue, httpPort, networkMonitor, finalConfig, wrappedEvents);
3687
- this.updateQueueState();
3688
- }
3689
- updateQueueState() {
3690
- this.queueSubject.next(this.queue.getPendingOperations());
3691
- this.syncStatusSubject.next(this.syncManager.getSyncStatus());
3692
- }
3693
- async queueOperation(type, resource, endpoint, method, data, priority = 1) {
3694
- const id = await this.queue.addOperation(type, resource, endpoint, method, data, priority);
3695
- this.updateQueueState();
3696
- return id;
3697
- }
3698
- async queueReceiptCreation(receiptData, priority = 2) {
3699
- return await this.queueOperation('CREATE', 'receipt', '/mf1/receipts', 'POST', receiptData, priority);
3700
- }
3701
- async queueReceiptVoid(voidData, priority = 3) {
3702
- return await this.queueOperation('DELETE', 'receipt', '/mf1/receipts', 'DELETE', voidData, priority);
3703
- }
3704
- async queueReceiptReturn(returnData, priority = 3) {
3705
- return await this.queueOperation('CREATE', 'receipt', '/mf1/receipts/return', 'POST', returnData, priority);
3706
- }
3707
- async queueCashierCreation(cashierData, priority = 1) {
3708
- return await this.queueOperation('CREATE', 'cashier', '/mf1/cashiers', 'POST', cashierData, priority);
3709
- }
3710
- isOnline() {
3711
- return this.syncManager.isCurrentlyOnline();
3712
- }
3713
- getStatus() {
3714
- return this.syncManager.getSyncStatus();
3715
- }
3716
- getPendingCount() {
3717
- return this.queue.getPendingOperations().length;
3718
- }
3719
- isEmpty() {
3720
- return this.queue.isEmpty();
3721
- }
3722
- async sync() {
3723
- const result = await this.syncManager.triggerSync();
3724
- this.updateQueueState();
3725
- return result;
3726
- }
3727
- async retryFailed() {
3728
- await this.queue.retryFailed();
3729
- this.updateQueueState();
3730
- if (this.isOnline()) {
3731
- await this.sync();
3732
- }
3733
- }
3734
- async clearCompleted() {
3735
- await this.queue.clearCompleted();
3736
- this.updateQueueState();
3737
- }
3738
- async clearFailed() {
3739
- await this.queue.clearFailed();
3740
- this.updateQueueState();
3741
- }
3742
- async clearAll() {
3743
- await this.queue.clearQueue();
3744
- this.updateQueueState();
3745
- }
3746
- getOperation(id) {
3747
- return this.queue.getOperation(id);
3748
- }
3749
- async removeOperation(id) {
3750
- const result = await this.queue.removeOperation(id);
3751
- this.updateQueueState();
3752
- return result;
3753
- }
3754
- getQueueStats() {
3755
- return this.queue.getStats();
3756
- }
3757
- startAutoSync() {
3758
- this.queue.startAutoSync();
3759
- }
3760
- stopAutoSync() {
3761
- this.queue.stopAutoSync();
3762
- }
3763
- destroy() {
3764
- this.destroy$.next();
3765
- this.destroy$.complete();
3766
- this.queue.destroy();
3767
- this.syncManager.destroy();
3768
- }
3769
- }
3770
-
3771
- class CompressionAdapter {
3772
- compress(data, threshold = 1024) {
3773
- const originalSize = data.length * 2;
3774
- if (originalSize < threshold) {
3775
- return {
3776
- data,
3777
- compressed: false,
3778
- originalSize,
3779
- compressedSize: originalSize,
3780
- };
3781
- }
3782
- try {
3783
- const compressed = this.compressString(data);
3784
- const compressedSize = compressed.length * 2;
3785
- if (compressedSize < originalSize) {
3786
- return {
3787
- data: compressed,
3788
- compressed: true,
3789
- originalSize,
3790
- compressedSize,
3791
- };
3792
- }
3793
- return {
3794
- data,
3795
- compressed: false,
3796
- originalSize,
3797
- compressedSize: originalSize,
3798
- };
3799
- }
3800
- catch {
3801
- return {
3802
- data,
3803
- compressed: false,
3804
- originalSize,
3805
- compressedSize: originalSize,
3806
- };
3807
- }
3808
- }
3809
- decompress(data, compressed) {
3810
- if (!compressed) {
3811
- return { data, wasCompressed: false };
3812
- }
3813
- try {
3814
- const decompressed = this.decompressString(data);
3815
- return { data: decompressed, wasCompressed: true };
3816
- }
3817
- catch {
3818
- return { data, wasCompressed: false };
3819
- }
3820
- }
3821
- estimateSavings(data) {
3822
- const repeated = data.match(/(.)\1{3,}/g);
3823
- if (!repeated)
3824
- return 0;
3825
- let savings = 0;
3826
- for (const match of repeated) {
3827
- const originalBytes = match.length * 2;
3828
- const compressedBytes = 6;
3829
- if (originalBytes > compressedBytes) {
3830
- savings += originalBytes - compressedBytes;
3831
- }
3832
- }
3833
- return Math.min(savings, data.length * 2 * 0.5);
3834
- }
3835
- compressString(input) {
3836
- let compressed = '';
3837
- let i = 0;
3838
- while (i < input.length) {
3839
- let count = 1;
3840
- const char = input[i];
3841
- while (i + count < input.length && input[i + count] === char && count < 255) {
3842
- count++;
3843
- }
3844
- if (count > 3) {
3845
- compressed += `~${count}${char}`;
3846
- }
3847
- else {
3848
- for (let j = 0; j < count; j++) {
3849
- compressed += char;
3850
- }
3851
- }
3852
- i += count;
3853
- }
3854
- return `COMP:${btoa(compressed)}`;
3855
- }
3856
- decompressString(input) {
3857
- if (!input.startsWith('COMP:')) {
3858
- return input;
3859
- }
3860
- const encodedData = input.substring(5);
3861
- if (!encodedData) {
3862
- return input;
3863
- }
3864
- const compressed = atob(encodedData);
3865
- let decompressed = '';
3866
- let i = 0;
3867
- while (i < compressed.length) {
3868
- if (compressed[i] === '~' && i + 2 < compressed.length) {
3869
- let countStr = '';
3870
- i++;
3871
- while (i < compressed.length) {
3872
- const char = compressed[i];
3873
- if (char && /\d/.test(char)) {
3874
- countStr += char;
3875
- i++;
3876
- }
3877
- else {
3878
- break;
3879
- }
3880
- }
3881
- if (countStr && i < compressed.length) {
3882
- const count = parseInt(countStr, 10);
3883
- const char = compressed[i];
3884
- for (let j = 0; j < count; j++) {
3885
- decompressed += char;
3886
- }
3887
- i++;
3888
- }
3889
- }
3890
- else {
3891
- decompressed += compressed[i];
3892
- i++;
3893
- }
3894
- }
3895
- return decompressed;
3896
- }
3897
- }
3898
- function compressData(data, threshold = 1024) {
3899
- return new CompressionAdapter().compress(data, threshold);
3900
- }
3901
- function decompressData(data, compressed) {
3902
- return new CompressionAdapter().decompress(data, compressed);
3903
- }
3904
-
3905
- const log$e = createPrefixedLogger('CACHE-RN');
3906
- /**
3907
- * React Native cache adapter using SQLite (Expo or react-native-sqlite-storage)
3908
- * Cache never expires - data persists until explicitly invalidated
3909
- */
3910
- class ReactNativeCacheAdapter {
3911
- constructor(options = {}) {
3912
- this.db = null;
3913
- this.initPromise = null;
3914
- this.isExpo = false;
3915
- this.hasCompressedColumn = false;
3916
- this.options = {
3917
- maxSize: 50 * 1024 * 1024, // 50MB
3918
- maxEntries: 10000,
3919
- compression: false,
3920
- compressionThreshold: 1024,
3921
- ...options,
3922
- };
3923
- this.initPromise = this.initialize();
3924
- }
3925
- normalizeResults(results) {
3926
- if (this.isExpo) {
3927
- const expoResults = results;
3928
- if (Array.isArray(expoResults)) {
3929
- return expoResults;
3930
- }
3931
- return expoResults.results || [];
3932
- }
3933
- else {
3934
- const rnResults = results;
3935
- const rows = rnResults.rows;
3936
- if (!rows || rows.length === 0)
3937
- return [];
3938
- const normalizedRows = [];
3939
- for (let i = 0; i < rows.length; i++) {
3940
- normalizedRows.push(rows.item(i));
3941
- }
3942
- return normalizedRows;
3943
- }
3944
- }
3945
- async initialize() {
3946
- if (this.db)
3947
- return;
3948
- try {
3949
- // Try Expo SQLite first
3950
- const ExpoSQLite = require('expo-sqlite');
3951
- this.db = await ExpoSQLite.openDatabaseAsync(ReactNativeCacheAdapter.DB_NAME);
3952
- this.isExpo = true;
3953
- await this.createTables();
3954
- }
3955
- catch (expoError) {
3956
- try {
3957
- // Fallback to react-native-sqlite-storage
3958
- const SQLite = require('react-native-sqlite-storage');
3959
- this.db = await new Promise((resolve, reject) => {
3960
- SQLite.openDatabase({
3961
- name: ReactNativeCacheAdapter.DB_NAME,
3962
- location: 'default',
3963
- }, resolve, reject);
3964
- });
3965
- this.isExpo = false;
3966
- await this.createTables();
3967
- }
3968
- catch (rnError) {
3969
- throw new Error(`Failed to initialize SQLite: Expo error: ${expoError}, RN error: ${rnError}`);
3970
- }
3971
- }
3972
- }
3973
- async createTables() {
3974
- // Create table with simplified schema (no TTL)
3975
- const createTableSQL = `
3976
- CREATE TABLE IF NOT EXISTS ${ReactNativeCacheAdapter.TABLE_NAME} (
3977
- cache_key TEXT PRIMARY KEY,
3978
- data TEXT NOT NULL,
3979
- timestamp INTEGER NOT NULL
3980
- );
3981
-
3982
- CREATE INDEX IF NOT EXISTS idx_timestamp ON ${ReactNativeCacheAdapter.TABLE_NAME}(timestamp);
3983
- `;
3984
- await this.executeSql(createTableSQL);
3985
- // Then, run migrations to add new columns if they don't exist
3986
- await this.runMigrations();
3987
- }
3988
- async runMigrations() {
3989
- log$e.debug('Running database migrations...');
3990
- try {
3991
- // Check if compressed column exists
3992
- this.hasCompressedColumn = await this.checkColumnExists('compressed');
3993
- if (!this.hasCompressedColumn) {
3994
- log$e.debug('Adding compressed column to cache table');
3995
- const addColumnSQL = `ALTER TABLE ${ReactNativeCacheAdapter.TABLE_NAME} ADD COLUMN compressed INTEGER DEFAULT 0`;
3996
- await this.executeSql(addColumnSQL);
3997
- this.hasCompressedColumn = true;
3998
- log$e.debug('Successfully added compressed column');
3999
- }
4000
- else {
4001
- log$e.debug('Compressed column already exists');
4002
- }
4003
- log$e.debug('Database migrations completed', {
4004
- hasCompressedColumn: this.hasCompressedColumn,
4005
- });
4006
- }
4007
- catch (error) {
4008
- log$e.debug('Migration failed, disabling compression features', error);
4009
- this.hasCompressedColumn = false;
4010
- // Don't throw - allow the app to continue even if migration fails
4011
- // The compressed feature will just be disabled
4012
- }
4013
- }
4014
- async checkColumnExists(columnName) {
4015
- try {
4016
- const pragmaSQL = `PRAGMA table_info(${ReactNativeCacheAdapter.TABLE_NAME})`;
4017
- const results = await this.executeSql(pragmaSQL);
4018
- const columns = this.normalizeResults(results);
4019
- log$e.debug('Table columns found', { columns: columns.map((c) => c.name) });
4020
- return columns.some((column) => column.name === columnName);
4021
- }
4022
- catch (error) {
4023
- log$e.debug('Error checking column existence', error);
4024
- return false;
4025
- }
4026
- }
4027
- async get(key) {
4028
- await this.ensureInitialized();
4029
- const sql = `SELECT * FROM ${ReactNativeCacheAdapter.TABLE_NAME} WHERE cache_key = ?`;
4030
- log$e.debug('Executing get query', { sql, key });
4031
- const results = await this.executeSql(sql, [key]);
4032
- log$e.debug('Get query results', { key, hasResults: !!results });
4033
- // Normalize results from different SQLite implementations
4034
- const rows = this.normalizeResults(results);
4035
- if (!rows || rows.length === 0) {
4036
- return null;
4037
- }
4038
- const row = rows[0];
4039
- if (!row) {
4040
- return null;
4041
- }
4042
- const isCompressed = this.hasCompressedColumn ? !!row.compressed : false;
4043
- const rawData = isCompressed ? decompressData(row.data, true).data : row.data;
4044
- return {
4045
- data: JSON.parse(rawData),
4046
- timestamp: row.timestamp,
4047
- compressed: isCompressed,
4048
- };
4049
- }
4050
- async set(key, data) {
4051
- const item = {
4052
- data,
4053
- timestamp: Date.now(),
4054
- };
4055
- log$e.debug('Setting cache item', { key });
4056
- return this.setItem(key, item);
4057
- }
4058
- async setItem(key, item) {
4059
- await this.ensureInitialized();
4060
- // Handle compression if enabled and compressed column is available
4061
- const serializedData = JSON.stringify(item.data);
4062
- let finalData = serializedData;
4063
- let isCompressed = false;
4064
- if (this.options.compression && this.options.compressionThreshold && this.hasCompressedColumn) {
4065
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4066
- finalData = compressionResult.data;
4067
- isCompressed = compressionResult.compressed;
4068
- log$e.debug('Compression result', {
4069
- key,
4070
- originalSize: compressionResult.originalSize,
4071
- compressedSize: compressionResult.compressedSize,
4072
- compressed: isCompressed,
4073
- savings: compressionResult.originalSize - compressionResult.compressedSize,
4074
- });
4075
- }
4076
- log$e.debug('Setting item with metadata', {
4077
- key,
4078
- timestamp: item.timestamp,
4079
- compressed: isCompressed,
4080
- hasCompressedColumn: this.hasCompressedColumn,
4081
- });
4082
- // Build SQL and parameters based on available columns
4083
- let sql;
4084
- let params;
4085
- if (this.hasCompressedColumn) {
4086
- sql = `
4087
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4088
- (cache_key, data, timestamp, compressed)
4089
- VALUES (?, ?, ?, ?)
4090
- `;
4091
- params = [key, finalData, item.timestamp, isCompressed ? 1 : 0];
4092
- }
4093
- else {
4094
- // Fallback for databases without compressed column
4095
- sql = `
4096
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4097
- (cache_key, data, timestamp)
4098
- VALUES (?, ?, ?)
4099
- `;
4100
- params = [key, finalData, item.timestamp];
4101
- }
4102
- log$e.debug('Executing setItem SQL', { key, paramsCount: params.length });
4103
- await this.executeSql(sql, params);
4104
- }
4105
- async setBatch(items) {
4106
- if (items.length === 0)
4107
- return;
4108
- await this.ensureInitialized();
4109
- log$e.debug('Batch setting items', { count: items.length });
4110
- if (this.isExpo) {
4111
- await this.db.withTransactionAsync(async () => {
4112
- for (const [key, item] of items) {
4113
- await this.setBatchItem(key, item);
4114
- }
4115
- });
4116
- }
4117
- else {
4118
- return new Promise((resolve, reject) => {
4119
- this.db.transaction((tx) => {
4120
- const promises = items.map(([key, item]) => this.setBatchItemRN(tx, key, item));
4121
- Promise.all(promises)
4122
- .then(() => resolve())
4123
- .catch(reject);
4124
- }, reject, () => resolve());
4125
- });
4126
- }
4127
- log$e.debug('Batch operation completed', { count: items.length });
4128
- }
4129
- async setBatchItem(key, item) {
4130
- // Handle compression if enabled and compressed column is available
4131
- const serializedData = JSON.stringify(item.data);
4132
- let finalData = serializedData;
4133
- let isCompressed = false;
4134
- if (this.options.compression && this.options.compressionThreshold && this.hasCompressedColumn) {
4135
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4136
- finalData = compressionResult.data;
4137
- isCompressed = compressionResult.compressed;
4138
- }
4139
- // Build SQL and parameters based on available columns
4140
- let sql;
4141
- let params;
4142
- if (this.hasCompressedColumn) {
4143
- sql = `
4144
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4145
- (cache_key, data, timestamp, compressed)
4146
- VALUES (?, ?, ?, ?)
4147
- `;
4148
- params = [key, finalData, item.timestamp, isCompressed ? 1 : 0];
4149
- }
4150
- else {
4151
- sql = `
4152
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4153
- (cache_key, data, timestamp)
4154
- VALUES (?, ?, ?)
4155
- `;
4156
- params = [key, finalData, item.timestamp];
4157
- }
4158
- await this.db.runAsync(sql, params);
4159
- }
4160
- async setBatchItemRN(tx, key, item) {
4161
- // Handle compression if enabled and compressed column is available
4162
- const serializedData = JSON.stringify(item.data);
4163
- let finalData = serializedData;
4164
- let isCompressed = false;
4165
- if (this.options.compression && this.options.compressionThreshold && this.hasCompressedColumn) {
4166
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4167
- finalData = compressionResult.data;
4168
- isCompressed = compressionResult.compressed;
4169
- }
4170
- // Build SQL and parameters based on available columns
4171
- let sql;
4172
- let params;
4173
- if (this.hasCompressedColumn) {
4174
- sql = `
4175
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4176
- (cache_key, data, timestamp, compressed)
4177
- VALUES (?, ?, ?, ?)
4178
- `;
4179
- params = [key, finalData, item.timestamp, isCompressed ? 1 : 0];
4180
- }
4181
- else {
4182
- sql = `
4183
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4184
- (cache_key, data, timestamp)
4185
- VALUES (?, ?, ?)
4186
- `;
4187
- params = [key, finalData, item.timestamp];
4188
- }
4189
- return new Promise((resolve, reject) => {
4190
- tx.executeSql(sql, params, () => resolve(), (_, error) => {
4191
- reject(error);
4192
- return false;
4193
- });
4194
- });
4195
- }
4196
- async invalidate(pattern) {
4197
- await this.ensureInitialized();
4198
- const keys = await this.getKeys(pattern);
4199
- if (keys.length === 0)
4200
- return;
4201
- const placeholders = keys.map(() => '?').join(',');
4202
- const sql = `DELETE FROM ${ReactNativeCacheAdapter.TABLE_NAME} WHERE cache_key IN (${placeholders})`;
4203
- await this.executeSql(sql, keys);
4204
- }
4205
- async clear() {
4206
- await this.ensureInitialized();
4207
- const sql = `DELETE FROM ${ReactNativeCacheAdapter.TABLE_NAME}`;
4208
- await this.executeSql(sql);
4209
- }
4210
- async getSize() {
4211
- await this.ensureInitialized();
4212
- const sql = `
4213
- SELECT
4214
- COUNT(*) as entries,
4215
- SUM(LENGTH(data)) as bytes
4216
- FROM ${ReactNativeCacheAdapter.TABLE_NAME}
4217
- `;
4218
- const results = await this.executeSql(sql);
4219
- const rows = this.normalizeResults(results);
4220
- const row = rows[0] || { entries: 0, bytes: 0 };
4221
- return {
4222
- entries: row.entries || 0,
4223
- bytes: (row.bytes || 0) * 2,
4224
- lastCleanup: Date.now(),
4225
- };
4226
- }
4227
- async cleanup() {
4228
- // No cleanup needed - cache never expires
4229
- return 0;
4230
- }
4231
- async getKeys(pattern) {
4232
- await this.ensureInitialized();
4233
- let sql = `SELECT cache_key FROM ${ReactNativeCacheAdapter.TABLE_NAME}`;
4234
- const params = [];
4235
- if (pattern) {
4236
- // Simple pattern matching with LIKE
4237
- const likePattern = pattern.replace(/\*/g, '%').replace(/\?/g, '_');
4238
- sql += ' WHERE cache_key LIKE ?';
4239
- params.push(likePattern);
4240
- }
4241
- const results = await this.executeSql(sql, params);
4242
- const keys = [];
4243
- const rows = this.normalizeResults(results);
4244
- for (const row of rows) {
4245
- keys.push(row.cache_key);
4246
- }
4247
- return keys;
4248
- }
4249
- async executeSql(sql, params = []) {
4250
- if (this.isExpo) {
4251
- const expoDB = this.db;
4252
- if (sql.toLowerCase().includes('select') || sql.toLowerCase().includes('pragma')) {
4253
- const result = await expoDB.getAllAsync(sql, params);
4254
- return Array.isArray(result) ? { results: result } : result;
4255
- }
4256
- else {
4257
- return await expoDB.runAsync(sql, params);
4258
- }
4259
- }
4260
- else {
4261
- // react-native-sqlite-storage
4262
- return new Promise((resolve, reject) => {
4263
- this.db.transaction((tx) => {
4264
- tx.executeSql(sql, params, (_, results) => resolve(results), (_, error) => {
4265
- reject(error);
4266
- return false;
4267
- });
4268
- });
4269
- });
4270
- }
4271
- }
4272
- async ensureInitialized() {
4273
- if (!this.initPromise) {
4274
- this.initPromise = this.initialize();
4275
- }
4276
- await this.initPromise;
4277
- }
4278
- }
4279
- ReactNativeCacheAdapter.DB_NAME = 'acube_cache.db';
4280
- ReactNativeCacheAdapter.TABLE_NAME = 'cache_entries';
4281
- /**
4282
- * Memory-based fallback cache adapter for environments without SQLite
4283
- * Cache never expires - data persists until explicitly invalidated
4284
- */
4285
- class MemoryCacheAdapter {
4286
- constructor(options = {}) {
4287
- this.cache = new Map();
4288
- this.totalBytes = 0;
4289
- this.options = {
4290
- maxEntries: 1000,
4291
- ...options,
4292
- };
4293
- }
4294
- calculateItemSize(key, item) {
4295
- // Calculate rough size estimation for memory usage
4296
- const keySize = key.length * 2; // UTF-16 estimation
4297
- const itemSize = JSON.stringify(item).length * 2; // UTF-16 estimation
4298
- return keySize + itemSize;
4299
- }
4300
- async get(key) {
4301
- log$e.debug('Getting cache item', { key });
4302
- const item = this.cache.get(key);
4303
- if (!item) {
4304
- log$e.debug('Cache miss', { key });
4305
- return null;
4306
- }
4307
- // Handle decompression if needed
4308
- const isCompressed = !!item.compressed;
4309
- let finalData = item.data;
4310
- if (isCompressed) {
4311
- const decompressed = decompressData(item.data, true);
4312
- finalData = JSON.parse(decompressed.data);
4313
- }
4314
- log$e.debug('Cache hit', { key, compressed: isCompressed });
4315
- return {
4316
- ...item,
4317
- data: finalData,
4318
- compressed: isCompressed,
4319
- };
4320
- }
4321
- async set(key, data) {
4322
- log$e.debug('Setting cache item', { key });
4323
- // Handle compression if enabled
4324
- let finalData = data;
4325
- let isCompressed = false;
4326
- if (this.options.compression && this.options.compressionThreshold) {
4327
- const serializedData = JSON.stringify(data);
4328
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4329
- if (compressionResult.compressed) {
4330
- finalData = compressionResult.data;
4331
- isCompressed = true;
4332
- log$e.debug('Compression result', {
4333
- key,
4334
- originalSize: compressionResult.originalSize,
4335
- compressedSize: compressionResult.compressedSize,
4336
- savings: compressionResult.originalSize - compressionResult.compressedSize,
4337
- });
4338
- }
4339
- }
4340
- const item = {
4341
- data: finalData,
4342
- timestamp: Date.now(),
4343
- compressed: isCompressed,
4344
- };
4345
- return this.setItem(key, item);
4346
- }
4347
- async setItem(key, item) {
4348
- // Calculate size of new item
4349
- const newItemSize = this.calculateItemSize(key, item);
4350
- // If item already exists, subtract old size
4351
- if (this.cache.has(key)) {
4352
- const oldItem = this.cache.get(key);
4353
- const oldItemSize = this.calculateItemSize(key, oldItem);
4354
- this.totalBytes -= oldItemSize;
4355
- }
4356
- // Enforce max entries limit
4357
- if (this.cache.size >= (this.options.maxEntries || 1000) && !this.cache.has(key)) {
4358
- const oldestKey = this.cache.keys().next().value;
4359
- if (oldestKey) {
4360
- const oldestItem = this.cache.get(oldestKey);
4361
- const oldestItemSize = this.calculateItemSize(oldestKey, oldestItem);
4362
- this.totalBytes -= oldestItemSize;
4363
- this.cache.delete(oldestKey);
4364
- log$e.debug('Removed oldest item for capacity', { oldestKey, freedBytes: oldestItemSize });
4365
- }
4366
- }
4367
- // Set new item and update total size
4368
- this.cache.set(key, item);
4369
- this.totalBytes += newItemSize;
4370
- log$e.debug('Updated cache size', {
4371
- entries: this.cache.size,
4372
- totalBytes: this.totalBytes,
4373
- newItemSize,
4374
- });
4375
- }
4376
- async setBatch(items) {
4377
- if (items.length === 0)
4378
- return;
4379
- log$e.debug('Batch setting items', { count: items.length });
4380
- let totalNewBytes = 0;
4381
- let totalOldBytes = 0;
4382
- const itemsToRemove = [];
4383
- // First pass: calculate size changes and identify capacity issues
4384
- for (const [key, item] of items) {
4385
- const newItemSize = this.calculateItemSize(key, item);
4386
- totalNewBytes += newItemSize;
4387
- // If item already exists, track old size for removal
4388
- if (this.cache.has(key)) {
4389
- const oldItem = this.cache.get(key);
4390
- const oldItemSize = this.calculateItemSize(key, oldItem);
4391
- totalOldBytes += oldItemSize;
4392
- }
4393
- }
4394
- // Handle capacity limits - remove oldest items if needed
4395
- const projectedEntries = this.cache.size + items.filter(([key]) => !this.cache.has(key)).length;
4396
- const maxEntries = this.options.maxEntries || 1000;
4397
- if (projectedEntries > maxEntries) {
4398
- const entriesToRemove = projectedEntries - maxEntries;
4399
- const oldestKeys = Array.from(this.cache.keys()).slice(0, entriesToRemove);
4400
- for (const oldKey of oldestKeys) {
4401
- const oldItem = this.cache.get(oldKey);
4402
- const oldItemSize = this.calculateItemSize(oldKey, oldItem);
4403
- this.totalBytes -= oldItemSize;
4404
- this.cache.delete(oldKey);
4405
- itemsToRemove.push(oldKey);
4406
- }
4407
- if (itemsToRemove.length > 0) {
4408
- log$e.debug('Removed items for batch capacity', {
4409
- removedCount: itemsToRemove.length,
4410
- removedKeys: itemsToRemove,
4411
- });
4412
- }
4413
- }
4414
- // Update total bytes accounting
4415
- this.totalBytes = this.totalBytes - totalOldBytes + totalNewBytes;
4416
- // Second pass: set all items
4417
- for (const [key, item] of items) {
4418
- this.cache.set(key, item);
4419
- }
4420
- log$e.debug('Batch operation completed', {
4421
- count: items.length,
4422
- totalBytes: this.totalBytes,
4423
- entries: this.cache.size,
4424
- bytesAdded: totalNewBytes - totalOldBytes,
4425
- });
4426
- }
4427
- async invalidate(pattern) {
4428
- const regex = this.patternToRegex(pattern);
4429
- let removed = 0;
4430
- let bytesFreed = 0;
4431
- for (const key of this.cache.keys()) {
4432
- if (regex.test(key)) {
4433
- const item = this.cache.get(key);
4434
- const itemSize = this.calculateItemSize(key, item);
4435
- this.cache.delete(key);
4436
- this.totalBytes -= itemSize;
4437
- bytesFreed += itemSize;
4438
- removed++;
4439
- }
4440
- }
4441
- if (removed > 0) {
4442
- log$e.debug('Invalidation completed', {
4443
- pattern,
4444
- entriesRemoved: removed,
4445
- bytesFreed,
4446
- remainingEntries: this.cache.size,
4447
- remainingBytes: this.totalBytes,
4448
- });
4449
- }
4450
- }
4451
- async clear() {
4452
- this.cache.clear();
4453
- this.totalBytes = 0;
4454
- log$e.debug('Cache cleared', { entries: 0, bytes: 0 });
4455
- }
4456
- async getSize() {
4457
- return {
4458
- entries: this.cache.size,
4459
- bytes: this.totalBytes,
4460
- lastCleanup: Date.now(),
4461
- };
4462
- }
4463
- async cleanup() {
4464
- // No cleanup needed - cache never expires
4465
- return 0;
4466
- }
4467
- async getKeys(pattern) {
4468
- const keys = Array.from(this.cache.keys());
4469
- if (!pattern)
4470
- return keys;
4471
- const regex = this.patternToRegex(pattern);
4472
- return keys.filter((key) => regex.test(key));
4473
- }
4474
- patternToRegex(pattern) {
4475
- const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&');
4476
- const regexPattern = escaped.replace(/\\\*/g, '.*').replace(/\\\?/g, '.');
4477
- return new RegExp(`^${regexPattern}$`);
4478
- }
4479
- }
4480
-
4481
- const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);
4482
-
4483
- let idbProxyableTypes;
4484
- let cursorAdvanceMethods;
4485
- // This is a function to prevent it throwing up in node environments.
4486
- function getIdbProxyableTypes() {
4487
- return (idbProxyableTypes ||
4488
- (idbProxyableTypes = [
4489
- IDBDatabase,
4490
- IDBObjectStore,
4491
- IDBIndex,
4492
- IDBCursor,
4493
- IDBTransaction,
4494
- ]));
4495
- }
4496
- // This is a function to prevent it throwing up in node environments.
4497
- function getCursorAdvanceMethods() {
4498
- return (cursorAdvanceMethods ||
4499
- (cursorAdvanceMethods = [
4500
- IDBCursor.prototype.advance,
4501
- IDBCursor.prototype.continue,
4502
- IDBCursor.prototype.continuePrimaryKey,
4503
- ]));
4504
- }
4505
- const transactionDoneMap = new WeakMap();
4506
- const transformCache = new WeakMap();
4507
- const reverseTransformCache = new WeakMap();
4508
- function promisifyRequest(request) {
4509
- const promise = new Promise((resolve, reject) => {
4510
- const unlisten = () => {
4511
- request.removeEventListener('success', success);
4512
- request.removeEventListener('error', error);
4513
- };
4514
- const success = () => {
4515
- resolve(wrap(request.result));
4516
- unlisten();
4517
- };
4518
- const error = () => {
4519
- reject(request.error);
4520
- unlisten();
4521
- };
4522
- request.addEventListener('success', success);
4523
- request.addEventListener('error', error);
4524
- });
4525
- // This mapping exists in reverseTransformCache but doesn't exist in transformCache. This
4526
- // is because we create many promises from a single IDBRequest.
4527
- reverseTransformCache.set(promise, request);
4528
- return promise;
4529
- }
4530
- function cacheDonePromiseForTransaction(tx) {
4531
- // Early bail if we've already created a done promise for this transaction.
4532
- if (transactionDoneMap.has(tx))
4533
- return;
4534
- const done = new Promise((resolve, reject) => {
4535
- const unlisten = () => {
4536
- tx.removeEventListener('complete', complete);
4537
- tx.removeEventListener('error', error);
4538
- tx.removeEventListener('abort', error);
4539
- };
4540
- const complete = () => {
4541
- resolve();
4542
- unlisten();
4543
- };
4544
- const error = () => {
4545
- reject(tx.error || new DOMException('AbortError', 'AbortError'));
4546
- unlisten();
4547
- };
4548
- tx.addEventListener('complete', complete);
4549
- tx.addEventListener('error', error);
4550
- tx.addEventListener('abort', error);
4551
- });
4552
- // Cache it for later retrieval.
4553
- transactionDoneMap.set(tx, done);
4554
- }
4555
- let idbProxyTraps = {
4556
- get(target, prop, receiver) {
4557
- if (target instanceof IDBTransaction) {
4558
- // Special handling for transaction.done.
4559
- if (prop === 'done')
4560
- return transactionDoneMap.get(target);
4561
- // Make tx.store return the only store in the transaction, or undefined if there are many.
4562
- if (prop === 'store') {
4563
- return receiver.objectStoreNames[1]
4564
- ? undefined
4565
- : receiver.objectStore(receiver.objectStoreNames[0]);
4566
- }
4567
- }
4568
- // Else transform whatever we get back.
4569
- return wrap(target[prop]);
4570
- },
4571
- set(target, prop, value) {
4572
- target[prop] = value;
4573
- return true;
4574
- },
4575
- has(target, prop) {
4576
- if (target instanceof IDBTransaction &&
4577
- (prop === 'done' || prop === 'store')) {
4578
- return true;
4579
- }
4580
- return prop in target;
4581
- },
4582
- };
4583
- function replaceTraps(callback) {
4584
- idbProxyTraps = callback(idbProxyTraps);
4585
- }
4586
- function wrapFunction(func) {
4587
- // Due to expected object equality (which is enforced by the caching in `wrap`), we
4588
- // only create one new func per func.
4589
- // Cursor methods are special, as the behaviour is a little more different to standard IDB. In
4590
- // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the
4591
- // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense
4592
- // with real promises, so each advance methods returns a new promise for the cursor object, or
4593
- // undefined if the end of the cursor has been reached.
4594
- if (getCursorAdvanceMethods().includes(func)) {
4595
- return function (...args) {
4596
- // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
4597
- // the original object.
4598
- func.apply(unwrap(this), args);
4599
- return wrap(this.request);
4600
- };
4601
- }
4602
- return function (...args) {
4603
- // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
4604
- // the original object.
4605
- return wrap(func.apply(unwrap(this), args));
4606
- };
4607
- }
4608
- function transformCachableValue(value) {
4609
- if (typeof value === 'function')
4610
- return wrapFunction(value);
4611
- // This doesn't return, it just creates a 'done' promise for the transaction,
4612
- // which is later returned for transaction.done (see idbObjectHandler).
4613
- if (value instanceof IDBTransaction)
4614
- cacheDonePromiseForTransaction(value);
4615
- if (instanceOfAny(value, getIdbProxyableTypes()))
4616
- return new Proxy(value, idbProxyTraps);
4617
- // Return the same value back if we're not going to transform it.
4618
- return value;
4619
- }
4620
- function wrap(value) {
4621
- // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because
4622
- // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.
4623
- if (value instanceof IDBRequest)
4624
- return promisifyRequest(value);
4625
- // If we've already transformed this value before, reuse the transformed value.
4626
- // This is faster, but it also provides object equality.
4627
- if (transformCache.has(value))
4628
- return transformCache.get(value);
4629
- const newValue = transformCachableValue(value);
4630
- // Not all types are transformed.
4631
- // These may be primitive types, so they can't be WeakMap keys.
4632
- if (newValue !== value) {
4633
- transformCache.set(value, newValue);
4634
- reverseTransformCache.set(newValue, value);
4635
- }
4636
- return newValue;
4637
- }
4638
- const unwrap = (value) => reverseTransformCache.get(value);
4639
-
4640
- /**
4641
- * Open a database.
4642
- *
4643
- * @param name Name of the database.
4644
- * @param version Schema version.
4645
- * @param callbacks Additional callbacks.
4646
- */
4647
- function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {
4648
- const request = indexedDB.open(name, version);
4649
- const openPromise = wrap(request);
4650
- if (upgrade) {
4651
- request.addEventListener('upgradeneeded', (event) => {
4652
- upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
4653
- });
4654
- }
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.newVersion, event));
4659
- }
4660
- openPromise
4661
- .then((db) => {
4662
- if (terminated)
4663
- db.addEventListener('close', () => terminated());
4664
- if (blocking) {
4665
- db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));
4666
- }
4667
- })
4668
- .catch(() => { });
4669
- return openPromise;
4670
- }
4671
- /**
4672
- * Delete a database.
4673
- *
4674
- * @param name Name of the database.
4675
- */
4676
- function deleteDB(name, { blocked } = {}) {
4677
- const request = indexedDB.deleteDatabase(name);
4678
- if (blocked) {
4679
- request.addEventListener('blocked', (event) => blocked(
4680
- // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
4681
- event.oldVersion, event));
4682
- }
4683
- return wrap(request).then(() => undefined);
4684
- }
4685
-
4686
- const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];
4687
- const writeMethods = ['put', 'add', 'delete', 'clear'];
4688
- const cachedMethods = new Map();
4689
- function getMethod(target, prop) {
4690
- if (!(target instanceof IDBDatabase &&
4691
- !(prop in target) &&
4692
- typeof prop === 'string')) {
4693
- return;
4694
- }
4695
- if (cachedMethods.get(prop))
4696
- return cachedMethods.get(prop);
4697
- const targetFuncName = prop.replace(/FromIndex$/, '');
4698
- const useIndex = prop !== targetFuncName;
4699
- const isWrite = writeMethods.includes(targetFuncName);
4700
- if (
4701
- // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.
4702
- !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||
4703
- !(isWrite || readMethods.includes(targetFuncName))) {
4704
- return;
4705
- }
4706
- const method = async function (storeName, ...args) {
4707
- // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(
4708
- const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');
4709
- let target = tx.store;
4710
- if (useIndex)
4711
- target = target.index(args.shift());
4712
- // Must reject if op rejects.
4713
- // If it's a write operation, must reject if tx.done rejects.
4714
- // Must reject with op rejection first.
4715
- // Must resolve with op value.
4716
- // Must handle both promises (no unhandled rejections)
4717
- return (await Promise.all([
4718
- target[targetFuncName](...args),
4719
- isWrite && tx.done,
4720
- ]))[0];
4721
- };
4722
- cachedMethods.set(prop, method);
4723
- return method;
4724
- }
4725
- replaceTraps((oldTraps) => ({
4726
- ...oldTraps,
4727
- get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),
4728
- has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),
4729
- }));
4730
-
4731
- const advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];
4732
- const methodMap = {};
4733
- const advanceResults = new WeakMap();
4734
- const ittrProxiedCursorToOriginalProxy = new WeakMap();
4735
- const cursorIteratorTraps = {
4736
- get(target, prop) {
4737
- if (!advanceMethodProps.includes(prop))
4738
- return target[prop];
4739
- let cachedFunc = methodMap[prop];
4740
- if (!cachedFunc) {
4741
- cachedFunc = methodMap[prop] = function (...args) {
4742
- advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));
4743
- };
4744
- }
4745
- return cachedFunc;
4746
- },
4747
- };
4748
- async function* iterate(...args) {
4749
- // tslint:disable-next-line:no-this-assignment
4750
- let cursor = this;
4751
- if (!(cursor instanceof IDBCursor)) {
4752
- cursor = await cursor.openCursor(...args);
4753
- }
4754
- if (!cursor)
4755
- return;
4756
- cursor = cursor;
4757
- const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
4758
- ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
4759
- // Map this double-proxy back to the original, so other cursor methods work.
4760
- reverseTransformCache.set(proxiedCursor, unwrap(cursor));
4761
- while (cursor) {
4762
- yield proxiedCursor;
4763
- // If one of the advancing methods was not called, call continue().
4764
- cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
4765
- advanceResults.delete(proxiedCursor);
4766
- }
4767
- }
4768
- function isIteratorProp(target, prop) {
4769
- return ((prop === Symbol.asyncIterator &&
4770
- instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||
4771
- (prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore])));
4772
- }
4773
- replaceTraps((oldTraps) => ({
4774
- ...oldTraps,
4775
- get(target, prop, receiver) {
4776
- if (isIteratorProp(target, prop))
4777
- return iterate;
4778
- return oldTraps.get(target, prop, receiver);
4779
- },
4780
- has(target, prop) {
4781
- return isIteratorProp(target, prop) || oldTraps.has(target, prop);
4782
- },
4783
- }));
4784
-
4785
- const log$d = createPrefixedLogger('CACHE-WEB');
4786
- /**
4787
- * Web cache adapter using IndexedDB with automatic error recovery
4788
- * Cache never expires - data persists until explicitly invalidated
4789
- */
4790
- class WebCacheAdapter {
4791
- constructor(options = {}) {
4792
- this.db = null;
4793
- this.initPromise = null;
4794
- this.retryCount = 0;
4795
- this.maxRetries = 3;
4796
- this.options = {
4797
- maxSize: 50 * 1024 * 1024, // 50MB
4798
- maxEntries: 10000,
4799
- compression: false,
4800
- compressionThreshold: 1024,
4801
- ...options,
4802
- };
4803
- this.initPromise = this.initialize();
4804
- }
4805
- async initialize() {
4806
- if (this.db)
4807
- return;
4808
- log$d.debug('Initializing IndexedDB cache', {
4809
- dbName: WebCacheAdapter.DB_NAME,
4810
- version: WebCacheAdapter.DB_VERSION,
4811
- });
4812
- try {
4813
- this.db = await this.openDatabase();
4814
- log$d.debug('IndexedDB cache initialized successfully');
4815
- this.retryCount = 0; // Reset retry count on success
4816
- }
4817
- catch (error) {
4818
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
4819
- log$d.debug('Failed to initialize IndexedDB', { error: errorMessage });
4820
- // Check if this is a version conflict error
4821
- if (this.isVersionConflictError(errorMessage)) {
4822
- await this.handleVersionConflict();
4823
- }
4824
- else {
4825
- throw new Error(`Failed to initialize IndexedDB: ${errorMessage}`);
4826
- }
4827
- }
4828
- }
4829
- async openDatabase() {
4830
- return await openDB(WebCacheAdapter.DB_NAME, WebCacheAdapter.DB_VERSION, {
4831
- upgrade: (db, oldVersion, newVersion, transaction) => {
4832
- log$d.debug('Database upgrade needed', { oldVersion, newVersion });
4833
- this.handleUpgrade(db, oldVersion, newVersion, transaction);
4834
- },
4835
- blocked: () => {
4836
- log$d.debug('Database blocked - another tab may be open');
4837
- },
4838
- blocking: () => {
4839
- log$d.debug('Database blocking - will close connection');
4840
- if (this.db) {
4841
- this.db.close();
4842
- this.db = null;
4843
- }
4844
- },
4845
- terminated: () => {
4846
- log$d.debug('Database connection terminated unexpectedly');
4847
- this.db = null;
4848
- },
4849
- });
4850
- }
4851
- handleUpgrade(db, oldVersion, newVersion, transaction) {
4852
- log$d.debug('Handling database upgrade', { oldVersion, newVersion });
4853
- // Create cache store if it doesn't exist (initial setup)
4854
- if (!db.objectStoreNames.contains(WebCacheAdapter.STORE_NAME)) {
4855
- const store = db.createObjectStore(WebCacheAdapter.STORE_NAME, { keyPath: 'key' });
4856
- store.createIndex('timestamp', 'timestamp', { unique: false });
4857
- log$d.debug('Created cache store and timestamp index');
4858
- }
4859
- // Handle migration from version 1 to 2
4860
- if (oldVersion < 2) {
4861
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
4862
- // Remove unused indexes from simplified cache structure
4863
- const indexesToRemove = ['tags', 'source', 'syncStatus'];
4864
- indexesToRemove.forEach((indexName) => {
4865
- try {
4866
- if (store.indexNames.contains(indexName)) {
4867
- store.deleteIndex(indexName);
4868
- log$d.debug(`Removed unused index: ${indexName}`);
4869
- }
4870
- }
4871
- catch (error) {
4872
- // Ignore errors if indexes don't exist
4873
- log$d.debug(`Warning: Could not remove index ${indexName}`, error);
4874
- }
4875
- });
4876
- }
4877
- log$d.debug('Database upgrade completed');
4878
- }
4879
- isVersionConflictError(errorMessage) {
4880
- return (errorMessage.includes('less than the existing version') ||
4881
- errorMessage.includes('version conflict') ||
4882
- errorMessage.includes('VersionError'));
4883
- }
4884
- async handleVersionConflict() {
4885
- log$d.debug('Handling version conflict, attempting recovery...');
4886
- if (this.retryCount >= this.maxRetries) {
4887
- throw new Error('Failed to resolve IndexedDB version conflict after multiple attempts');
4888
- }
4889
- this.retryCount++;
4890
- try {
4891
- // Close any existing connection
4892
- if (this.db) {
4893
- this.db.close();
4894
- this.db = null;
4895
- }
4896
- // Delete the problematic database
4897
- log$d.debug('Deleting problematic database to resolve version conflict');
4898
- await deleteDB(WebCacheAdapter.DB_NAME);
4899
- // Wait a bit for the deletion to complete
4900
- await new Promise((resolve) => setTimeout(resolve, 200));
4901
- // Try to open the database again
4902
- log$d.debug(`Retrying database initialization (attempt ${this.retryCount}/${this.maxRetries})`);
4903
- this.db = await this.openDatabase();
4904
- log$d.debug('Successfully recovered from version conflict');
4905
- this.retryCount = 0; // Reset retry count on success
4906
- }
4907
- catch (retryError) {
4908
- const retryErrorMessage = retryError instanceof Error ? retryError.message : 'Unknown error';
4909
- log$d.debug('Recovery attempt failed', { attempt: this.retryCount, error: retryErrorMessage });
4910
- if (this.retryCount < this.maxRetries) {
4911
- // Try again
4912
- await this.handleVersionConflict();
4913
- }
4914
- else {
4915
- throw new Error(`Failed to recover from IndexedDB version conflict: ${retryErrorMessage}`);
4916
- }
4917
- }
4918
- }
4919
- async get(key) {
4920
- await this.ensureInitialized();
4921
- log$d.debug('Getting cache item', { key });
4922
- try {
4923
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readonly');
4924
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
4925
- const result = await store.get(key);
4926
- if (!result) {
4927
- return null;
4928
- }
4929
- const item = result;
4930
- // Handle decompression if needed
4931
- const isCompressed = !!item.compressed;
4932
- let finalData;
4933
- if (isCompressed) {
4934
- const decompressed = decompressData(item.data, true);
4935
- finalData = JSON.parse(decompressed.data);
4936
- }
4937
- else {
4938
- finalData = item.data;
4939
- }
4940
- return {
4941
- data: finalData,
4942
- timestamp: item.timestamp,
4943
- compressed: isCompressed,
4944
- };
4945
- }
4946
- catch (error) {
4947
- log$d.debug('Error getting cache item', { key, error });
4948
- return null; // Return null on error instead of throwing
4949
- }
4950
- }
4951
- async set(key, data) {
4952
- const item = {
4953
- data,
4954
- timestamp: Date.now(),
4955
- };
4956
- return this.setItem(key, item);
4957
- }
4958
- async setItem(key, item) {
4959
- await this.ensureInitialized();
4960
- // Handle compression if enabled
4961
- let finalData = item.data;
4962
- let isCompressed = false;
4963
- if (this.options.compression && this.options.compressionThreshold) {
4964
- const serializedData = JSON.stringify(item.data);
4965
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4966
- if (compressionResult.compressed) {
4967
- finalData = compressionResult.data;
4968
- isCompressed = true;
4969
- log$d.debug('Compression result', {
4970
- key,
4971
- originalSize: compressionResult.originalSize,
4972
- compressedSize: compressionResult.compressedSize,
4973
- compressed: isCompressed,
4974
- savings: compressionResult.originalSize - compressionResult.compressedSize,
4975
- });
4976
- }
4977
- }
4978
- log$d.debug('Setting cache item', { key, timestamp: item.timestamp, compressed: isCompressed });
4979
- const storedItem = {
4980
- key,
4981
- data: finalData,
4982
- timestamp: item.timestamp,
4983
- compressed: isCompressed,
4984
- };
4985
- try {
4986
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readwrite');
4987
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
4988
- await store.put(storedItem);
4989
- }
4990
- catch (error) {
4991
- log$d.debug('Error setting cache item', { key, error });
4992
- // Silently fail for cache writes
4993
- }
4994
- }
4995
- async setBatch(items) {
4996
- if (items.length === 0)
4997
- return;
4998
- await this.ensureInitialized();
4999
- log$d.debug('Batch setting items', { count: items.length });
5000
- try {
5001
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readwrite');
5002
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5003
- // Process all items in the transaction
5004
- const promises = items.map(([key, item]) => {
5005
- const storedItem = this.prepareBatchItem(key, item);
5006
- return store.put(storedItem);
5007
- });
5008
- await Promise.all(promises);
5009
- log$d.debug('Batch operation completed', { count: items.length });
5010
- }
5011
- catch (error) {
5012
- log$d.debug('Error in batch operation', { count: items.length, error });
5013
- // Silently fail for batch writes
5014
- }
5015
- }
5016
- prepareBatchItem(key, item) {
5017
- // Handle compression if enabled (same logic as setItem)
5018
- let finalData = item.data;
5019
- let isCompressed = false;
5020
- if (this.options.compression && this.options.compressionThreshold) {
5021
- const serializedData = JSON.stringify(item.data);
5022
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
5023
- if (compressionResult.compressed) {
5024
- finalData = compressionResult.data;
5025
- isCompressed = true;
5026
- }
5027
- }
5028
- return {
5029
- key,
5030
- data: finalData,
5031
- timestamp: item.timestamp,
5032
- compressed: isCompressed,
5033
- };
5034
- }
5035
- async invalidate(pattern) {
5036
- await this.ensureInitialized();
5037
- const keys = await this.getKeys(pattern);
5038
- const deletePromises = keys.map((key) => this.delete(key));
5039
- await Promise.all(deletePromises);
5040
- }
5041
- async clear() {
5042
- await this.ensureInitialized();
5043
- try {
5044
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readwrite');
5045
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5046
- await store.clear();
5047
- log$d.debug('Cache cleared successfully');
5048
- }
5049
- catch (error) {
5050
- log$d.debug('Error clearing cache', error);
5051
- // Silently fail for cache clear
5052
- }
5053
- }
5054
- async getSize() {
5055
- await this.ensureInitialized();
5056
- try {
5057
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readonly');
5058
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5059
- let entries = 0;
5060
- let bytes = 0;
5061
- // Use cursor for efficient iteration
5062
- let cursor = await store.openCursor();
5063
- while (cursor) {
5064
- entries++;
5065
- // Rough estimation of size
5066
- bytes += JSON.stringify(cursor.value).length * 2; // UTF-16 encoding
5067
- cursor = await cursor.continue();
5068
- }
5069
- return {
5070
- entries,
5071
- bytes,
5072
- lastCleanup: Date.now(),
5073
- };
5074
- }
5075
- catch (error) {
5076
- log$d.debug('Error getting cache size', error);
5077
- return {
5078
- entries: 0,
5079
- bytes: 0,
5080
- lastCleanup: Date.now(),
5081
- };
5082
- }
5083
- }
5084
- async cleanup() {
5085
- // No cleanup needed - cache never expires
5086
- return 0;
5087
- }
5088
- async getKeys(pattern) {
5089
- await this.ensureInitialized();
5090
- try {
5091
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readonly');
5092
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5093
- const allKeys = (await store.getAllKeys());
5094
- if (!pattern) {
5095
- return allKeys;
5096
- }
5097
- const regex = this.patternToRegex(pattern);
5098
- return allKeys.filter((key) => regex.test(key));
5099
- }
5100
- catch (error) {
5101
- log$d.debug('Error getting cache keys', error);
5102
- return [];
5103
- }
5104
- }
5105
- async delete(key) {
5106
- await this.ensureInitialized();
5107
- try {
5108
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readwrite');
5109
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5110
- await store.delete(key);
5111
- return true;
5112
- }
5113
- catch (error) {
5114
- log$d.debug('Error deleting cache item', { key, error });
5115
- return false;
5116
- }
5117
- }
5118
- async ensureInitialized() {
5119
- if (!this.initPromise) {
5120
- this.initPromise = this.initialize();
5121
- }
5122
- try {
5123
- await this.initPromise;
5124
- }
5125
- catch (error) {
5126
- log$d.debug('Failed to ensure initialization', error);
5127
- // Reset and try once more
5128
- this.initPromise = null;
5129
- this.db = null;
5130
- this.initPromise = this.initialize();
5131
- await this.initPromise;
5132
- }
5133
- }
5134
- patternToRegex(pattern) {
5135
- // Convert simple glob patterns to regex
5136
- const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&');
5137
- const regexPattern = escaped.replace(/\\\*/g, '.*').replace(/\\\?/g, '.');
5138
- return new RegExp(`^${regexPattern}$`);
5139
- }
5140
- }
5141
- WebCacheAdapter.DB_NAME = 'acube_cache';
5142
- WebCacheAdapter.DB_VERSION = 2;
5143
- WebCacheAdapter.STORE_NAME = 'cache_entries';
5144
-
5145
- const log$c = createPrefixedLogger('CACHE-LOADER');
5146
- function loadCacheAdapter(platform) {
5147
- try {
5148
- switch (platform) {
5149
- case 'web':
5150
- return new WebCacheAdapter({
5151
- maxSize: 50 * 1024 * 1024,
5152
- maxEntries: 10000,
5153
- compression: false,
5154
- });
5155
- case 'react-native':
5156
- try {
5157
- return new ReactNativeCacheAdapter({
5158
- maxSize: 100 * 1024 * 1024,
5159
- maxEntries: 15000,
5160
- });
5161
- }
5162
- catch {
5163
- return new MemoryCacheAdapter({
5164
- maxSize: 10 * 1024 * 1024,
5165
- maxEntries: 5000,
5166
- });
5167
- }
5168
- case 'node':
5169
- default:
5170
- return new MemoryCacheAdapter({
5171
- maxSize: 10 * 1024 * 1024,
5172
- maxEntries: 5000,
5173
- });
5174
- }
5175
- }
5176
- catch (error) {
5177
- log$c.warn(`Cache adapter not available for platform ${platform}:`, error);
5178
- return undefined;
5179
- }
5180
- }
5181
-
5182
3286
  /**
5183
3287
  * Mixin that adds multiGet, multiSet, multiRemove to any storage adapter
5184
3288
  * Eliminates duplicate code across Node, Web, and React Native adapters
@@ -5231,7 +3335,7 @@ class BaseSecureStorageAdapter {
5231
3335
  }
5232
3336
  }
5233
3337
 
5234
- const log$b = createPrefixedLogger('NETWORK-BASE');
3338
+ const log$8 = createPrefixedLogger('NETWORK-BASE');
5235
3339
  class NetworkBase {
5236
3340
  constructor(initialOnline = true, debounceMs = 300) {
5237
3341
  this.destroy$ = new Subject();
@@ -5251,14 +3355,14 @@ class NetworkBase {
5251
3355
  const current = this.statusSubject.getValue();
5252
3356
  if (current.online !== online) {
5253
3357
  this.statusSubject.next({ online, timestamp: Date.now() });
5254
- log$b.debug(`Network status changed: ${online ? 'online' : 'offline'}`);
3358
+ log$8.debug(`Network status changed: ${online ? 'online' : 'offline'}`);
5255
3359
  }
5256
3360
  }
5257
3361
  destroy() {
5258
3362
  this.destroy$.next();
5259
3363
  this.destroy$.complete();
5260
3364
  this.statusSubject.complete();
5261
- log$b.debug('Network monitor destroyed');
3365
+ log$8.debug('Network monitor destroyed');
5262
3366
  }
5263
3367
  }
5264
3368
 
@@ -5318,7 +3422,7 @@ class NodeSecureStorageAdapter extends BaseSecureStorageAdapter {
5318
3422
  }
5319
3423
  }
5320
3424
 
5321
- const log$a = createPrefixedLogger('RN-STORAGE');
3425
+ const log$7 = createPrefixedLogger('RN-STORAGE');
5322
3426
  /**
5323
3427
  * React Native storage adapter using AsyncStorage
5324
3428
  * Note: Uses native batch operations for better performance (not base class)
@@ -5350,7 +3454,7 @@ class ReactNativeStorageAdapter {
5350
3454
  return await this.AsyncStorage.getItem(key);
5351
3455
  }
5352
3456
  catch (error) {
5353
- log$a.error('Failed to get item from AsyncStorage:', error);
3457
+ log$7.error('Failed to get item from AsyncStorage:', error);
5354
3458
  return null;
5355
3459
  }
5356
3460
  }
@@ -5391,7 +3495,7 @@ class ReactNativeStorageAdapter {
5391
3495
  return await this.AsyncStorage.getAllKeys();
5392
3496
  }
5393
3497
  catch (error) {
5394
- log$a.error('Failed to get all keys:', error);
3498
+ log$7.error('Failed to get all keys:', error);
5395
3499
  return [];
5396
3500
  }
5397
3501
  }
@@ -5408,7 +3512,7 @@ class ReactNativeStorageAdapter {
5408
3512
  return result;
5409
3513
  }
5410
3514
  catch (error) {
5411
- log$a.error('Failed to get multiple items:', error);
3515
+ log$7.error('Failed to get multiple items:', error);
5412
3516
  const result = {};
5413
3517
  keys.forEach((key) => {
5414
3518
  result[key] = null;
@@ -5458,7 +3562,7 @@ class ReactNativeSecureStorageAdapter extends BaseSecureStorageAdapter {
5458
3562
  return;
5459
3563
  }
5460
3564
  catch {
5461
- log$a.debug('expo-secure-store not available, trying react-native-keychain');
3565
+ log$7.debug('expo-secure-store not available, trying react-native-keychain');
5462
3566
  }
5463
3567
  try {
5464
3568
  const Keychain = require('react-native-keychain');
@@ -5467,7 +3571,7 @@ class ReactNativeSecureStorageAdapter extends BaseSecureStorageAdapter {
5467
3571
  return;
5468
3572
  }
5469
3573
  catch {
5470
- log$a.error('react-native-keychain not available');
3574
+ log$7.error('react-native-keychain not available');
5471
3575
  }
5472
3576
  throw new Error('No secure storage available. Please install expo-secure-store or react-native-keychain');
5473
3577
  }
@@ -5485,7 +3589,7 @@ class ReactNativeSecureStorageAdapter extends BaseSecureStorageAdapter {
5485
3589
  }
5486
3590
  }
5487
3591
  catch (error) {
5488
- log$a.error('Failed to get secure item:', error);
3592
+ log$7.error('Failed to get secure item:', error);
5489
3593
  }
5490
3594
  return null;
5491
3595
  }
@@ -5522,10 +3626,10 @@ class ReactNativeSecureStorageAdapter extends BaseSecureStorageAdapter {
5522
3626
  }
5523
3627
  }
5524
3628
  async clear() {
5525
- log$a.warn('Clear all secure items not fully implemented for React Native');
3629
+ log$7.warn('Clear all secure items not fully implemented for React Native');
5526
3630
  }
5527
3631
  async getAllKeys() {
5528
- log$a.warn('Get all secure keys not implemented for React Native');
3632
+ log$7.warn('Get all secure keys not implemented for React Native');
5529
3633
  return [];
5530
3634
  }
5531
3635
  async isAvailable() {
@@ -5743,7 +3847,7 @@ class NodeNetworkMonitor extends NetworkBase {
5743
3847
  }
5744
3848
  }
5745
3849
 
5746
- const log$9 = createPrefixedLogger('RN-NETWORK');
3850
+ const log$6 = createPrefixedLogger('RN-NETWORK');
5747
3851
  /**
5748
3852
  * React Native network monitor using RxJS
5749
3853
  * Supports both @react-native-community/netinfo and expo-network
@@ -5756,7 +3860,7 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5756
3860
  this.moduleReady$ = new Subject();
5757
3861
  this.isExpo = detectPlatform().isExpo;
5758
3862
  this.init().catch((error) => {
5759
- log$9.error('Network monitor initialization failed:', error);
3863
+ log$6.error('Network monitor initialization failed:', error);
5760
3864
  });
5761
3865
  }
5762
3866
  async init() {
@@ -5775,10 +3879,10 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5775
3879
  try {
5776
3880
  const module = require('@react-native-community/netinfo');
5777
3881
  this.netInfoModule = module.default || module;
5778
- log$9.debug('Loaded @react-native-community/netinfo module');
3882
+ log$6.debug('Loaded @react-native-community/netinfo module');
5779
3883
  }
5780
3884
  catch (error) {
5781
- log$9.error('Failed to load React Native NetInfo module:', error);
3885
+ log$6.error('Failed to load React Native NetInfo module:', error);
5782
3886
  this.netInfoModule = null;
5783
3887
  }
5784
3888
  }
@@ -5786,10 +3890,10 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5786
3890
  try {
5787
3891
  const module = require('expo-network');
5788
3892
  this.netInfoModule = module.default || module;
5789
- log$9.debug('Loaded expo-network module');
3893
+ log$6.debug('Loaded expo-network module');
5790
3894
  }
5791
3895
  catch (error) {
5792
- log$9.error('Failed to load Expo Network module:', error);
3896
+ log$6.error('Failed to load Expo Network module:', error);
5793
3897
  this.netInfoModule = null;
5794
3898
  }
5795
3899
  }
@@ -5806,16 +3910,16 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5806
3910
  }
5807
3911
  const online = !!(state.isConnected && state.isInternetReachable !== false);
5808
3912
  this.updateStatus(online);
5809
- log$9.debug('Initial network state:', online ? 'online' : 'offline');
3913
+ log$6.debug('Initial network state:', online ? 'online' : 'offline');
5810
3914
  }
5811
3915
  catch (error) {
5812
- log$9.warn('Could not fetch initial network state:', error);
3916
+ log$6.warn('Could not fetch initial network state:', error);
5813
3917
  }
5814
3918
  }
5815
3919
  subscribeToStateChanges() {
5816
3920
  if (!this.netInfoModule)
5817
3921
  return;
5818
- log$9.debug('Subscribing to network state changes');
3922
+ log$6.debug('Subscribing to network state changes');
5819
3923
  const handleState = (state) => {
5820
3924
  const online = !!(state.isConnected && (state.isInternetReachable ?? true));
5821
3925
  this.updateStatus(online);
@@ -5857,7 +3961,7 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5857
3961
  };
5858
3962
  }
5859
3963
  catch (error) {
5860
- log$9.error('Failed to fetch detailed network info:', error);
3964
+ log$6.error('Failed to fetch detailed network info:', error);
5861
3965
  return null;
5862
3966
  }
5863
3967
  }
@@ -5993,7 +4097,7 @@ class CertificateValidator {
5993
4097
  }
5994
4098
  }
5995
4099
 
5996
- const log$8 = createPrefixedLogger('RN-MTLS');
4100
+ const log$5 = createPrefixedLogger('RN-MTLS');
5997
4101
  /**
5998
4102
  * React Native mTLS Adapter using @a-cube-io/expo-mutual-tls
5999
4103
  */
@@ -6015,7 +4119,7 @@ class ReactNativeMTLSAdapter {
6015
4119
  this.expoMTLS = ExpoMutualTls;
6016
4120
  // Set up debug logging with the correct event signature
6017
4121
  const debugListener = ExpoMutualTls.onDebugLog((event) => {
6018
- log$8.debug(`${event.type}: ${event.message}`, {
4122
+ log$5.debug(`${event.type}: ${event.message}`, {
6019
4123
  method: event.method,
6020
4124
  url: event.url,
6021
4125
  statusCode: event.statusCode,
@@ -6025,28 +4129,28 @@ class ReactNativeMTLSAdapter {
6025
4129
  this.eventListeners.push(debugListener);
6026
4130
  // Set up error logging with the correct event signature
6027
4131
  const errorListener = ExpoMutualTls.onError((event) => {
6028
- log$8.error(event.message, {
4132
+ log$5.error(event.message, {
6029
4133
  code: event.code,
6030
4134
  });
6031
4135
  });
6032
4136
  this.eventListeners.push(errorListener);
6033
4137
  // Set up certificate expiry monitoring with the correct event signature
6034
4138
  const expiryListener = ExpoMutualTls.onCertificateExpiry((event) => {
6035
- log$8.warn(`Certificate ${event.subject} expires at ${new Date(event.expiry)}`, {
4139
+ log$5.warn(`Certificate ${event.subject} expires at ${new Date(event.expiry)}`, {
6036
4140
  alias: event.alias,
6037
4141
  warning: event.warning,
6038
4142
  });
6039
4143
  });
6040
4144
  this.eventListeners.push(expiryListener);
6041
- log$8.debug('Expo mTLS module loaded successfully');
4145
+ log$5.debug('Expo mTLS module loaded successfully');
6042
4146
  }
6043
4147
  catch (error) {
6044
- log$8.warn('@a-cube-io/expo-mutual-tls not available:', error);
4148
+ log$5.warn('@a-cube-io/expo-mutual-tls not available:', error);
6045
4149
  }
6046
4150
  }
6047
4151
  async isMTLSSupported() {
6048
4152
  const supported = this.expoMTLS !== null;
6049
- log$8.debug('mTLS support check:', {
4153
+ log$5.debug('mTLS support check:', {
6050
4154
  supported,
6051
4155
  platform: this.getPlatformInfo().platform,
6052
4156
  moduleAvailable: !!this.expoMTLS,
@@ -6058,7 +4162,7 @@ class ReactNativeMTLSAdapter {
6058
4162
  throw new MTLSError(exports.MTLSErrorType.NOT_SUPPORTED, 'Expo mTLS module not available');
6059
4163
  }
6060
4164
  this.config = config;
6061
- log$8.debug('Initialized with config:', {
4165
+ log$5.debug('Initialized with config:', {
6062
4166
  baseUrl: config.baseUrl,
6063
4167
  port: config.port,
6064
4168
  timeout: config.timeout,
@@ -6072,7 +4176,7 @@ class ReactNativeMTLSAdapter {
6072
4176
  if (!this.config) {
6073
4177
  throw new MTLSError(exports.MTLSErrorType.CONFIGURATION_ERROR, 'Adapter not initialized. Call initialize() first.');
6074
4178
  }
6075
- log$8.debug('Configuring certificate:', {
4179
+ log$5.debug('Configuring certificate:', {
6076
4180
  format: certificateData.format,
6077
4181
  hasPassword: !!certificateData.password,
6078
4182
  certificateLength: certificateData.certificate.length,
@@ -6089,14 +4193,14 @@ class ReactNativeMTLSAdapter {
6089
4193
  'client-key-service', // keyService
6090
4194
  true // enableLogging - let the native module handle its own debug logging
6091
4195
  );
6092
- log$8.debug('PEM services configured:', configResult);
4196
+ log$5.debug('PEM services configured:', configResult);
6093
4197
  if (!configResult.success) {
6094
4198
  throw new MTLSError(exports.MTLSErrorType.CONFIGURATION_ERROR, `PEM configuration failed: ${configResult.state}`);
6095
4199
  }
6096
4200
  // Step 2: Store the actual PEM certificate and private key
6097
4201
  const storeResult = await this.expoMTLS.storePEM(certificateData.certificate, certificateData.privateKey, certificateData.password // passphrase (optional)
6098
4202
  );
6099
- log$8.debug('PEM certificate store result:', storeResult);
4203
+ log$5.debug('PEM certificate store result:', storeResult);
6100
4204
  if (!storeResult) {
6101
4205
  throw new MTLSError(exports.MTLSErrorType.CERTIFICATE_INVALID, 'Failed to store PEM certificate');
6102
4206
  }
@@ -6109,14 +4213,14 @@ class ReactNativeMTLSAdapter {
6109
4213
  const configResult = await this.expoMTLS.configureP12('client-p12-service', // keychainService
6110
4214
  true // enableLogging - let the native module handle its own debug logging
6111
4215
  );
6112
- log$8.debug('P12 service configured:', configResult);
4216
+ log$5.debug('P12 service configured:', configResult);
6113
4217
  if (!configResult.success) {
6114
4218
  throw new MTLSError(exports.MTLSErrorType.CONFIGURATION_ERROR, `P12 configuration failed: ${configResult.state}`);
6115
4219
  }
6116
4220
  // Step 2: Store the P12 certificate data
6117
4221
  const storeResult = await this.expoMTLS.storeP12(certificateData.certificate, // P12 data in certificate field
6118
4222
  certificateData.password);
6119
- log$8.debug('P12 certificate store result:', storeResult);
4223
+ log$5.debug('P12 certificate store result:', storeResult);
6120
4224
  if (!storeResult) {
6121
4225
  throw new MTLSError(exports.MTLSErrorType.CERTIFICATE_INVALID, 'Failed to store P12 certificate');
6122
4226
  }
@@ -6130,7 +4234,7 @@ class ReactNativeMTLSAdapter {
6130
4234
  if (error instanceof MTLSError) {
6131
4235
  throw error;
6132
4236
  }
6133
- log$8.error('Certificate configuration failed:', error);
4237
+ log$5.error('Certificate configuration failed:', error);
6134
4238
  throw new MTLSError(exports.MTLSErrorType.CONFIGURATION_ERROR, 'Failed to configure certificate', error);
6135
4239
  }
6136
4240
  }
@@ -6141,38 +4245,38 @@ class ReactNativeMTLSAdapter {
6141
4245
  try {
6142
4246
  // Use static method call
6143
4247
  const hasCert = await this.expoMTLS.hasCertificate();
6144
- log$8.debug('Certificate availability check:', hasCert);
4248
+ log$5.debug('Certificate availability check:', hasCert);
6145
4249
  return hasCert;
6146
4250
  }
6147
4251
  catch (error) {
6148
- log$8.error('Certificate check failed:', error);
4252
+ log$5.error('Certificate check failed:', error);
6149
4253
  return false;
6150
4254
  }
6151
4255
  }
6152
4256
  async getCertificateInfo() {
6153
4257
  if (!this.expoMTLS) {
6154
- log$8.debug('Certificate info requested but module not available');
4258
+ log$5.debug('Certificate info requested but module not available');
6155
4259
  return null;
6156
4260
  }
6157
4261
  try {
6158
4262
  const hasCert = await this.hasCertificate();
6159
4263
  if (!hasCert) {
6160
- log$8.debug('No certificate stored');
4264
+ log$5.debug('No certificate stored');
6161
4265
  return null;
6162
4266
  }
6163
4267
  // Use getCertificatesInfo to retrieve information about stored certificates
6164
4268
  const result = await this.expoMTLS.getCertificatesInfo();
6165
4269
  if (!result || !result.certificates || result.certificates.length === 0) {
6166
- log$8.debug('No certificate information available');
4270
+ log$5.debug('No certificate information available');
6167
4271
  return null;
6168
4272
  }
6169
4273
  // Get the first certificate (primary client certificate)
6170
4274
  const cert = result.certificates[0];
6171
4275
  if (!cert) {
6172
- log$8.debug('Certificate data is empty');
4276
+ log$5.debug('Certificate data is empty');
6173
4277
  return null;
6174
4278
  }
6175
- log$8.debug('Retrieved certificate info:', {
4279
+ log$5.debug('Retrieved certificate info:', {
6176
4280
  subject: cert.subject.commonName,
6177
4281
  issuer: cert.issuer.commonName,
6178
4282
  validFrom: new Date(cert.validFrom),
@@ -6191,7 +4295,7 @@ class ReactNativeMTLSAdapter {
6191
4295
  };
6192
4296
  }
6193
4297
  catch (error) {
6194
- log$8.error('Failed to get certificate info:', error);
4298
+ log$5.error('Failed to get certificate info:', error);
6195
4299
  return null;
6196
4300
  }
6197
4301
  }
@@ -6202,7 +4306,7 @@ class ReactNativeMTLSAdapter {
6202
4306
  */
6203
4307
  async parseCertificateData(certificateData) {
6204
4308
  if (!this.expoMTLS) {
6205
- log$8.debug('Parse certificate: Module not available');
4309
+ log$5.debug('Parse certificate: Module not available');
6206
4310
  return null;
6207
4311
  }
6208
4312
  try {
@@ -6219,14 +4323,14 @@ class ReactNativeMTLSAdapter {
6219
4323
  else {
6220
4324
  throw new MTLSError(exports.MTLSErrorType.CERTIFICATE_INVALID, `Unsupported certificate format: ${certificateData.format}`);
6221
4325
  }
6222
- log$8.debug('Certificate parsed successfully:', {
4326
+ log$5.debug('Certificate parsed successfully:', {
6223
4327
  certificateCount: result.certificates.length,
6224
4328
  subjects: result.certificates.map((cert) => cert.subject.commonName),
6225
4329
  });
6226
4330
  return result;
6227
4331
  }
6228
4332
  catch (error) {
6229
- log$8.error('Failed to parse certificate:', error);
4333
+ log$5.error('Failed to parse certificate:', error);
6230
4334
  if (error instanceof MTLSError) {
6231
4335
  throw error;
6232
4336
  }
@@ -6241,7 +4345,7 @@ class ReactNativeMTLSAdapter {
6241
4345
  if (!hasCert) {
6242
4346
  throw new MTLSError(exports.MTLSErrorType.CERTIFICATE_NOT_FOUND, 'No certificate configured');
6243
4347
  }
6244
- log$8.debug('Making mTLS request:', {
4348
+ log$5.debug('Making mTLS request:', {
6245
4349
  method: requestConfig.method || 'GET',
6246
4350
  url: requestConfig.url,
6247
4351
  headers: requestConfig.headers,
@@ -6249,7 +4353,7 @@ class ReactNativeMTLSAdapter {
6249
4353
  responseType: requestConfig.responseType,
6250
4354
  });
6251
4355
  if (requestConfig.data) {
6252
- log$8.debug('mTLS request body:', requestConfig.data);
4356
+ log$5.debug('mTLS request body:', requestConfig.data);
6253
4357
  }
6254
4358
  try {
6255
4359
  const response = await this.expoMTLS.request(requestConfig.url, {
@@ -6258,7 +4362,7 @@ class ReactNativeMTLSAdapter {
6258
4362
  body: requestConfig.data ? JSON.stringify(requestConfig.data) : undefined,
6259
4363
  responseType: requestConfig.responseType,
6260
4364
  });
6261
- log$8.debug('mTLS request successful:', response);
4365
+ log$5.debug('mTLS request successful:', response);
6262
4366
  if (!response.success) {
6263
4367
  throw new MTLSError(exports.MTLSErrorType.CONNECTION_FAILED, `mTLS request failed: ${response.statusMessage} (${response.statusCode})`, undefined, response.statusCode);
6264
4368
  }
@@ -6270,7 +4374,7 @@ class ReactNativeMTLSAdapter {
6270
4374
  data = JSON.parse(response.body);
6271
4375
  }
6272
4376
  catch (parseError) {
6273
- log$8.warn('Failed to parse JSON response:', parseError);
4377
+ log$5.warn('Failed to parse JSON response:', parseError);
6274
4378
  // If parsing fails, keep raw body
6275
4379
  }
6276
4380
  }
@@ -6287,7 +4391,7 @@ class ReactNativeMTLSAdapter {
6287
4391
  };
6288
4392
  }
6289
4393
  catch (error) {
6290
- log$8.error('mTLS request failed:', error);
4394
+ log$5.error('mTLS request failed:', error);
6291
4395
  throw new MTLSError(exports.MTLSErrorType.CONNECTION_FAILED, 'mTLS request failed', error);
6292
4396
  }
6293
4397
  }
@@ -6300,18 +4404,18 @@ class ReactNativeMTLSAdapter {
6300
4404
  */
6301
4405
  async testConnection() {
6302
4406
  if (!this.expoMTLS || !this.config) {
6303
- log$8.debug('Diagnostic test: No mTLS module or config available');
4407
+ log$5.debug('Diagnostic test: No mTLS module or config available');
6304
4408
  return false;
6305
4409
  }
6306
4410
  try {
6307
4411
  const hasCert = await this.hasCertificate();
6308
4412
  if (!hasCert) {
6309
- log$8.debug('Diagnostic test: No certificate configured');
4413
+ log$5.debug('Diagnostic test: No certificate configured');
6310
4414
  return false;
6311
4415
  }
6312
- log$8.debug('Running diagnostic test (may fail even if mTLS works):', this.config.baseUrl);
4416
+ log$5.debug('Running diagnostic test (may fail even if mTLS works):', this.config.baseUrl);
6313
4417
  const result = await this.expoMTLS.testConnection(this.config.baseUrl);
6314
- log$8.debug('Diagnostic test result (NOT validation):', {
4418
+ log$5.debug('Diagnostic test result (NOT validation):', {
6315
4419
  success: result.success,
6316
4420
  statusCode: result.statusCode,
6317
4421
  statusMessage: result.statusMessage,
@@ -6322,13 +4426,13 @@ class ReactNativeMTLSAdapter {
6322
4426
  return result.success;
6323
4427
  }
6324
4428
  catch (error) {
6325
- log$8.warn('Diagnostic test failed (this is expected):', error);
4429
+ log$5.warn('Diagnostic test failed (this is expected):', error);
6326
4430
  return false;
6327
4431
  }
6328
4432
  }
6329
4433
  async removeCertificate() {
6330
4434
  if (!this.expoMTLS) {
6331
- log$8.debug('Remove certificate: Module not available');
4435
+ log$5.debug('Remove certificate: Module not available');
6332
4436
  return;
6333
4437
  }
6334
4438
  try {
@@ -6337,10 +4441,10 @@ class ReactNativeMTLSAdapter {
6337
4441
  this.isConfigured = false;
6338
4442
  // Cleanup event listeners
6339
4443
  this.cleanupEventListeners();
6340
- log$8.debug('Certificate removed successfully');
4444
+ log$5.debug('Certificate removed successfully');
6341
4445
  }
6342
4446
  catch (error) {
6343
- log$8.error('Failed to remove certificate:', error);
4447
+ log$5.error('Failed to remove certificate:', error);
6344
4448
  throw new MTLSError(exports.MTLSErrorType.CONFIGURATION_ERROR, 'Failed to remove certificate', error);
6345
4449
  }
6346
4450
  }
@@ -6349,7 +4453,7 @@ class ReactNativeMTLSAdapter {
6349
4453
  */
6350
4454
  cleanupEventListeners() {
6351
4455
  if (this.eventListeners.length > 0) {
6352
- log$8.debug(`Cleaning up ${this.eventListeners.length} event listeners`);
4456
+ log$5.debug(`Cleaning up ${this.eventListeners.length} event listeners`);
6353
4457
  }
6354
4458
  // Remove individual listeners if they have remove methods
6355
4459
  this.eventListeners.forEach((listener) => {
@@ -6386,7 +4490,7 @@ class ReactNativeMTLSAdapter {
6386
4490
  }
6387
4491
  }
6388
4492
 
6389
- const log$7 = createPrefixedLogger('WEB-MTLS');
4493
+ const log$4 = createPrefixedLogger('WEB-MTLS');
6390
4494
  /**
6391
4495
  * Web mTLS Adapter - Graceful fallback for web browsers
6392
4496
  *
@@ -6400,13 +4504,13 @@ const log$7 = createPrefixedLogger('WEB-MTLS');
6400
4504
  */
6401
4505
  class WebMTLSAdapter {
6402
4506
  constructor() {
6403
- log$7.warn('Web browsers do not support programmatic mTLS configuration');
6404
- log$7.info('Use JWT authentication or configure client certificates in browser settings');
4507
+ log$4.warn('Web browsers do not support programmatic mTLS configuration');
4508
+ log$4.info('Use JWT authentication or configure client certificates in browser settings');
6405
4509
  }
6406
4510
  async isMTLSSupported() {
6407
4511
  // mTLS is not supported programmatically in web browsers
6408
4512
  const supported = false;
6409
- log$7.debug('mTLS support check:', {
4513
+ log$4.debug('mTLS support check:', {
6410
4514
  supported,
6411
4515
  platform: this.getPlatformInfo().platform,
6412
4516
  reason: 'Browser security model prevents programmatic certificate configuration',
@@ -6415,14 +4519,14 @@ class WebMTLSAdapter {
6415
4519
  return supported;
6416
4520
  }
6417
4521
  async initialize(config) {
6418
- log$7.warn('Initialized but mTLS not available in web browsers:', {
4522
+ log$4.warn('Initialized but mTLS not available in web browsers:', {
6419
4523
  baseUrl: config.baseUrl,
6420
4524
  port: config.port,
6421
4525
  recommendation: 'Use standard HTTPS with JWT authentication',
6422
4526
  });
6423
4527
  }
6424
4528
  async configureCertificate(certificateData) {
6425
- log$7.error('Certificate configuration attempted:', {
4529
+ log$4.error('Certificate configuration attempted:', {
6426
4530
  format: certificateData.format,
6427
4531
  reason: 'Not supported in web browsers',
6428
4532
  alternatives: [
@@ -6437,15 +4541,15 @@ class WebMTLSAdapter {
6437
4541
  }
6438
4542
  async hasCertificate() {
6439
4543
  // We cannot detect if the browser has certificates configured
6440
- log$7.debug('Certificate availability check: Cannot detect browser certificates programmatically');
4544
+ log$4.debug('Certificate availability check: Cannot detect browser certificates programmatically');
6441
4545
  return false;
6442
4546
  }
6443
4547
  async getCertificateInfo() {
6444
- log$7.debug('Certificate info requested: Not accessible in web browsers');
4548
+ log$4.debug('Certificate info requested: Not accessible in web browsers');
6445
4549
  return null;
6446
4550
  }
6447
4551
  async request(requestConfig) {
6448
- log$7.error('mTLS request attempted:', {
4552
+ log$4.error('mTLS request attempted:', {
6449
4553
  method: requestConfig.method,
6450
4554
  url: requestConfig.url,
6451
4555
  reason: 'Not supported in web browsers',
@@ -6460,11 +4564,11 @@ class WebMTLSAdapter {
6460
4564
  'are properly configured in the browser certificate store.');
6461
4565
  }
6462
4566
  async testConnection() {
6463
- log$7.debug('Connection test: mTLS not available in web browsers');
4567
+ log$4.debug('Connection test: mTLS not available in web browsers');
6464
4568
  return false;
6465
4569
  }
6466
4570
  async removeCertificate() {
6467
- log$7.debug('Remove certificate: No certificates to remove (not supported in web browsers)');
4571
+ log$4.debug('Remove certificate: No certificates to remove (not supported in web browsers)');
6468
4572
  // No-op - cannot remove certificates programmatically in browsers
6469
4573
  }
6470
4574
  /**
@@ -6472,7 +4576,7 @@ class WebMTLSAdapter {
6472
4576
  * Always returns null for web browsers as mTLS is not supported
6473
4577
  */
6474
4578
  getBaseUrl() {
6475
- log$7.debug('Base URL requested: Not supported in web browsers');
4579
+ log$4.debug('Base URL requested: Not supported in web browsers');
6476
4580
  return null;
6477
4581
  }
6478
4582
  getPlatformInfo() {
@@ -6505,7 +4609,7 @@ class WebMTLSAdapter {
6505
4609
  }
6506
4610
  }
6507
4611
 
6508
- const log$6 = createPrefixedLogger('MTLS-LOADER');
4612
+ const log$3 = createPrefixedLogger('MTLS-LOADER');
6509
4613
  function loadMTLSAdapter(platform, config) {
6510
4614
  try {
6511
4615
  let adapter;
@@ -6539,7 +4643,7 @@ function loadMTLSAdapter(platform, config) {
6539
4643
  return adapter;
6540
4644
  }
6541
4645
  catch (error) {
6542
- log$6.warn(`mTLS adapter not available for platform ${platform}:`, error);
4646
+ log$3.warn(`mTLS adapter not available for platform ${platform}:`, error);
6543
4647
  return null;
6544
4648
  }
6545
4649
  }
@@ -6549,7 +4653,7 @@ async function initializeAdapterAsync(adapter, config) {
6549
4653
  if (isSupported) {
6550
4654
  await adapter.initialize(config);
6551
4655
  const platformInfo = adapter.getPlatformInfo();
6552
- log$6.debug('mTLS adapter initialized:', {
4656
+ log$3.debug('mTLS adapter initialized:', {
6553
4657
  platform: platformInfo.platform,
6554
4658
  mtlsSupported: platformInfo.mtlsSupported,
6555
4659
  certificateStorage: platformInfo.certificateStorage,
@@ -6558,31 +4662,28 @@ async function initializeAdapterAsync(adapter, config) {
6558
4662
  }
6559
4663
  }
6560
4664
  catch (error) {
6561
- log$6.warn('Failed to initialize mTLS adapter:', error);
4665
+ log$3.warn('Failed to initialize mTLS adapter:', error);
6562
4666
  }
6563
4667
  }
6564
4668
 
6565
- const log$5 = createPrefixedLogger('ADAPTER-LOADER');
4669
+ const log$2 = createPrefixedLogger('ADAPTER-LOADER');
6566
4670
  function loadPlatformAdapters(options = {}) {
6567
4671
  const { mtlsConfig } = options;
6568
4672
  const { platform } = detectPlatform();
6569
- log$5.debug('Loading adapters for platform:', platform);
4673
+ log$2.debug('Loading adapters for platform:', platform);
6570
4674
  const storageAdapters = loadStorageAdapters(platform);
6571
4675
  const networkMonitor = loadNetworkMonitor(platform);
6572
- const cache = loadCacheAdapter(platform);
6573
4676
  const mtls = loadMTLSAdapter(platform, mtlsConfig);
6574
- log$5.debug('Adapters loaded:', {
4677
+ log$2.debug('Adapters loaded:', {
6575
4678
  platform,
6576
4679
  hasStorage: !!storageAdapters.storage,
6577
4680
  hasSecureStorage: !!storageAdapters.secureStorage,
6578
4681
  hasNetworkMonitor: !!networkMonitor,
6579
- hasCache: !!cache,
6580
4682
  hasMTLS: !!mtls,
6581
4683
  });
6582
4684
  return {
6583
4685
  ...storageAdapters,
6584
4686
  networkMonitor,
6585
- cache,
6586
4687
  mtls: mtls || undefined,
6587
4688
  };
6588
4689
  }
@@ -6599,12 +4700,9 @@ function createACubeMTLSConfig(baseUrl, timeout, autoInitialize = true, forcePor
6599
4700
 
6600
4701
  const DI_TOKENS = {
6601
4702
  HTTP_PORT: Symbol('HTTP_PORT'),
6602
- BASE_HTTP_PORT: Symbol('BASE_HTTP_PORT'),
6603
4703
  STORAGE_PORT: Symbol('STORAGE_PORT'),
6604
4704
  SECURE_STORAGE_PORT: Symbol('SECURE_STORAGE_PORT'),
6605
4705
  NETWORK_PORT: Symbol('NETWORK_PORT'),
6606
- CACHE_PORT: Symbol('CACHE_PORT'),
6607
- CACHE_KEY_GENERATOR: Symbol('CACHE_KEY_GENERATOR'),
6608
4706
  MTLS_PORT: Symbol('MTLS_PORT'),
6609
4707
  TOKEN_STORAGE_PORT: Symbol('TOKEN_STORAGE_PORT'),
6610
4708
  RECEIPT_REPOSITORY: Symbol('RECEIPT_REPOSITORY'),
@@ -6622,7 +4720,6 @@ const DI_TOKENS = {
6622
4720
  AUTH_SERVICE: Symbol('AUTH_SERVICE'),
6623
4721
  AUTHENTICATION_SERVICE: Symbol('AUTHENTICATION_SERVICE'),
6624
4722
  CERTIFICATE_SERVICE: Symbol('CERTIFICATE_SERVICE'),
6625
- OFFLINE_SERVICE: Symbol('OFFLINE_SERVICE'),
6626
4723
  NOTIFICATION_SERVICE: Symbol('NOTIFICATION_SERVICE'),
6627
4724
  TELEMETRY_SERVICE: Symbol('TELEMETRY_SERVICE'),
6628
4725
  };
@@ -7597,468 +5694,6 @@ class TelemetryRepositoryImpl {
7597
5694
  }
7598
5695
  }
7599
5696
 
7600
- const log$4 = createPrefixedLogger('CACHE-KEY');
7601
- const URL_PATTERNS = [
7602
- // Receipt (mf1) - specific patterns first
7603
- {
7604
- pattern: /^\/mf1\/receipts\/([^/]+)\/returnable-items$/,
7605
- resource: 'receipt',
7606
- action: 'returnable',
7607
- },
7608
- {
7609
- pattern: /^\/mf1\/receipts\/([^/]+)\/details$/,
7610
- resource: 'receipt',
7611
- action: 'details',
7612
- },
7613
- { pattern: /^\/mf1\/receipts\/([^/]+)$/, resource: 'receipt' },
7614
- {
7615
- pattern: /^\/mf1\/pems\/([^/]+)\/receipts$/,
7616
- resource: 'receipt',
7617
- parent: 'point-of-sale',
7618
- isList: true,
7619
- },
7620
- { pattern: /^\/mf1\/receipts$/, resource: 'receipt', isList: true },
7621
- // Merchant (mf2)
7622
- { pattern: /^\/mf2\/merchants\/([^/]+)$/, resource: 'merchant' },
7623
- { pattern: /^\/mf2\/merchants$/, resource: 'merchant', isList: true },
7624
- // Cashier (mf1)
7625
- { pattern: /^\/mf1\/cashiers\/me$/, resource: 'cashier', action: 'me' },
7626
- { pattern: /^\/mf1\/cashiers\/([^/]+)$/, resource: 'cashier' },
7627
- { pattern: /^\/mf1\/cashiers$/, resource: 'cashier', isList: true },
7628
- // Cash Register (mf1)
7629
- { pattern: /^\/mf1\/cash-registers\/([^/]+)$/, resource: 'cash-register' },
7630
- { pattern: /^\/mf1\/cash-registers$/, resource: 'cash-register', isList: true },
7631
- // Point of Sale (mf1)
7632
- { pattern: /^\/mf1\/pems\/([^/]+)$/, resource: 'point-of-sale' },
7633
- { pattern: /^\/mf1\/pems$/, resource: 'point-of-sale', isList: true },
7634
- // Nested resources under merchant (mf2)
7635
- {
7636
- pattern: /^\/mf2\/merchants\/([^/]+)\/suppliers\/([^/]+)$/,
7637
- resource: 'supplier',
7638
- parent: 'merchant',
7639
- },
7640
- {
7641
- pattern: /^\/mf2\/merchants\/([^/]+)\/suppliers$/,
7642
- resource: 'supplier',
7643
- parent: 'merchant',
7644
- isList: true,
7645
- },
7646
- {
7647
- pattern: /^\/mf2\/merchants\/([^/]+)\/daily-reports/,
7648
- resource: 'daily-report',
7649
- parent: 'merchant',
7650
- isList: true,
7651
- },
7652
- {
7653
- pattern: /^\/mf2\/merchants\/([^/]+)\/journals/,
7654
- resource: 'journal',
7655
- parent: 'merchant',
7656
- isList: true,
7657
- },
7658
- // PEM (mf2)
7659
- {
7660
- pattern: /^\/mf2\/pems\/([^/]+)\/certificates$/,
7661
- resource: 'pem',
7662
- action: 'certificates',
7663
- },
7664
- { pattern: /^\/mf2\/pems\/([^/]+)$/, resource: 'pem' },
7665
- // Others
7666
- { pattern: /^\/mf1\/notifications/, resource: 'notification', isList: true },
7667
- {
7668
- pattern: /^\/mf1\/pems\/([^/]+)\/telemetry$/,
7669
- resource: 'telemetry',
7670
- },
7671
- ];
7672
- const DEFAULT_TTL_CONFIG = {
7673
- // Data that rarely changes - 30 min TTL for items only
7674
- merchant: { ttlMs: 30 * 60 * 1000, cacheList: false, cacheItem: true },
7675
- 'point-of-sale': { ttlMs: 30 * 60 * 1000, cacheList: false, cacheItem: true },
7676
- 'cash-register': { ttlMs: 30 * 60 * 1000, cacheList: false, cacheItem: true },
7677
- pem: { ttlMs: 30 * 60 * 1000, cacheList: false, cacheItem: false },
7678
- // Data that changes moderately - 10 min TTL for items only
7679
- cashier: { ttlMs: 10 * 60 * 1000, cacheList: false, cacheItem: true },
7680
- supplier: { ttlMs: 10 * 60 * 1000, cacheList: false, cacheItem: true },
7681
- // Data that can change - 5 min TTL for items only
7682
- receipt: { ttlMs: 5 * 60 * 1000, cacheList: false, cacheItem: true },
7683
- 'daily-report': { ttlMs: 5 * 60 * 1000, cacheList: false, cacheItem: true },
7684
- journal: { ttlMs: 5 * 60 * 1000, cacheList: false, cacheItem: true },
7685
- // Real-time data - 1 min TTL
7686
- notification: { ttlMs: 1 * 60 * 1000, cacheList: false, cacheItem: false },
7687
- telemetry: { ttlMs: 1 * 60 * 1000, cacheList: false, cacheItem: false },
7688
- };
7689
- const DEFAULT_TTL = 5 * 60 * 1000; // 5 minutes
7690
- class CacheKeyGenerator {
7691
- constructor(customConfig) {
7692
- this.config = { ...DEFAULT_TTL_CONFIG, ...customConfig };
7693
- log$4.info('CacheKeyGenerator initialized with config:', {
7694
- resources: Object.keys(this.config),
7695
- });
7696
- }
7697
- generate(url, params) {
7698
- const parsed = this.parseUrl(url);
7699
- if (!parsed) {
7700
- // Fallback: use URL as key
7701
- const paramStr = params ? this.serializeParams(params) : '';
7702
- const key = paramStr ? `${url}?${paramStr}` : url;
7703
- log$4.debug('URL not matched, using fallback key:', { url, key });
7704
- return key;
7705
- }
7706
- const { resource, ids, action, isList, parent } = parsed;
7707
- if (isList) {
7708
- const paramStr = params ? this.serializeParams(params) : '';
7709
- const parentPart = parent && ids.length > 0 ? `${parent}=${ids[0]}&` : '';
7710
- const key = `${resource}:list:${parentPart}${paramStr}`;
7711
- log$4.debug('Generated list cache key:', { url, key, resource });
7712
- return key;
7713
- }
7714
- // Single item
7715
- if (ids.length === 0 && action) {
7716
- // Special case for endpoints like /cashiers/me
7717
- const key = `${resource}:${action}`;
7718
- log$4.debug('Generated special action cache key:', { url, key, resource, action });
7719
- return key;
7720
- }
7721
- let key = `${resource}:${ids.join(':')}`;
7722
- if (action) {
7723
- key += `:${action}`;
7724
- }
7725
- log$4.debug('Generated item cache key:', { url, key, resource, ids, action });
7726
- return key;
7727
- }
7728
- parseResource(url) {
7729
- const parsed = this.parseUrl(url);
7730
- return parsed?.resource;
7731
- }
7732
- getTTL(url) {
7733
- const resource = this.parseResource(url);
7734
- if (!resource) {
7735
- log$4.debug('No resource found for URL, using default TTL:', { url, ttl: DEFAULT_TTL });
7736
- return DEFAULT_TTL;
7737
- }
7738
- const ttl = this.config[resource].ttlMs;
7739
- log$4.debug('TTL for resource:', { url, resource, ttlMs: ttl, ttlMin: ttl / 60000 });
7740
- return ttl;
7741
- }
7742
- shouldCache(url) {
7743
- const parsed = this.parseUrl(url);
7744
- if (!parsed) {
7745
- log$4.debug('URL not recognized, should not cache:', { url });
7746
- return false;
7747
- }
7748
- const { resource, isList } = parsed;
7749
- const config = this.config[resource];
7750
- if (isList) {
7751
- log$4.debug('List endpoint cache decision:', {
7752
- url,
7753
- resource,
7754
- isList: true,
7755
- shouldCache: config.cacheList,
7756
- });
7757
- return config.cacheList;
7758
- }
7759
- log$4.debug('Item endpoint cache decision:', {
7760
- url,
7761
- resource,
7762
- isList: false,
7763
- shouldCache: config.cacheItem,
7764
- });
7765
- return config.cacheItem;
7766
- }
7767
- getInvalidationPatterns(url, method) {
7768
- const parsed = this.parseUrl(url);
7769
- if (!parsed) {
7770
- log$4.debug('No patterns to invalidate for URL:', { url, method });
7771
- return [];
7772
- }
7773
- const { resource, ids, parent } = parsed;
7774
- const patterns = [];
7775
- // Always invalidate list on mutations
7776
- if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE') {
7777
- if (parent && ids.length > 0) {
7778
- patterns.push(`${resource}:list:${parent}=${ids[0]}*`);
7779
- }
7780
- patterns.push(`${resource}:list:*`);
7781
- }
7782
- // Invalidate specific item on PUT/PATCH/DELETE
7783
- if (method === 'PUT' || method === 'PATCH' || method === 'DELETE') {
7784
- if (ids.length > 0) {
7785
- patterns.push(`${resource}:${ids.join(':')}*`);
7786
- }
7787
- }
7788
- // Special cases
7789
- if (resource === 'cashier' && (method === 'PUT' || method === 'DELETE')) {
7790
- patterns.push('cashier:me');
7791
- }
7792
- log$4.debug('Invalidation patterns:', { url, method, patterns });
7793
- return patterns;
7794
- }
7795
- parseUrl(url) {
7796
- // Remove query string for pattern matching
7797
- const urlPath = url.split('?')[0];
7798
- for (const pattern of URL_PATTERNS) {
7799
- const match = urlPath?.match(pattern.pattern);
7800
- if (match) {
7801
- // Extract IDs from capture groups
7802
- const ids = match.slice(1).filter(Boolean);
7803
- return {
7804
- resource: pattern.resource,
7805
- ids,
7806
- action: pattern.action,
7807
- isList: pattern.isList,
7808
- parent: pattern.parent,
7809
- };
7810
- }
7811
- }
7812
- return null;
7813
- }
7814
- serializeParams(params) {
7815
- const sortedKeys = Object.keys(params).sort();
7816
- const parts = [];
7817
- for (const key of sortedKeys) {
7818
- const value = params[key];
7819
- if (value !== undefined && value !== null) {
7820
- parts.push(`${key}=${String(value)}`);
7821
- }
7822
- }
7823
- return parts.join('&');
7824
- }
7825
- }
7826
-
7827
- const log$3 = createPrefixedLogger('CACHE');
7828
- class CachingHttpDecorator {
7829
- constructor(http, cache, keyGenerator, networkMonitor, config = {}) {
7830
- this.http = http;
7831
- this.cache = cache;
7832
- this.keyGenerator = keyGenerator;
7833
- this.networkMonitor = networkMonitor;
7834
- this.config = config;
7835
- this.currentOnlineState = true;
7836
- this.authToken = null;
7837
- log$3.info('CachingHttpDecorator initialized', {
7838
- enabled: config.enabled !== false,
7839
- hasNetworkMonitor: !!networkMonitor,
7840
- });
7841
- this.setupNetworkMonitoring();
7842
- }
7843
- setupNetworkMonitoring() {
7844
- if (this.networkMonitor) {
7845
- this.networkSubscription = this.networkMonitor.online$.subscribe((online) => {
7846
- if (this.currentOnlineState !== online) {
7847
- log$3.info('Network state changed:', { online });
7848
- }
7849
- this.currentOnlineState = online;
7850
- });
7851
- }
7852
- }
7853
- isOnline() {
7854
- if (this.networkMonitor) {
7855
- return this.currentOnlineState;
7856
- }
7857
- if (typeof navigator !== 'undefined' && 'onLine' in navigator) {
7858
- return navigator.onLine;
7859
- }
7860
- return true;
7861
- }
7862
- async get(url, config) {
7863
- const startTime = Date.now();
7864
- // Check if caching is disabled globally
7865
- if (this.config.enabled === false) {
7866
- log$3.debug('GET (cache disabled globally):', { url });
7867
- return this.http.get(url, config);
7868
- }
7869
- // Check if this URL should be cached
7870
- const shouldCache = this.keyGenerator.shouldCache(url);
7871
- if (!shouldCache) {
7872
- log$3.debug('GET (not cacheable - likely a list endpoint):', { url });
7873
- return this.http.get(url, config);
7874
- }
7875
- const cacheKey = this.keyGenerator.generate(url, config?.params);
7876
- const ttl = this.keyGenerator.getTTL(url);
7877
- const resource = this.keyGenerator.parseResource(url);
7878
- log$3.info('GET request starting:', {
7879
- url,
7880
- resource,
7881
- cacheKey,
7882
- ttlMs: ttl,
7883
- ttlMin: Math.round(ttl / 60000),
7884
- params: config?.params,
7885
- });
7886
- // Check cache
7887
- let cached = null;
7888
- try {
7889
- cached = await this.cache.get(cacheKey);
7890
- if (cached) {
7891
- log$3.debug('Cache entry found:', {
7892
- cacheKey,
7893
- timestamp: new Date(cached.timestamp).toISOString(),
7894
- ageMs: Date.now() - cached.timestamp,
7895
- });
7896
- }
7897
- else {
7898
- log$3.debug('Cache entry not found:', { cacheKey });
7899
- }
7900
- }
7901
- catch (error) {
7902
- log$3.warn('Cache lookup failed:', {
7903
- cacheKey,
7904
- error: error instanceof Error ? error.message : error,
7905
- });
7906
- }
7907
- if (cached) {
7908
- const age = Date.now() - cached.timestamp;
7909
- const isExpired = age >= ttl;
7910
- log$3.debug('Cache analysis:', {
7911
- cacheKey,
7912
- ageMs: age,
7913
- ageSec: Math.round(age / 1000),
7914
- ttlMs: ttl,
7915
- isExpired,
7916
- isOnline: this.isOnline(),
7917
- });
7918
- // If within TTL, return cached data
7919
- if (!isExpired) {
7920
- const duration = Date.now() - startTime;
7921
- log$3.info('CACHE HIT:', {
7922
- url,
7923
- cacheKey,
7924
- ageMs: age,
7925
- durationMs: duration,
7926
- });
7927
- return {
7928
- data: cached.data,
7929
- status: 200,
7930
- headers: { 'x-cache': 'HIT' },
7931
- };
7932
- }
7933
- // If offline and cache is stale, return stale data
7934
- if (!this.isOnline()) {
7935
- const duration = Date.now() - startTime;
7936
- log$3.info('CACHE STALE (offline):', {
7937
- url,
7938
- cacheKey,
7939
- ageMs: age,
7940
- durationMs: duration,
7941
- });
7942
- return {
7943
- data: cached.data,
7944
- status: 200,
7945
- headers: { 'x-cache': 'STALE' },
7946
- };
7947
- }
7948
- log$3.debug('Cache expired, fetching fresh data:', { cacheKey, ageMs: age, ttlMs: ttl });
7949
- }
7950
- // Fetch fresh data
7951
- try {
7952
- log$3.debug('Fetching from network:', { url });
7953
- const response = await this.http.get(url, config);
7954
- // Cache the response
7955
- try {
7956
- await this.cache.set(cacheKey, response.data);
7957
- log$3.debug('Response cached successfully:', { cacheKey });
7958
- }
7959
- catch (error) {
7960
- log$3.error('Failed to cache response:', {
7961
- cacheKey,
7962
- error: error instanceof Error ? error.message : error,
7963
- });
7964
- }
7965
- const duration = Date.now() - startTime;
7966
- log$3.info('CACHE MISS (fetched fresh):', {
7967
- url,
7968
- cacheKey,
7969
- status: response.status,
7970
- durationMs: duration,
7971
- });
7972
- return {
7973
- ...response,
7974
- headers: { ...response.headers, 'x-cache': 'MISS' },
7975
- };
7976
- }
7977
- catch (error) {
7978
- // On error, return stale cache if available
7979
- if (cached) {
7980
- const duration = Date.now() - startTime;
7981
- log$3.warn('CACHE STALE (network error):', {
7982
- url,
7983
- cacheKey,
7984
- error: error instanceof Error ? error.message : 'Unknown error',
7985
- durationMs: duration,
7986
- });
7987
- return {
7988
- data: cached.data,
7989
- status: 200,
7990
- headers: { 'x-cache': 'STALE' },
7991
- };
7992
- }
7993
- log$3.error('Network error with no cache fallback:', {
7994
- url,
7995
- error: error instanceof Error ? error.message : error,
7996
- });
7997
- throw error;
7998
- }
7999
- }
8000
- async post(url, data, config) {
8001
- log$3.info('POST request:', { url });
8002
- const response = await this.http.post(url, data, config);
8003
- await this.invalidateRelated(url, 'POST');
8004
- return response;
8005
- }
8006
- async put(url, data, config) {
8007
- log$3.info('PUT request:', { url });
8008
- const response = await this.http.put(url, data, config);
8009
- await this.invalidateRelated(url, 'PUT');
8010
- return response;
8011
- }
8012
- async patch(url, data, config) {
8013
- log$3.info('PATCH request:', { url });
8014
- const response = await this.http.patch(url, data, config);
8015
- await this.invalidateRelated(url, 'PATCH');
8016
- return response;
8017
- }
8018
- async delete(url, config) {
8019
- log$3.info('DELETE request:', { url });
8020
- const response = await this.http.delete(url, config);
8021
- await this.invalidateRelated(url, 'DELETE');
8022
- return response;
8023
- }
8024
- setAuthToken(token) {
8025
- log$3.debug('CachingHttpDecorator.setAuthToken called:', {
8026
- hasToken: !!token,
8027
- tokenPrefix: token?.substring(0, 20),
8028
- underlyingHttpType: this.http.constructor.name,
8029
- });
8030
- this.authToken = token;
8031
- this.http.setAuthToken(token);
8032
- }
8033
- getAuthToken() {
8034
- return this.authToken;
8035
- }
8036
- async invalidateRelated(url, method) {
8037
- const patterns = this.keyGenerator.getInvalidationPatterns(url, method);
8038
- if (patterns.length === 0) {
8039
- log$3.debug('No cache patterns to invalidate:', { url, method });
8040
- return;
8041
- }
8042
- log$3.info('Invalidating cache patterns:', { url, method, patterns });
8043
- for (const pattern of patterns) {
8044
- try {
8045
- await this.cache.invalidate(pattern);
8046
- log$3.debug('Cache pattern invalidated:', { pattern });
8047
- }
8048
- catch (error) {
8049
- log$3.error('Failed to invalidate pattern:', {
8050
- pattern,
8051
- error: error instanceof Error ? error.message : error,
8052
- });
8053
- }
8054
- }
8055
- }
8056
- destroy() {
8057
- log$3.debug('CachingHttpDecorator destroyed');
8058
- this.networkSubscription?.unsubscribe();
8059
- }
8060
- }
8061
-
8062
5697
  const logJwt = createPrefixedLogger('HTTP-JWT');
8063
5698
  const logMtls = createPrefixedLogger('HTTP-MTLS');
8064
5699
  class AxiosHttpAdapter {
@@ -8328,7 +5963,6 @@ class SDKFactory {
8328
5963
  baseUrl: config.baseUrl,
8329
5964
  timeout: config.timeout,
8330
5965
  });
8331
- container.register(DI_TOKENS.BASE_HTTP_PORT, httpAdapter);
8332
5966
  container.register(DI_TOKENS.HTTP_PORT, httpAdapter);
8333
5967
  container.registerFactory(DI_TOKENS.RECEIPT_REPOSITORY, () => {
8334
5968
  const http = container.get(DI_TOKENS.HTTP_PORT);
@@ -8376,23 +6010,6 @@ class SDKFactory {
8376
6010
  });
8377
6011
  return container;
8378
6012
  }
8379
- static registerCacheServices(container, cache, network) {
8380
- container.register(DI_TOKENS.CACHE_PORT, cache);
8381
- if (network) {
8382
- container.register(DI_TOKENS.NETWORK_PORT, network);
8383
- }
8384
- const keyGenerator = new CacheKeyGenerator();
8385
- container.register(DI_TOKENS.CACHE_KEY_GENERATOR, keyGenerator);
8386
- const baseHttp = container.get(DI_TOKENS.BASE_HTTP_PORT);
8387
- const cachingHttp = new CachingHttpDecorator(baseHttp, cache, keyGenerator, network);
8388
- container.register(DI_TOKENS.HTTP_PORT, cachingHttp);
8389
- }
8390
- static getCacheKeyGenerator(container) {
8391
- if (container.has(DI_TOKENS.CACHE_KEY_GENERATOR)) {
8392
- return container.get(DI_TOKENS.CACHE_KEY_GENERATOR);
8393
- }
8394
- return undefined;
8395
- }
8396
6013
  static registerAuthServices(container, secureStorage, config) {
8397
6014
  const tokenStorage = new TokenStorageAdapter(secureStorage);
8398
6015
  container.register(DI_TOKENS.TOKEN_STORAGE_PORT, tokenStorage);
@@ -8430,7 +6047,7 @@ class SDKFactory {
8430
6047
  }
8431
6048
  }
8432
6049
 
8433
- const log$2 = createPrefixedLogger('SDK');
6050
+ const log$1 = createPrefixedLogger('SDK');
8434
6051
  class ACubeSDK {
8435
6052
  constructor(config, customAdapters, events = {}) {
8436
6053
  this.events = events;
@@ -8444,23 +6061,22 @@ class ACubeSDK {
8444
6061
  }
8445
6062
  async initialize() {
8446
6063
  if (this.isInitialized) {
8447
- log$2.debug('SDK already initialized, skipping');
6064
+ log$1.debug('SDK already initialized, skipping');
8448
6065
  return;
8449
6066
  }
8450
- log$2.info('Initializing SDK', {
6067
+ log$1.info('Initializing SDK', {
8451
6068
  apiUrl: this.config.getApiUrl(),
8452
6069
  authUrl: this.config.getAuthUrl(),
8453
6070
  debugEnabled: this.config.isDebugEnabled(),
8454
6071
  });
8455
6072
  try {
8456
6073
  if (!this.adapters) {
8457
- log$2.debug('Loading platform adapters');
6074
+ log$1.debug('Loading platform adapters');
8458
6075
  const mtlsConfig = createACubeMTLSConfig(this.config.getApiUrl(), this.config.getTimeout(), true);
8459
6076
  this.adapters = loadPlatformAdapters({
8460
6077
  mtlsConfig,
8461
6078
  });
8462
- log$2.info('Platform adapters loaded', {
8463
- hasCache: !!this.adapters.cache,
6079
+ log$1.info('Platform adapters loaded', {
8464
6080
  hasNetworkMonitor: !!this.adapters.networkMonitor,
8465
6081
  hasMtls: !!this.adapters.mtls,
8466
6082
  hasSecureStorage: !!this.adapters.secureStorage,
@@ -8472,30 +6088,15 @@ class ACubeSDK {
8472
6088
  timeout: this.config.getTimeout(),
8473
6089
  debugEnabled: this.config.isDebugEnabled(),
8474
6090
  };
8475
- log$2.debug('Creating DI container');
6091
+ log$1.debug('Creating DI container');
8476
6092
  this.container = SDKFactory.createContainer(factoryConfig);
8477
- log$2.debug('Registering auth services');
6093
+ log$1.debug('Registering auth services');
8478
6094
  SDKFactory.registerAuthServices(this.container, this.adapters.secureStorage, factoryConfig);
8479
- if (this.adapters.cache) {
8480
- log$2.info('Registering cache services', {
8481
- hasNetworkMonitor: !!this.adapters.networkMonitor,
8482
- });
8483
- SDKFactory.registerCacheServices(this.container, this.adapters.cache, this.adapters.networkMonitor);
8484
- }
8485
- else {
8486
- log$2.debug('No cache adapter available, caching disabled');
8487
- }
8488
- log$2.debug('Initializing certificate service');
6095
+ log$1.debug('Initializing certificate service');
8489
6096
  this.certificateService = new CertificateService(this.adapters.secureStorage);
8490
6097
  const tokenStorage = this.container.get(DI_TOKENS.TOKEN_STORAGE_PORT);
8491
6098
  const httpPort = this.container.get(DI_TOKENS.HTTP_PORT);
8492
- const baseHttpPort = this.container.get(DI_TOKENS.BASE_HTTP_PORT);
8493
- log$2.debug('HTTP ports initialized', {
8494
- httpPortType: httpPort.constructor.name,
8495
- baseHttpPortType: baseHttpPort.constructor.name,
8496
- areSameInstance: httpPort === baseHttpPort,
8497
- });
8498
- log$2.debug('Initializing authentication service');
6099
+ log$1.debug('Initializing authentication service');
8499
6100
  this.authService = new AuthenticationService(httpPort, tokenStorage, {
8500
6101
  authUrl: this.config.getAuthUrl(),
8501
6102
  timeout: this.config.getTimeout(),
@@ -8505,51 +6106,33 @@ class ACubeSDK {
8505
6106
  this.events.onAuthError?.(new ACubeSDKError('AUTH_ERROR', error.message, error));
8506
6107
  },
8507
6108
  });
8508
- log$2.debug('Initializing offline manager');
8509
- const queueEvents = {
8510
- onOperationAdded: (operation) => {
8511
- this.events.onOfflineOperationAdded?.(operation.id);
8512
- },
8513
- onOperationCompleted: (result) => {
8514
- this.events.onOfflineOperationCompleted?.(result.operation.id, result.success);
8515
- },
8516
- onOperationFailed: (result) => {
8517
- this.events.onOfflineOperationCompleted?.(result.operation.id, false);
8518
- },
8519
- };
8520
- this.offlineManager = new OfflineManager(this.adapters.storage, httpPort, this.adapters.networkMonitor, {
8521
- syncInterval: 30000,
8522
- }, queueEvents);
8523
6109
  this.networkSubscription = this.adapters.networkMonitor.online$.subscribe((online) => {
8524
6110
  this.currentOnlineState = online;
8525
6111
  this.events.onNetworkStatusChanged?.(online);
8526
- if (online && this.offlineManager) {
8527
- this.offlineManager.sync().catch(() => { });
8528
- }
8529
6112
  });
8530
6113
  const isAuth = await this.authService.isAuthenticated();
8531
- log$2.debug('Checking authentication status during init', { isAuthenticated: isAuth });
6114
+ log$1.debug('Checking authentication status during init', { isAuthenticated: isAuth });
8532
6115
  if (isAuth) {
8533
6116
  const token = await this.authService.getAccessToken();
8534
- log$2.debug('Token retrieved during init', {
6117
+ log$1.debug('Token retrieved during init', {
8535
6118
  hasToken: !!token,
8536
6119
  tokenPrefix: token?.substring(0, 20),
8537
6120
  });
8538
6121
  if (token) {
8539
6122
  httpPort.setAuthToken(token);
8540
- log$2.info('Auth token set on HTTP port during initialization');
6123
+ log$1.info('Auth token set on HTTP port during initialization');
8541
6124
  }
8542
6125
  }
8543
6126
  else {
8544
- log$2.warn('User not authenticated during SDK init - token will be set after login');
6127
+ log$1.warn('User not authenticated during SDK init - token will be set after login');
8545
6128
  }
8546
- if (this.adapters?.mtls && 'setMTLSAdapter' in baseHttpPort) {
8547
- log$2.debug('Connecting mTLS adapter to HTTP port');
8548
- const httpWithMtls = baseHttpPort;
6129
+ if (this.adapters?.mtls && 'setMTLSAdapter' in httpPort) {
6130
+ log$1.debug('Connecting mTLS adapter to HTTP port');
6131
+ const httpWithMtls = httpPort;
8549
6132
  httpWithMtls.setMTLSAdapter(this.adapters.mtls);
8550
6133
  }
8551
- if ('setAuthStrategy' in baseHttpPort) {
8552
- log$2.debug('Configuring auth strategy');
6134
+ if ('setAuthStrategy' in httpPort) {
6135
+ log$1.debug('Configuring auth strategy');
8553
6136
  const jwtHandler = new JwtAuthHandler(tokenStorage);
8554
6137
  const certificatePort = this.certificateService
8555
6138
  ? {
@@ -8580,7 +6163,7 @@ class ACubeSDK {
8580
6163
  },
8581
6164
  };
8582
6165
  const authStrategy = new AuthStrategy(jwtHandler, mtlsHandler, userProvider, this.adapters?.mtls || null);
8583
- const httpWithStrategy = baseHttpPort;
6166
+ const httpWithStrategy = httpPort;
8584
6167
  httpWithStrategy.setAuthStrategy(authStrategy);
8585
6168
  }
8586
6169
  if (this.adapters?.mtls && this.certificateService) {
@@ -8598,19 +6181,18 @@ class ACubeSDK {
8598
6181
  }
8599
6182
  }
8600
6183
  catch (certError) {
8601
- log$2.warn('Certificate auto-configuration failed, will retry on demand', {
6184
+ log$1.warn('Certificate auto-configuration failed, will retry on demand', {
8602
6185
  error: certError instanceof Error ? certError.message : certError,
8603
6186
  });
8604
6187
  }
8605
6188
  }
8606
6189
  this.isInitialized = true;
8607
- log$2.info('SDK initialized successfully', {
8608
- hasCache: !!this.adapters.cache,
6190
+ log$1.info('SDK initialized successfully', {
8609
6191
  hasMtls: !!this.adapters.mtls,
8610
6192
  });
8611
6193
  }
8612
6194
  catch (error) {
8613
- log$2.error('SDK initialization failed', {
6195
+ log$1.error('SDK initialization failed', {
8614
6196
  error: error instanceof Error ? error.message : error,
8615
6197
  });
8616
6198
  throw new ACubeSDKError('SDK_INITIALIZATION_ERROR', `Failed to initialize SDK: ${error instanceof Error ? error.message : 'Unknown error'}`, error);
@@ -8666,19 +6248,19 @@ class ACubeSDK {
8666
6248
  }
8667
6249
  async login(credentials) {
8668
6250
  this.ensureInitialized();
8669
- log$2.info('Login attempt', { email: credentials.email });
6251
+ log$1.info('Login attempt', { email: credentials.email });
8670
6252
  const user = await this.authService.login(credentials);
8671
- log$2.info('Login successful', { roles: user.roles });
6253
+ log$1.info('Login successful', { roles: user.roles });
8672
6254
  const token = await this.authService.getAccessToken();
8673
6255
  if (token) {
8674
6256
  this.httpPort.setAuthToken(token);
8675
- log$2.debug('Auth token set on HTTP port');
6257
+ log$1.debug('Auth token set on HTTP port');
8676
6258
  }
8677
6259
  return user;
8678
6260
  }
8679
6261
  async logout() {
8680
6262
  this.ensureInitialized();
8681
- log$2.info('Logout');
6263
+ log$1.info('Logout');
8682
6264
  await this.authService.logout();
8683
6265
  this.httpPort.setAuthToken(null);
8684
6266
  }
@@ -8696,10 +6278,6 @@ class ACubeSDK {
8696
6278
  this.ensureInitialized();
8697
6279
  return await this.authService.isAuthenticated();
8698
6280
  }
8699
- getOfflineManager() {
8700
- this.ensureInitialized();
8701
- return this.offlineManager;
8702
- }
8703
6281
  isOnline() {
8704
6282
  this.ensureInitialized();
8705
6283
  return this.currentOnlineState;
@@ -8827,7 +6405,6 @@ class ACubeSDK {
8827
6405
  }
8828
6406
  destroy() {
8829
6407
  this.networkSubscription?.unsubscribe();
8830
- this.offlineManager?.destroy();
8831
6408
  this.container?.clear();
8832
6409
  this.isInitialized = false;
8833
6410
  }
@@ -9113,7 +6690,6 @@ class TelemetryService {
9113
6690
  this.events = events;
9114
6691
  this.stateSubject = new BehaviorSubject({
9115
6692
  data: null,
9116
- isCached: false,
9117
6693
  isLoading: false,
9118
6694
  lastFetchedAt: null,
9119
6695
  });
@@ -9183,7 +6759,6 @@ class TelemetryService {
9183
6759
  const data = await this.repository.getTelemetry(this.currentPemId);
9184
6760
  const newState = {
9185
6761
  data,
9186
- isCached: false,
9187
6762
  isLoading: false,
9188
6763
  lastFetchedAt: Date.now(),
9189
6764
  };
@@ -9208,7 +6783,6 @@ class TelemetryService {
9208
6783
  clearTelemetry() {
9209
6784
  this.stateSubject.next({
9210
6785
  data: null,
9211
- isCached: false,
9212
6786
  isLoading: false,
9213
6787
  lastFetchedAt: null,
9214
6788
  });
@@ -9221,7 +6795,7 @@ class TelemetryService {
9221
6795
  }
9222
6796
  }
9223
6797
 
9224
- const log$1 = createPrefixedLogger('SDK-MANAGER');
6798
+ const log = createPrefixedLogger('SDK-MANAGER');
9225
6799
  /**
9226
6800
  * SDKManager - Singleton wrapper for ACubeSDK with simplified API
9227
6801
  *
@@ -9288,7 +6862,7 @@ class SDKManager {
9288
6862
  if (canPoll && !this.isPollingActive) {
9289
6863
  const hasCert = await this.checkCertificate();
9290
6864
  if (!hasCert) {
9291
- log$1.warn('Certificate missing — polling blocked until certificate is installed');
6865
+ log.warn('Certificate missing — polling blocked until certificate is installed');
9292
6866
  return;
9293
6867
  }
9294
6868
  this.notificationService?.startPolling();
@@ -9390,7 +6964,7 @@ class SDKManager {
9390
6964
  this.isPollingActive = true;
9391
6965
  }
9392
6966
  else {
9393
- log$1.warn('Certificate missing at init — polling blocked until certificate is installed');
6967
+ log.warn('Certificate missing at init — polling blocked until certificate is installed');
9394
6968
  }
9395
6969
  }
9396
6970
  // AppStateService remains active for all users (handles OFFLINE network state)
@@ -9433,7 +7007,7 @@ class SDKManager {
9433
7007
  return this.certificateMissingSubject.asObservable();
9434
7008
  }
9435
7009
  /**
9436
- * Observable stream of telemetry state (data, isLoading, isCached, error)
7010
+ * Observable stream of telemetry state (data, isLoading, error)
9437
7011
  */
9438
7012
  get telemetryState$() {
9439
7013
  this.ensureInitialized();
@@ -9517,7 +7091,7 @@ class SDKManager {
9517
7091
  const user = await sdk.getCurrentUser();
9518
7092
  const canPoll = user && hasAnyRole(user.roles, ['ROLE_MERCHANT', 'ROLE_CASHIER']);
9519
7093
  if (canPoll) {
9520
- log$1.info('Certificate installed — starting polling');
7094
+ log.info('Certificate installed — starting polling');
9521
7095
  this.notificationService?.startPolling();
9522
7096
  await this.startTelemetryPollingAuto();
9523
7097
  this.isPollingActive = true;
@@ -9530,7 +7104,7 @@ class SDKManager {
9530
7104
  this.certificateMissingSubject.next(true);
9531
7105
  // Stop polling since certificate is required
9532
7106
  if (this.isPollingActive) {
9533
- log$1.info('Certificate removed — stopping polling');
7107
+ log.info('Certificate removed — stopping polling');
9534
7108
  this.notificationService?.stopPolling();
9535
7109
  this.telemetryService?.stopPolling();
9536
7110
  this.telemetryService?.clearTelemetry();
@@ -9610,91 +7184,6 @@ const RECEIPT_SENT = 'sent';
9610
7184
  const RECEIPT_SORT_DESCENDING = 'descending';
9611
7185
  const RECEIPT_SORT_ASCENDING = 'ascending';
9612
7186
 
9613
- const log = createPrefixedLogger('CACHE-HANDLER');
9614
- class CacheHandler {
9615
- constructor(cache, networkMonitor) {
9616
- this.cache = cache;
9617
- this.networkMonitor = networkMonitor;
9618
- this.currentOnlineState = true;
9619
- this.setupNetworkMonitoring();
9620
- }
9621
- setupNetworkMonitoring() {
9622
- if (this.networkMonitor) {
9623
- this.networkSubscription = this.networkMonitor.online$.subscribe((online) => {
9624
- this.currentOnlineState = online;
9625
- });
9626
- }
9627
- }
9628
- isOnline() {
9629
- if (this.networkMonitor) {
9630
- return this.currentOnlineState;
9631
- }
9632
- if (typeof navigator !== 'undefined' && 'onLine' in navigator) {
9633
- return navigator.onLine;
9634
- }
9635
- return false;
9636
- }
9637
- async handleCachedRequest(url, requestFn, config) {
9638
- if (!this.cache || config?.useCache === false) {
9639
- const response = await requestFn();
9640
- return response.data;
9641
- }
9642
- const cacheKey = this.generateCacheKey(url);
9643
- const online = this.isOnline();
9644
- log.debug('Request:', { url, cacheKey, online });
9645
- if (online) {
9646
- try {
9647
- const response = await requestFn();
9648
- if (this.cache) {
9649
- await this.cache.set(cacheKey, response.data).catch((error) => {
9650
- log.error('Failed to cache:', error instanceof Error ? error.message : error);
9651
- });
9652
- }
9653
- return response.data;
9654
- }
9655
- catch (error) {
9656
- const cached = await this.cache.get(cacheKey).catch(() => null);
9657
- if (cached) {
9658
- log.debug('Network failed, using cache fallback');
9659
- return cached.data;
9660
- }
9661
- throw error;
9662
- }
9663
- }
9664
- else {
9665
- const cached = await this.cache.get(cacheKey).catch(() => null);
9666
- if (cached) {
9667
- log.debug('Offline, returning cached data');
9668
- return cached.data;
9669
- }
9670
- throw new Error('Offline: No cached data available');
9671
- }
9672
- }
9673
- generateCacheKey(url) {
9674
- return url;
9675
- }
9676
- async invalidateCache(pattern) {
9677
- if (!this.cache)
9678
- return;
9679
- try {
9680
- await this.cache.invalidate(pattern);
9681
- }
9682
- catch (error) {
9683
- log.error('Invalidation failed:', error instanceof Error ? error.message : error);
9684
- }
9685
- }
9686
- getCacheStatus() {
9687
- return {
9688
- available: !!this.cache,
9689
- networkMonitorAvailable: !!this.networkMonitor,
9690
- isOnline: this.isOnline(),
9691
- };
9692
- }
9693
- destroy() {
9694
- this.networkSubscription?.unsubscribe();
9695
- }
9696
- }
9697
-
9698
7187
  function transformError(error) {
9699
7188
  if (axios.isAxiosError(error)) {
9700
7189
  const response = error.response;
@@ -9882,7 +7371,6 @@ exports.AppStateService = AppStateService;
9882
7371
  exports.AuthStrategy = AuthStrategy;
9883
7372
  exports.AuthenticationService = AuthenticationService;
9884
7373
  exports.AxiosHttpAdapter = AxiosHttpAdapter;
9885
- exports.CacheHandler = CacheHandler;
9886
7374
  exports.CashRegisterCreateSchema = CashRegisterCreateSchema;
9887
7375
  exports.CashRegisterMapper = CashRegisterMapper;
9888
7376
  exports.CashRegisterRepositoryImpl = CashRegisterRepositoryImpl;
@@ -9893,7 +7381,6 @@ exports.CertificateService = CertificateService;
9893
7381
  exports.CertificateValidator = CertificateValidator;
9894
7382
  exports.ConfigManager = ConfigManager;
9895
7383
  exports.DAILY_REPORT_STATUS_OPTIONS = DAILY_REPORT_STATUS_OPTIONS;
9896
- exports.DEFAULT_QUEUE_CONFIG = DEFAULT_QUEUE_CONFIG;
9897
7384
  exports.DIContainer = DIContainer;
9898
7385
  exports.DI_TOKENS = DI_TOKENS;
9899
7386
  exports.DailyReportMapper = DailyReportMapper;
@@ -9932,8 +7419,6 @@ exports.NotificationRepositoryImpl = NotificationRepositoryImpl;
9932
7419
  exports.NotificationSchema = NotificationSchema;
9933
7420
  exports.NotificationScopeSchema = NotificationScopeSchema;
9934
7421
  exports.NotificationService = NotificationService;
9935
- exports.OfflineManager = OfflineManager;
9936
- exports.OperationQueue = OperationQueue;
9937
7422
  exports.PEMStatusOfflineRequestSchema = PEMStatusOfflineRequestSchema;
9938
7423
  exports.PEMStatusSchema = PEMStatusSchema;
9939
7424
  exports.PEM_STATUS_OPTIONS = PEM_STATUS_OPTIONS;
@@ -9968,7 +7453,6 @@ exports.SupplierCreateInputSchema = SupplierCreateInputSchema;
9968
7453
  exports.SupplierMapper = SupplierMapper;
9969
7454
  exports.SupplierRepositoryImpl = SupplierRepositoryImpl;
9970
7455
  exports.SupplierUpdateInputSchema = SupplierUpdateInputSchema;
9971
- exports.SyncManager = SyncManager;
9972
7456
  exports.TelemetryMapper = TelemetryMapper;
9973
7457
  exports.TelemetryMerchantSchema = TelemetryMerchantSchema;
9974
7458
  exports.TelemetryRepositoryImpl = TelemetryRepositoryImpl;