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

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.
@@ -1869,27 +1869,6 @@ function clearObject(input) {
1869
1869
  }
1870
1870
  return input;
1871
1871
  }
1872
- function clearObjectShallow(obj) {
1873
- if (!obj || typeof obj !== 'object') {
1874
- return {};
1875
- }
1876
- const cleaned = {};
1877
- for (const [key, value] of Object.entries(obj)) {
1878
- if (value !== null && value !== undefined && value !== '') {
1879
- cleaned[key] = value;
1880
- }
1881
- }
1882
- return cleaned;
1883
- }
1884
- function isEmpty(value) {
1885
- return value === null || value === undefined || value === '';
1886
- }
1887
- function hasNonEmptyValues(obj) {
1888
- if (!obj || typeof obj !== 'object') {
1889
- return false;
1890
- }
1891
- return Object.values(obj).some((value) => !isEmpty(value));
1892
- }
1893
1872
 
1894
1873
  /**
1895
1874
  * Platform detection utilities
@@ -2112,7 +2091,7 @@ function formatDecimal(value, decimals = 2) {
2112
2091
  return num.toFixed(decimals);
2113
2092
  }
2114
2093
 
2115
- const log$h = createPrefixedLogger('AUTH-SERVICE');
2094
+ const log$b = createPrefixedLogger('AUTH-SERVICE');
2116
2095
  class AuthenticationService {
2117
2096
  get user$() {
2118
2097
  return this.userSubject.asObservable();
@@ -2134,7 +2113,7 @@ class AuthenticationService {
2134
2113
  }
2135
2114
  async login(credentials) {
2136
2115
  this.authStateSubject.next('authenticating');
2137
- log$h.info('Login attempt', {
2116
+ log$b.info('Login attempt', {
2138
2117
  authUrl: this.config.authUrl,
2139
2118
  email: credentials.email,
2140
2119
  });
@@ -2145,7 +2124,7 @@ class AuthenticationService {
2145
2124
  });
2146
2125
  const jwtPayload = parseJwt(response.data.token);
2147
2126
  const expiresAt = jwtPayload.exp * 1000;
2148
- log$h.info('Login successful', {
2127
+ log$b.info('Login successful', {
2149
2128
  authUrl: this.config.authUrl,
2150
2129
  tokenPrefix: response.data.token.substring(0, 30) + '...',
2151
2130
  expiresAt: new Date(expiresAt).toISOString(),
@@ -2174,21 +2153,21 @@ class AuthenticationService {
2174
2153
  const token = await this.tokenStorage.getAccessToken();
2175
2154
  if (!token) {
2176
2155
  // No token - clear any stale user state
2177
- log$h.debug('getCurrentUser: No token in storage');
2156
+ log$b.debug('getCurrentUser: No token in storage');
2178
2157
  if (this.userSubject.value) {
2179
2158
  this.userSubject.next(null);
2180
2159
  this.authStateSubject.next('idle');
2181
2160
  }
2182
2161
  return null;
2183
2162
  }
2184
- log$h.debug('getCurrentUser: Token found', {
2163
+ log$b.debug('getCurrentUser: Token found', {
2185
2164
  tokenPrefix: token.substring(0, 30) + '...',
2186
2165
  tokenLength: token.length,
2187
2166
  });
2188
2167
  const jwtPayload = parseJwt(token);
2189
2168
  if (isTokenExpired(jwtPayload)) {
2190
2169
  // Token expired - clear everything
2191
- log$h.warn('getCurrentUser: Token expired');
2170
+ log$b.warn('getCurrentUser: Token expired');
2192
2171
  await this.tokenStorage.clearTokens();
2193
2172
  this.userSubject.next(null);
2194
2173
  this.authStateSubject.next('idle');
@@ -2198,7 +2177,7 @@ class AuthenticationService {
2198
2177
  // Token is valid - return cached user if available
2199
2178
  const currentUser = this.userSubject.value;
2200
2179
  if (currentUser) {
2201
- log$h.debug('getCurrentUser: Returning cached user', {
2180
+ log$b.debug('getCurrentUser: Returning cached user', {
2202
2181
  email: currentUser.email,
2203
2182
  roles: currentUser.roles,
2204
2183
  });
@@ -2221,12 +2200,12 @@ class AuthenticationService {
2221
2200
  async isAuthenticated() {
2222
2201
  const token = await this.tokenStorage.getAccessToken();
2223
2202
  if (!token) {
2224
- log$h.debug('isAuthenticated: No token in storage');
2203
+ log$b.debug('isAuthenticated: No token in storage');
2225
2204
  return false;
2226
2205
  }
2227
2206
  const jwtPayload = parseJwt(token);
2228
2207
  const expired = isTokenExpired(jwtPayload);
2229
- log$h.debug('isAuthenticated: Token check', {
2208
+ log$b.debug('isAuthenticated: Token check', {
2230
2209
  hasToken: true,
2231
2210
  expired,
2232
2211
  expiresAt: new Date(jwtPayload.exp * 1000).toISOString(),
@@ -2446,7 +2425,7 @@ class ConfigManager {
2446
2425
  }
2447
2426
  }
2448
2427
 
2449
- // Enum options arrays
2428
+ // Enum options arrays (used by consumers for dropdowns and form validation)
2450
2429
  const VAT_RATE_CODE_OPTIONS = [
2451
2430
  '4.00',
2452
2431
  '5.00',
@@ -2473,103 +2452,10 @@ const VAT_RATE_CODE_OPTIONS = [
2473
2452
  ];
2474
2453
  const GOOD_OR_SERVICE_OPTIONS = ['goods', 'service'];
2475
2454
  const RECEIPT_PROOF_TYPE_OPTIONS = ['POS', 'VR', 'ND'];
2476
- // Enum types for receipt validation
2455
+ // Enum schemas (used by consumers as building blocks for their own form schemas)
2477
2456
  const VatRateCodeSchema = z.enum(VAT_RATE_CODE_OPTIONS);
2478
2457
  const GoodOrServiceSchema = z.enum(GOOD_OR_SERVICE_OPTIONS);
2479
2458
  const ReceiptProofTypeSchema = z.enum(RECEIPT_PROOF_TYPE_OPTIONS);
2480
- // Receipt Item Schema
2481
- const ReceiptItemSchema = z.object({
2482
- type: GoodOrServiceSchema.optional(),
2483
- quantity: z.string().min(1, { error: 'fieldIsRequired' }),
2484
- description: z.string().min(1, { error: 'fieldIsRequired' }),
2485
- unit_price: z.string().min(1, { error: 'fieldIsRequired' }),
2486
- vat_rate_code: VatRateCodeSchema.optional(),
2487
- simplified_vat_allocation: z.boolean().optional(),
2488
- discount: z.string().nullable().optional(),
2489
- is_down_payment_or_voucher_redemption: z.boolean().optional(),
2490
- complimentary: z.boolean().optional(),
2491
- });
2492
- // Main Receipt Input Schema
2493
- const ReceiptInputSchema = z
2494
- .object({
2495
- items: z.array(ReceiptItemSchema).min(1, { error: 'arrayMin1' }),
2496
- customer_tax_code: z.string().optional(),
2497
- customer_lottery_code: z.string().optional(),
2498
- discount: z.string().nullable().optional(),
2499
- invoice_issuing: z.boolean().optional(),
2500
- uncollected_dcr_to_ssn: z.boolean().optional(),
2501
- services_uncollected_amount: z.string().nullable().optional(),
2502
- goods_uncollected_amount: z.string().nullable().optional(),
2503
- cash_payment_amount: z.string().nullable().optional(),
2504
- electronic_payment_amount: z.string().nullable().optional(),
2505
- ticket_restaurant_payment_amount: z.string().nullable().optional(),
2506
- ticket_restaurant_quantity: z.number().optional(),
2507
- })
2508
- .refine((data) => {
2509
- // At least one payment method should be provided
2510
- const hasCashPayment = data.cash_payment_amount && parseFloat(data.cash_payment_amount) > 0;
2511
- const hasElectronicPayment = data.electronic_payment_amount && parseFloat(data.electronic_payment_amount) > 0;
2512
- const hasTicketPayment = data.ticket_restaurant_payment_amount &&
2513
- parseFloat(data.ticket_restaurant_payment_amount) > 0;
2514
- return hasCashPayment || hasElectronicPayment || hasTicketPayment;
2515
- }, {
2516
- error: 'At least one payment method is required',
2517
- path: ['payment_methods'],
2518
- })
2519
- .refine((data) => {
2520
- // only one between customer_tax_code and customer_lottery_code can be provided
2521
- return !data.customer_tax_code || !data.customer_lottery_code;
2522
- }, {
2523
- error: 'Only one between customer_tax_code and customer_lottery_code can be provided',
2524
- path: ['customer_tax_code', 'customer_lottery_code'],
2525
- });
2526
- // Receipt Return or Void via PEM Schema
2527
- const ReceiptReturnOrVoidViaPEMInputSchema = z.object({
2528
- device_id: z.string().optional(),
2529
- items: z.array(ReceiptItemSchema).min(1, { error: 'arrayMin1' }),
2530
- document_number: z.string().min(1, { error: 'fieldIsRequired' }),
2531
- document_datetime: z.string().optional(),
2532
- lottery_code: z.string().optional(),
2533
- });
2534
- // Receipt Return or Void with Proof Schema
2535
- const ReceiptReturnOrVoidWithProofInputSchema = z.object({
2536
- items: z.array(ReceiptItemSchema).min(1, { error: 'arrayMin1' }),
2537
- proof: ReceiptProofTypeSchema,
2538
- document_datetime: z.string().min(1, { error: 'fieldIsRequired' }),
2539
- });
2540
- // Void Receipt Schema
2541
- const VoidReceiptInputSchema = z.object({
2542
- document_number: z.string().min(1, { error: 'fieldIsRequired' }),
2543
- });
2544
- const ReceiptReturnItemSchema = z
2545
- .array(z.object({
2546
- id: z.number(),
2547
- quantity: z.string().min(1, { error: 'fieldIsRequired' }),
2548
- }))
2549
- .min(1, { error: 'arrayMin1' });
2550
- // Receipt Return Schema
2551
- const ReceiptReturnInputSchema = z.object({
2552
- items: z.array(ReceiptReturnItemSchema).min(1, { error: 'arrayMin1' }),
2553
- document_number: z.string().min(1, { error: 'fieldIsRequired' }),
2554
- });
2555
-
2556
- // Cashier Create Input Schema (MF1)
2557
- const CashierCreateInputSchema = z.object({
2558
- email: z
2559
- .string()
2560
- .min(1, { error: 'fieldIsRequired' })
2561
- .max(255, { error: 'emailMaxLength' })
2562
- .email({ error: 'invalidEmail' }),
2563
- password: z
2564
- .string()
2565
- .min(8, { error: 'passwordMinLength' })
2566
- .max(40, { error: 'passwordMaxLength' }),
2567
- name: z.string().min(1, { error: 'fieldIsRequired' }).max(255, { error: 'nameMaxLength' }),
2568
- display_name: z
2569
- .string()
2570
- .min(1, { error: 'fieldIsRequired' })
2571
- .max(255, { error: 'displayNameMaxLength' }),
2572
- });
2573
2459
 
2574
2460
  // Enum options arrays
2575
2461
  const PEM_STATUS_OPTIONS = [
@@ -2580,312 +2466,12 @@ const PEM_STATUS_OPTIONS = [
2580
2466
  'OFFLINE',
2581
2467
  'DISCARDED',
2582
2468
  ];
2583
- // Address Schema (reusable)
2584
- const AddressSchema = z.object({
2585
- street_address: z.string().min(1, { error: 'fieldIsRequired' }),
2586
- street_number: z.string().min(1, { error: 'fieldIsRequired' }),
2587
- zip_code: z
2588
- .string()
2589
- .min(1, { error: 'fieldIsRequired' })
2590
- .regex(/^\d{5}$/, { error: 'invalidZipCode' }),
2591
- city: z.string().min(1, { error: 'fieldIsRequired' }),
2592
- province: z
2593
- .string()
2594
- .min(2, { error: 'provinceMinLength' })
2595
- .max(2, { error: 'provinceMaxLength' })
2596
- .toUpperCase(),
2597
- });
2598
- // PEM Status Schema
2599
- const PEMStatusSchema = z.enum(PEM_STATUS_OPTIONS);
2600
- // Activation Request Schema
2601
- const ActivationRequestSchema = z.object({
2602
- registration_key: z.string().min(1, { error: 'fieldIsRequired' }),
2603
- });
2604
- // PEM Status Offline Request Schema
2605
- const PEMStatusOfflineRequestSchema = z.object({
2606
- timestamp: z
2607
- .string()
2608
- .min(1, { error: 'fieldIsRequired' })
2609
- .refine((val) => !isNaN(Date.parse(val)), {
2610
- error: 'invalidDateFormat',
2611
- }),
2612
- reason: z.string().min(1, { error: 'fieldIsRequired' }),
2613
- });
2614
-
2615
- // Cash Register Create Schema
2616
- const CashRegisterCreateSchema = z.object({
2617
- pem_serial_number: z.string().min(1, { error: 'fieldIsRequired' }),
2618
- name: z.string().min(1, { error: 'fieldIsRequired' }).max(100, { error: 'nameMaxLength' }),
2619
- });
2620
-
2621
- // VAT number validation regex (Partita IVA - 11 digits)
2622
- const VAT_NUMBER_REGEX = /^\d{11}$/;
2623
- // Fiscal code validation regex (Codice Fiscale - 11 digits only for merchants)
2624
- const FISCAL_CODE_REGEX = /^\d{11}$/;
2625
- // Password validation regex (from OpenAPI spec)
2626
- const PASSWORD_REGEX = /^((?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{10,}).*)$/;
2627
- // Merchant Create Input Schema
2628
- const MerchantCreateInputSchema = z
2629
- .object({
2630
- vat_number: z
2631
- .string()
2632
- .min(1, { error: 'fieldIsRequired' })
2633
- .regex(VAT_NUMBER_REGEX, { error: 'invalidVatNumber' }),
2634
- fiscal_code: z.string().regex(FISCAL_CODE_REGEX, { error: 'invalidFiscalCode' }).optional(),
2635
- business_name: z.string().max(200, { error: 'businessNameMaxLength' }).optional().nullable(),
2636
- first_name: z.string().max(100, { error: 'firstNameMaxLength' }).optional().nullable(),
2637
- last_name: z.string().max(100, { error: 'lastNameMaxLength' }).optional().nullable(),
2638
- email: z.string().min(1, { error: 'fieldIsRequired' }).email({ error: 'invalidEmail' }),
2639
- password: z
2640
- .string()
2641
- .min(1, { error: 'fieldIsRequired' })
2642
- .regex(PASSWORD_REGEX, { error: 'passwordComplexity' }),
2643
- address: AddressSchema.optional(),
2644
- })
2645
- .refine((data) => {
2646
- const hasBusinessName = data.business_name && data.business_name.trim() !== '';
2647
- const hasPersonalNames = (data.first_name && data.first_name.trim() !== '') ||
2648
- (data.last_name && data.last_name.trim() !== '');
2649
- // If business name is set, first/last name must not be provided
2650
- if (hasBusinessName && hasPersonalNames) {
2651
- return false;
2652
- }
2653
- // At least one naming method must be provided
2654
- if (!hasBusinessName && !hasPersonalNames) {
2655
- return false;
2656
- }
2657
- return true;
2658
- }, {
2659
- error: 'businessNameOrPersonalNamesRequired',
2660
- path: ['business_name'],
2661
- });
2662
- // Merchant Update Input Schema
2663
- const MerchantUpdateInputSchema = z.object({
2664
- business_name: z.string().max(200, { error: 'businessNameMaxLength' }).optional().nullable(),
2665
- first_name: z.string().max(100, { error: 'firstNameMaxLength' }).optional().nullable(),
2666
- last_name: z.string().max(100, { error: 'lastNameMaxLength' }).optional().nullable(),
2667
- address: AddressSchema.optional().nullable(),
2668
- });
2669
2469
 
2670
2470
  // Enum options arrays
2671
2471
  const PEM_TYPE_OPTIONS = ['AP', 'SP', 'TM', 'PV'];
2672
- // PEM Data Schema
2673
- const PemDataSchema = z.object({
2674
- version: z.string().min(1, { error: 'fieldIsRequired' }),
2675
- type: z.enum(PEM_TYPE_OPTIONS, {
2676
- error: 'invalidPemType',
2677
- }),
2678
- });
2679
- // PEM Create Input Schema
2680
- const PemCreateInputSchema = z.object({
2681
- merchant_uuid: z.string().min(1, { error: 'fieldIsRequired' }).uuid({ error: 'invalidUuid' }),
2682
- address: AddressSchema.optional(),
2683
- /* external_pem_data: PemDataSchema.optional(), */
2684
- });
2685
2472
 
2686
- // Italian Fiscal ID validation regex (Codice Fiscale for individuals or Partita IVA for companies)
2687
- const FISCAL_ID_REGEX = /^([A-Z]{6}[0-9LMNPQRSTUV]{2}[ABCDEHLMPRST][0-9LMNPQRSTUV]{2}[A-Z][0-9LMNPQRSTUV]{3}[A-Z]|[0-9]{11})$/;
2688
- // Supplier Create Input Schema
2689
- const SupplierCreateInputSchema = z.object({
2690
- fiscal_id: z
2691
- .string()
2692
- .min(1, { error: 'fieldIsRequired' })
2693
- .regex(FISCAL_ID_REGEX, { error: 'invalidFiscalId' })
2694
- .toUpperCase(),
2695
- name: z.string().min(1, { error: 'fieldIsRequired' }).max(200, { error: 'nameMaxLength' }),
2696
- address: AddressSchema.optional(),
2697
- });
2698
- // Supplier Update Input Schema
2699
- const SupplierUpdateInputSchema = z.object({
2700
- name: z.string().min(1, { error: 'fieldIsRequired' }).max(200, { error: 'nameMaxLength' }),
2701
- address: AddressSchema.optional(),
2702
- });
2703
-
2704
- // Journal Close Input Schema
2705
- const JournalCloseInputSchema = z.object({
2706
- closing_timestamp: z
2707
- .string()
2708
- .min(1, { error: 'fieldIsRequired' })
2709
- .refine((val) => !isNaN(Date.parse(val)), {
2710
- error: 'invalidDateFormat',
2711
- }),
2712
- reason: z.string().max(255, { error: 'reasonMaxLength' }).optional(),
2713
- });
2714
-
2715
- // Daily Report Status Options
2473
+ // Enum options arrays
2716
2474
  const DAILY_REPORT_STATUS_OPTIONS = ['pending', 'sent', 'error'];
2717
- // Daily Report Status Schema
2718
- const DailyReportStatusSchema = z.enum(DAILY_REPORT_STATUS_OPTIONS, {
2719
- error: 'invalidDailyReportStatus',
2720
- });
2721
- // Daily Reports List Parameters Schema
2722
- const DailyReportsParamsSchema = z.object({
2723
- pem_serial_number: z.string().min(1, { error: 'fieldIsRequired' }).optional(),
2724
- date_from: z
2725
- .string()
2726
- .refine((val) => !isNaN(Date.parse(val)), {
2727
- error: 'invalidDateFormat',
2728
- })
2729
- .optional(),
2730
- date_to: z
2731
- .string()
2732
- .refine((val) => !isNaN(Date.parse(val)), {
2733
- error: 'invalidDateFormat',
2734
- })
2735
- .optional(),
2736
- status: DailyReportStatusSchema.optional(),
2737
- page: z.number().min(1, { error: 'pageMinValue' }).optional(),
2738
- });
2739
-
2740
- const NotificationScopeSchema = z.object({
2741
- type: z.literal('global'),
2742
- });
2743
- const PemStatusSchema = z.enum(['ONLINE', 'OFFLINE']);
2744
- const NotificationDataBlockAtSchema = z.object({
2745
- block_at: z.string(),
2746
- });
2747
- const NotificationDataPemStatusSchema = z.object({
2748
- from: PemStatusSchema,
2749
- to: PemStatusSchema,
2750
- });
2751
- const NotificationBaseSchema = z.object({
2752
- uuid: z.string().uuid({ error: 'invalidUuid' }),
2753
- scope: NotificationScopeSchema,
2754
- source: z.enum(['system', 'Italian Tax Authority']),
2755
- level: z.enum(['info', 'warning', 'error', 'critical']),
2756
- created_at: z.string(),
2757
- });
2758
- const NotificationMf2UnreachableSchema = NotificationBaseSchema.extend({
2759
- type: z.literal('INTERNAL_COMMUNICATION_FAILURE'),
2760
- code: z.literal('SYS-W-01'),
2761
- data: NotificationDataBlockAtSchema,
2762
- });
2763
- const NotificationPemsBlockedSchema = NotificationBaseSchema.extend({
2764
- type: z.literal('PEM_STATUS_CHANGED'),
2765
- code: z.literal('SYS-C-01'),
2766
- data: NotificationDataPemStatusSchema,
2767
- });
2768
- const NotificationPemBackOnlineSchema = NotificationBaseSchema.extend({
2769
- type: z.literal('PEM_STATUS_CHANGED'),
2770
- code: z.literal('SYS-I-01'),
2771
- data: NotificationDataPemStatusSchema,
2772
- });
2773
- const NotificationSchema = z.discriminatedUnion('code', [
2774
- NotificationMf2UnreachableSchema,
2775
- NotificationPemsBlockedSchema,
2776
- NotificationPemBackOnlineSchema,
2777
- ]);
2778
- const NotificationListResponseSchema = z.object({
2779
- members: z.array(NotificationSchema),
2780
- });
2781
-
2782
- const TelemetryMerchantSchema = z.object({
2783
- vat_number: z.string(),
2784
- fiscal_code: z.string().nullable(),
2785
- business_name: z.string(),
2786
- });
2787
- const TelemetrySupplierSchema = z.object({
2788
- vat_number: z.string(),
2789
- fiscal_code: z.string().nullable(),
2790
- business_name: z.string(),
2791
- });
2792
- const TelemetrySoftwareVersionSchema = z.object({
2793
- version: z.string(),
2794
- swid: z.string(),
2795
- installed_at: z.string(),
2796
- status: z.enum(['active', 'inactive', 'archived']),
2797
- });
2798
- const TelemetrySoftwareSchema = z.object({
2799
- code: z.string(),
2800
- name: z.string(),
2801
- approval_reference: z.string(),
2802
- version_info: TelemetrySoftwareVersionSchema,
2803
- });
2804
- const PendingReceiptsSchema = z.object({
2805
- count: z.number().int().nonnegative(),
2806
- total_amount: z.string(),
2807
- });
2808
- const TransmissionSchema = z.object({
2809
- attempted_at: z.string(),
2810
- outcome: z.enum(['success', 'failed', 'pending']),
2811
- });
2812
- const MessageSchema = z.object({
2813
- received_at: z.string(),
2814
- content: z.string(),
2815
- });
2816
- const LotterySecretRequestSchema = z.object({
2817
- requested_at: z.string(),
2818
- outcome: z.enum(['success', 'failed', 'pending']),
2819
- });
2820
- const LotterySchema = z.object({
2821
- last_transmission: TransmissionSchema,
2822
- secret_request: LotterySecretRequestSchema,
2823
- });
2824
- const TelemetrySchema = z.object({
2825
- pem_id: z.string(),
2826
- pem_status: z.enum(['ONLINE', 'OFFLINE', 'ERROR']),
2827
- pem_status_changed_at: z.string(),
2828
- merchant: TelemetryMerchantSchema,
2829
- supplier: TelemetrySupplierSchema,
2830
- software: TelemetrySoftwareSchema,
2831
- last_communication_at: z.string(),
2832
- pending_receipts: PendingReceiptsSchema,
2833
- last_receipt_transmission: TransmissionSchema,
2834
- last_message_from_mf2: MessageSchema,
2835
- ade_corrispettivi_transmission: TransmissionSchema,
2836
- last_message_from_ade: MessageSchema,
2837
- lottery: LotterySchema,
2838
- });
2839
-
2840
- // Receipt schemas and types
2841
- // Common validation utilities
2842
- const ValidationMessages = {
2843
- fieldIsRequired: 'This field is required',
2844
- arrayMin1: 'At least one item is required',
2845
- paymentMethodRequired: 'At least one payment method is required',
2846
- invalidEmail: 'Please enter a valid email address',
2847
- passwordMinLength: 'Password must be at least 8 characters long',
2848
- passwordComplexity: 'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character',
2849
- invalidZipCode: 'Please enter a valid 5-digit zip code',
2850
- provinceMinLength: 'Province code must be 2 characters',
2851
- provinceMaxLength: 'Province code must be 2 characters',
2852
- invalidDateFormat: 'Please enter a valid date',
2853
- nameMaxLength: 'Name is too long',
2854
- invalidFiscalId: 'Please enter a valid Italian fiscal ID (Codice Fiscale or Partita IVA)',
2855
- invalidVatNumber: 'Please enter a valid VAT number (11 digits)',
2856
- invalidFiscalCode: 'Please enter a valid fiscal code (11 digits)',
2857
- businessNameMaxLength: 'Business name is too long (max 200 characters)',
2858
- businessNameOrPersonalNamesRequired: 'Please provide either a business name or first/last name, but not both',
2859
- firstNameMaxLength: 'First name is too long (max 100 characters)',
2860
- lastNameMaxLength: 'Last name is too long (max 100 characters)',
2861
- invalidUuid: 'Please enter a valid UUID',
2862
- invalidPemType: 'PEM type must be one of: AP, SP, TM, PV',
2863
- reasonMaxLength: 'Reason is too long (max 255 characters)',
2864
- pageMinValue: 'Page number must be at least 1',
2865
- invalidDailyReportStatus: 'Daily report status must be one of: pending, sent, error',
2866
- displayNameMaxLength: 'Display name is too long (max 255 characters)',
2867
- };
2868
- // Validation helper functions
2869
- const validateInput = (schema, data) => {
2870
- const result = schema.safeParse(data);
2871
- if (!result.success) {
2872
- const errors = result.error.issues.map((error) => ({
2873
- field: error.path.join('.'),
2874
- message: error.message,
2875
- code: error.code,
2876
- }));
2877
- return {
2878
- success: false,
2879
- errors,
2880
- data: null,
2881
- };
2882
- }
2883
- return {
2884
- success: true,
2885
- errors: [],
2886
- data: result.data,
2887
- };
2888
- };
2889
2475
 
2890
2476
  class ACubeSDKError extends Error {
2891
2477
  constructor(type, message, originalError, statusCode, violations) {
@@ -2898,7 +2484,7 @@ class ACubeSDKError extends Error {
2898
2484
  }
2899
2485
  }
2900
2486
 
2901
- const log$g = createPrefixedLogger('AUTH-STRATEGY');
2487
+ const log$a = createPrefixedLogger('AUTH-STRATEGY');
2902
2488
  class AuthStrategy {
2903
2489
  constructor(jwtHandler, mtlsHandler, userProvider, mtlsAdapter) {
2904
2490
  this.jwtHandler = jwtHandler;
@@ -2913,7 +2499,7 @@ class AuthStrategy {
2913
2499
  const platform = this.detectPlatform();
2914
2500
  const userRole = await this.getUserRole();
2915
2501
  const isReceiptEndpoint = this.isReceiptEndpoint(url);
2916
- log$g.debug('Determining auth config', {
2502
+ log$a.debug('Determining auth config', {
2917
2503
  url,
2918
2504
  method,
2919
2505
  platform,
@@ -3044,7 +2630,7 @@ class JwtAuthHandler {
3044
2630
  }
3045
2631
  }
3046
2632
 
3047
- const log$f = createPrefixedLogger('MTLS-HANDLER');
2633
+ const log$9 = createPrefixedLogger('MTLS-HANDLER');
3048
2634
  class MtlsAuthHandler {
3049
2635
  constructor(mtlsAdapter, certificatePort) {
3050
2636
  this.mtlsAdapter = mtlsAdapter;
@@ -3086,7 +2672,7 @@ class MtlsAuthHandler {
3086
2672
  async makeRequest(url, config, jwtToken) {
3087
2673
  const requestKey = this.generateRequestKey(url, config, jwtToken);
3088
2674
  if (this.pendingRequests.has(requestKey)) {
3089
- log$f.debug('Deduplicating concurrent request:', url);
2675
+ log$9.debug('Deduplicating concurrent request:', url);
3090
2676
  return this.pendingRequests.get(requestKey);
3091
2677
  }
3092
2678
  const requestPromise = this.executeRequest(url, config, jwtToken, false);
@@ -3110,10 +2696,10 @@ class MtlsAuthHandler {
3110
2696
  };
3111
2697
  if (jwtToken) {
3112
2698
  headers['Authorization'] = `Bearer ${jwtToken}`;
3113
- log$f.debug('JWT token present:', jwtToken.substring(0, 20) + '...');
2699
+ log$9.debug('JWT token present:', jwtToken.substring(0, 20) + '...');
3114
2700
  }
3115
2701
  else {
3116
- log$f.warn('No JWT token provided for mTLS request');
2702
+ log$9.warn('No JWT token provided for mTLS request');
3117
2703
  }
3118
2704
  const fullUrl = this.constructMtlsUrl(url);
3119
2705
  const mtlsConfig = {
@@ -3124,25 +2710,25 @@ class MtlsAuthHandler {
3124
2710
  timeout: config.timeout,
3125
2711
  responseType: config.responseType,
3126
2712
  };
3127
- log$f.debug('header-mtls', headers);
3128
- log$f.debug(`${config.method} ${fullUrl}`);
2713
+ log$9.debug('header-mtls', headers);
2714
+ log$9.debug(`${config.method} ${fullUrl}`);
3129
2715
  if (config.data) {
3130
- log$f.debug('Request body:', config.data);
2716
+ log$9.debug('Request body:', config.data);
3131
2717
  }
3132
2718
  try {
3133
2719
  const response = await this.mtlsAdapter.request(mtlsConfig);
3134
- log$f.debug(`Response ${response.status} from ${fullUrl}`);
2720
+ log$9.debug(`Response ${response.status} from ${fullUrl}`);
3135
2721
  if (response.data) {
3136
- log$f.debug('Response body:', response.data);
2722
+ log$9.debug('Response body:', response.data);
3137
2723
  }
3138
2724
  return response.data;
3139
2725
  }
3140
2726
  catch (error) {
3141
- log$f.error(`Response error from ${fullUrl}:`, error);
2727
+ log$9.error(`Response error from ${fullUrl}:`, error);
3142
2728
  if (error && typeof error === 'object' && 'response' in error) {
3143
2729
  const axiosError = error;
3144
2730
  if (axiosError.response?.data) {
3145
- log$f.error('Response body:', axiosError.response.data);
2731
+ log$9.error('Response body:', axiosError.response.data);
3146
2732
  }
3147
2733
  }
3148
2734
  if (isRetryAttempt) {
@@ -3152,7 +2738,7 @@ class MtlsAuthHandler {
3152
2738
  if (!shouldRetry) {
3153
2739
  throw error;
3154
2740
  }
3155
- log$f.debug('Request failed, reconfiguring certificate and retrying...');
2741
+ log$9.debug('Request failed, reconfiguring certificate and retrying...');
3156
2742
  try {
3157
2743
  await this.configureCertificate(certificate);
3158
2744
  return await this.executeRequest(url, config, jwtToken, true);
@@ -3167,2000 +2753,99 @@ class MtlsAuthHandler {
3167
2753
  const message = error.message.toLowerCase();
3168
2754
  return (message.includes('certificate') ||
3169
2755
  message.includes('ssl') ||
3170
- message.includes('tls') ||
3171
- message.includes('handshake'));
3172
- }
3173
- return false;
3174
- }
3175
- async configureCertificate(certificate) {
3176
- if (!this.mtlsAdapter) {
3177
- throw new Error('mTLS adapter not available');
3178
- }
3179
- const certificateData = {
3180
- certificate: certificate.certificate,
3181
- privateKey: certificate.privateKey,
3182
- format: certificate.format.toUpperCase(),
3183
- };
3184
- await this.mtlsAdapter.configureCertificate(certificateData);
3185
- }
3186
- async storeCertificate(certificate, privateKey, options = {}) {
3187
- if (!this.certificatePort) {
3188
- throw new Error('Certificate port not available');
3189
- }
3190
- if (this.mtlsAdapter) {
3191
- try {
3192
- await this.mtlsAdapter.removeCertificate();
3193
- }
3194
- catch {
3195
- // No existing certificate to remove
3196
- }
3197
- }
3198
- const format = (options.format || 'pem');
3199
- await this.certificatePort.storeCertificate(certificate, privateKey, format);
3200
- if (this.mtlsAdapter) {
3201
- const certificateData = {
3202
- certificate,
3203
- privateKey,
3204
- format: format.toUpperCase(),
3205
- };
3206
- await this.mtlsAdapter.configureCertificate(certificateData);
3207
- }
3208
- }
3209
- async clearCertificate() {
3210
- if (this.mtlsAdapter) {
3211
- try {
3212
- await this.mtlsAdapter.removeCertificate();
3213
- }
3214
- catch {
3215
- // No certificate to remove
3216
- }
3217
- }
3218
- if (this.certificatePort) {
3219
- await this.certificatePort.clearCertificate();
3220
- }
3221
- }
3222
- async testConnection() {
3223
- if (!this.mtlsAdapter) {
3224
- return false;
3225
- }
3226
- return this.mtlsAdapter.testConnection();
3227
- }
3228
- getBaseUrl() {
3229
- if (!this.mtlsAdapter) {
3230
- return null;
3231
- }
3232
- return this.mtlsAdapter.getBaseUrl();
3233
- }
3234
- async getStatus() {
3235
- const status = {
3236
- adapterAvailable: !!this.mtlsAdapter,
3237
- certificatePortAvailable: !!this.certificatePort,
3238
- isReady: false,
3239
- hasCertificate: false,
3240
- certificateInfo: null,
3241
- platformInfo: this.mtlsAdapter?.getPlatformInfo() || null,
3242
- pendingRequestsCount: this.pendingRequests.size,
3243
- };
3244
- if (this.certificatePort) {
3245
- try {
3246
- status.hasCertificate = await this.certificatePort.hasCertificate();
3247
- if (status.hasCertificate) {
3248
- status.certificateInfo = await this.certificatePort.getCertificateInfo();
3249
- }
3250
- }
3251
- catch {
3252
- // Ignore errors
3253
- }
3254
- }
3255
- status.isReady = await this.isMtlsReady();
3256
- return status;
3257
- }
3258
- clearPendingRequests() {
3259
- this.pendingRequests.clear();
3260
- }
3261
- }
3262
-
3263
- const DEFAULT_QUEUE_CONFIG = {
3264
- maxRetries: 3,
3265
- retryDelay: 1000,
3266
- maxRetryDelay: 30000,
3267
- backoffMultiplier: 2,
3268
- maxQueueSize: 1000,
3269
- batchSize: 10,
3270
- syncInterval: 30000,
3271
- };
3272
-
3273
- class OperationQueue {
3274
- constructor(storage, config = DEFAULT_QUEUE_CONFIG, events = {}) {
3275
- this.storage = storage;
3276
- this.config = config;
3277
- this.events = events;
3278
- this.queue = [];
3279
- this.processing = false;
3280
- this.config = { ...DEFAULT_QUEUE_CONFIG, ...config };
3281
- this.loadQueue();
3282
- if (this.config.syncInterval > 0) {
3283
- this.startAutoSync();
3284
- }
3285
- }
3286
- async addOperation(type, resource, endpoint, method, data, priority = 1) {
3287
- if (this.queue.length >= this.config.maxQueueSize) {
3288
- const lowPriorityIndex = this.queue.findIndex((op) => op.priority === 1);
3289
- if (lowPriorityIndex !== -1) {
3290
- this.queue.splice(lowPriorityIndex, 1);
3291
- }
3292
- else {
3293
- throw new Error('Queue is full');
3294
- }
3295
- }
3296
- const operation = {
3297
- id: this.generateId(),
3298
- type,
3299
- resource,
3300
- endpoint,
3301
- method,
3302
- data,
3303
- status: 'pending',
3304
- createdAt: Date.now(),
3305
- updatedAt: Date.now(),
3306
- retryCount: 0,
3307
- maxRetries: this.config.maxRetries,
3308
- priority,
3309
- };
3310
- const insertIndex = this.queue.findIndex((op) => op.priority < priority);
3311
- if (insertIndex === -1) {
3312
- this.queue.push(operation);
3313
- }
3314
- else {
3315
- this.queue.splice(insertIndex, 0, operation);
3316
- }
3317
- await this.saveQueue();
3318
- this.events.onOperationAdded?.(operation);
3319
- return operation.id;
3320
- }
3321
- getPendingOperations() {
3322
- return this.queue.filter((op) => op.status === 'pending' || op.status === 'failed');
3323
- }
3324
- getOperation(id) {
3325
- return this.queue.find((op) => op.id === id);
3326
- }
3327
- async removeOperation(id) {
3328
- const index = this.queue.findIndex((op) => op.id === id);
3329
- if (index === -1)
3330
- return false;
3331
- this.queue.splice(index, 1);
3332
- await this.saveQueue();
3333
- return true;
3334
- }
3335
- async updateOperation(id, updates) {
3336
- const operation = this.queue.find((op) => op.id === id);
3337
- if (!operation)
3338
- return false;
3339
- Object.assign(operation, { ...updates, updatedAt: Date.now() });
3340
- await this.saveQueue();
3341
- return true;
3342
- }
3343
- getStats() {
3344
- return {
3345
- total: this.queue.length,
3346
- pending: this.queue.filter((op) => op.status === 'pending').length,
3347
- processing: this.queue.filter((op) => op.status === 'processing').length,
3348
- completed: this.queue.filter((op) => op.status === 'completed').length,
3349
- failed: this.queue.filter((op) => op.status === 'failed').length,
3350
- };
3351
- }
3352
- async clearQueue() {
3353
- this.queue = [];
3354
- await this.saveQueue();
3355
- }
3356
- async clearCompleted() {
3357
- this.queue = this.queue.filter((op) => op.status !== 'completed');
3358
- await this.saveQueue();
3359
- }
3360
- async clearFailed() {
3361
- this.queue = this.queue.filter((op) => op.status !== 'failed');
3362
- await this.saveQueue();
3363
- }
3364
- async retryFailed() {
3365
- for (const operation of this.queue.filter((op) => op.status === 'failed')) {
3366
- if (operation.retryCount < operation.maxRetries) {
3367
- operation.status = 'pending';
3368
- operation.retryCount++;
3369
- operation.updatedAt = Date.now();
3370
- delete operation.error;
3371
- }
3372
- }
3373
- await this.saveQueue();
3374
- }
3375
- getNextBatch() {
3376
- return this.queue
3377
- .filter((op) => op.status === 'pending')
3378
- .sort((a, b) => b.priority - a.priority || a.createdAt - b.createdAt)
3379
- .slice(0, this.config.batchSize);
3380
- }
3381
- isEmpty() {
3382
- return this.getPendingOperations().length === 0;
3383
- }
3384
- startAutoSync() {
3385
- if (this.syncIntervalId)
3386
- return;
3387
- this.syncIntervalId = setInterval(() => {
3388
- if (!this.isEmpty() && !this.processing) {
3389
- this.events.onQueueEmpty?.();
3390
- }
3391
- }, this.config.syncInterval);
3392
- }
3393
- stopAutoSync() {
3394
- if (this.syncIntervalId) {
3395
- clearInterval(this.syncIntervalId);
3396
- this.syncIntervalId = undefined;
3397
- }
3398
- }
3399
- setProcessing(value) {
3400
- this.processing = value;
3401
- }
3402
- isCurrentlyProcessing() {
3403
- return this.processing;
3404
- }
3405
- async loadQueue() {
3406
- try {
3407
- const queueData = await this.storage.get(OperationQueue.QUEUE_KEY);
3408
- if (queueData) {
3409
- this.queue = JSON.parse(queueData);
3410
- this.queue.forEach((op) => {
3411
- if (op.status === 'processing') {
3412
- op.status = 'pending';
3413
- }
3414
- });
3415
- }
3416
- }
3417
- catch {
3418
- this.queue = [];
3419
- }
3420
- }
3421
- async saveQueue() {
3422
- try {
3423
- await this.storage.set(OperationQueue.QUEUE_KEY, JSON.stringify(this.queue));
3424
- }
3425
- catch (error) {
3426
- this.events.onError?.(new Error(`Failed to save queue: ${error}`));
3427
- }
3428
- }
3429
- generateId() {
3430
- return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
3431
- }
3432
- destroy() {
3433
- this.stopAutoSync();
3434
- }
3435
- }
3436
- OperationQueue.QUEUE_KEY = 'acube_operation_queue';
3437
-
3438
- class SyncManager {
3439
- constructor(queue, httpPort, networkMonitor, config, events = {}) {
3440
- this.queue = queue;
3441
- this.httpPort = httpPort;
3442
- this.networkMonitor = networkMonitor;
3443
- this.config = config;
3444
- this.events = events;
3445
- this.isOnline = true;
3446
- this.destroy$ = new Subject();
3447
- this.setupNetworkMonitoring();
3448
- }
3449
- setupNetworkMonitoring() {
3450
- // Subscribe to online$ to track current state
3451
- this.networkSubscription = this.networkMonitor.online$
3452
- .pipe(startWith(true), // Assume online initially
3453
- pairwise(), filter(([wasOnline, isNowOnline]) => !wasOnline && isNowOnline), takeUntil(this.destroy$))
3454
- .subscribe(() => {
3455
- // Offline → Online transition detected
3456
- this.syncPendingOperations();
3457
- });
3458
- // Track current online state
3459
- this.networkMonitor.online$.pipe(takeUntil(this.destroy$)).subscribe((online) => {
3460
- this.isOnline = online;
3461
- });
3462
- }
3463
- async syncPendingOperations() {
3464
- if (!this.isOnline) {
3465
- throw new Error('Cannot sync while offline');
3466
- }
3467
- if (this.queue.isCurrentlyProcessing()) {
3468
- throw new Error('Sync already in progress');
3469
- }
3470
- this.queue.setProcessing(true);
3471
- try {
3472
- const results = [];
3473
- let successCount = 0;
3474
- let failureCount = 0;
3475
- while (!this.queue.isEmpty()) {
3476
- const batch = this.queue.getNextBatch();
3477
- if (batch.length === 0)
3478
- break;
3479
- const batchPromises = batch.map((operation) => this.processOperation(operation));
3480
- const batchResults = await Promise.allSettled(batchPromises);
3481
- batchResults.forEach((result, index) => {
3482
- const operation = batch[index];
3483
- if (!operation)
3484
- return;
3485
- if (result.status === 'fulfilled') {
3486
- const syncResult = result.value;
3487
- results.push(syncResult);
3488
- if (syncResult.success) {
3489
- successCount++;
3490
- this.events.onOperationCompleted?.(syncResult);
3491
- }
3492
- else {
3493
- failureCount++;
3494
- this.events.onOperationFailed?.(syncResult);
3495
- }
3496
- }
3497
- else {
3498
- const syncResult = {
3499
- operation,
3500
- success: false,
3501
- error: result.reason?.message || 'Unknown error',
3502
- };
3503
- results.push(syncResult);
3504
- failureCount++;
3505
- this.events.onOperationFailed?.(syncResult);
3506
- this.queue.updateOperation(operation.id, {
3507
- status: 'failed',
3508
- error: syncResult.error,
3509
- });
3510
- }
3511
- });
3512
- if (!this.queue.isEmpty()) {
3513
- await this.delay(500);
3514
- }
3515
- }
3516
- const batchResult = {
3517
- totalOperations: results.length,
3518
- successCount,
3519
- failureCount,
3520
- results,
3521
- };
3522
- this.events.onBatchSyncCompleted?.(batchResult);
3523
- if (this.queue.isEmpty()) {
3524
- this.events.onQueueEmpty?.();
3525
- }
3526
- return batchResult;
3527
- }
3528
- finally {
3529
- this.queue.setProcessing(false);
3530
- }
3531
- }
3532
- async processOperation(operation) {
3533
- await this.queue.updateOperation(operation.id, { status: 'processing' });
3534
- try {
3535
- const response = await this.executeOperation(operation);
3536
- await this.queue.updateOperation(operation.id, { status: 'completed' });
3537
- return { operation, success: true, response };
3538
- }
3539
- catch (error) {
3540
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
3541
- if (operation.retryCount < operation.maxRetries && this.isRetryableError(error)) {
3542
- const delay = this.calculateRetryDelay(operation.retryCount);
3543
- await this.queue.updateOperation(operation.id, {
3544
- status: 'pending',
3545
- retryCount: operation.retryCount + 1,
3546
- error: errorMessage,
3547
- });
3548
- setTimeout(() => {
3549
- if (this.isOnline && !this.queue.isCurrentlyProcessing()) {
3550
- this.syncPendingOperations();
3551
- }
3552
- }, delay);
3553
- return { operation, success: false, error: `Retrying: ${errorMessage}` };
3554
- }
3555
- else {
3556
- await this.queue.updateOperation(operation.id, {
3557
- status: 'failed',
3558
- error: errorMessage,
3559
- });
3560
- return { operation, success: false, error: errorMessage };
3561
- }
3562
- }
3563
- }
3564
- async executeOperation(operation) {
3565
- const { method, endpoint, data, headers } = operation;
3566
- const config = headers ? { headers } : undefined;
3567
- switch (method) {
3568
- case 'GET':
3569
- return (await this.httpPort.get(endpoint, config)).data;
3570
- case 'POST':
3571
- return (await this.httpPort.post(endpoint, data, config)).data;
3572
- case 'PUT':
3573
- return (await this.httpPort.put(endpoint, data, config)).data;
3574
- case 'PATCH':
3575
- return (await this.httpPort.patch(endpoint, data, config)).data;
3576
- case 'DELETE':
3577
- return (await this.httpPort.delete(endpoint, config)).data;
3578
- default:
3579
- throw new Error(`Unsupported HTTP method: ${method}`);
3580
- }
3581
- }
3582
- isRetryableError(error) {
3583
- const errorObj = error;
3584
- if (errorObj.code === 'NETWORK_ERROR')
3585
- return true;
3586
- if (errorObj.statusCode && errorObj.statusCode >= 500)
3587
- return true;
3588
- if (errorObj.statusCode === 429)
3589
- return true;
3590
- const errorMessage = error?.message;
3591
- if (errorObj.code === 'ECONNABORTED' || errorMessage?.includes('timeout'))
3592
- return true;
3593
- return false;
3594
- }
3595
- calculateRetryDelay(retryCount) {
3596
- const delay = this.config.retryDelay * Math.pow(this.config.backoffMultiplier, retryCount);
3597
- return Math.min(delay, this.config.maxRetryDelay);
3598
- }
3599
- delay(ms) {
3600
- return new Promise((resolve) => setTimeout(resolve, ms));
3601
- }
3602
- isCurrentlyOnline() {
3603
- return this.isOnline;
3604
- }
3605
- async triggerSync() {
3606
- if (!this.isOnline)
3607
- return null;
3608
- if (this.queue.isEmpty()) {
3609
- return { totalOperations: 0, successCount: 0, failureCount: 0, results: [] };
3610
- }
3611
- return await this.syncPendingOperations();
3612
- }
3613
- getSyncStatus() {
3614
- return {
3615
- isOnline: this.isOnline,
3616
- isProcessing: this.queue.isCurrentlyProcessing(),
3617
- queueStats: this.queue.getStats(),
3618
- };
3619
- }
3620
- destroy() {
3621
- this.destroy$.next();
3622
- this.destroy$.complete();
3623
- this.networkSubscription?.unsubscribe();
3624
- }
3625
- }
3626
-
3627
- class OfflineManager {
3628
- get queue$() {
3629
- return this.queueSubject.asObservable();
3630
- }
3631
- get syncStatus$() {
3632
- return this.syncStatusSubject.asObservable();
3633
- }
3634
- constructor(storage, httpPort, networkMonitor, config = {}, events = {}, _cache) {
3635
- this.queueSubject = new BehaviorSubject([]);
3636
- this.syncStatusSubject = new BehaviorSubject({
3637
- isOnline: true,
3638
- isProcessing: false,
3639
- queueStats: { total: 0, pending: 0, processing: 0, completed: 0, failed: 0 },
3640
- });
3641
- this.destroy$ = new Subject();
3642
- const finalConfig = { ...DEFAULT_QUEUE_CONFIG, ...config };
3643
- const wrappedEvents = {
3644
- ...events,
3645
- onOperationAdded: (op) => {
3646
- this.updateQueueState();
3647
- events.onOperationAdded?.(op);
3648
- },
3649
- onOperationCompleted: (result) => {
3650
- this.updateQueueState();
3651
- events.onOperationCompleted?.(result);
3652
- },
3653
- onOperationFailed: (result) => {
3654
- this.updateQueueState();
3655
- events.onOperationFailed?.(result);
3656
- },
3657
- onBatchSyncCompleted: (result) => {
3658
- this.updateQueueState();
3659
- events.onBatchSyncCompleted?.(result);
3660
- },
3661
- };
3662
- this.queue = new OperationQueue(storage, finalConfig, wrappedEvents);
3663
- this.syncManager = new SyncManager(this.queue, httpPort, networkMonitor, finalConfig, wrappedEvents);
3664
- this.updateQueueState();
3665
- }
3666
- updateQueueState() {
3667
- this.queueSubject.next(this.queue.getPendingOperations());
3668
- this.syncStatusSubject.next(this.syncManager.getSyncStatus());
3669
- }
3670
- async queueOperation(type, resource, endpoint, method, data, priority = 1) {
3671
- const id = await this.queue.addOperation(type, resource, endpoint, method, data, priority);
3672
- this.updateQueueState();
3673
- return id;
3674
- }
3675
- async queueReceiptCreation(receiptData, priority = 2) {
3676
- return await this.queueOperation('CREATE', 'receipt', '/mf1/receipts', 'POST', receiptData, priority);
3677
- }
3678
- async queueReceiptVoid(voidData, priority = 3) {
3679
- return await this.queueOperation('DELETE', 'receipt', '/mf1/receipts', 'DELETE', voidData, priority);
3680
- }
3681
- async queueReceiptReturn(returnData, priority = 3) {
3682
- return await this.queueOperation('CREATE', 'receipt', '/mf1/receipts/return', 'POST', returnData, priority);
3683
- }
3684
- async queueCashierCreation(cashierData, priority = 1) {
3685
- return await this.queueOperation('CREATE', 'cashier', '/mf1/cashiers', 'POST', cashierData, priority);
3686
- }
3687
- isOnline() {
3688
- return this.syncManager.isCurrentlyOnline();
3689
- }
3690
- getStatus() {
3691
- return this.syncManager.getSyncStatus();
3692
- }
3693
- getPendingCount() {
3694
- return this.queue.getPendingOperations().length;
3695
- }
3696
- isEmpty() {
3697
- return this.queue.isEmpty();
3698
- }
3699
- async sync() {
3700
- const result = await this.syncManager.triggerSync();
3701
- this.updateQueueState();
3702
- return result;
3703
- }
3704
- async retryFailed() {
3705
- await this.queue.retryFailed();
3706
- this.updateQueueState();
3707
- if (this.isOnline()) {
3708
- await this.sync();
3709
- }
3710
- }
3711
- async clearCompleted() {
3712
- await this.queue.clearCompleted();
3713
- this.updateQueueState();
3714
- }
3715
- async clearFailed() {
3716
- await this.queue.clearFailed();
3717
- this.updateQueueState();
3718
- }
3719
- async clearAll() {
3720
- await this.queue.clearQueue();
3721
- this.updateQueueState();
3722
- }
3723
- getOperation(id) {
3724
- return this.queue.getOperation(id);
3725
- }
3726
- async removeOperation(id) {
3727
- const result = await this.queue.removeOperation(id);
3728
- this.updateQueueState();
3729
- return result;
3730
- }
3731
- getQueueStats() {
3732
- return this.queue.getStats();
3733
- }
3734
- startAutoSync() {
3735
- this.queue.startAutoSync();
3736
- }
3737
- stopAutoSync() {
3738
- this.queue.stopAutoSync();
3739
- }
3740
- destroy() {
3741
- this.destroy$.next();
3742
- this.destroy$.complete();
3743
- this.queue.destroy();
3744
- this.syncManager.destroy();
3745
- }
3746
- }
3747
-
3748
- class CompressionAdapter {
3749
- compress(data, threshold = 1024) {
3750
- const originalSize = data.length * 2;
3751
- if (originalSize < threshold) {
3752
- return {
3753
- data,
3754
- compressed: false,
3755
- originalSize,
3756
- compressedSize: originalSize,
3757
- };
3758
- }
3759
- try {
3760
- const compressed = this.compressString(data);
3761
- const compressedSize = compressed.length * 2;
3762
- if (compressedSize < originalSize) {
3763
- return {
3764
- data: compressed,
3765
- compressed: true,
3766
- originalSize,
3767
- compressedSize,
3768
- };
3769
- }
3770
- return {
3771
- data,
3772
- compressed: false,
3773
- originalSize,
3774
- compressedSize: originalSize,
3775
- };
3776
- }
3777
- catch {
3778
- return {
3779
- data,
3780
- compressed: false,
3781
- originalSize,
3782
- compressedSize: originalSize,
3783
- };
3784
- }
3785
- }
3786
- decompress(data, compressed) {
3787
- if (!compressed) {
3788
- return { data, wasCompressed: false };
3789
- }
3790
- try {
3791
- const decompressed = this.decompressString(data);
3792
- return { data: decompressed, wasCompressed: true };
3793
- }
3794
- catch {
3795
- return { data, wasCompressed: false };
3796
- }
3797
- }
3798
- estimateSavings(data) {
3799
- const repeated = data.match(/(.)\1{3,}/g);
3800
- if (!repeated)
3801
- return 0;
3802
- let savings = 0;
3803
- for (const match of repeated) {
3804
- const originalBytes = match.length * 2;
3805
- const compressedBytes = 6;
3806
- if (originalBytes > compressedBytes) {
3807
- savings += originalBytes - compressedBytes;
3808
- }
3809
- }
3810
- return Math.min(savings, data.length * 2 * 0.5);
3811
- }
3812
- compressString(input) {
3813
- let compressed = '';
3814
- let i = 0;
3815
- while (i < input.length) {
3816
- let count = 1;
3817
- const char = input[i];
3818
- while (i + count < input.length && input[i + count] === char && count < 255) {
3819
- count++;
3820
- }
3821
- if (count > 3) {
3822
- compressed += `~${count}${char}`;
3823
- }
3824
- else {
3825
- for (let j = 0; j < count; j++) {
3826
- compressed += char;
3827
- }
3828
- }
3829
- i += count;
3830
- }
3831
- return `COMP:${btoa(compressed)}`;
3832
- }
3833
- decompressString(input) {
3834
- if (!input.startsWith('COMP:')) {
3835
- return input;
3836
- }
3837
- const encodedData = input.substring(5);
3838
- if (!encodedData) {
3839
- return input;
3840
- }
3841
- const compressed = atob(encodedData);
3842
- let decompressed = '';
3843
- let i = 0;
3844
- while (i < compressed.length) {
3845
- if (compressed[i] === '~' && i + 2 < compressed.length) {
3846
- let countStr = '';
3847
- i++;
3848
- while (i < compressed.length) {
3849
- const char = compressed[i];
3850
- if (char && /\d/.test(char)) {
3851
- countStr += char;
3852
- i++;
3853
- }
3854
- else {
3855
- break;
3856
- }
3857
- }
3858
- if (countStr && i < compressed.length) {
3859
- const count = parseInt(countStr, 10);
3860
- const char = compressed[i];
3861
- for (let j = 0; j < count; j++) {
3862
- decompressed += char;
3863
- }
3864
- i++;
3865
- }
3866
- }
3867
- else {
3868
- decompressed += compressed[i];
3869
- i++;
3870
- }
3871
- }
3872
- return decompressed;
3873
- }
3874
- }
3875
- function compressData(data, threshold = 1024) {
3876
- return new CompressionAdapter().compress(data, threshold);
3877
- }
3878
- function decompressData(data, compressed) {
3879
- return new CompressionAdapter().decompress(data, compressed);
3880
- }
3881
-
3882
- const log$e = createPrefixedLogger('CACHE-RN');
3883
- /**
3884
- * React Native cache adapter using SQLite (Expo or react-native-sqlite-storage)
3885
- * Cache never expires - data persists until explicitly invalidated
3886
- */
3887
- class ReactNativeCacheAdapter {
3888
- constructor(options = {}) {
3889
- this.db = null;
3890
- this.initPromise = null;
3891
- this.isExpo = false;
3892
- this.hasCompressedColumn = false;
3893
- this.options = {
3894
- maxSize: 50 * 1024 * 1024, // 50MB
3895
- maxEntries: 10000,
3896
- compression: false,
3897
- compressionThreshold: 1024,
3898
- ...options,
3899
- };
3900
- this.initPromise = this.initialize();
3901
- }
3902
- normalizeResults(results) {
3903
- if (this.isExpo) {
3904
- const expoResults = results;
3905
- if (Array.isArray(expoResults)) {
3906
- return expoResults;
3907
- }
3908
- return expoResults.results || [];
3909
- }
3910
- else {
3911
- const rnResults = results;
3912
- const rows = rnResults.rows;
3913
- if (!rows || rows.length === 0)
3914
- return [];
3915
- const normalizedRows = [];
3916
- for (let i = 0; i < rows.length; i++) {
3917
- normalizedRows.push(rows.item(i));
3918
- }
3919
- return normalizedRows;
3920
- }
3921
- }
3922
- async initialize() {
3923
- if (this.db)
3924
- return;
3925
- try {
3926
- // Try Expo SQLite first
3927
- const ExpoSQLite = require('expo-sqlite');
3928
- this.db = await ExpoSQLite.openDatabaseAsync(ReactNativeCacheAdapter.DB_NAME);
3929
- this.isExpo = true;
3930
- await this.createTables();
3931
- }
3932
- catch (expoError) {
3933
- try {
3934
- // Fallback to react-native-sqlite-storage
3935
- const SQLite = require('react-native-sqlite-storage');
3936
- this.db = await new Promise((resolve, reject) => {
3937
- SQLite.openDatabase({
3938
- name: ReactNativeCacheAdapter.DB_NAME,
3939
- location: 'default',
3940
- }, resolve, reject);
3941
- });
3942
- this.isExpo = false;
3943
- await this.createTables();
3944
- }
3945
- catch (rnError) {
3946
- throw new Error(`Failed to initialize SQLite: Expo error: ${expoError}, RN error: ${rnError}`);
3947
- }
3948
- }
3949
- }
3950
- async createTables() {
3951
- // Create table with simplified schema (no TTL)
3952
- const createTableSQL = `
3953
- CREATE TABLE IF NOT EXISTS ${ReactNativeCacheAdapter.TABLE_NAME} (
3954
- cache_key TEXT PRIMARY KEY,
3955
- data TEXT NOT NULL,
3956
- timestamp INTEGER NOT NULL
3957
- );
3958
-
3959
- CREATE INDEX IF NOT EXISTS idx_timestamp ON ${ReactNativeCacheAdapter.TABLE_NAME}(timestamp);
3960
- `;
3961
- await this.executeSql(createTableSQL);
3962
- // Then, run migrations to add new columns if they don't exist
3963
- await this.runMigrations();
3964
- }
3965
- async runMigrations() {
3966
- log$e.debug('Running database migrations...');
3967
- try {
3968
- // Check if compressed column exists
3969
- this.hasCompressedColumn = await this.checkColumnExists('compressed');
3970
- if (!this.hasCompressedColumn) {
3971
- log$e.debug('Adding compressed column to cache table');
3972
- const addColumnSQL = `ALTER TABLE ${ReactNativeCacheAdapter.TABLE_NAME} ADD COLUMN compressed INTEGER DEFAULT 0`;
3973
- await this.executeSql(addColumnSQL);
3974
- this.hasCompressedColumn = true;
3975
- log$e.debug('Successfully added compressed column');
3976
- }
3977
- else {
3978
- log$e.debug('Compressed column already exists');
3979
- }
3980
- log$e.debug('Database migrations completed', {
3981
- hasCompressedColumn: this.hasCompressedColumn,
3982
- });
3983
- }
3984
- catch (error) {
3985
- log$e.debug('Migration failed, disabling compression features', error);
3986
- this.hasCompressedColumn = false;
3987
- // Don't throw - allow the app to continue even if migration fails
3988
- // The compressed feature will just be disabled
3989
- }
3990
- }
3991
- async checkColumnExists(columnName) {
3992
- try {
3993
- const pragmaSQL = `PRAGMA table_info(${ReactNativeCacheAdapter.TABLE_NAME})`;
3994
- const results = await this.executeSql(pragmaSQL);
3995
- const columns = this.normalizeResults(results);
3996
- log$e.debug('Table columns found', { columns: columns.map((c) => c.name) });
3997
- return columns.some((column) => column.name === columnName);
3998
- }
3999
- catch (error) {
4000
- log$e.debug('Error checking column existence', error);
4001
- return false;
4002
- }
4003
- }
4004
- async get(key) {
4005
- await this.ensureInitialized();
4006
- const sql = `SELECT * FROM ${ReactNativeCacheAdapter.TABLE_NAME} WHERE cache_key = ?`;
4007
- log$e.debug('Executing get query', { sql, key });
4008
- const results = await this.executeSql(sql, [key]);
4009
- log$e.debug('Get query results', { key, hasResults: !!results });
4010
- // Normalize results from different SQLite implementations
4011
- const rows = this.normalizeResults(results);
4012
- if (!rows || rows.length === 0) {
4013
- return null;
4014
- }
4015
- const row = rows[0];
4016
- if (!row) {
4017
- return null;
4018
- }
4019
- const isCompressed = this.hasCompressedColumn ? !!row.compressed : false;
4020
- const rawData = isCompressed ? decompressData(row.data, true).data : row.data;
4021
- return {
4022
- data: JSON.parse(rawData),
4023
- timestamp: row.timestamp,
4024
- compressed: isCompressed,
4025
- };
4026
- }
4027
- async set(key, data) {
4028
- const item = {
4029
- data,
4030
- timestamp: Date.now(),
4031
- };
4032
- log$e.debug('Setting cache item', { key });
4033
- return this.setItem(key, item);
4034
- }
4035
- async setItem(key, item) {
4036
- await this.ensureInitialized();
4037
- // Handle compression if enabled and compressed column is available
4038
- const serializedData = JSON.stringify(item.data);
4039
- let finalData = serializedData;
4040
- let isCompressed = false;
4041
- if (this.options.compression && this.options.compressionThreshold && this.hasCompressedColumn) {
4042
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4043
- finalData = compressionResult.data;
4044
- isCompressed = compressionResult.compressed;
4045
- log$e.debug('Compression result', {
4046
- key,
4047
- originalSize: compressionResult.originalSize,
4048
- compressedSize: compressionResult.compressedSize,
4049
- compressed: isCompressed,
4050
- savings: compressionResult.originalSize - compressionResult.compressedSize,
4051
- });
4052
- }
4053
- log$e.debug('Setting item with metadata', {
4054
- key,
4055
- timestamp: item.timestamp,
4056
- compressed: isCompressed,
4057
- hasCompressedColumn: this.hasCompressedColumn,
4058
- });
4059
- // Build SQL and parameters based on available columns
4060
- let sql;
4061
- let params;
4062
- if (this.hasCompressedColumn) {
4063
- sql = `
4064
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4065
- (cache_key, data, timestamp, compressed)
4066
- VALUES (?, ?, ?, ?)
4067
- `;
4068
- params = [key, finalData, item.timestamp, isCompressed ? 1 : 0];
4069
- }
4070
- else {
4071
- // Fallback for databases without compressed column
4072
- sql = `
4073
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4074
- (cache_key, data, timestamp)
4075
- VALUES (?, ?, ?)
4076
- `;
4077
- params = [key, finalData, item.timestamp];
4078
- }
4079
- log$e.debug('Executing setItem SQL', { key, paramsCount: params.length });
4080
- await this.executeSql(sql, params);
4081
- }
4082
- async setBatch(items) {
4083
- if (items.length === 0)
4084
- return;
4085
- await this.ensureInitialized();
4086
- log$e.debug('Batch setting items', { count: items.length });
4087
- if (this.isExpo) {
4088
- await this.db.withTransactionAsync(async () => {
4089
- for (const [key, item] of items) {
4090
- await this.setBatchItem(key, item);
4091
- }
4092
- });
4093
- }
4094
- else {
4095
- return new Promise((resolve, reject) => {
4096
- this.db.transaction((tx) => {
4097
- const promises = items.map(([key, item]) => this.setBatchItemRN(tx, key, item));
4098
- Promise.all(promises)
4099
- .then(() => resolve())
4100
- .catch(reject);
4101
- }, reject, () => resolve());
4102
- });
4103
- }
4104
- log$e.debug('Batch operation completed', { count: items.length });
4105
- }
4106
- async setBatchItem(key, item) {
4107
- // Handle compression if enabled and compressed column is available
4108
- const serializedData = JSON.stringify(item.data);
4109
- let finalData = serializedData;
4110
- let isCompressed = false;
4111
- if (this.options.compression && this.options.compressionThreshold && this.hasCompressedColumn) {
4112
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4113
- finalData = compressionResult.data;
4114
- isCompressed = compressionResult.compressed;
4115
- }
4116
- // Build SQL and parameters based on available columns
4117
- let sql;
4118
- let params;
4119
- if (this.hasCompressedColumn) {
4120
- sql = `
4121
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4122
- (cache_key, data, timestamp, compressed)
4123
- VALUES (?, ?, ?, ?)
4124
- `;
4125
- params = [key, finalData, item.timestamp, isCompressed ? 1 : 0];
4126
- }
4127
- else {
4128
- sql = `
4129
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4130
- (cache_key, data, timestamp)
4131
- VALUES (?, ?, ?)
4132
- `;
4133
- params = [key, finalData, item.timestamp];
4134
- }
4135
- await this.db.runAsync(sql, params);
4136
- }
4137
- async setBatchItemRN(tx, key, item) {
4138
- // Handle compression if enabled and compressed column is available
4139
- const serializedData = JSON.stringify(item.data);
4140
- let finalData = serializedData;
4141
- let isCompressed = false;
4142
- if (this.options.compression && this.options.compressionThreshold && this.hasCompressedColumn) {
4143
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4144
- finalData = compressionResult.data;
4145
- isCompressed = compressionResult.compressed;
4146
- }
4147
- // Build SQL and parameters based on available columns
4148
- let sql;
4149
- let params;
4150
- if (this.hasCompressedColumn) {
4151
- sql = `
4152
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4153
- (cache_key, data, timestamp, compressed)
4154
- VALUES (?, ?, ?, ?)
4155
- `;
4156
- params = [key, finalData, item.timestamp, isCompressed ? 1 : 0];
4157
- }
4158
- else {
4159
- sql = `
4160
- INSERT OR REPLACE INTO ${ReactNativeCacheAdapter.TABLE_NAME}
4161
- (cache_key, data, timestamp)
4162
- VALUES (?, ?, ?)
4163
- `;
4164
- params = [key, finalData, item.timestamp];
4165
- }
4166
- return new Promise((resolve, reject) => {
4167
- tx.executeSql(sql, params, () => resolve(), (_, error) => {
4168
- reject(error);
4169
- return false;
4170
- });
4171
- });
4172
- }
4173
- async invalidate(pattern) {
4174
- await this.ensureInitialized();
4175
- const keys = await this.getKeys(pattern);
4176
- if (keys.length === 0)
4177
- return;
4178
- const placeholders = keys.map(() => '?').join(',');
4179
- const sql = `DELETE FROM ${ReactNativeCacheAdapter.TABLE_NAME} WHERE cache_key IN (${placeholders})`;
4180
- await this.executeSql(sql, keys);
4181
- }
4182
- async clear() {
4183
- await this.ensureInitialized();
4184
- const sql = `DELETE FROM ${ReactNativeCacheAdapter.TABLE_NAME}`;
4185
- await this.executeSql(sql);
4186
- }
4187
- async getSize() {
4188
- await this.ensureInitialized();
4189
- const sql = `
4190
- SELECT
4191
- COUNT(*) as entries,
4192
- SUM(LENGTH(data)) as bytes
4193
- FROM ${ReactNativeCacheAdapter.TABLE_NAME}
4194
- `;
4195
- const results = await this.executeSql(sql);
4196
- const rows = this.normalizeResults(results);
4197
- const row = rows[0] || { entries: 0, bytes: 0 };
4198
- return {
4199
- entries: row.entries || 0,
4200
- bytes: (row.bytes || 0) * 2,
4201
- lastCleanup: Date.now(),
4202
- };
4203
- }
4204
- async cleanup() {
4205
- // No cleanup needed - cache never expires
4206
- return 0;
4207
- }
4208
- async getKeys(pattern) {
4209
- await this.ensureInitialized();
4210
- let sql = `SELECT cache_key FROM ${ReactNativeCacheAdapter.TABLE_NAME}`;
4211
- const params = [];
4212
- if (pattern) {
4213
- // Simple pattern matching with LIKE
4214
- const likePattern = pattern.replace(/\*/g, '%').replace(/\?/g, '_');
4215
- sql += ' WHERE cache_key LIKE ?';
4216
- params.push(likePattern);
4217
- }
4218
- const results = await this.executeSql(sql, params);
4219
- const keys = [];
4220
- const rows = this.normalizeResults(results);
4221
- for (const row of rows) {
4222
- keys.push(row.cache_key);
4223
- }
4224
- return keys;
4225
- }
4226
- async executeSql(sql, params = []) {
4227
- if (this.isExpo) {
4228
- const expoDB = this.db;
4229
- if (sql.toLowerCase().includes('select') || sql.toLowerCase().includes('pragma')) {
4230
- const result = await expoDB.getAllAsync(sql, params);
4231
- return Array.isArray(result) ? { results: result } : result;
4232
- }
4233
- else {
4234
- return await expoDB.runAsync(sql, params);
4235
- }
4236
- }
4237
- else {
4238
- // react-native-sqlite-storage
4239
- return new Promise((resolve, reject) => {
4240
- this.db.transaction((tx) => {
4241
- tx.executeSql(sql, params, (_, results) => resolve(results), (_, error) => {
4242
- reject(error);
4243
- return false;
4244
- });
4245
- });
4246
- });
4247
- }
4248
- }
4249
- async ensureInitialized() {
4250
- if (!this.initPromise) {
4251
- this.initPromise = this.initialize();
4252
- }
4253
- await this.initPromise;
4254
- }
4255
- }
4256
- ReactNativeCacheAdapter.DB_NAME = 'acube_cache.db';
4257
- ReactNativeCacheAdapter.TABLE_NAME = 'cache_entries';
4258
- /**
4259
- * Memory-based fallback cache adapter for environments without SQLite
4260
- * Cache never expires - data persists until explicitly invalidated
4261
- */
4262
- class MemoryCacheAdapter {
4263
- constructor(options = {}) {
4264
- this.cache = new Map();
4265
- this.totalBytes = 0;
4266
- this.options = {
4267
- maxEntries: 1000,
4268
- ...options,
4269
- };
4270
- }
4271
- calculateItemSize(key, item) {
4272
- // Calculate rough size estimation for memory usage
4273
- const keySize = key.length * 2; // UTF-16 estimation
4274
- const itemSize = JSON.stringify(item).length * 2; // UTF-16 estimation
4275
- return keySize + itemSize;
4276
- }
4277
- async get(key) {
4278
- log$e.debug('Getting cache item', { key });
4279
- const item = this.cache.get(key);
4280
- if (!item) {
4281
- log$e.debug('Cache miss', { key });
4282
- return null;
4283
- }
4284
- // Handle decompression if needed
4285
- const isCompressed = !!item.compressed;
4286
- let finalData = item.data;
4287
- if (isCompressed) {
4288
- const decompressed = decompressData(item.data, true);
4289
- finalData = JSON.parse(decompressed.data);
4290
- }
4291
- log$e.debug('Cache hit', { key, compressed: isCompressed });
4292
- return {
4293
- ...item,
4294
- data: finalData,
4295
- compressed: isCompressed,
4296
- };
4297
- }
4298
- async set(key, data) {
4299
- log$e.debug('Setting cache item', { key });
4300
- // Handle compression if enabled
4301
- let finalData = data;
4302
- let isCompressed = false;
4303
- if (this.options.compression && this.options.compressionThreshold) {
4304
- const serializedData = JSON.stringify(data);
4305
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4306
- if (compressionResult.compressed) {
4307
- finalData = compressionResult.data;
4308
- isCompressed = true;
4309
- log$e.debug('Compression result', {
4310
- key,
4311
- originalSize: compressionResult.originalSize,
4312
- compressedSize: compressionResult.compressedSize,
4313
- savings: compressionResult.originalSize - compressionResult.compressedSize,
4314
- });
4315
- }
4316
- }
4317
- const item = {
4318
- data: finalData,
4319
- timestamp: Date.now(),
4320
- compressed: isCompressed,
4321
- };
4322
- return this.setItem(key, item);
4323
- }
4324
- async setItem(key, item) {
4325
- // Calculate size of new item
4326
- const newItemSize = this.calculateItemSize(key, item);
4327
- // If item already exists, subtract old size
4328
- if (this.cache.has(key)) {
4329
- const oldItem = this.cache.get(key);
4330
- const oldItemSize = this.calculateItemSize(key, oldItem);
4331
- this.totalBytes -= oldItemSize;
4332
- }
4333
- // Enforce max entries limit
4334
- if (this.cache.size >= (this.options.maxEntries || 1000) && !this.cache.has(key)) {
4335
- const oldestKey = this.cache.keys().next().value;
4336
- if (oldestKey) {
4337
- const oldestItem = this.cache.get(oldestKey);
4338
- const oldestItemSize = this.calculateItemSize(oldestKey, oldestItem);
4339
- this.totalBytes -= oldestItemSize;
4340
- this.cache.delete(oldestKey);
4341
- log$e.debug('Removed oldest item for capacity', { oldestKey, freedBytes: oldestItemSize });
4342
- }
4343
- }
4344
- // Set new item and update total size
4345
- this.cache.set(key, item);
4346
- this.totalBytes += newItemSize;
4347
- log$e.debug('Updated cache size', {
4348
- entries: this.cache.size,
4349
- totalBytes: this.totalBytes,
4350
- newItemSize,
4351
- });
4352
- }
4353
- async setBatch(items) {
4354
- if (items.length === 0)
4355
- return;
4356
- log$e.debug('Batch setting items', { count: items.length });
4357
- let totalNewBytes = 0;
4358
- let totalOldBytes = 0;
4359
- const itemsToRemove = [];
4360
- // First pass: calculate size changes and identify capacity issues
4361
- for (const [key, item] of items) {
4362
- const newItemSize = this.calculateItemSize(key, item);
4363
- totalNewBytes += newItemSize;
4364
- // If item already exists, track old size for removal
4365
- if (this.cache.has(key)) {
4366
- const oldItem = this.cache.get(key);
4367
- const oldItemSize = this.calculateItemSize(key, oldItem);
4368
- totalOldBytes += oldItemSize;
4369
- }
4370
- }
4371
- // Handle capacity limits - remove oldest items if needed
4372
- const projectedEntries = this.cache.size + items.filter(([key]) => !this.cache.has(key)).length;
4373
- const maxEntries = this.options.maxEntries || 1000;
4374
- if (projectedEntries > maxEntries) {
4375
- const entriesToRemove = projectedEntries - maxEntries;
4376
- const oldestKeys = Array.from(this.cache.keys()).slice(0, entriesToRemove);
4377
- for (const oldKey of oldestKeys) {
4378
- const oldItem = this.cache.get(oldKey);
4379
- const oldItemSize = this.calculateItemSize(oldKey, oldItem);
4380
- this.totalBytes -= oldItemSize;
4381
- this.cache.delete(oldKey);
4382
- itemsToRemove.push(oldKey);
4383
- }
4384
- if (itemsToRemove.length > 0) {
4385
- log$e.debug('Removed items for batch capacity', {
4386
- removedCount: itemsToRemove.length,
4387
- removedKeys: itemsToRemove,
4388
- });
4389
- }
4390
- }
4391
- // Update total bytes accounting
4392
- this.totalBytes = this.totalBytes - totalOldBytes + totalNewBytes;
4393
- // Second pass: set all items
4394
- for (const [key, item] of items) {
4395
- this.cache.set(key, item);
4396
- }
4397
- log$e.debug('Batch operation completed', {
4398
- count: items.length,
4399
- totalBytes: this.totalBytes,
4400
- entries: this.cache.size,
4401
- bytesAdded: totalNewBytes - totalOldBytes,
4402
- });
4403
- }
4404
- async invalidate(pattern) {
4405
- const regex = this.patternToRegex(pattern);
4406
- let removed = 0;
4407
- let bytesFreed = 0;
4408
- for (const key of this.cache.keys()) {
4409
- if (regex.test(key)) {
4410
- const item = this.cache.get(key);
4411
- const itemSize = this.calculateItemSize(key, item);
4412
- this.cache.delete(key);
4413
- this.totalBytes -= itemSize;
4414
- bytesFreed += itemSize;
4415
- removed++;
4416
- }
4417
- }
4418
- if (removed > 0) {
4419
- log$e.debug('Invalidation completed', {
4420
- pattern,
4421
- entriesRemoved: removed,
4422
- bytesFreed,
4423
- remainingEntries: this.cache.size,
4424
- remainingBytes: this.totalBytes,
4425
- });
4426
- }
4427
- }
4428
- async clear() {
4429
- this.cache.clear();
4430
- this.totalBytes = 0;
4431
- log$e.debug('Cache cleared', { entries: 0, bytes: 0 });
4432
- }
4433
- async getSize() {
4434
- return {
4435
- entries: this.cache.size,
4436
- bytes: this.totalBytes,
4437
- lastCleanup: Date.now(),
4438
- };
4439
- }
4440
- async cleanup() {
4441
- // No cleanup needed - cache never expires
4442
- return 0;
4443
- }
4444
- async getKeys(pattern) {
4445
- const keys = Array.from(this.cache.keys());
4446
- if (!pattern)
4447
- return keys;
4448
- const regex = this.patternToRegex(pattern);
4449
- return keys.filter((key) => regex.test(key));
4450
- }
4451
- patternToRegex(pattern) {
4452
- const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&');
4453
- const regexPattern = escaped.replace(/\\\*/g, '.*').replace(/\\\?/g, '.');
4454
- return new RegExp(`^${regexPattern}$`);
4455
- }
4456
- }
4457
-
4458
- const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);
4459
-
4460
- let idbProxyableTypes;
4461
- let cursorAdvanceMethods;
4462
- // This is a function to prevent it throwing up in node environments.
4463
- function getIdbProxyableTypes() {
4464
- return (idbProxyableTypes ||
4465
- (idbProxyableTypes = [
4466
- IDBDatabase,
4467
- IDBObjectStore,
4468
- IDBIndex,
4469
- IDBCursor,
4470
- IDBTransaction,
4471
- ]));
4472
- }
4473
- // This is a function to prevent it throwing up in node environments.
4474
- function getCursorAdvanceMethods() {
4475
- return (cursorAdvanceMethods ||
4476
- (cursorAdvanceMethods = [
4477
- IDBCursor.prototype.advance,
4478
- IDBCursor.prototype.continue,
4479
- IDBCursor.prototype.continuePrimaryKey,
4480
- ]));
4481
- }
4482
- const transactionDoneMap = new WeakMap();
4483
- const transformCache = new WeakMap();
4484
- const reverseTransformCache = new WeakMap();
4485
- function promisifyRequest(request) {
4486
- const promise = new Promise((resolve, reject) => {
4487
- const unlisten = () => {
4488
- request.removeEventListener('success', success);
4489
- request.removeEventListener('error', error);
4490
- };
4491
- const success = () => {
4492
- resolve(wrap(request.result));
4493
- unlisten();
4494
- };
4495
- const error = () => {
4496
- reject(request.error);
4497
- unlisten();
4498
- };
4499
- request.addEventListener('success', success);
4500
- request.addEventListener('error', error);
4501
- });
4502
- // This mapping exists in reverseTransformCache but doesn't exist in transformCache. This
4503
- // is because we create many promises from a single IDBRequest.
4504
- reverseTransformCache.set(promise, request);
4505
- return promise;
4506
- }
4507
- function cacheDonePromiseForTransaction(tx) {
4508
- // Early bail if we've already created a done promise for this transaction.
4509
- if (transactionDoneMap.has(tx))
4510
- return;
4511
- const done = new Promise((resolve, reject) => {
4512
- const unlisten = () => {
4513
- tx.removeEventListener('complete', complete);
4514
- tx.removeEventListener('error', error);
4515
- tx.removeEventListener('abort', error);
4516
- };
4517
- const complete = () => {
4518
- resolve();
4519
- unlisten();
4520
- };
4521
- const error = () => {
4522
- reject(tx.error || new DOMException('AbortError', 'AbortError'));
4523
- unlisten();
4524
- };
4525
- tx.addEventListener('complete', complete);
4526
- tx.addEventListener('error', error);
4527
- tx.addEventListener('abort', error);
4528
- });
4529
- // Cache it for later retrieval.
4530
- transactionDoneMap.set(tx, done);
4531
- }
4532
- let idbProxyTraps = {
4533
- get(target, prop, receiver) {
4534
- if (target instanceof IDBTransaction) {
4535
- // Special handling for transaction.done.
4536
- if (prop === 'done')
4537
- return transactionDoneMap.get(target);
4538
- // Make tx.store return the only store in the transaction, or undefined if there are many.
4539
- if (prop === 'store') {
4540
- return receiver.objectStoreNames[1]
4541
- ? undefined
4542
- : receiver.objectStore(receiver.objectStoreNames[0]);
4543
- }
4544
- }
4545
- // Else transform whatever we get back.
4546
- return wrap(target[prop]);
4547
- },
4548
- set(target, prop, value) {
4549
- target[prop] = value;
4550
- return true;
4551
- },
4552
- has(target, prop) {
4553
- if (target instanceof IDBTransaction &&
4554
- (prop === 'done' || prop === 'store')) {
4555
- return true;
4556
- }
4557
- return prop in target;
4558
- },
4559
- };
4560
- function replaceTraps(callback) {
4561
- idbProxyTraps = callback(idbProxyTraps);
4562
- }
4563
- function wrapFunction(func) {
4564
- // Due to expected object equality (which is enforced by the caching in `wrap`), we
4565
- // only create one new func per func.
4566
- // Cursor methods are special, as the behaviour is a little more different to standard IDB. In
4567
- // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the
4568
- // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense
4569
- // with real promises, so each advance methods returns a new promise for the cursor object, or
4570
- // undefined if the end of the cursor has been reached.
4571
- if (getCursorAdvanceMethods().includes(func)) {
4572
- return function (...args) {
4573
- // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
4574
- // the original object.
4575
- func.apply(unwrap(this), args);
4576
- return wrap(this.request);
4577
- };
4578
- }
4579
- return function (...args) {
4580
- // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
4581
- // the original object.
4582
- return wrap(func.apply(unwrap(this), args));
4583
- };
4584
- }
4585
- function transformCachableValue(value) {
4586
- if (typeof value === 'function')
4587
- return wrapFunction(value);
4588
- // This doesn't return, it just creates a 'done' promise for the transaction,
4589
- // which is later returned for transaction.done (see idbObjectHandler).
4590
- if (value instanceof IDBTransaction)
4591
- cacheDonePromiseForTransaction(value);
4592
- if (instanceOfAny(value, getIdbProxyableTypes()))
4593
- return new Proxy(value, idbProxyTraps);
4594
- // Return the same value back if we're not going to transform it.
4595
- return value;
4596
- }
4597
- function wrap(value) {
4598
- // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because
4599
- // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.
4600
- if (value instanceof IDBRequest)
4601
- return promisifyRequest(value);
4602
- // If we've already transformed this value before, reuse the transformed value.
4603
- // This is faster, but it also provides object equality.
4604
- if (transformCache.has(value))
4605
- return transformCache.get(value);
4606
- const newValue = transformCachableValue(value);
4607
- // Not all types are transformed.
4608
- // These may be primitive types, so they can't be WeakMap keys.
4609
- if (newValue !== value) {
4610
- transformCache.set(value, newValue);
4611
- reverseTransformCache.set(newValue, value);
4612
- }
4613
- return newValue;
4614
- }
4615
- const unwrap = (value) => reverseTransformCache.get(value);
4616
-
4617
- /**
4618
- * Open a database.
4619
- *
4620
- * @param name Name of the database.
4621
- * @param version Schema version.
4622
- * @param callbacks Additional callbacks.
4623
- */
4624
- function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {
4625
- const request = indexedDB.open(name, version);
4626
- const openPromise = wrap(request);
4627
- if (upgrade) {
4628
- request.addEventListener('upgradeneeded', (event) => {
4629
- upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
4630
- });
4631
- }
4632
- if (blocked) {
4633
- request.addEventListener('blocked', (event) => blocked(
4634
- // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
4635
- event.oldVersion, event.newVersion, event));
4636
- }
4637
- openPromise
4638
- .then((db) => {
4639
- if (terminated)
4640
- db.addEventListener('close', () => terminated());
4641
- if (blocking) {
4642
- db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));
4643
- }
4644
- })
4645
- .catch(() => { });
4646
- return openPromise;
4647
- }
4648
- /**
4649
- * Delete a database.
4650
- *
4651
- * @param name Name of the database.
4652
- */
4653
- function deleteDB(name, { blocked } = {}) {
4654
- const request = indexedDB.deleteDatabase(name);
4655
- if (blocked) {
4656
- request.addEventListener('blocked', (event) => blocked(
4657
- // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
4658
- event.oldVersion, event));
4659
- }
4660
- return wrap(request).then(() => undefined);
4661
- }
4662
-
4663
- const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];
4664
- const writeMethods = ['put', 'add', 'delete', 'clear'];
4665
- const cachedMethods = new Map();
4666
- function getMethod(target, prop) {
4667
- if (!(target instanceof IDBDatabase &&
4668
- !(prop in target) &&
4669
- typeof prop === 'string')) {
4670
- return;
4671
- }
4672
- if (cachedMethods.get(prop))
4673
- return cachedMethods.get(prop);
4674
- const targetFuncName = prop.replace(/FromIndex$/, '');
4675
- const useIndex = prop !== targetFuncName;
4676
- const isWrite = writeMethods.includes(targetFuncName);
4677
- if (
4678
- // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.
4679
- !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||
4680
- !(isWrite || readMethods.includes(targetFuncName))) {
4681
- return;
4682
- }
4683
- const method = async function (storeName, ...args) {
4684
- // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(
4685
- const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');
4686
- let target = tx.store;
4687
- if (useIndex)
4688
- target = target.index(args.shift());
4689
- // Must reject if op rejects.
4690
- // If it's a write operation, must reject if tx.done rejects.
4691
- // Must reject with op rejection first.
4692
- // Must resolve with op value.
4693
- // Must handle both promises (no unhandled rejections)
4694
- return (await Promise.all([
4695
- target[targetFuncName](...args),
4696
- isWrite && tx.done,
4697
- ]))[0];
4698
- };
4699
- cachedMethods.set(prop, method);
4700
- return method;
4701
- }
4702
- replaceTraps((oldTraps) => ({
4703
- ...oldTraps,
4704
- get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),
4705
- has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),
4706
- }));
4707
-
4708
- const advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];
4709
- const methodMap = {};
4710
- const advanceResults = new WeakMap();
4711
- const ittrProxiedCursorToOriginalProxy = new WeakMap();
4712
- const cursorIteratorTraps = {
4713
- get(target, prop) {
4714
- if (!advanceMethodProps.includes(prop))
4715
- return target[prop];
4716
- let cachedFunc = methodMap[prop];
4717
- if (!cachedFunc) {
4718
- cachedFunc = methodMap[prop] = function (...args) {
4719
- advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));
4720
- };
4721
- }
4722
- return cachedFunc;
4723
- },
4724
- };
4725
- async function* iterate(...args) {
4726
- // tslint:disable-next-line:no-this-assignment
4727
- let cursor = this;
4728
- if (!(cursor instanceof IDBCursor)) {
4729
- cursor = await cursor.openCursor(...args);
4730
- }
4731
- if (!cursor)
4732
- return;
4733
- cursor = cursor;
4734
- const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
4735
- ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
4736
- // Map this double-proxy back to the original, so other cursor methods work.
4737
- reverseTransformCache.set(proxiedCursor, unwrap(cursor));
4738
- while (cursor) {
4739
- yield proxiedCursor;
4740
- // If one of the advancing methods was not called, call continue().
4741
- cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
4742
- advanceResults.delete(proxiedCursor);
4743
- }
4744
- }
4745
- function isIteratorProp(target, prop) {
4746
- return ((prop === Symbol.asyncIterator &&
4747
- instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||
4748
- (prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore])));
4749
- }
4750
- replaceTraps((oldTraps) => ({
4751
- ...oldTraps,
4752
- get(target, prop, receiver) {
4753
- if (isIteratorProp(target, prop))
4754
- return iterate;
4755
- return oldTraps.get(target, prop, receiver);
4756
- },
4757
- has(target, prop) {
4758
- return isIteratorProp(target, prop) || oldTraps.has(target, prop);
4759
- },
4760
- }));
4761
-
4762
- const log$d = createPrefixedLogger('CACHE-WEB');
4763
- /**
4764
- * Web cache adapter using IndexedDB with automatic error recovery
4765
- * Cache never expires - data persists until explicitly invalidated
4766
- */
4767
- class WebCacheAdapter {
4768
- constructor(options = {}) {
4769
- this.db = null;
4770
- this.initPromise = null;
4771
- this.retryCount = 0;
4772
- this.maxRetries = 3;
4773
- this.options = {
4774
- maxSize: 50 * 1024 * 1024, // 50MB
4775
- maxEntries: 10000,
4776
- compression: false,
4777
- compressionThreshold: 1024,
4778
- ...options,
4779
- };
4780
- this.initPromise = this.initialize();
4781
- }
4782
- async initialize() {
4783
- if (this.db)
4784
- return;
4785
- log$d.debug('Initializing IndexedDB cache', {
4786
- dbName: WebCacheAdapter.DB_NAME,
4787
- version: WebCacheAdapter.DB_VERSION,
4788
- });
4789
- try {
4790
- this.db = await this.openDatabase();
4791
- log$d.debug('IndexedDB cache initialized successfully');
4792
- this.retryCount = 0; // Reset retry count on success
4793
- }
4794
- catch (error) {
4795
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
4796
- log$d.debug('Failed to initialize IndexedDB', { error: errorMessage });
4797
- // Check if this is a version conflict error
4798
- if (this.isVersionConflictError(errorMessage)) {
4799
- await this.handleVersionConflict();
4800
- }
4801
- else {
4802
- throw new Error(`Failed to initialize IndexedDB: ${errorMessage}`);
4803
- }
4804
- }
4805
- }
4806
- async openDatabase() {
4807
- return await openDB(WebCacheAdapter.DB_NAME, WebCacheAdapter.DB_VERSION, {
4808
- upgrade: (db, oldVersion, newVersion, transaction) => {
4809
- log$d.debug('Database upgrade needed', { oldVersion, newVersion });
4810
- this.handleUpgrade(db, oldVersion, newVersion, transaction);
4811
- },
4812
- blocked: () => {
4813
- log$d.debug('Database blocked - another tab may be open');
4814
- },
4815
- blocking: () => {
4816
- log$d.debug('Database blocking - will close connection');
4817
- if (this.db) {
4818
- this.db.close();
4819
- this.db = null;
4820
- }
4821
- },
4822
- terminated: () => {
4823
- log$d.debug('Database connection terminated unexpectedly');
4824
- this.db = null;
4825
- },
4826
- });
4827
- }
4828
- handleUpgrade(db, oldVersion, newVersion, transaction) {
4829
- log$d.debug('Handling database upgrade', { oldVersion, newVersion });
4830
- // Create cache store if it doesn't exist (initial setup)
4831
- if (!db.objectStoreNames.contains(WebCacheAdapter.STORE_NAME)) {
4832
- const store = db.createObjectStore(WebCacheAdapter.STORE_NAME, { keyPath: 'key' });
4833
- store.createIndex('timestamp', 'timestamp', { unique: false });
4834
- log$d.debug('Created cache store and timestamp index');
4835
- }
4836
- // Handle migration from version 1 to 2
4837
- if (oldVersion < 2) {
4838
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
4839
- // Remove unused indexes from simplified cache structure
4840
- const indexesToRemove = ['tags', 'source', 'syncStatus'];
4841
- indexesToRemove.forEach((indexName) => {
4842
- try {
4843
- if (store.indexNames.contains(indexName)) {
4844
- store.deleteIndex(indexName);
4845
- log$d.debug(`Removed unused index: ${indexName}`);
4846
- }
4847
- }
4848
- catch (error) {
4849
- // Ignore errors if indexes don't exist
4850
- log$d.debug(`Warning: Could not remove index ${indexName}`, error);
4851
- }
4852
- });
4853
- }
4854
- log$d.debug('Database upgrade completed');
4855
- }
4856
- isVersionConflictError(errorMessage) {
4857
- return (errorMessage.includes('less than the existing version') ||
4858
- errorMessage.includes('version conflict') ||
4859
- errorMessage.includes('VersionError'));
4860
- }
4861
- async handleVersionConflict() {
4862
- log$d.debug('Handling version conflict, attempting recovery...');
4863
- if (this.retryCount >= this.maxRetries) {
4864
- throw new Error('Failed to resolve IndexedDB version conflict after multiple attempts');
4865
- }
4866
- this.retryCount++;
4867
- try {
4868
- // Close any existing connection
4869
- if (this.db) {
4870
- this.db.close();
4871
- this.db = null;
4872
- }
4873
- // Delete the problematic database
4874
- log$d.debug('Deleting problematic database to resolve version conflict');
4875
- await deleteDB(WebCacheAdapter.DB_NAME);
4876
- // Wait a bit for the deletion to complete
4877
- await new Promise((resolve) => setTimeout(resolve, 200));
4878
- // Try to open the database again
4879
- log$d.debug(`Retrying database initialization (attempt ${this.retryCount}/${this.maxRetries})`);
4880
- this.db = await this.openDatabase();
4881
- log$d.debug('Successfully recovered from version conflict');
4882
- this.retryCount = 0; // Reset retry count on success
4883
- }
4884
- catch (retryError) {
4885
- const retryErrorMessage = retryError instanceof Error ? retryError.message : 'Unknown error';
4886
- log$d.debug('Recovery attempt failed', { attempt: this.retryCount, error: retryErrorMessage });
4887
- if (this.retryCount < this.maxRetries) {
4888
- // Try again
4889
- await this.handleVersionConflict();
4890
- }
4891
- else {
4892
- throw new Error(`Failed to recover from IndexedDB version conflict: ${retryErrorMessage}`);
4893
- }
4894
- }
4895
- }
4896
- async get(key) {
4897
- await this.ensureInitialized();
4898
- log$d.debug('Getting cache item', { key });
4899
- try {
4900
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readonly');
4901
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
4902
- const result = await store.get(key);
4903
- if (!result) {
4904
- return null;
4905
- }
4906
- const item = result;
4907
- // Handle decompression if needed
4908
- const isCompressed = !!item.compressed;
4909
- let finalData;
4910
- if (isCompressed) {
4911
- const decompressed = decompressData(item.data, true);
4912
- finalData = JSON.parse(decompressed.data);
4913
- }
4914
- else {
4915
- finalData = item.data;
4916
- }
4917
- return {
4918
- data: finalData,
4919
- timestamp: item.timestamp,
4920
- compressed: isCompressed,
4921
- };
4922
- }
4923
- catch (error) {
4924
- log$d.debug('Error getting cache item', { key, error });
4925
- return null; // Return null on error instead of throwing
4926
- }
4927
- }
4928
- async set(key, data) {
4929
- const item = {
4930
- data,
4931
- timestamp: Date.now(),
4932
- };
4933
- return this.setItem(key, item);
4934
- }
4935
- async setItem(key, item) {
4936
- await this.ensureInitialized();
4937
- // Handle compression if enabled
4938
- let finalData = item.data;
4939
- let isCompressed = false;
4940
- if (this.options.compression && this.options.compressionThreshold) {
4941
- const serializedData = JSON.stringify(item.data);
4942
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
4943
- if (compressionResult.compressed) {
4944
- finalData = compressionResult.data;
4945
- isCompressed = true;
4946
- log$d.debug('Compression result', {
4947
- key,
4948
- originalSize: compressionResult.originalSize,
4949
- compressedSize: compressionResult.compressedSize,
4950
- compressed: isCompressed,
4951
- savings: compressionResult.originalSize - compressionResult.compressedSize,
4952
- });
4953
- }
4954
- }
4955
- log$d.debug('Setting cache item', { key, timestamp: item.timestamp, compressed: isCompressed });
4956
- const storedItem = {
4957
- key,
4958
- data: finalData,
4959
- timestamp: item.timestamp,
4960
- compressed: isCompressed,
4961
- };
4962
- try {
4963
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readwrite');
4964
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
4965
- await store.put(storedItem);
4966
- }
4967
- catch (error) {
4968
- log$d.debug('Error setting cache item', { key, error });
4969
- // Silently fail for cache writes
2756
+ message.includes('tls') ||
2757
+ message.includes('handshake'));
4970
2758
  }
2759
+ return false;
4971
2760
  }
4972
- async setBatch(items) {
4973
- if (items.length === 0)
4974
- return;
4975
- await this.ensureInitialized();
4976
- log$d.debug('Batch setting items', { count: items.length });
4977
- try {
4978
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readwrite');
4979
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
4980
- // Process all items in the transaction
4981
- const promises = items.map(([key, item]) => {
4982
- const storedItem = this.prepareBatchItem(key, item);
4983
- return store.put(storedItem);
4984
- });
4985
- await Promise.all(promises);
4986
- log$d.debug('Batch operation completed', { count: items.length });
4987
- }
4988
- catch (error) {
4989
- log$d.debug('Error in batch operation', { count: items.length, error });
4990
- // Silently fail for batch writes
4991
- }
4992
- }
4993
- prepareBatchItem(key, item) {
4994
- // Handle compression if enabled (same logic as setItem)
4995
- let finalData = item.data;
4996
- let isCompressed = false;
4997
- if (this.options.compression && this.options.compressionThreshold) {
4998
- const serializedData = JSON.stringify(item.data);
4999
- const compressionResult = compressData(serializedData, this.options.compressionThreshold);
5000
- if (compressionResult.compressed) {
5001
- finalData = compressionResult.data;
5002
- isCompressed = true;
5003
- }
2761
+ async configureCertificate(certificate) {
2762
+ if (!this.mtlsAdapter) {
2763
+ throw new Error('mTLS adapter not available');
5004
2764
  }
5005
- return {
5006
- key,
5007
- data: finalData,
5008
- timestamp: item.timestamp,
5009
- compressed: isCompressed,
2765
+ const certificateData = {
2766
+ certificate: certificate.certificate,
2767
+ privateKey: certificate.privateKey,
2768
+ format: certificate.format.toUpperCase(),
5010
2769
  };
2770
+ await this.mtlsAdapter.configureCertificate(certificateData);
5011
2771
  }
5012
- async invalidate(pattern) {
5013
- await this.ensureInitialized();
5014
- const keys = await this.getKeys(pattern);
5015
- const deletePromises = keys.map((key) => this.delete(key));
5016
- await Promise.all(deletePromises);
5017
- }
5018
- async clear() {
5019
- await this.ensureInitialized();
5020
- try {
5021
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readwrite');
5022
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5023
- await store.clear();
5024
- log$d.debug('Cache cleared successfully');
5025
- }
5026
- catch (error) {
5027
- log$d.debug('Error clearing cache', error);
5028
- // Silently fail for cache clear
2772
+ async storeCertificate(certificate, privateKey, options = {}) {
2773
+ if (!this.certificatePort) {
2774
+ throw new Error('Certificate port not available');
5029
2775
  }
5030
- }
5031
- async getSize() {
5032
- await this.ensureInitialized();
5033
- try {
5034
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readonly');
5035
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5036
- let entries = 0;
5037
- let bytes = 0;
5038
- // Use cursor for efficient iteration
5039
- let cursor = await store.openCursor();
5040
- while (cursor) {
5041
- entries++;
5042
- // Rough estimation of size
5043
- bytes += JSON.stringify(cursor.value).length * 2; // UTF-16 encoding
5044
- cursor = await cursor.continue();
2776
+ if (this.mtlsAdapter) {
2777
+ try {
2778
+ await this.mtlsAdapter.removeCertificate();
2779
+ }
2780
+ catch {
2781
+ // No existing certificate to remove
5045
2782
  }
5046
- return {
5047
- entries,
5048
- bytes,
5049
- lastCleanup: Date.now(),
5050
- };
5051
2783
  }
5052
- catch (error) {
5053
- log$d.debug('Error getting cache size', error);
5054
- return {
5055
- entries: 0,
5056
- bytes: 0,
5057
- lastCleanup: Date.now(),
2784
+ const format = (options.format || 'pem');
2785
+ await this.certificatePort.storeCertificate(certificate, privateKey, format);
2786
+ if (this.mtlsAdapter) {
2787
+ const certificateData = {
2788
+ certificate,
2789
+ privateKey,
2790
+ format: format.toUpperCase(),
5058
2791
  };
2792
+ await this.mtlsAdapter.configureCertificate(certificateData);
5059
2793
  }
5060
2794
  }
5061
- async cleanup() {
5062
- // No cleanup needed - cache never expires
5063
- return 0;
5064
- }
5065
- async getKeys(pattern) {
5066
- await this.ensureInitialized();
5067
- try {
5068
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readonly');
5069
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5070
- const allKeys = (await store.getAllKeys());
5071
- if (!pattern) {
5072
- return allKeys;
2795
+ async clearCertificate() {
2796
+ if (this.mtlsAdapter) {
2797
+ try {
2798
+ await this.mtlsAdapter.removeCertificate();
2799
+ }
2800
+ catch {
2801
+ // No certificate to remove
5073
2802
  }
5074
- const regex = this.patternToRegex(pattern);
5075
- return allKeys.filter((key) => regex.test(key));
5076
2803
  }
5077
- catch (error) {
5078
- log$d.debug('Error getting cache keys', error);
5079
- return [];
2804
+ if (this.certificatePort) {
2805
+ await this.certificatePort.clearCertificate();
5080
2806
  }
5081
2807
  }
5082
- async delete(key) {
5083
- await this.ensureInitialized();
5084
- try {
5085
- const transaction = this.db.transaction([WebCacheAdapter.STORE_NAME], 'readwrite');
5086
- const store = transaction.objectStore(WebCacheAdapter.STORE_NAME);
5087
- await store.delete(key);
5088
- return true;
5089
- }
5090
- catch (error) {
5091
- log$d.debug('Error deleting cache item', { key, error });
2808
+ async testConnection() {
2809
+ if (!this.mtlsAdapter) {
5092
2810
  return false;
5093
2811
  }
2812
+ return this.mtlsAdapter.testConnection();
5094
2813
  }
5095
- async ensureInitialized() {
5096
- if (!this.initPromise) {
5097
- this.initPromise = this.initialize();
5098
- }
5099
- try {
5100
- await this.initPromise;
5101
- }
5102
- catch (error) {
5103
- log$d.debug('Failed to ensure initialization', error);
5104
- // Reset and try once more
5105
- this.initPromise = null;
5106
- this.db = null;
5107
- this.initPromise = this.initialize();
5108
- await this.initPromise;
2814
+ getBaseUrl() {
2815
+ if (!this.mtlsAdapter) {
2816
+ return null;
5109
2817
  }
2818
+ return this.mtlsAdapter.getBaseUrl();
5110
2819
  }
5111
- patternToRegex(pattern) {
5112
- // Convert simple glob patterns to regex
5113
- const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&');
5114
- const regexPattern = escaped.replace(/\\\*/g, '.*').replace(/\\\?/g, '.');
5115
- return new RegExp(`^${regexPattern}$`);
5116
- }
5117
- }
5118
- WebCacheAdapter.DB_NAME = 'acube_cache';
5119
- WebCacheAdapter.DB_VERSION = 2;
5120
- WebCacheAdapter.STORE_NAME = 'cache_entries';
5121
-
5122
- const log$c = createPrefixedLogger('CACHE-LOADER');
5123
- function loadCacheAdapter(platform) {
5124
- try {
5125
- switch (platform) {
5126
- case 'web':
5127
- return new WebCacheAdapter({
5128
- maxSize: 50 * 1024 * 1024,
5129
- maxEntries: 10000,
5130
- compression: false,
5131
- });
5132
- case 'react-native':
5133
- try {
5134
- return new ReactNativeCacheAdapter({
5135
- maxSize: 100 * 1024 * 1024,
5136
- maxEntries: 15000,
5137
- });
5138
- }
5139
- catch {
5140
- return new MemoryCacheAdapter({
5141
- maxSize: 10 * 1024 * 1024,
5142
- maxEntries: 5000,
5143
- });
2820
+ async getStatus() {
2821
+ const status = {
2822
+ adapterAvailable: !!this.mtlsAdapter,
2823
+ certificatePortAvailable: !!this.certificatePort,
2824
+ isReady: false,
2825
+ hasCertificate: false,
2826
+ certificateInfo: null,
2827
+ platformInfo: this.mtlsAdapter?.getPlatformInfo() || null,
2828
+ pendingRequestsCount: this.pendingRequests.size,
2829
+ };
2830
+ if (this.certificatePort) {
2831
+ try {
2832
+ status.hasCertificate = await this.certificatePort.hasCertificate();
2833
+ if (status.hasCertificate) {
2834
+ status.certificateInfo = await this.certificatePort.getCertificateInfo();
5144
2835
  }
5145
- case 'node':
5146
- default:
5147
- return new MemoryCacheAdapter({
5148
- maxSize: 10 * 1024 * 1024,
5149
- maxEntries: 5000,
5150
- });
2836
+ }
2837
+ catch {
2838
+ // Ignore errors
2839
+ }
5151
2840
  }
2841
+ status.isReady = await this.isMtlsReady();
2842
+ return status;
5152
2843
  }
5153
- catch (error) {
5154
- log$c.warn(`Cache adapter not available for platform ${platform}:`, error);
5155
- return undefined;
2844
+ clearPendingRequests() {
2845
+ this.pendingRequests.clear();
5156
2846
  }
5157
2847
  }
5158
2848
 
5159
- /**
5160
- * Mixin that adds multiGet, multiSet, multiRemove to any storage adapter
5161
- * Eliminates duplicate code across Node, Web, and React Native adapters
5162
- */
5163
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5164
2849
  /**
5165
2850
  * Abstract base class for standard storage adapters
5166
2851
  * Implements multi-operations, subclasses implement core operations
@@ -5208,7 +2893,7 @@ class BaseSecureStorageAdapter {
5208
2893
  }
5209
2894
  }
5210
2895
 
5211
- const log$b = createPrefixedLogger('NETWORK-BASE');
2896
+ const log$8 = createPrefixedLogger('NETWORK-BASE');
5212
2897
  class NetworkBase {
5213
2898
  constructor(initialOnline = true, debounceMs = 300) {
5214
2899
  this.destroy$ = new Subject();
@@ -5228,14 +2913,14 @@ class NetworkBase {
5228
2913
  const current = this.statusSubject.getValue();
5229
2914
  if (current.online !== online) {
5230
2915
  this.statusSubject.next({ online, timestamp: Date.now() });
5231
- log$b.debug(`Network status changed: ${online ? 'online' : 'offline'}`);
2916
+ log$8.debug(`Network status changed: ${online ? 'online' : 'offline'}`);
5232
2917
  }
5233
2918
  }
5234
2919
  destroy() {
5235
2920
  this.destroy$.next();
5236
2921
  this.destroy$.complete();
5237
2922
  this.statusSubject.complete();
5238
- log$b.debug('Network monitor destroyed');
2923
+ log$8.debug('Network monitor destroyed');
5239
2924
  }
5240
2925
  }
5241
2926
 
@@ -5295,7 +2980,7 @@ class NodeSecureStorageAdapter extends BaseSecureStorageAdapter {
5295
2980
  }
5296
2981
  }
5297
2982
 
5298
- const log$a = createPrefixedLogger('RN-STORAGE');
2983
+ const log$7 = createPrefixedLogger('RN-STORAGE');
5299
2984
  /**
5300
2985
  * React Native storage adapter using AsyncStorage
5301
2986
  * Note: Uses native batch operations for better performance (not base class)
@@ -5327,7 +3012,7 @@ class ReactNativeStorageAdapter {
5327
3012
  return await this.AsyncStorage.getItem(key);
5328
3013
  }
5329
3014
  catch (error) {
5330
- log$a.error('Failed to get item from AsyncStorage:', error);
3015
+ log$7.error('Failed to get item from AsyncStorage:', error);
5331
3016
  return null;
5332
3017
  }
5333
3018
  }
@@ -5368,7 +3053,7 @@ class ReactNativeStorageAdapter {
5368
3053
  return await this.AsyncStorage.getAllKeys();
5369
3054
  }
5370
3055
  catch (error) {
5371
- log$a.error('Failed to get all keys:', error);
3056
+ log$7.error('Failed to get all keys:', error);
5372
3057
  return [];
5373
3058
  }
5374
3059
  }
@@ -5385,7 +3070,7 @@ class ReactNativeStorageAdapter {
5385
3070
  return result;
5386
3071
  }
5387
3072
  catch (error) {
5388
- log$a.error('Failed to get multiple items:', error);
3073
+ log$7.error('Failed to get multiple items:', error);
5389
3074
  const result = {};
5390
3075
  keys.forEach((key) => {
5391
3076
  result[key] = null;
@@ -5435,7 +3120,7 @@ class ReactNativeSecureStorageAdapter extends BaseSecureStorageAdapter {
5435
3120
  return;
5436
3121
  }
5437
3122
  catch {
5438
- log$a.debug('expo-secure-store not available, trying react-native-keychain');
3123
+ log$7.debug('expo-secure-store not available, trying react-native-keychain');
5439
3124
  }
5440
3125
  try {
5441
3126
  const Keychain = require('react-native-keychain');
@@ -5444,7 +3129,7 @@ class ReactNativeSecureStorageAdapter extends BaseSecureStorageAdapter {
5444
3129
  return;
5445
3130
  }
5446
3131
  catch {
5447
- log$a.error('react-native-keychain not available');
3132
+ log$7.error('react-native-keychain not available');
5448
3133
  }
5449
3134
  throw new Error('No secure storage available. Please install expo-secure-store or react-native-keychain');
5450
3135
  }
@@ -5462,7 +3147,7 @@ class ReactNativeSecureStorageAdapter extends BaseSecureStorageAdapter {
5462
3147
  }
5463
3148
  }
5464
3149
  catch (error) {
5465
- log$a.error('Failed to get secure item:', error);
3150
+ log$7.error('Failed to get secure item:', error);
5466
3151
  }
5467
3152
  return null;
5468
3153
  }
@@ -5499,10 +3184,10 @@ class ReactNativeSecureStorageAdapter extends BaseSecureStorageAdapter {
5499
3184
  }
5500
3185
  }
5501
3186
  async clear() {
5502
- log$a.warn('Clear all secure items not fully implemented for React Native');
3187
+ log$7.warn('Clear all secure items not fully implemented for React Native');
5503
3188
  }
5504
3189
  async getAllKeys() {
5505
- log$a.warn('Get all secure keys not implemented for React Native');
3190
+ log$7.warn('Get all secure keys not implemented for React Native');
5506
3191
  return [];
5507
3192
  }
5508
3193
  async isAvailable() {
@@ -5720,7 +3405,7 @@ class NodeNetworkMonitor extends NetworkBase {
5720
3405
  }
5721
3406
  }
5722
3407
 
5723
- const log$9 = createPrefixedLogger('RN-NETWORK');
3408
+ const log$6 = createPrefixedLogger('RN-NETWORK');
5724
3409
  /**
5725
3410
  * React Native network monitor using RxJS
5726
3411
  * Supports both @react-native-community/netinfo and expo-network
@@ -5733,7 +3418,7 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5733
3418
  this.moduleReady$ = new Subject();
5734
3419
  this.isExpo = detectPlatform().isExpo;
5735
3420
  this.init().catch((error) => {
5736
- log$9.error('Network monitor initialization failed:', error);
3421
+ log$6.error('Network monitor initialization failed:', error);
5737
3422
  });
5738
3423
  }
5739
3424
  async init() {
@@ -5752,10 +3437,10 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5752
3437
  try {
5753
3438
  const module = require('@react-native-community/netinfo');
5754
3439
  this.netInfoModule = module.default || module;
5755
- log$9.debug('Loaded @react-native-community/netinfo module');
3440
+ log$6.debug('Loaded @react-native-community/netinfo module');
5756
3441
  }
5757
3442
  catch (error) {
5758
- log$9.error('Failed to load React Native NetInfo module:', error);
3443
+ log$6.error('Failed to load React Native NetInfo module:', error);
5759
3444
  this.netInfoModule = null;
5760
3445
  }
5761
3446
  }
@@ -5763,10 +3448,10 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5763
3448
  try {
5764
3449
  const module = require('expo-network');
5765
3450
  this.netInfoModule = module.default || module;
5766
- log$9.debug('Loaded expo-network module');
3451
+ log$6.debug('Loaded expo-network module');
5767
3452
  }
5768
3453
  catch (error) {
5769
- log$9.error('Failed to load Expo Network module:', error);
3454
+ log$6.error('Failed to load Expo Network module:', error);
5770
3455
  this.netInfoModule = null;
5771
3456
  }
5772
3457
  }
@@ -5783,16 +3468,16 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5783
3468
  }
5784
3469
  const online = !!(state.isConnected && state.isInternetReachable !== false);
5785
3470
  this.updateStatus(online);
5786
- log$9.debug('Initial network state:', online ? 'online' : 'offline');
3471
+ log$6.debug('Initial network state:', online ? 'online' : 'offline');
5787
3472
  }
5788
3473
  catch (error) {
5789
- log$9.warn('Could not fetch initial network state:', error);
3474
+ log$6.warn('Could not fetch initial network state:', error);
5790
3475
  }
5791
3476
  }
5792
3477
  subscribeToStateChanges() {
5793
3478
  if (!this.netInfoModule)
5794
3479
  return;
5795
- log$9.debug('Subscribing to network state changes');
3480
+ log$6.debug('Subscribing to network state changes');
5796
3481
  const handleState = (state) => {
5797
3482
  const online = !!(state.isConnected && (state.isInternetReachable ?? true));
5798
3483
  this.updateStatus(online);
@@ -5834,7 +3519,7 @@ class ReactNativeNetworkMonitor extends NetworkBase {
5834
3519
  };
5835
3520
  }
5836
3521
  catch (error) {
5837
- log$9.error('Failed to fetch detailed network info:', error);
3522
+ log$6.error('Failed to fetch detailed network info:', error);
5838
3523
  return null;
5839
3524
  }
5840
3525
  }
@@ -5934,7 +3619,7 @@ function loadNetworkMonitor(platform) {
5934
3619
  }
5935
3620
  }
5936
3621
 
5937
- var MTLSErrorType$1;
3622
+ var MTLSErrorType;
5938
3623
  (function (MTLSErrorType) {
5939
3624
  MTLSErrorType["NOT_SUPPORTED"] = "MTLS_NOT_SUPPORTED";
5940
3625
  MTLSErrorType["CERTIFICATE_NOT_FOUND"] = "MTLS_CERTIFICATE_NOT_FOUND";
@@ -5943,7 +3628,7 @@ var MTLSErrorType$1;
5943
3628
  MTLSErrorType["CONNECTION_FAILED"] = "MTLS_CONNECTION_FAILED";
5944
3629
  MTLSErrorType["AUTHENTICATION_FAILED"] = "MTLS_AUTHENTICATION_FAILED";
5945
3630
  MTLSErrorType["CONFIGURATION_ERROR"] = "MTLS_CONFIGURATION_ERROR";
5946
- })(MTLSErrorType$1 || (MTLSErrorType$1 = {}));
3631
+ })(MTLSErrorType || (MTLSErrorType = {}));
5947
3632
  class MTLSError extends Error {
5948
3633
  constructor(type, message, originalError, statusCode) {
5949
3634
  super(message);
@@ -5970,7 +3655,7 @@ class CertificateValidator {
5970
3655
  }
5971
3656
  }
5972
3657
 
5973
- const log$8 = createPrefixedLogger('RN-MTLS');
3658
+ const log$5 = createPrefixedLogger('RN-MTLS');
5974
3659
  /**
5975
3660
  * React Native mTLS Adapter using @a-cube-io/expo-mutual-tls
5976
3661
  */
@@ -5992,7 +3677,7 @@ class ReactNativeMTLSAdapter {
5992
3677
  this.expoMTLS = ExpoMutualTls;
5993
3678
  // Set up debug logging with the correct event signature
5994
3679
  const debugListener = ExpoMutualTls.onDebugLog((event) => {
5995
- log$8.debug(`${event.type}: ${event.message}`, {
3680
+ log$5.debug(`${event.type}: ${event.message}`, {
5996
3681
  method: event.method,
5997
3682
  url: event.url,
5998
3683
  statusCode: event.statusCode,
@@ -6002,28 +3687,28 @@ class ReactNativeMTLSAdapter {
6002
3687
  this.eventListeners.push(debugListener);
6003
3688
  // Set up error logging with the correct event signature
6004
3689
  const errorListener = ExpoMutualTls.onError((event) => {
6005
- log$8.error(event.message, {
3690
+ log$5.error(event.message, {
6006
3691
  code: event.code,
6007
3692
  });
6008
3693
  });
6009
3694
  this.eventListeners.push(errorListener);
6010
3695
  // Set up certificate expiry monitoring with the correct event signature
6011
3696
  const expiryListener = ExpoMutualTls.onCertificateExpiry((event) => {
6012
- log$8.warn(`Certificate ${event.subject} expires at ${new Date(event.expiry)}`, {
3697
+ log$5.warn(`Certificate ${event.subject} expires at ${new Date(event.expiry)}`, {
6013
3698
  alias: event.alias,
6014
3699
  warning: event.warning,
6015
3700
  });
6016
3701
  });
6017
3702
  this.eventListeners.push(expiryListener);
6018
- log$8.debug('Expo mTLS module loaded successfully');
3703
+ log$5.debug('Expo mTLS module loaded successfully');
6019
3704
  }
6020
3705
  catch (error) {
6021
- log$8.warn('@a-cube-io/expo-mutual-tls not available:', error);
3706
+ log$5.warn('@a-cube-io/expo-mutual-tls not available:', error);
6022
3707
  }
6023
3708
  }
6024
3709
  async isMTLSSupported() {
6025
3710
  const supported = this.expoMTLS !== null;
6026
- log$8.debug('mTLS support check:', {
3711
+ log$5.debug('mTLS support check:', {
6027
3712
  supported,
6028
3713
  platform: this.getPlatformInfo().platform,
6029
3714
  moduleAvailable: !!this.expoMTLS,
@@ -6032,10 +3717,10 @@ class ReactNativeMTLSAdapter {
6032
3717
  }
6033
3718
  async initialize(config) {
6034
3719
  if (!this.expoMTLS) {
6035
- throw new MTLSError(MTLSErrorType$1.NOT_SUPPORTED, 'Expo mTLS module not available');
3720
+ throw new MTLSError(MTLSErrorType.NOT_SUPPORTED, 'Expo mTLS module not available');
6036
3721
  }
6037
3722
  this.config = config;
6038
- log$8.debug('Initialized with config:', {
3723
+ log$5.debug('Initialized with config:', {
6039
3724
  baseUrl: config.baseUrl,
6040
3725
  port: config.port,
6041
3726
  timeout: config.timeout,
@@ -6044,12 +3729,12 @@ class ReactNativeMTLSAdapter {
6044
3729
  }
6045
3730
  async configureCertificate(certificateData) {
6046
3731
  if (!this.expoMTLS) {
6047
- throw new MTLSError(MTLSErrorType$1.NOT_SUPPORTED, 'Expo mTLS module not available');
3732
+ throw new MTLSError(MTLSErrorType.NOT_SUPPORTED, 'Expo mTLS module not available');
6048
3733
  }
6049
3734
  if (!this.config) {
6050
- throw new MTLSError(MTLSErrorType$1.CONFIGURATION_ERROR, 'Adapter not initialized. Call initialize() first.');
3735
+ throw new MTLSError(MTLSErrorType.CONFIGURATION_ERROR, 'Adapter not initialized. Call initialize() first.');
6051
3736
  }
6052
- log$8.debug('Configuring certificate:', {
3737
+ log$5.debug('Configuring certificate:', {
6053
3738
  format: certificateData.format,
6054
3739
  hasPassword: !!certificateData.password,
6055
3740
  certificateLength: certificateData.certificate.length,
@@ -6059,47 +3744,47 @@ class ReactNativeMTLSAdapter {
6059
3744
  if (certificateData.format === 'PEM') {
6060
3745
  // Validate PEM format
6061
3746
  if (!CertificateValidator.validatePEMFormat(certificateData.certificate, certificateData.privateKey)) {
6062
- throw new MTLSError(MTLSErrorType$1.CERTIFICATE_INVALID, 'Invalid PEM certificate format');
3747
+ throw new MTLSError(MTLSErrorType.CERTIFICATE_INVALID, 'Invalid PEM certificate format');
6063
3748
  }
6064
3749
  // Step 1: Configure PEM services (optional parameters for keychain services)
6065
3750
  const configResult = await this.expoMTLS.configurePEM('client-cert-service', // certService
6066
3751
  'client-key-service', // keyService
6067
3752
  true // enableLogging - let the native module handle its own debug logging
6068
3753
  );
6069
- log$8.debug('PEM services configured:', configResult);
3754
+ log$5.debug('PEM services configured:', configResult);
6070
3755
  if (!configResult.success) {
6071
- throw new MTLSError(MTLSErrorType$1.CONFIGURATION_ERROR, `PEM configuration failed: ${configResult.state}`);
3756
+ throw new MTLSError(MTLSErrorType.CONFIGURATION_ERROR, `PEM configuration failed: ${configResult.state}`);
6072
3757
  }
6073
3758
  // Step 2: Store the actual PEM certificate and private key
6074
3759
  const storeResult = await this.expoMTLS.storePEM(certificateData.certificate, certificateData.privateKey, certificateData.password // passphrase (optional)
6075
3760
  );
6076
- log$8.debug('PEM certificate store result:', storeResult);
3761
+ log$5.debug('PEM certificate store result:', storeResult);
6077
3762
  if (!storeResult) {
6078
- throw new MTLSError(MTLSErrorType$1.CERTIFICATE_INVALID, 'Failed to store PEM certificate');
3763
+ throw new MTLSError(MTLSErrorType.CERTIFICATE_INVALID, 'Failed to store PEM certificate');
6079
3764
  }
6080
3765
  }
6081
3766
  else if (certificateData.format === 'P12') {
6082
3767
  if (!certificateData.password) {
6083
- throw new MTLSError(MTLSErrorType$1.CONFIGURATION_ERROR, 'P12 certificate requires password');
3768
+ throw new MTLSError(MTLSErrorType.CONFIGURATION_ERROR, 'P12 certificate requires password');
6084
3769
  }
6085
3770
  // Step 1: Configure P12 keychain service
6086
3771
  const configResult = await this.expoMTLS.configureP12('client-p12-service', // keychainService
6087
3772
  true // enableLogging - let the native module handle its own debug logging
6088
3773
  );
6089
- log$8.debug('P12 service configured:', configResult);
3774
+ log$5.debug('P12 service configured:', configResult);
6090
3775
  if (!configResult.success) {
6091
- throw new MTLSError(MTLSErrorType$1.CONFIGURATION_ERROR, `P12 configuration failed: ${configResult.state}`);
3776
+ throw new MTLSError(MTLSErrorType.CONFIGURATION_ERROR, `P12 configuration failed: ${configResult.state}`);
6092
3777
  }
6093
3778
  // Step 2: Store the P12 certificate data
6094
3779
  const storeResult = await this.expoMTLS.storeP12(certificateData.certificate, // P12 data in certificate field
6095
3780
  certificateData.password);
6096
- log$8.debug('P12 certificate store result:', storeResult);
3781
+ log$5.debug('P12 certificate store result:', storeResult);
6097
3782
  if (!storeResult) {
6098
- throw new MTLSError(MTLSErrorType$1.CERTIFICATE_INVALID, 'Failed to store P12 certificate');
3783
+ throw new MTLSError(MTLSErrorType.CERTIFICATE_INVALID, 'Failed to store P12 certificate');
6099
3784
  }
6100
3785
  }
6101
3786
  else {
6102
- throw new MTLSError(MTLSErrorType$1.CERTIFICATE_INVALID, `Unsupported certificate format: ${certificateData.format}`);
3787
+ throw new MTLSError(MTLSErrorType.CERTIFICATE_INVALID, `Unsupported certificate format: ${certificateData.format}`);
6103
3788
  }
6104
3789
  this.isConfigured = true;
6105
3790
  }
@@ -6107,8 +3792,8 @@ class ReactNativeMTLSAdapter {
6107
3792
  if (error instanceof MTLSError) {
6108
3793
  throw error;
6109
3794
  }
6110
- log$8.error('Certificate configuration failed:', error);
6111
- throw new MTLSError(MTLSErrorType$1.CONFIGURATION_ERROR, 'Failed to configure certificate', error);
3795
+ log$5.error('Certificate configuration failed:', error);
3796
+ throw new MTLSError(MTLSErrorType.CONFIGURATION_ERROR, 'Failed to configure certificate', error);
6112
3797
  }
6113
3798
  }
6114
3799
  async hasCertificate() {
@@ -6118,38 +3803,38 @@ class ReactNativeMTLSAdapter {
6118
3803
  try {
6119
3804
  // Use static method call
6120
3805
  const hasCert = await this.expoMTLS.hasCertificate();
6121
- log$8.debug('Certificate availability check:', hasCert);
3806
+ log$5.debug('Certificate availability check:', hasCert);
6122
3807
  return hasCert;
6123
3808
  }
6124
3809
  catch (error) {
6125
- log$8.error('Certificate check failed:', error);
3810
+ log$5.error('Certificate check failed:', error);
6126
3811
  return false;
6127
3812
  }
6128
3813
  }
6129
3814
  async getCertificateInfo() {
6130
3815
  if (!this.expoMTLS) {
6131
- log$8.debug('Certificate info requested but module not available');
3816
+ log$5.debug('Certificate info requested but module not available');
6132
3817
  return null;
6133
3818
  }
6134
3819
  try {
6135
3820
  const hasCert = await this.hasCertificate();
6136
3821
  if (!hasCert) {
6137
- log$8.debug('No certificate stored');
3822
+ log$5.debug('No certificate stored');
6138
3823
  return null;
6139
3824
  }
6140
3825
  // Use getCertificatesInfo to retrieve information about stored certificates
6141
3826
  const result = await this.expoMTLS.getCertificatesInfo();
6142
3827
  if (!result || !result.certificates || result.certificates.length === 0) {
6143
- log$8.debug('No certificate information available');
3828
+ log$5.debug('No certificate information available');
6144
3829
  return null;
6145
3830
  }
6146
3831
  // Get the first certificate (primary client certificate)
6147
3832
  const cert = result.certificates[0];
6148
3833
  if (!cert) {
6149
- log$8.debug('Certificate data is empty');
3834
+ log$5.debug('Certificate data is empty');
6150
3835
  return null;
6151
3836
  }
6152
- log$8.debug('Retrieved certificate info:', {
3837
+ log$5.debug('Retrieved certificate info:', {
6153
3838
  subject: cert.subject.commonName,
6154
3839
  issuer: cert.issuer.commonName,
6155
3840
  validFrom: new Date(cert.validFrom),
@@ -6168,7 +3853,7 @@ class ReactNativeMTLSAdapter {
6168
3853
  };
6169
3854
  }
6170
3855
  catch (error) {
6171
- log$8.error('Failed to get certificate info:', error);
3856
+ log$5.error('Failed to get certificate info:', error);
6172
3857
  return null;
6173
3858
  }
6174
3859
  }
@@ -6179,14 +3864,14 @@ class ReactNativeMTLSAdapter {
6179
3864
  */
6180
3865
  async parseCertificateData(certificateData) {
6181
3866
  if (!this.expoMTLS) {
6182
- log$8.debug('Parse certificate: Module not available');
3867
+ log$5.debug('Parse certificate: Module not available');
6183
3868
  return null;
6184
3869
  }
6185
3870
  try {
6186
3871
  let result;
6187
3872
  if (certificateData.format === 'P12') {
6188
3873
  if (!certificateData.password) {
6189
- throw new MTLSError(MTLSErrorType$1.CONFIGURATION_ERROR, 'P12 certificate requires password for parsing');
3874
+ throw new MTLSError(MTLSErrorType.CONFIGURATION_ERROR, 'P12 certificate requires password for parsing');
6190
3875
  }
6191
3876
  result = await this.expoMTLS.parseCertificateP12(certificateData.certificate, certificateData.password);
6192
3877
  }
@@ -6194,31 +3879,31 @@ class ReactNativeMTLSAdapter {
6194
3879
  result = await this.expoMTLS.parseCertificatePEM(certificateData.certificate);
6195
3880
  }
6196
3881
  else {
6197
- throw new MTLSError(MTLSErrorType$1.CERTIFICATE_INVALID, `Unsupported certificate format: ${certificateData.format}`);
3882
+ throw new MTLSError(MTLSErrorType.CERTIFICATE_INVALID, `Unsupported certificate format: ${certificateData.format}`);
6198
3883
  }
6199
- log$8.debug('Certificate parsed successfully:', {
3884
+ log$5.debug('Certificate parsed successfully:', {
6200
3885
  certificateCount: result.certificates.length,
6201
3886
  subjects: result.certificates.map((cert) => cert.subject.commonName),
6202
3887
  });
6203
3888
  return result;
6204
3889
  }
6205
3890
  catch (error) {
6206
- log$8.error('Failed to parse certificate:', error);
3891
+ log$5.error('Failed to parse certificate:', error);
6207
3892
  if (error instanceof MTLSError) {
6208
3893
  throw error;
6209
3894
  }
6210
- throw new MTLSError(MTLSErrorType$1.CERTIFICATE_INVALID, 'Failed to parse certificate data', error);
3895
+ throw new MTLSError(MTLSErrorType.CERTIFICATE_INVALID, 'Failed to parse certificate data', error);
6211
3896
  }
6212
3897
  }
6213
3898
  async request(requestConfig) {
6214
3899
  if (!this.expoMTLS) {
6215
- throw new MTLSError(MTLSErrorType$1.NOT_SUPPORTED, 'Expo mTLS module not available');
3900
+ throw new MTLSError(MTLSErrorType.NOT_SUPPORTED, 'Expo mTLS module not available');
6216
3901
  }
6217
3902
  const hasCert = await this.hasCertificate();
6218
3903
  if (!hasCert) {
6219
- throw new MTLSError(MTLSErrorType$1.CERTIFICATE_NOT_FOUND, 'No certificate configured');
3904
+ throw new MTLSError(MTLSErrorType.CERTIFICATE_NOT_FOUND, 'No certificate configured');
6220
3905
  }
6221
- log$8.debug('Making mTLS request:', {
3906
+ log$5.debug('Making mTLS request:', {
6222
3907
  method: requestConfig.method || 'GET',
6223
3908
  url: requestConfig.url,
6224
3909
  headers: requestConfig.headers,
@@ -6226,7 +3911,7 @@ class ReactNativeMTLSAdapter {
6226
3911
  responseType: requestConfig.responseType,
6227
3912
  });
6228
3913
  if (requestConfig.data) {
6229
- log$8.debug('mTLS request body:', requestConfig.data);
3914
+ log$5.debug('mTLS request body:', requestConfig.data);
6230
3915
  }
6231
3916
  try {
6232
3917
  const response = await this.expoMTLS.request(requestConfig.url, {
@@ -6235,9 +3920,9 @@ class ReactNativeMTLSAdapter {
6235
3920
  body: requestConfig.data ? JSON.stringify(requestConfig.data) : undefined,
6236
3921
  responseType: requestConfig.responseType,
6237
3922
  });
6238
- log$8.debug('mTLS request successful:', response);
3923
+ log$5.debug('mTLS request successful:', response);
6239
3924
  if (!response.success) {
6240
- throw new MTLSError(MTLSErrorType$1.CONNECTION_FAILED, `mTLS request failed: ${response.statusMessage} (${response.statusCode})`, undefined, response.statusCode);
3925
+ throw new MTLSError(MTLSErrorType.CONNECTION_FAILED, `mTLS request failed: ${response.statusMessage} (${response.statusCode})`, undefined, response.statusCode);
6241
3926
  }
6242
3927
  let data = response.body;
6243
3928
  // only parse if responseType is 'json' or if Content-Type header indicates JSON
@@ -6247,7 +3932,7 @@ class ReactNativeMTLSAdapter {
6247
3932
  data = JSON.parse(response.body);
6248
3933
  }
6249
3934
  catch (parseError) {
6250
- log$8.warn('Failed to parse JSON response:', parseError);
3935
+ log$5.warn('Failed to parse JSON response:', parseError);
6251
3936
  // If parsing fails, keep raw body
6252
3937
  }
6253
3938
  }
@@ -6264,8 +3949,8 @@ class ReactNativeMTLSAdapter {
6264
3949
  };
6265
3950
  }
6266
3951
  catch (error) {
6267
- log$8.error('mTLS request failed:', error);
6268
- throw new MTLSError(MTLSErrorType$1.CONNECTION_FAILED, 'mTLS request failed', error);
3952
+ log$5.error('mTLS request failed:', error);
3953
+ throw new MTLSError(MTLSErrorType.CONNECTION_FAILED, 'mTLS request failed', error);
6269
3954
  }
6270
3955
  }
6271
3956
  /**
@@ -6277,18 +3962,18 @@ class ReactNativeMTLSAdapter {
6277
3962
  */
6278
3963
  async testConnection() {
6279
3964
  if (!this.expoMTLS || !this.config) {
6280
- log$8.debug('Diagnostic test: No mTLS module or config available');
3965
+ log$5.debug('Diagnostic test: No mTLS module or config available');
6281
3966
  return false;
6282
3967
  }
6283
3968
  try {
6284
3969
  const hasCert = await this.hasCertificate();
6285
3970
  if (!hasCert) {
6286
- log$8.debug('Diagnostic test: No certificate configured');
3971
+ log$5.debug('Diagnostic test: No certificate configured');
6287
3972
  return false;
6288
3973
  }
6289
- log$8.debug('Running diagnostic test (may fail even if mTLS works):', this.config.baseUrl);
3974
+ log$5.debug('Running diagnostic test (may fail even if mTLS works):', this.config.baseUrl);
6290
3975
  const result = await this.expoMTLS.testConnection(this.config.baseUrl);
6291
- log$8.debug('Diagnostic test result (NOT validation):', {
3976
+ log$5.debug('Diagnostic test result (NOT validation):', {
6292
3977
  success: result.success,
6293
3978
  statusCode: result.statusCode,
6294
3979
  statusMessage: result.statusMessage,
@@ -6299,13 +3984,13 @@ class ReactNativeMTLSAdapter {
6299
3984
  return result.success;
6300
3985
  }
6301
3986
  catch (error) {
6302
- log$8.warn('Diagnostic test failed (this is expected):', error);
3987
+ log$5.warn('Diagnostic test failed (this is expected):', error);
6303
3988
  return false;
6304
3989
  }
6305
3990
  }
6306
3991
  async removeCertificate() {
6307
3992
  if (!this.expoMTLS) {
6308
- log$8.debug('Remove certificate: Module not available');
3993
+ log$5.debug('Remove certificate: Module not available');
6309
3994
  return;
6310
3995
  }
6311
3996
  try {
@@ -6314,11 +3999,11 @@ class ReactNativeMTLSAdapter {
6314
3999
  this.isConfigured = false;
6315
4000
  // Cleanup event listeners
6316
4001
  this.cleanupEventListeners();
6317
- log$8.debug('Certificate removed successfully');
4002
+ log$5.debug('Certificate removed successfully');
6318
4003
  }
6319
4004
  catch (error) {
6320
- log$8.error('Failed to remove certificate:', error);
6321
- throw new MTLSError(MTLSErrorType$1.CONFIGURATION_ERROR, 'Failed to remove certificate', error);
4005
+ log$5.error('Failed to remove certificate:', error);
4006
+ throw new MTLSError(MTLSErrorType.CONFIGURATION_ERROR, 'Failed to remove certificate', error);
6322
4007
  }
6323
4008
  }
6324
4009
  /**
@@ -6326,7 +4011,7 @@ class ReactNativeMTLSAdapter {
6326
4011
  */
6327
4012
  cleanupEventListeners() {
6328
4013
  if (this.eventListeners.length > 0) {
6329
- log$8.debug(`Cleaning up ${this.eventListeners.length} event listeners`);
4014
+ log$5.debug(`Cleaning up ${this.eventListeners.length} event listeners`);
6330
4015
  }
6331
4016
  // Remove individual listeners if they have remove methods
6332
4017
  this.eventListeners.forEach((listener) => {
@@ -6363,7 +4048,7 @@ class ReactNativeMTLSAdapter {
6363
4048
  }
6364
4049
  }
6365
4050
 
6366
- const log$7 = createPrefixedLogger('WEB-MTLS');
4051
+ const log$4 = createPrefixedLogger('WEB-MTLS');
6367
4052
  /**
6368
4053
  * Web mTLS Adapter - Graceful fallback for web browsers
6369
4054
  *
@@ -6377,13 +4062,13 @@ const log$7 = createPrefixedLogger('WEB-MTLS');
6377
4062
  */
6378
4063
  class WebMTLSAdapter {
6379
4064
  constructor() {
6380
- log$7.warn('Web browsers do not support programmatic mTLS configuration');
6381
- log$7.info('Use JWT authentication or configure client certificates in browser settings');
4065
+ log$4.warn('Web browsers do not support programmatic mTLS configuration');
4066
+ log$4.info('Use JWT authentication or configure client certificates in browser settings');
6382
4067
  }
6383
4068
  async isMTLSSupported() {
6384
4069
  // mTLS is not supported programmatically in web browsers
6385
4070
  const supported = false;
6386
- log$7.debug('mTLS support check:', {
4071
+ log$4.debug('mTLS support check:', {
6387
4072
  supported,
6388
4073
  platform: this.getPlatformInfo().platform,
6389
4074
  reason: 'Browser security model prevents programmatic certificate configuration',
@@ -6392,14 +4077,14 @@ class WebMTLSAdapter {
6392
4077
  return supported;
6393
4078
  }
6394
4079
  async initialize(config) {
6395
- log$7.warn('Initialized but mTLS not available in web browsers:', {
4080
+ log$4.warn('Initialized but mTLS not available in web browsers:', {
6396
4081
  baseUrl: config.baseUrl,
6397
4082
  port: config.port,
6398
4083
  recommendation: 'Use standard HTTPS with JWT authentication',
6399
4084
  });
6400
4085
  }
6401
4086
  async configureCertificate(certificateData) {
6402
- log$7.error('Certificate configuration attempted:', {
4087
+ log$4.error('Certificate configuration attempted:', {
6403
4088
  format: certificateData.format,
6404
4089
  reason: 'Not supported in web browsers',
6405
4090
  alternatives: [
@@ -6408,21 +4093,21 @@ class WebMTLSAdapter {
6408
4093
  'Configure server-side proxy for certificate handling',
6409
4094
  ],
6410
4095
  });
6411
- throw new MTLSError(MTLSErrorType$1.NOT_SUPPORTED, 'mTLS client certificate configuration is not supported in web browsers. ' +
4096
+ throw new MTLSError(MTLSErrorType.NOT_SUPPORTED, 'mTLS client certificate configuration is not supported in web browsers. ' +
6412
4097
  'Web browsers manage client certificates through the browser certificate store. ' +
6413
4098
  'Please use JWT authentication or import certificates manually into your browser.');
6414
4099
  }
6415
4100
  async hasCertificate() {
6416
4101
  // We cannot detect if the browser has certificates configured
6417
- log$7.debug('Certificate availability check: Cannot detect browser certificates programmatically');
4102
+ log$4.debug('Certificate availability check: Cannot detect browser certificates programmatically');
6418
4103
  return false;
6419
4104
  }
6420
4105
  async getCertificateInfo() {
6421
- log$7.debug('Certificate info requested: Not accessible in web browsers');
4106
+ log$4.debug('Certificate info requested: Not accessible in web browsers');
6422
4107
  return null;
6423
4108
  }
6424
4109
  async request(requestConfig) {
6425
- log$7.error('mTLS request attempted:', {
4110
+ log$4.error('mTLS request attempted:', {
6426
4111
  method: requestConfig.method,
6427
4112
  url: requestConfig.url,
6428
4113
  reason: 'Not supported in web browsers',
@@ -6432,16 +4117,16 @@ class WebMTLSAdapter {
6432
4117
  'Rely on browser-managed certificates (if configured by user)',
6433
4118
  ],
6434
4119
  });
6435
- throw new MTLSError(MTLSErrorType$1.NOT_SUPPORTED, 'mTLS requests are not supported in web browsers via JavaScript. ' +
4120
+ throw new MTLSError(MTLSErrorType.NOT_SUPPORTED, 'mTLS requests are not supported in web browsers via JavaScript. ' +
6436
4121
  'Use standard HTTP client with JWT authentication, or ensure client certificates ' +
6437
4122
  'are properly configured in the browser certificate store.');
6438
4123
  }
6439
4124
  async testConnection() {
6440
- log$7.debug('Connection test: mTLS not available in web browsers');
4125
+ log$4.debug('Connection test: mTLS not available in web browsers');
6441
4126
  return false;
6442
4127
  }
6443
4128
  async removeCertificate() {
6444
- log$7.debug('Remove certificate: No certificates to remove (not supported in web browsers)');
4129
+ log$4.debug('Remove certificate: No certificates to remove (not supported in web browsers)');
6445
4130
  // No-op - cannot remove certificates programmatically in browsers
6446
4131
  }
6447
4132
  /**
@@ -6449,7 +4134,7 @@ class WebMTLSAdapter {
6449
4134
  * Always returns null for web browsers as mTLS is not supported
6450
4135
  */
6451
4136
  getBaseUrl() {
6452
- log$7.debug('Base URL requested: Not supported in web browsers');
4137
+ log$4.debug('Base URL requested: Not supported in web browsers');
6453
4138
  return null;
6454
4139
  }
6455
4140
  getPlatformInfo() {
@@ -6482,7 +4167,7 @@ class WebMTLSAdapter {
6482
4167
  }
6483
4168
  }
6484
4169
 
6485
- const log$6 = createPrefixedLogger('MTLS-LOADER');
4170
+ const log$3 = createPrefixedLogger('MTLS-LOADER');
6486
4171
  function loadMTLSAdapter(platform, config) {
6487
4172
  try {
6488
4173
  let adapter;
@@ -6516,7 +4201,7 @@ function loadMTLSAdapter(platform, config) {
6516
4201
  return adapter;
6517
4202
  }
6518
4203
  catch (error) {
6519
- log$6.warn(`mTLS adapter not available for platform ${platform}:`, error);
4204
+ log$3.warn(`mTLS adapter not available for platform ${platform}:`, error);
6520
4205
  return null;
6521
4206
  }
6522
4207
  }
@@ -6526,7 +4211,7 @@ async function initializeAdapterAsync(adapter, config) {
6526
4211
  if (isSupported) {
6527
4212
  await adapter.initialize(config);
6528
4213
  const platformInfo = adapter.getPlatformInfo();
6529
- log$6.debug('mTLS adapter initialized:', {
4214
+ log$3.debug('mTLS adapter initialized:', {
6530
4215
  platform: platformInfo.platform,
6531
4216
  mtlsSupported: platformInfo.mtlsSupported,
6532
4217
  certificateStorage: platformInfo.certificateStorage,
@@ -6535,31 +4220,28 @@ async function initializeAdapterAsync(adapter, config) {
6535
4220
  }
6536
4221
  }
6537
4222
  catch (error) {
6538
- log$6.warn('Failed to initialize mTLS adapter:', error);
4223
+ log$3.warn('Failed to initialize mTLS adapter:', error);
6539
4224
  }
6540
4225
  }
6541
4226
 
6542
- const log$5 = createPrefixedLogger('ADAPTER-LOADER');
4227
+ const log$2 = createPrefixedLogger('ADAPTER-LOADER');
6543
4228
  function loadPlatformAdapters(options = {}) {
6544
4229
  const { mtlsConfig } = options;
6545
4230
  const { platform } = detectPlatform();
6546
- log$5.debug('Loading adapters for platform:', platform);
4231
+ log$2.debug('Loading adapters for platform:', platform);
6547
4232
  const storageAdapters = loadStorageAdapters(platform);
6548
4233
  const networkMonitor = loadNetworkMonitor(platform);
6549
- const cache = loadCacheAdapter(platform);
6550
4234
  const mtls = loadMTLSAdapter(platform, mtlsConfig);
6551
- log$5.debug('Adapters loaded:', {
4235
+ log$2.debug('Adapters loaded:', {
6552
4236
  platform,
6553
4237
  hasStorage: !!storageAdapters.storage,
6554
4238
  hasSecureStorage: !!storageAdapters.secureStorage,
6555
4239
  hasNetworkMonitor: !!networkMonitor,
6556
- hasCache: !!cache,
6557
4240
  hasMTLS: !!mtls,
6558
4241
  });
6559
4242
  return {
6560
4243
  ...storageAdapters,
6561
4244
  networkMonitor,
6562
- cache,
6563
4245
  mtls: mtls || undefined,
6564
4246
  };
6565
4247
  }
@@ -6576,12 +4258,9 @@ function createACubeMTLSConfig(baseUrl, timeout, autoInitialize = true, forcePor
6576
4258
 
6577
4259
  const DI_TOKENS = {
6578
4260
  HTTP_PORT: Symbol('HTTP_PORT'),
6579
- BASE_HTTP_PORT: Symbol('BASE_HTTP_PORT'),
6580
4261
  STORAGE_PORT: Symbol('STORAGE_PORT'),
6581
4262
  SECURE_STORAGE_PORT: Symbol('SECURE_STORAGE_PORT'),
6582
4263
  NETWORK_PORT: Symbol('NETWORK_PORT'),
6583
- CACHE_PORT: Symbol('CACHE_PORT'),
6584
- CACHE_KEY_GENERATOR: Symbol('CACHE_KEY_GENERATOR'),
6585
4264
  MTLS_PORT: Symbol('MTLS_PORT'),
6586
4265
  TOKEN_STORAGE_PORT: Symbol('TOKEN_STORAGE_PORT'),
6587
4266
  RECEIPT_REPOSITORY: Symbol('RECEIPT_REPOSITORY'),
@@ -6599,7 +4278,6 @@ const DI_TOKENS = {
6599
4278
  AUTH_SERVICE: Symbol('AUTH_SERVICE'),
6600
4279
  AUTHENTICATION_SERVICE: Symbol('AUTHENTICATION_SERVICE'),
6601
4280
  CERTIFICATE_SERVICE: Symbol('CERTIFICATE_SERVICE'),
6602
- OFFLINE_SERVICE: Symbol('OFFLINE_SERVICE'),
6603
4281
  NOTIFICATION_SERVICE: Symbol('NOTIFICATION_SERVICE'),
6604
4282
  TELEMETRY_SERVICE: Symbol('TELEMETRY_SERVICE'),
6605
4283
  };
@@ -7494,545 +5172,83 @@ class TelemetryMapper {
7494
5172
  : null,
7495
5173
  lastMessageFromAde: output.last_message_from_ade
7496
5174
  ? this.messageFromApi(output.last_message_from_ade)
7497
- : null,
7498
- lottery: this.lotteryFromApi(output.lottery),
7499
- };
7500
- }
7501
- static merchantFromApi(output) {
7502
- return {
7503
- vatNumber: output.vat_number,
7504
- fiscalCode: output.fiscal_code,
7505
- businessName: output.business_name,
7506
- };
7507
- }
7508
- static supplierFromApi(output) {
7509
- return {
7510
- vatNumber: output.vat_number,
7511
- fiscalCode: output.fiscal_code,
7512
- businessName: output.business_name,
7513
- };
7514
- }
7515
- static softwareVersionFromApi(output) {
7516
- return {
7517
- version: output.version,
7518
- swid: output.swid,
7519
- installedAt: output.installed_at,
7520
- status: output.status,
7521
- };
7522
- }
7523
- static softwareFromApi(output) {
7524
- return {
7525
- code: output.code,
7526
- name: output.name,
7527
- approvalReference: output.approval_reference,
7528
- versionInfo: output.version_info ? this.softwareVersionFromApi(output.version_info) : null,
7529
- };
7530
- }
7531
- static pendingReceiptsFromApi(output) {
7532
- return {
7533
- count: output.count,
7534
- totalAmount: output.total_amount,
7535
- };
7536
- }
7537
- static transmissionFromApi(output) {
7538
- return {
7539
- attemptedAt: output.attempted_at,
7540
- outcome: output.outcome,
7541
- };
7542
- }
7543
- static messageFromApi(output) {
7544
- return {
7545
- receivedAt: output.received_at,
7546
- content: output.content,
7547
- };
7548
- }
7549
- static secretRequestFromApi(output) {
7550
- return {
7551
- requestedAt: output.requested_at,
7552
- outcome: output.outcome,
7553
- };
7554
- }
7555
- static lotteryFromApi(output) {
7556
- return {
7557
- lastTransmission: output.last_transmission
7558
- ? this.transmissionFromApi(output.last_transmission)
7559
- : null,
7560
- secretRequest: output.secret_request
7561
- ? this.secretRequestFromApi(output.secret_request)
7562
- : null,
7563
- };
7564
- }
7565
- }
7566
-
7567
- class TelemetryRepositoryImpl {
7568
- constructor(http) {
7569
- this.http = http;
7570
- }
7571
- async getTelemetry(pemId) {
7572
- const response = await this.http.get(`/mf1/pems/${pemId}/telemetry`);
7573
- return TelemetryMapper.fromApiOutput(response.data);
7574
- }
7575
- }
7576
-
7577
- const log$4 = createPrefixedLogger('CACHE-KEY');
7578
- const URL_PATTERNS = [
7579
- // Receipt (mf1) - specific patterns first
7580
- {
7581
- pattern: /^\/mf1\/receipts\/([^/]+)\/returnable-items$/,
7582
- resource: 'receipt',
7583
- action: 'returnable',
7584
- },
7585
- {
7586
- pattern: /^\/mf1\/receipts\/([^/]+)\/details$/,
7587
- resource: 'receipt',
7588
- action: 'details',
7589
- },
7590
- { pattern: /^\/mf1\/receipts\/([^/]+)$/, resource: 'receipt' },
7591
- {
7592
- pattern: /^\/mf1\/pems\/([^/]+)\/receipts$/,
7593
- resource: 'receipt',
7594
- parent: 'point-of-sale',
7595
- isList: true,
7596
- },
7597
- { pattern: /^\/mf1\/receipts$/, resource: 'receipt', isList: true },
7598
- // Merchant (mf2)
7599
- { pattern: /^\/mf2\/merchants\/([^/]+)$/, resource: 'merchant' },
7600
- { pattern: /^\/mf2\/merchants$/, resource: 'merchant', isList: true },
7601
- // Cashier (mf1)
7602
- { pattern: /^\/mf1\/cashiers\/me$/, resource: 'cashier', action: 'me' },
7603
- { pattern: /^\/mf1\/cashiers\/([^/]+)$/, resource: 'cashier' },
7604
- { pattern: /^\/mf1\/cashiers$/, resource: 'cashier', isList: true },
7605
- // Cash Register (mf1)
7606
- { pattern: /^\/mf1\/cash-registers\/([^/]+)$/, resource: 'cash-register' },
7607
- { pattern: /^\/mf1\/cash-registers$/, resource: 'cash-register', isList: true },
7608
- // Point of Sale (mf1)
7609
- { pattern: /^\/mf1\/pems\/([^/]+)$/, resource: 'point-of-sale' },
7610
- { pattern: /^\/mf1\/pems$/, resource: 'point-of-sale', isList: true },
7611
- // Nested resources under merchant (mf2)
7612
- {
7613
- pattern: /^\/mf2\/merchants\/([^/]+)\/suppliers\/([^/]+)$/,
7614
- resource: 'supplier',
7615
- parent: 'merchant',
7616
- },
7617
- {
7618
- pattern: /^\/mf2\/merchants\/([^/]+)\/suppliers$/,
7619
- resource: 'supplier',
7620
- parent: 'merchant',
7621
- isList: true,
7622
- },
7623
- {
7624
- pattern: /^\/mf2\/merchants\/([^/]+)\/daily-reports/,
7625
- resource: 'daily-report',
7626
- parent: 'merchant',
7627
- isList: true,
7628
- },
7629
- {
7630
- pattern: /^\/mf2\/merchants\/([^/]+)\/journals/,
7631
- resource: 'journal',
7632
- parent: 'merchant',
7633
- isList: true,
7634
- },
7635
- // PEM (mf2)
7636
- {
7637
- pattern: /^\/mf2\/pems\/([^/]+)\/certificates$/,
7638
- resource: 'pem',
7639
- action: 'certificates',
7640
- },
7641
- { pattern: /^\/mf2\/pems\/([^/]+)$/, resource: 'pem' },
7642
- // Others
7643
- { pattern: /^\/mf1\/notifications/, resource: 'notification', isList: true },
7644
- {
7645
- pattern: /^\/mf1\/pems\/([^/]+)\/telemetry$/,
7646
- resource: 'telemetry',
7647
- },
7648
- ];
7649
- const DEFAULT_TTL_CONFIG = {
7650
- // Data that rarely changes - 30 min TTL for items only
7651
- merchant: { ttlMs: 30 * 60 * 1000, cacheList: false, cacheItem: true },
7652
- 'point-of-sale': { ttlMs: 30 * 60 * 1000, cacheList: false, cacheItem: true },
7653
- 'cash-register': { ttlMs: 30 * 60 * 1000, cacheList: false, cacheItem: true },
7654
- pem: { ttlMs: 30 * 60 * 1000, cacheList: false, cacheItem: false },
7655
- // Data that changes moderately - 10 min TTL for items only
7656
- cashier: { ttlMs: 10 * 60 * 1000, cacheList: false, cacheItem: true },
7657
- supplier: { ttlMs: 10 * 60 * 1000, cacheList: false, cacheItem: true },
7658
- // Data that can change - 5 min TTL for items only
7659
- receipt: { ttlMs: 5 * 60 * 1000, cacheList: false, cacheItem: true },
7660
- 'daily-report': { ttlMs: 5 * 60 * 1000, cacheList: false, cacheItem: true },
7661
- journal: { ttlMs: 5 * 60 * 1000, cacheList: false, cacheItem: true },
7662
- // Real-time data - 1 min TTL
7663
- notification: { ttlMs: 1 * 60 * 1000, cacheList: false, cacheItem: false },
7664
- telemetry: { ttlMs: 1 * 60 * 1000, cacheList: false, cacheItem: false },
7665
- };
7666
- const DEFAULT_TTL = 5 * 60 * 1000; // 5 minutes
7667
- class CacheKeyGenerator {
7668
- constructor(customConfig) {
7669
- this.config = { ...DEFAULT_TTL_CONFIG, ...customConfig };
7670
- log$4.info('CacheKeyGenerator initialized with config:', {
7671
- resources: Object.keys(this.config),
7672
- });
7673
- }
7674
- generate(url, params) {
7675
- const parsed = this.parseUrl(url);
7676
- if (!parsed) {
7677
- // Fallback: use URL as key
7678
- const paramStr = params ? this.serializeParams(params) : '';
7679
- const key = paramStr ? `${url}?${paramStr}` : url;
7680
- log$4.debug('URL not matched, using fallback key:', { url, key });
7681
- return key;
7682
- }
7683
- const { resource, ids, action, isList, parent } = parsed;
7684
- if (isList) {
7685
- const paramStr = params ? this.serializeParams(params) : '';
7686
- const parentPart = parent && ids.length > 0 ? `${parent}=${ids[0]}&` : '';
7687
- const key = `${resource}:list:${parentPart}${paramStr}`;
7688
- log$4.debug('Generated list cache key:', { url, key, resource });
7689
- return key;
7690
- }
7691
- // Single item
7692
- if (ids.length === 0 && action) {
7693
- // Special case for endpoints like /cashiers/me
7694
- const key = `${resource}:${action}`;
7695
- log$4.debug('Generated special action cache key:', { url, key, resource, action });
7696
- return key;
7697
- }
7698
- let key = `${resource}:${ids.join(':')}`;
7699
- if (action) {
7700
- key += `:${action}`;
7701
- }
7702
- log$4.debug('Generated item cache key:', { url, key, resource, ids, action });
7703
- return key;
7704
- }
7705
- parseResource(url) {
7706
- const parsed = this.parseUrl(url);
7707
- return parsed?.resource;
7708
- }
7709
- getTTL(url) {
7710
- const resource = this.parseResource(url);
7711
- if (!resource) {
7712
- log$4.debug('No resource found for URL, using default TTL:', { url, ttl: DEFAULT_TTL });
7713
- return DEFAULT_TTL;
7714
- }
7715
- const ttl = this.config[resource].ttlMs;
7716
- log$4.debug('TTL for resource:', { url, resource, ttlMs: ttl, ttlMin: ttl / 60000 });
7717
- return ttl;
7718
- }
7719
- shouldCache(url) {
7720
- const parsed = this.parseUrl(url);
7721
- if (!parsed) {
7722
- log$4.debug('URL not recognized, should not cache:', { url });
7723
- return false;
7724
- }
7725
- const { resource, isList } = parsed;
7726
- const config = this.config[resource];
7727
- if (isList) {
7728
- log$4.debug('List endpoint cache decision:', {
7729
- url,
7730
- resource,
7731
- isList: true,
7732
- shouldCache: config.cacheList,
7733
- });
7734
- return config.cacheList;
7735
- }
7736
- log$4.debug('Item endpoint cache decision:', {
7737
- url,
7738
- resource,
7739
- isList: false,
7740
- shouldCache: config.cacheItem,
7741
- });
7742
- return config.cacheItem;
7743
- }
7744
- getInvalidationPatterns(url, method) {
7745
- const parsed = this.parseUrl(url);
7746
- if (!parsed) {
7747
- log$4.debug('No patterns to invalidate for URL:', { url, method });
7748
- return [];
7749
- }
7750
- const { resource, ids, parent } = parsed;
7751
- const patterns = [];
7752
- // Always invalidate list on mutations
7753
- if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE') {
7754
- if (parent && ids.length > 0) {
7755
- patterns.push(`${resource}:list:${parent}=${ids[0]}*`);
7756
- }
7757
- patterns.push(`${resource}:list:*`);
7758
- }
7759
- // Invalidate specific item on PUT/PATCH/DELETE
7760
- if (method === 'PUT' || method === 'PATCH' || method === 'DELETE') {
7761
- if (ids.length > 0) {
7762
- patterns.push(`${resource}:${ids.join(':')}*`);
7763
- }
7764
- }
7765
- // Special cases
7766
- if (resource === 'cashier' && (method === 'PUT' || method === 'DELETE')) {
7767
- patterns.push('cashier:me');
7768
- }
7769
- log$4.debug('Invalidation patterns:', { url, method, patterns });
7770
- return patterns;
7771
- }
7772
- parseUrl(url) {
7773
- // Remove query string for pattern matching
7774
- const urlPath = url.split('?')[0];
7775
- for (const pattern of URL_PATTERNS) {
7776
- const match = urlPath?.match(pattern.pattern);
7777
- if (match) {
7778
- // Extract IDs from capture groups
7779
- const ids = match.slice(1).filter(Boolean);
7780
- return {
7781
- resource: pattern.resource,
7782
- ids,
7783
- action: pattern.action,
7784
- isList: pattern.isList,
7785
- parent: pattern.parent,
7786
- };
7787
- }
7788
- }
7789
- return null;
7790
- }
7791
- serializeParams(params) {
7792
- const sortedKeys = Object.keys(params).sort();
7793
- const parts = [];
7794
- for (const key of sortedKeys) {
7795
- const value = params[key];
7796
- if (value !== undefined && value !== null) {
7797
- parts.push(`${key}=${String(value)}`);
7798
- }
7799
- }
7800
- return parts.join('&');
7801
- }
7802
- }
7803
-
7804
- const log$3 = createPrefixedLogger('CACHE');
7805
- class CachingHttpDecorator {
7806
- constructor(http, cache, keyGenerator, networkMonitor, config = {}) {
7807
- this.http = http;
7808
- this.cache = cache;
7809
- this.keyGenerator = keyGenerator;
7810
- this.networkMonitor = networkMonitor;
7811
- this.config = config;
7812
- this.currentOnlineState = true;
7813
- this.authToken = null;
7814
- log$3.info('CachingHttpDecorator initialized', {
7815
- enabled: config.enabled !== false,
7816
- hasNetworkMonitor: !!networkMonitor,
7817
- });
7818
- this.setupNetworkMonitoring();
5175
+ : null,
5176
+ lottery: this.lotteryFromApi(output.lottery),
5177
+ };
7819
5178
  }
7820
- setupNetworkMonitoring() {
7821
- if (this.networkMonitor) {
7822
- this.networkSubscription = this.networkMonitor.online$.subscribe((online) => {
7823
- if (this.currentOnlineState !== online) {
7824
- log$3.info('Network state changed:', { online });
7825
- }
7826
- this.currentOnlineState = online;
7827
- });
7828
- }
5179
+ static merchantFromApi(output) {
5180
+ return {
5181
+ vatNumber: output.vat_number,
5182
+ fiscalCode: output.fiscal_code,
5183
+ businessName: output.business_name,
5184
+ };
7829
5185
  }
7830
- isOnline() {
7831
- if (this.networkMonitor) {
7832
- return this.currentOnlineState;
7833
- }
7834
- if (typeof navigator !== 'undefined' && 'onLine' in navigator) {
7835
- return navigator.onLine;
7836
- }
7837
- return true;
5186
+ static supplierFromApi(output) {
5187
+ return {
5188
+ vatNumber: output.vat_number,
5189
+ fiscalCode: output.fiscal_code,
5190
+ businessName: output.business_name,
5191
+ };
7838
5192
  }
7839
- async get(url, config) {
7840
- const startTime = Date.now();
7841
- // Check if caching is disabled globally
7842
- if (this.config.enabled === false) {
7843
- log$3.debug('GET (cache disabled globally):', { url });
7844
- return this.http.get(url, config);
7845
- }
7846
- // Check if this URL should be cached
7847
- const shouldCache = this.keyGenerator.shouldCache(url);
7848
- if (!shouldCache) {
7849
- log$3.debug('GET (not cacheable - likely a list endpoint):', { url });
7850
- return this.http.get(url, config);
7851
- }
7852
- const cacheKey = this.keyGenerator.generate(url, config?.params);
7853
- const ttl = this.keyGenerator.getTTL(url);
7854
- const resource = this.keyGenerator.parseResource(url);
7855
- log$3.info('GET request starting:', {
7856
- url,
7857
- resource,
7858
- cacheKey,
7859
- ttlMs: ttl,
7860
- ttlMin: Math.round(ttl / 60000),
7861
- params: config?.params,
7862
- });
7863
- // Check cache
7864
- let cached = null;
7865
- try {
7866
- cached = await this.cache.get(cacheKey);
7867
- if (cached) {
7868
- log$3.debug('Cache entry found:', {
7869
- cacheKey,
7870
- timestamp: new Date(cached.timestamp).toISOString(),
7871
- ageMs: Date.now() - cached.timestamp,
7872
- });
7873
- }
7874
- else {
7875
- log$3.debug('Cache entry not found:', { cacheKey });
7876
- }
7877
- }
7878
- catch (error) {
7879
- log$3.warn('Cache lookup failed:', {
7880
- cacheKey,
7881
- error: error instanceof Error ? error.message : error,
7882
- });
7883
- }
7884
- if (cached) {
7885
- const age = Date.now() - cached.timestamp;
7886
- const isExpired = age >= ttl;
7887
- log$3.debug('Cache analysis:', {
7888
- cacheKey,
7889
- ageMs: age,
7890
- ageSec: Math.round(age / 1000),
7891
- ttlMs: ttl,
7892
- isExpired,
7893
- isOnline: this.isOnline(),
7894
- });
7895
- // If within TTL, return cached data
7896
- if (!isExpired) {
7897
- const duration = Date.now() - startTime;
7898
- log$3.info('CACHE HIT:', {
7899
- url,
7900
- cacheKey,
7901
- ageMs: age,
7902
- durationMs: duration,
7903
- });
7904
- return {
7905
- data: cached.data,
7906
- status: 200,
7907
- headers: { 'x-cache': 'HIT' },
7908
- };
7909
- }
7910
- // If offline and cache is stale, return stale data
7911
- if (!this.isOnline()) {
7912
- const duration = Date.now() - startTime;
7913
- log$3.info('CACHE STALE (offline):', {
7914
- url,
7915
- cacheKey,
7916
- ageMs: age,
7917
- durationMs: duration,
7918
- });
7919
- return {
7920
- data: cached.data,
7921
- status: 200,
7922
- headers: { 'x-cache': 'STALE' },
7923
- };
7924
- }
7925
- log$3.debug('Cache expired, fetching fresh data:', { cacheKey, ageMs: age, ttlMs: ttl });
7926
- }
7927
- // Fetch fresh data
7928
- try {
7929
- log$3.debug('Fetching from network:', { url });
7930
- const response = await this.http.get(url, config);
7931
- // Cache the response
7932
- try {
7933
- await this.cache.set(cacheKey, response.data);
7934
- log$3.debug('Response cached successfully:', { cacheKey });
7935
- }
7936
- catch (error) {
7937
- log$3.error('Failed to cache response:', {
7938
- cacheKey,
7939
- error: error instanceof Error ? error.message : error,
7940
- });
7941
- }
7942
- const duration = Date.now() - startTime;
7943
- log$3.info('CACHE MISS (fetched fresh):', {
7944
- url,
7945
- cacheKey,
7946
- status: response.status,
7947
- durationMs: duration,
7948
- });
7949
- return {
7950
- ...response,
7951
- headers: { ...response.headers, 'x-cache': 'MISS' },
7952
- };
7953
- }
7954
- catch (error) {
7955
- // On error, return stale cache if available
7956
- if (cached) {
7957
- const duration = Date.now() - startTime;
7958
- log$3.warn('CACHE STALE (network error):', {
7959
- url,
7960
- cacheKey,
7961
- error: error instanceof Error ? error.message : 'Unknown error',
7962
- durationMs: duration,
7963
- });
7964
- return {
7965
- data: cached.data,
7966
- status: 200,
7967
- headers: { 'x-cache': 'STALE' },
7968
- };
7969
- }
7970
- log$3.error('Network error with no cache fallback:', {
7971
- url,
7972
- error: error instanceof Error ? error.message : error,
7973
- });
7974
- throw error;
7975
- }
5193
+ static softwareVersionFromApi(output) {
5194
+ return {
5195
+ version: output.version,
5196
+ swid: output.swid,
5197
+ installedAt: output.installed_at,
5198
+ status: output.status,
5199
+ };
7976
5200
  }
7977
- async post(url, data, config) {
7978
- log$3.info('POST request:', { url });
7979
- const response = await this.http.post(url, data, config);
7980
- await this.invalidateRelated(url, 'POST');
7981
- return response;
5201
+ static softwareFromApi(output) {
5202
+ return {
5203
+ code: output.code,
5204
+ name: output.name,
5205
+ approvalReference: output.approval_reference,
5206
+ versionInfo: output.version_info ? this.softwareVersionFromApi(output.version_info) : null,
5207
+ };
7982
5208
  }
7983
- async put(url, data, config) {
7984
- log$3.info('PUT request:', { url });
7985
- const response = await this.http.put(url, data, config);
7986
- await this.invalidateRelated(url, 'PUT');
7987
- return response;
5209
+ static pendingReceiptsFromApi(output) {
5210
+ return {
5211
+ count: output.count,
5212
+ totalAmount: output.total_amount,
5213
+ };
7988
5214
  }
7989
- async patch(url, data, config) {
7990
- log$3.info('PATCH request:', { url });
7991
- const response = await this.http.patch(url, data, config);
7992
- await this.invalidateRelated(url, 'PATCH');
7993
- return response;
5215
+ static transmissionFromApi(output) {
5216
+ return {
5217
+ attemptedAt: output.attempted_at,
5218
+ outcome: output.outcome,
5219
+ };
7994
5220
  }
7995
- async delete(url, config) {
7996
- log$3.info('DELETE request:', { url });
7997
- const response = await this.http.delete(url, config);
7998
- await this.invalidateRelated(url, 'DELETE');
7999
- return response;
5221
+ static messageFromApi(output) {
5222
+ return {
5223
+ receivedAt: output.received_at,
5224
+ content: output.content,
5225
+ };
8000
5226
  }
8001
- setAuthToken(token) {
8002
- log$3.debug('CachingHttpDecorator.setAuthToken called:', {
8003
- hasToken: !!token,
8004
- tokenPrefix: token?.substring(0, 20),
8005
- underlyingHttpType: this.http.constructor.name,
8006
- });
8007
- this.authToken = token;
8008
- this.http.setAuthToken(token);
5227
+ static secretRequestFromApi(output) {
5228
+ return {
5229
+ requestedAt: output.requested_at,
5230
+ outcome: output.outcome,
5231
+ };
8009
5232
  }
8010
- getAuthToken() {
8011
- return this.authToken;
5233
+ static lotteryFromApi(output) {
5234
+ return {
5235
+ lastTransmission: output.last_transmission
5236
+ ? this.transmissionFromApi(output.last_transmission)
5237
+ : null,
5238
+ secretRequest: output.secret_request
5239
+ ? this.secretRequestFromApi(output.secret_request)
5240
+ : null,
5241
+ };
8012
5242
  }
8013
- async invalidateRelated(url, method) {
8014
- const patterns = this.keyGenerator.getInvalidationPatterns(url, method);
8015
- if (patterns.length === 0) {
8016
- log$3.debug('No cache patterns to invalidate:', { url, method });
8017
- return;
8018
- }
8019
- log$3.info('Invalidating cache patterns:', { url, method, patterns });
8020
- for (const pattern of patterns) {
8021
- try {
8022
- await this.cache.invalidate(pattern);
8023
- log$3.debug('Cache pattern invalidated:', { pattern });
8024
- }
8025
- catch (error) {
8026
- log$3.error('Failed to invalidate pattern:', {
8027
- pattern,
8028
- error: error instanceof Error ? error.message : error,
8029
- });
8030
- }
8031
- }
5243
+ }
5244
+
5245
+ class TelemetryRepositoryImpl {
5246
+ constructor(http) {
5247
+ this.http = http;
8032
5248
  }
8033
- destroy() {
8034
- log$3.debug('CachingHttpDecorator destroyed');
8035
- this.networkSubscription?.unsubscribe();
5249
+ async getTelemetry(pemId) {
5250
+ const response = await this.http.get(`/mf1/pems/${pemId}/telemetry`);
5251
+ return TelemetryMapper.fromApiOutput(response.data);
8036
5252
  }
8037
5253
  }
8038
5254
 
@@ -8305,7 +5521,6 @@ class SDKFactory {
8305
5521
  baseUrl: config.baseUrl,
8306
5522
  timeout: config.timeout,
8307
5523
  });
8308
- container.register(DI_TOKENS.BASE_HTTP_PORT, httpAdapter);
8309
5524
  container.register(DI_TOKENS.HTTP_PORT, httpAdapter);
8310
5525
  container.registerFactory(DI_TOKENS.RECEIPT_REPOSITORY, () => {
8311
5526
  const http = container.get(DI_TOKENS.HTTP_PORT);
@@ -8353,23 +5568,6 @@ class SDKFactory {
8353
5568
  });
8354
5569
  return container;
8355
5570
  }
8356
- static registerCacheServices(container, cache, network) {
8357
- container.register(DI_TOKENS.CACHE_PORT, cache);
8358
- if (network) {
8359
- container.register(DI_TOKENS.NETWORK_PORT, network);
8360
- }
8361
- const keyGenerator = new CacheKeyGenerator();
8362
- container.register(DI_TOKENS.CACHE_KEY_GENERATOR, keyGenerator);
8363
- const baseHttp = container.get(DI_TOKENS.BASE_HTTP_PORT);
8364
- const cachingHttp = new CachingHttpDecorator(baseHttp, cache, keyGenerator, network);
8365
- container.register(DI_TOKENS.HTTP_PORT, cachingHttp);
8366
- }
8367
- static getCacheKeyGenerator(container) {
8368
- if (container.has(DI_TOKENS.CACHE_KEY_GENERATOR)) {
8369
- return container.get(DI_TOKENS.CACHE_KEY_GENERATOR);
8370
- }
8371
- return undefined;
8372
- }
8373
5571
  static registerAuthServices(container, secureStorage, config) {
8374
5572
  const tokenStorage = new TokenStorageAdapter(secureStorage);
8375
5573
  container.register(DI_TOKENS.TOKEN_STORAGE_PORT, tokenStorage);
@@ -8407,7 +5605,7 @@ class SDKFactory {
8407
5605
  }
8408
5606
  }
8409
5607
 
8410
- const log$2 = createPrefixedLogger('SDK');
5608
+ const log$1 = createPrefixedLogger('SDK');
8411
5609
  class ACubeSDK {
8412
5610
  constructor(config, customAdapters, events = {}) {
8413
5611
  this.events = events;
@@ -8421,23 +5619,22 @@ class ACubeSDK {
8421
5619
  }
8422
5620
  async initialize() {
8423
5621
  if (this.isInitialized) {
8424
- log$2.debug('SDK already initialized, skipping');
5622
+ log$1.debug('SDK already initialized, skipping');
8425
5623
  return;
8426
5624
  }
8427
- log$2.info('Initializing SDK', {
5625
+ log$1.info('Initializing SDK', {
8428
5626
  apiUrl: this.config.getApiUrl(),
8429
5627
  authUrl: this.config.getAuthUrl(),
8430
5628
  debugEnabled: this.config.isDebugEnabled(),
8431
5629
  });
8432
5630
  try {
8433
5631
  if (!this.adapters) {
8434
- log$2.debug('Loading platform adapters');
5632
+ log$1.debug('Loading platform adapters');
8435
5633
  const mtlsConfig = createACubeMTLSConfig(this.config.getApiUrl(), this.config.getTimeout(), true);
8436
5634
  this.adapters = loadPlatformAdapters({
8437
5635
  mtlsConfig,
8438
5636
  });
8439
- log$2.info('Platform adapters loaded', {
8440
- hasCache: !!this.adapters.cache,
5637
+ log$1.info('Platform adapters loaded', {
8441
5638
  hasNetworkMonitor: !!this.adapters.networkMonitor,
8442
5639
  hasMtls: !!this.adapters.mtls,
8443
5640
  hasSecureStorage: !!this.adapters.secureStorage,
@@ -8449,30 +5646,15 @@ class ACubeSDK {
8449
5646
  timeout: this.config.getTimeout(),
8450
5647
  debugEnabled: this.config.isDebugEnabled(),
8451
5648
  };
8452
- log$2.debug('Creating DI container');
5649
+ log$1.debug('Creating DI container');
8453
5650
  this.container = SDKFactory.createContainer(factoryConfig);
8454
- log$2.debug('Registering auth services');
5651
+ log$1.debug('Registering auth services');
8455
5652
  SDKFactory.registerAuthServices(this.container, this.adapters.secureStorage, factoryConfig);
8456
- if (this.adapters.cache) {
8457
- log$2.info('Registering cache services', {
8458
- hasNetworkMonitor: !!this.adapters.networkMonitor,
8459
- });
8460
- SDKFactory.registerCacheServices(this.container, this.adapters.cache, this.adapters.networkMonitor);
8461
- }
8462
- else {
8463
- log$2.debug('No cache adapter available, caching disabled');
8464
- }
8465
- log$2.debug('Initializing certificate service');
5653
+ log$1.debug('Initializing certificate service');
8466
5654
  this.certificateService = new CertificateService(this.adapters.secureStorage);
8467
5655
  const tokenStorage = this.container.get(DI_TOKENS.TOKEN_STORAGE_PORT);
8468
5656
  const httpPort = this.container.get(DI_TOKENS.HTTP_PORT);
8469
- const baseHttpPort = this.container.get(DI_TOKENS.BASE_HTTP_PORT);
8470
- log$2.debug('HTTP ports initialized', {
8471
- httpPortType: httpPort.constructor.name,
8472
- baseHttpPortType: baseHttpPort.constructor.name,
8473
- areSameInstance: httpPort === baseHttpPort,
8474
- });
8475
- log$2.debug('Initializing authentication service');
5657
+ log$1.debug('Initializing authentication service');
8476
5658
  this.authService = new AuthenticationService(httpPort, tokenStorage, {
8477
5659
  authUrl: this.config.getAuthUrl(),
8478
5660
  timeout: this.config.getTimeout(),
@@ -8482,51 +5664,33 @@ class ACubeSDK {
8482
5664
  this.events.onAuthError?.(new ACubeSDKError('AUTH_ERROR', error.message, error));
8483
5665
  },
8484
5666
  });
8485
- log$2.debug('Initializing offline manager');
8486
- const queueEvents = {
8487
- onOperationAdded: (operation) => {
8488
- this.events.onOfflineOperationAdded?.(operation.id);
8489
- },
8490
- onOperationCompleted: (result) => {
8491
- this.events.onOfflineOperationCompleted?.(result.operation.id, result.success);
8492
- },
8493
- onOperationFailed: (result) => {
8494
- this.events.onOfflineOperationCompleted?.(result.operation.id, false);
8495
- },
8496
- };
8497
- this.offlineManager = new OfflineManager(this.adapters.storage, httpPort, this.adapters.networkMonitor, {
8498
- syncInterval: 30000,
8499
- }, queueEvents);
8500
5667
  this.networkSubscription = this.adapters.networkMonitor.online$.subscribe((online) => {
8501
5668
  this.currentOnlineState = online;
8502
5669
  this.events.onNetworkStatusChanged?.(online);
8503
- if (online && this.offlineManager) {
8504
- this.offlineManager.sync().catch(() => { });
8505
- }
8506
5670
  });
8507
5671
  const isAuth = await this.authService.isAuthenticated();
8508
- log$2.debug('Checking authentication status during init', { isAuthenticated: isAuth });
5672
+ log$1.debug('Checking authentication status during init', { isAuthenticated: isAuth });
8509
5673
  if (isAuth) {
8510
5674
  const token = await this.authService.getAccessToken();
8511
- log$2.debug('Token retrieved during init', {
5675
+ log$1.debug('Token retrieved during init', {
8512
5676
  hasToken: !!token,
8513
5677
  tokenPrefix: token?.substring(0, 20),
8514
5678
  });
8515
5679
  if (token) {
8516
5680
  httpPort.setAuthToken(token);
8517
- log$2.info('Auth token set on HTTP port during initialization');
5681
+ log$1.info('Auth token set on HTTP port during initialization');
8518
5682
  }
8519
5683
  }
8520
5684
  else {
8521
- log$2.warn('User not authenticated during SDK init - token will be set after login');
5685
+ log$1.warn('User not authenticated during SDK init - token will be set after login');
8522
5686
  }
8523
- if (this.adapters?.mtls && 'setMTLSAdapter' in baseHttpPort) {
8524
- log$2.debug('Connecting mTLS adapter to HTTP port');
8525
- const httpWithMtls = baseHttpPort;
5687
+ if (this.adapters?.mtls && 'setMTLSAdapter' in httpPort) {
5688
+ log$1.debug('Connecting mTLS adapter to HTTP port');
5689
+ const httpWithMtls = httpPort;
8526
5690
  httpWithMtls.setMTLSAdapter(this.adapters.mtls);
8527
5691
  }
8528
- if ('setAuthStrategy' in baseHttpPort) {
8529
- log$2.debug('Configuring auth strategy');
5692
+ if ('setAuthStrategy' in httpPort) {
5693
+ log$1.debug('Configuring auth strategy');
8530
5694
  const jwtHandler = new JwtAuthHandler(tokenStorage);
8531
5695
  const certificatePort = this.certificateService
8532
5696
  ? {
@@ -8557,7 +5721,7 @@ class ACubeSDK {
8557
5721
  },
8558
5722
  };
8559
5723
  const authStrategy = new AuthStrategy(jwtHandler, mtlsHandler, userProvider, this.adapters?.mtls || null);
8560
- const httpWithStrategy = baseHttpPort;
5724
+ const httpWithStrategy = httpPort;
8561
5725
  httpWithStrategy.setAuthStrategy(authStrategy);
8562
5726
  }
8563
5727
  if (this.adapters?.mtls && this.certificateService) {
@@ -8575,19 +5739,18 @@ class ACubeSDK {
8575
5739
  }
8576
5740
  }
8577
5741
  catch (certError) {
8578
- log$2.warn('Certificate auto-configuration failed, will retry on demand', {
5742
+ log$1.warn('Certificate auto-configuration failed, will retry on demand', {
8579
5743
  error: certError instanceof Error ? certError.message : certError,
8580
5744
  });
8581
5745
  }
8582
5746
  }
8583
5747
  this.isInitialized = true;
8584
- log$2.info('SDK initialized successfully', {
8585
- hasCache: !!this.adapters.cache,
5748
+ log$1.info('SDK initialized successfully', {
8586
5749
  hasMtls: !!this.adapters.mtls,
8587
5750
  });
8588
5751
  }
8589
5752
  catch (error) {
8590
- log$2.error('SDK initialization failed', {
5753
+ log$1.error('SDK initialization failed', {
8591
5754
  error: error instanceof Error ? error.message : error,
8592
5755
  });
8593
5756
  throw new ACubeSDKError('SDK_INITIALIZATION_ERROR', `Failed to initialize SDK: ${error instanceof Error ? error.message : 'Unknown error'}`, error);
@@ -8643,19 +5806,19 @@ class ACubeSDK {
8643
5806
  }
8644
5807
  async login(credentials) {
8645
5808
  this.ensureInitialized();
8646
- log$2.info('Login attempt', { email: credentials.email });
5809
+ log$1.info('Login attempt', { email: credentials.email });
8647
5810
  const user = await this.authService.login(credentials);
8648
- log$2.info('Login successful', { roles: user.roles });
5811
+ log$1.info('Login successful', { roles: user.roles });
8649
5812
  const token = await this.authService.getAccessToken();
8650
5813
  if (token) {
8651
5814
  this.httpPort.setAuthToken(token);
8652
- log$2.debug('Auth token set on HTTP port');
5815
+ log$1.debug('Auth token set on HTTP port');
8653
5816
  }
8654
5817
  return user;
8655
5818
  }
8656
5819
  async logout() {
8657
5820
  this.ensureInitialized();
8658
- log$2.info('Logout');
5821
+ log$1.info('Logout');
8659
5822
  await this.authService.logout();
8660
5823
  this.httpPort.setAuthToken(null);
8661
5824
  }
@@ -8673,10 +5836,6 @@ class ACubeSDK {
8673
5836
  this.ensureInitialized();
8674
5837
  return await this.authService.isAuthenticated();
8675
5838
  }
8676
- getOfflineManager() {
8677
- this.ensureInitialized();
8678
- return this.offlineManager;
8679
- }
8680
5839
  isOnline() {
8681
5840
  this.ensureInitialized();
8682
5841
  return this.currentOnlineState;
@@ -8804,7 +5963,6 @@ class ACubeSDK {
8804
5963
  }
8805
5964
  destroy() {
8806
5965
  this.networkSubscription?.unsubscribe();
8807
- this.offlineManager?.destroy();
8808
5966
  this.container?.clear();
8809
5967
  this.isInitialized = false;
8810
5968
  }
@@ -9090,7 +6248,6 @@ class TelemetryService {
9090
6248
  this.events = events;
9091
6249
  this.stateSubject = new BehaviorSubject({
9092
6250
  data: null,
9093
- isCached: false,
9094
6251
  isLoading: false,
9095
6252
  lastFetchedAt: null,
9096
6253
  });
@@ -9160,7 +6317,6 @@ class TelemetryService {
9160
6317
  const data = await this.repository.getTelemetry(this.currentPemId);
9161
6318
  const newState = {
9162
6319
  data,
9163
- isCached: false,
9164
6320
  isLoading: false,
9165
6321
  lastFetchedAt: Date.now(),
9166
6322
  };
@@ -9185,7 +6341,6 @@ class TelemetryService {
9185
6341
  clearTelemetry() {
9186
6342
  this.stateSubject.next({
9187
6343
  data: null,
9188
- isCached: false,
9189
6344
  isLoading: false,
9190
6345
  lastFetchedAt: null,
9191
6346
  });
@@ -9198,7 +6353,7 @@ class TelemetryService {
9198
6353
  }
9199
6354
  }
9200
6355
 
9201
- const log$1 = createPrefixedLogger('SDK-MANAGER');
6356
+ const log = createPrefixedLogger('SDK-MANAGER');
9202
6357
  /**
9203
6358
  * SDKManager - Singleton wrapper for ACubeSDK with simplified API
9204
6359
  *
@@ -9265,7 +6420,7 @@ class SDKManager {
9265
6420
  if (canPoll && !this.isPollingActive) {
9266
6421
  const hasCert = await this.checkCertificate();
9267
6422
  if (!hasCert) {
9268
- log$1.warn('Certificate missing — polling blocked until certificate is installed');
6423
+ log.warn('Certificate missing — polling blocked until certificate is installed');
9269
6424
  return;
9270
6425
  }
9271
6426
  this.notificationService?.startPolling();
@@ -9367,7 +6522,7 @@ class SDKManager {
9367
6522
  this.isPollingActive = true;
9368
6523
  }
9369
6524
  else {
9370
- log$1.warn('Certificate missing at init — polling blocked until certificate is installed');
6525
+ log.warn('Certificate missing at init — polling blocked until certificate is installed');
9371
6526
  }
9372
6527
  }
9373
6528
  // AppStateService remains active for all users (handles OFFLINE network state)
@@ -9410,7 +6565,7 @@ class SDKManager {
9410
6565
  return this.certificateMissingSubject.asObservable();
9411
6566
  }
9412
6567
  /**
9413
- * Observable stream of telemetry state (data, isLoading, isCached, error)
6568
+ * Observable stream of telemetry state (data, isLoading, error)
9414
6569
  */
9415
6570
  get telemetryState$() {
9416
6571
  this.ensureInitialized();
@@ -9494,7 +6649,7 @@ class SDKManager {
9494
6649
  const user = await sdk.getCurrentUser();
9495
6650
  const canPoll = user && hasAnyRole(user.roles, ['ROLE_MERCHANT', 'ROLE_CASHIER']);
9496
6651
  if (canPoll) {
9497
- log$1.info('Certificate installed — starting polling');
6652
+ log.info('Certificate installed — starting polling');
9498
6653
  this.notificationService?.startPolling();
9499
6654
  await this.startTelemetryPollingAuto();
9500
6655
  this.isPollingActive = true;
@@ -9507,7 +6662,7 @@ class SDKManager {
9507
6662
  this.certificateMissingSubject.next(true);
9508
6663
  // Stop polling since certificate is required
9509
6664
  if (this.isPollingActive) {
9510
- log$1.info('Certificate removed — stopping polling');
6665
+ log.info('Certificate removed — stopping polling');
9511
6666
  this.notificationService?.stopPolling();
9512
6667
  this.telemetryService?.stopPolling();
9513
6668
  this.telemetryService?.clearTelemetry();
@@ -9587,268 +6742,5 @@ const RECEIPT_SENT = 'sent';
9587
6742
  const RECEIPT_SORT_DESCENDING = 'descending';
9588
6743
  const RECEIPT_SORT_ASCENDING = 'ascending';
9589
6744
 
9590
- const log = createPrefixedLogger('CACHE-HANDLER');
9591
- class CacheHandler {
9592
- constructor(cache, networkMonitor) {
9593
- this.cache = cache;
9594
- this.networkMonitor = networkMonitor;
9595
- this.currentOnlineState = true;
9596
- this.setupNetworkMonitoring();
9597
- }
9598
- setupNetworkMonitoring() {
9599
- if (this.networkMonitor) {
9600
- this.networkSubscription = this.networkMonitor.online$.subscribe((online) => {
9601
- this.currentOnlineState = online;
9602
- });
9603
- }
9604
- }
9605
- isOnline() {
9606
- if (this.networkMonitor) {
9607
- return this.currentOnlineState;
9608
- }
9609
- if (typeof navigator !== 'undefined' && 'onLine' in navigator) {
9610
- return navigator.onLine;
9611
- }
9612
- return false;
9613
- }
9614
- async handleCachedRequest(url, requestFn, config) {
9615
- if (!this.cache || config?.useCache === false) {
9616
- const response = await requestFn();
9617
- return response.data;
9618
- }
9619
- const cacheKey = this.generateCacheKey(url);
9620
- const online = this.isOnline();
9621
- log.debug('Request:', { url, cacheKey, online });
9622
- if (online) {
9623
- try {
9624
- const response = await requestFn();
9625
- if (this.cache) {
9626
- await this.cache.set(cacheKey, response.data).catch((error) => {
9627
- log.error('Failed to cache:', error instanceof Error ? error.message : error);
9628
- });
9629
- }
9630
- return response.data;
9631
- }
9632
- catch (error) {
9633
- const cached = await this.cache.get(cacheKey).catch(() => null);
9634
- if (cached) {
9635
- log.debug('Network failed, using cache fallback');
9636
- return cached.data;
9637
- }
9638
- throw error;
9639
- }
9640
- }
9641
- else {
9642
- const cached = await this.cache.get(cacheKey).catch(() => null);
9643
- if (cached) {
9644
- log.debug('Offline, returning cached data');
9645
- return cached.data;
9646
- }
9647
- throw new Error('Offline: No cached data available');
9648
- }
9649
- }
9650
- generateCacheKey(url) {
9651
- return url;
9652
- }
9653
- async invalidateCache(pattern) {
9654
- if (!this.cache)
9655
- return;
9656
- try {
9657
- await this.cache.invalidate(pattern);
9658
- }
9659
- catch (error) {
9660
- log.error('Invalidation failed:', error instanceof Error ? error.message : error);
9661
- }
9662
- }
9663
- getCacheStatus() {
9664
- return {
9665
- available: !!this.cache,
9666
- networkMonitorAvailable: !!this.networkMonitor,
9667
- isOnline: this.isOnline(),
9668
- };
9669
- }
9670
- destroy() {
9671
- this.networkSubscription?.unsubscribe();
9672
- }
9673
- }
9674
-
9675
- function transformError(error) {
9676
- if (axios.isAxiosError(error)) {
9677
- const response = error.response;
9678
- if (!response) {
9679
- return new ACubeSDKError('NETWORK_ERROR', 'Network error occurred', error);
9680
- }
9681
- const status = response.status;
9682
- const data = response.data;
9683
- const violations = data?.violations;
9684
- let message = 'Unknown error occurred';
9685
- if (data?.detail) {
9686
- message = data.detail;
9687
- }
9688
- else if (data?.title) {
9689
- message = data.title;
9690
- }
9691
- else if (error.message) {
9692
- message = error.message;
9693
- }
9694
- switch (status) {
9695
- case 400:
9696
- return new ACubeSDKError('VALIDATION_ERROR', message, error, status, violations);
9697
- case 401:
9698
- return new ACubeSDKError('AUTH_ERROR', message, error, status, violations);
9699
- case 403:
9700
- return new ACubeSDKError('FORBIDDEN_ERROR', message, error, status, violations);
9701
- case 404:
9702
- return new ACubeSDKError('NOT_FOUND_ERROR', message, error, status, violations);
9703
- case 422:
9704
- return new ACubeSDKError('VALIDATION_ERROR', message, error, status, violations);
9705
- default:
9706
- return new ACubeSDKError('UNKNOWN_ERROR', message, error, status, violations);
9707
- }
9708
- }
9709
- return new ACubeSDKError('UNKNOWN_ERROR', 'Unknown error occurred', error);
9710
- }
9711
-
9712
- var ErrorCategory;
9713
- (function (ErrorCategory) {
9714
- ErrorCategory["SERVER_ERROR"] = "SERVER_ERROR";
9715
- ErrorCategory["CLIENT_ERROR"] = "CLIENT_ERROR";
9716
- ErrorCategory["AUTH_ERROR"] = "AUTH_ERROR";
9717
- ErrorCategory["CERTIFICATE_ERROR"] = "CERTIFICATE_ERROR";
9718
- ErrorCategory["NETWORK_ERROR"] = "NETWORK_ERROR";
9719
- ErrorCategory["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
9720
- })(ErrorCategory || (ErrorCategory = {}));
9721
- function extractStatusCode(error) {
9722
- if (error instanceof MTLSError && error.statusCode) {
9723
- return error.statusCode;
9724
- }
9725
- const errorObj = error;
9726
- if (errorObj?.response?.status) {
9727
- return errorObj.response.status;
9728
- }
9729
- if (typeof errorObj?.statusCode === 'number') {
9730
- return errorObj.statusCode;
9731
- }
9732
- return undefined;
9733
- }
9734
- function classifyError(error) {
9735
- const statusCode = extractStatusCode(error);
9736
- const errorMessage = error instanceof Error ? error.message : String(error);
9737
- if (statusCode && statusCode >= 500 && statusCode < 600) {
9738
- return {
9739
- category: ErrorCategory.SERVER_ERROR,
9740
- statusCode,
9741
- message: errorMessage,
9742
- shouldRetry: false,
9743
- userMessage: `Server error (${statusCode}): The server encountered an error.`,
9744
- };
9745
- }
9746
- if (statusCode === 401 || statusCode === 403) {
9747
- return {
9748
- category: ErrorCategory.AUTH_ERROR,
9749
- statusCode,
9750
- message: errorMessage,
9751
- shouldRetry: false,
9752
- userMessage: `Authentication error (${statusCode}): Invalid credentials or insufficient permissions.`,
9753
- };
9754
- }
9755
- if (statusCode && statusCode >= 400 && statusCode < 500) {
9756
- return {
9757
- category: ErrorCategory.CLIENT_ERROR,
9758
- statusCode,
9759
- message: errorMessage,
9760
- shouldRetry: false,
9761
- userMessage: `Request error (${statusCode}): ${errorMessage}`,
9762
- };
9763
- }
9764
- if (error instanceof MTLSError) {
9765
- return {
9766
- category: ErrorCategory.CERTIFICATE_ERROR,
9767
- statusCode,
9768
- message: errorMessage,
9769
- shouldRetry: true,
9770
- userMessage: 'Certificate error: Unable to establish secure connection.',
9771
- };
9772
- }
9773
- if (!statusCode &&
9774
- (errorMessage.toLowerCase().includes('network') ||
9775
- errorMessage.toLowerCase().includes('timeout') ||
9776
- errorMessage.toLowerCase().includes('connection'))) {
9777
- return {
9778
- category: ErrorCategory.NETWORK_ERROR,
9779
- message: errorMessage,
9780
- shouldRetry: true,
9781
- userMessage: 'Network error: Unable to connect to server.',
9782
- };
9783
- }
9784
- return {
9785
- category: ErrorCategory.UNKNOWN_ERROR,
9786
- statusCode,
9787
- message: errorMessage,
9788
- shouldRetry: false,
9789
- userMessage: `Unexpected error: ${errorMessage}`,
9790
- };
9791
- }
9792
- function shouldReconfigureCertificate(error) {
9793
- const classification = classifyError(error);
9794
- return classification.category === ErrorCategory.CERTIFICATE_ERROR;
9795
- }
9796
- function shouldRetryRequest(error, isRetryAttempt) {
9797
- if (isRetryAttempt) {
9798
- return false;
9799
- }
9800
- const classification = classifyError(error);
9801
- return classification.shouldRetry;
9802
- }
9803
- function getUserFriendlyMessage(error) {
9804
- const classification = classifyError(error);
9805
- return classification.userMessage;
9806
- }
9807
-
9808
- var MTLSErrorType;
9809
- (function (MTLSErrorType) {
9810
- MTLSErrorType["NOT_SUPPORTED"] = "MTLS_NOT_SUPPORTED";
9811
- MTLSErrorType["CERTIFICATE_NOT_FOUND"] = "MTLS_CERTIFICATE_NOT_FOUND";
9812
- MTLSErrorType["CERTIFICATE_EXPIRED"] = "MTLS_CERTIFICATE_EXPIRED";
9813
- MTLSErrorType["CERTIFICATE_INVALID"] = "MTLS_CERTIFICATE_INVALID";
9814
- MTLSErrorType["CONNECTION_FAILED"] = "MTLS_CONNECTION_FAILED";
9815
- MTLSErrorType["AUTHENTICATION_FAILED"] = "MTLS_AUTHENTICATION_FAILED";
9816
- MTLSErrorType["CONFIGURATION_ERROR"] = "MTLS_CONFIGURATION_ERROR";
9817
- })(MTLSErrorType || (MTLSErrorType = {}));
9818
- class PlatformDetector {
9819
- static detectPlatform() {
9820
- if ((typeof global !== 'undefined' && global.__expo) ||
9821
- (typeof navigator !== 'undefined' &&
9822
- navigator.product === 'ReactNative')) {
9823
- return 'react-native';
9824
- }
9825
- if (typeof process !== 'undefined' && process.versions?.node) {
9826
- return 'node';
9827
- }
9828
- return 'web';
9829
- }
9830
- static isReactNative() {
9831
- return this.detectPlatform() === 'react-native';
9832
- }
9833
- static isNode() {
9834
- return this.detectPlatform() === 'node';
9835
- }
9836
- static isWeb() {
9837
- return this.detectPlatform() === 'web';
9838
- }
9839
- static getPlatformDetails() {
9840
- const platform = this.detectPlatform();
9841
- return {
9842
- platform,
9843
- userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : 'unknown',
9844
- nodeVersion: typeof process !== 'undefined' ? process.version : undefined,
9845
- isExpo: typeof global !== 'undefined' && !!global.__expo,
9846
- hasWindow: typeof window !== 'undefined',
9847
- hasDocument: typeof document !== 'undefined',
9848
- hasProcess: typeof process !== 'undefined',
9849
- };
9850
- }
9851
- }
9852
-
9853
- export { ACubeSDK, ACubeSDKError, ActivationRequestSchema, AddressMapper, AddressSchema, AppStateService, AuthStrategy, AuthenticationService, AxiosHttpAdapter, CacheHandler, CashRegisterCreateSchema, CashRegisterMapper, CashRegisterRepositoryImpl, CashierCreateInputSchema, CashierMapper, CashierRepositoryImpl, CertificateService, CertificateValidator, ConfigManager, DAILY_REPORT_STATUS_OPTIONS, DEFAULT_QUEUE_CONFIG, DIContainer, DI_TOKENS, DailyReportMapper, DailyReportRepositoryImpl, DailyReportStatusSchema, DailyReportsParamsSchema, EXEMPT_VAT_CODES, ErrorCategory, GOOD_OR_SERVICE_OPTIONS, GoodOrServiceSchema, JournalCloseInputSchema, JournalMapper, JournalRepositoryImpl, JwtAuthHandler, LotterySchema, LotterySecretRequestSchema, MTLSError, MTLSErrorType$1 as MTLSErrorType, MerchantCreateInputSchema, MerchantMapper, MerchantRepositoryImpl, MerchantUpdateInputSchema, MessageSchema, MtlsAuthHandler, NOTIFICATION_CODES, NOTIFICATION_LEVELS, NOTIFICATION_SCOPES, NOTIFICATION_SOURCES, NOTIFICATION_TYPES, NotificationDataBlockAtSchema, NotificationDataPemStatusSchema, NotificationListResponseSchema, NotificationMapper, NotificationMf2UnreachableSchema, NotificationPemBackOnlineSchema, NotificationPemsBlockedSchema, NotificationRepositoryImpl, NotificationSchema, NotificationScopeSchema, NotificationService, OfflineManager, OperationQueue, PEMStatusOfflineRequestSchema, PEMStatusSchema, PEM_STATUS_OPTIONS, PEM_TYPE_OPTIONS, PemCreateInputSchema, PemDataSchema, PemMapper, PemRepositoryImpl, PemStatusSchema, PendingReceiptsSchema, PlatformDetector, PointOfSaleMapper, PointOfSaleRepositoryImpl, RECEIPT_PROOF_TYPE_OPTIONS, RECEIPT_READY, RECEIPT_SENT, RECEIPT_SORT_ASCENDING, RECEIPT_SORT_DESCENDING, ReceiptInputSchema, ReceiptItemSchema, ReceiptMapper, ReceiptProofTypeSchema, ReceiptRepositoryImpl, ReceiptReturnInputSchema, ReceiptReturnItemSchema, ReceiptReturnOrVoidViaPEMInputSchema, ReceiptReturnOrVoidWithProofInputSchema, SDKFactory, SDKManager, STANDARD_VAT_RATES, SupplierCreateInputSchema, SupplierMapper, SupplierRepositoryImpl, SupplierUpdateInputSchema, SyncManager, TelemetryMapper, TelemetryMerchantSchema, TelemetryRepositoryImpl, TelemetrySchema, TelemetryService, TelemetrySoftwareSchema, TelemetrySoftwareVersionSchema, TelemetrySupplierSchema, TransmissionSchema, VAT_RATE_CODES, VAT_RATE_CODE_OPTIONS, ValidationMessages, VatRateCodeSchema, VoidReceiptInputSchema, classifyError, clearObject, clearObjectShallow, createACubeMTLSConfig, createACubeSDK, createPrefixedLogger, createACubeSDK as default, detectPlatform, extractRoles, formatDecimal, getUserFriendlyMessage, hasAnyRole, hasNonEmptyValues, hasRole, isEmpty, isTokenExpired, loadPlatformAdapters, logger, parseJwt, shouldReconfigureCertificate, shouldRetryRequest, transformError, validateInput };
6745
+ export { ACubeSDK, ACubeSDKError, AddressMapper, AppStateService, AuthenticationService, CashRegisterMapper, CashierMapper, CertificateService, CertificateValidator, ConfigManager, DAILY_REPORT_STATUS_OPTIONS, DailyReportMapper, EXEMPT_VAT_CODES, GOOD_OR_SERVICE_OPTIONS, GoodOrServiceSchema, JournalMapper, MTLSError, MTLSErrorType, MerchantMapper, NOTIFICATION_CODES, NOTIFICATION_LEVELS, NOTIFICATION_SCOPES, NOTIFICATION_SOURCES, NOTIFICATION_TYPES, NotificationMapper, NotificationService, PEM_STATUS_OPTIONS, PEM_TYPE_OPTIONS, PemMapper, PointOfSaleMapper, RECEIPT_PROOF_TYPE_OPTIONS, RECEIPT_READY, RECEIPT_SENT, RECEIPT_SORT_ASCENDING, RECEIPT_SORT_DESCENDING, ReceiptMapper, ReceiptProofTypeSchema, SDKManager, STANDARD_VAT_RATES, SupplierMapper, TelemetryMapper, TelemetryService, VAT_RATE_CODES, VAT_RATE_CODE_OPTIONS, VatRateCodeSchema, createACubeMTLSConfig, createACubeSDK, createPrefixedLogger, createACubeSDK as default, extractRoles, hasAnyRole, hasRole, isTokenExpired, loadPlatformAdapters, logger, parseJwt };
9854
6746
  //# sourceMappingURL=index.native.js.map