Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 86 additions & 108 deletions bun.lock

Large diffs are not rendered by default.

6,284 changes: 0 additions & 6,284 deletions package-lock.json

This file was deleted.

5 changes: 4 additions & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ const external = [
'react-native-keychain',
'react-native-sqlite-storage',
'zod',
'@a-cube-io/expo-mutual-tls'
'@a-cube-io/expo-mutual-tls',
'expo-task-manager',
'expo-background-task',
'react-native-background-task'
];

// Node.js specific externals (only for Node.js/web builds, not React Native)
Expand Down
17 changes: 9 additions & 8 deletions src/acube-sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from './core';
import { PlatformAdapters } from './adapters';
import { OfflineManager, QueueEvents } from './offline';
import { CertificateManager } from './core/certificates/certificate-manager';
import { CertificateManager } from './core';

/**
* SDK Events interface
Expand All @@ -31,8 +31,11 @@ export class ACubeSDK {
private config: ConfigManager;
private adapters?: PlatformAdapters;
private authManager?: AuthManager;

// TODO: Remove offlineManager
private offlineManager?: OfflineManager;
private certificateManager?: CertificateManager;

private isInitialized = false;

// Public API clients
Expand Down Expand Up @@ -83,7 +86,7 @@ export class ACubeSDK {
this.config.isDebugEnabled()
);

// Initialize auth manager first (needed for API client)
// Initialize auth manager first (needed for an API client)
this.authManager = new AuthManager(
this.config,
this.adapters.secureStorage,
Expand All @@ -97,14 +100,12 @@ export class ACubeSDK {
// Pass authManager as userProvider for role-based auth decisions
this.api = new APIClient(
this.config,
this.adapters,
this.certificateManager,
this.adapters.cache,
this.adapters.networkMonitor,
this.adapters.mtls,
this.authManager // AuthManager implements IUserProvider
);

// Initialize offline manager
//TODO: REMOVE THIS Initialize offline manager
const queueEvents: QueueEvents = {
onOperationAdded: (operation) => {
this.events.onOfflineOperationAdded?.(operation.id);
Expand Down Expand Up @@ -347,7 +348,7 @@ export class ACubeSDK {


/**
* Get certificate manager for advanced certificate operations
* Get a certificate manager for advanced certificate operations
*/
getCertificateManager() {
this.ensureInitialized();
Expand All @@ -371,7 +372,7 @@ export class ACubeSDK {
}

/**
* Get certificate information (without private key)
* Get certificate information (without a private key)
*/
async getCertificateInfo() {
this.ensureInitialized();
Expand Down
4 changes: 4 additions & 0 deletions src/adapters/background-task-adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface IBackgroundTaskAdapter {
registerTask(taskName: string, task: () => Promise<void>): Promise<void>;
unregisterTask(taskName: string): Promise<void>;
}
3 changes: 3 additions & 0 deletions src/adapters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ export * from './secure-storage';
export * from './network';
export * from './cache';
export * from './mtls';
export * from './background-task-adapter'

import { IStorage } from './storage';
import { ISecureStorage } from './secure-storage';
import { INetworkMonitor } from './network';
import { ICacheAdapter } from './cache';
import { IMTLSAdapter } from './mtls';
import { IBackgroundTaskAdapter } from './background-task-adapter';

/**
* Platform adapters collection
Expand All @@ -19,4 +21,5 @@ export interface PlatformAdapters {
networkMonitor: INetworkMonitor;
cache?: ICacheAdapter; // Optional for backward compatibility
mtls?: IMTLSAdapter; // Optional for backward compatibility and unsupported platforms
backgroundTask?: IBackgroundTaskAdapter; // Optional for platforms that support background tasks
}
2 changes: 1 addition & 1 deletion src/adapters/secure-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { IStorage } from './storage';

/**
* Secure storage adapter interface for sensitive data like tokens
* Extends IStorage with the same interface but different implementations
* Extends IStorage with the same interface, but different implementations
* should use platform-specific secure storage mechanisms
*/
export interface ISecureStorage extends IStorage {
Expand Down
4 changes: 4 additions & 0 deletions src/core/adapter-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
loadNetworkMonitor,
loadMTLSAdapter
} from './loaders';
import {loadBackgroundTask} from "./loaders/background-task-loader";

/**
* Configuration for mTLS adapter initialization
Expand Down Expand Up @@ -48,6 +49,7 @@ export function loadPlatformAdapters(
const storageAdapters = loadStorageAdapters(platform);
const networkMonitor = loadNetworkMonitor(platform);
const cache = loadCacheAdapter(platform);
const backgroundTask = loadBackgroundTask(platform)

// Load mTLS adapter with optional configuration
const mtls = loadMTLSAdapter(platform, debugEnabled, mtlsConfig ? {
Expand All @@ -64,6 +66,7 @@ export function loadPlatformAdapters(
hasStorage: !!storageAdapters.storage,
hasSecureStorage: !!storageAdapters.secureStorage,
hasNetworkMonitor: !!networkMonitor,
hasBackgroundTask: !!backgroundTask,
hasCache: !!cache,
hasMTLS: !!mtls,
mtlsAutoInitialize: mtlsConfig?.autoInitialize || false,
Expand All @@ -76,6 +79,7 @@ export function loadPlatformAdapters(
networkMonitor,
cache,
mtls: mtls || undefined,
backgroundTask
};
}

Expand Down
96 changes: 25 additions & 71 deletions src/core/api/api-client.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ConfigManager } from '../config';
import { HttpClient } from './http-client';
import { ICacheAdapter, INetworkMonitor, IMTLSAdapter } from '../../adapters';
import { CertificateManager } from '../certificates/certificate-manager';
import { HttpClient } from '../http';
import { PlatformAdapters } from '../../adapters';
import { CertificateManager } from '../certificates';
import { IUserProvider } from '../types';
import { ReceiptsAPI } from './receipts';
import { CashiersAPI } from './cashiers';
Expand All @@ -12,15 +12,14 @@ import { PemsAPI } from './pems';
import { SuppliersAPI } from './suppliers';
import { DailyReportsAPI } from './daily-reports';
import { JournalsAPI } from './journals';
import {OfflineMaster} from "../../offline";
import {ReceiptInput} from "./types";

/**
* Main API client that combines all resource managers
*/
export class APIClient {
private httpClient: HttpClient;
private cache?: ICacheAdapter;
private networkMonitor?: INetworkMonitor;

private readonly httpClient: HttpClient;
// Resource managers
public readonly receipts: ReceiptsAPI;
public readonly cashiers: CashiersAPI;
Expand All @@ -34,18 +33,29 @@ export class APIClient {

constructor(
config: ConfigManager,
adapters: PlatformAdapters,
certificateManager?: CertificateManager,
cache?: ICacheAdapter,
networkMonitor?: INetworkMonitor,
mtlsAdapter?: IMTLSAdapter,
userProvider?: IUserProvider
userProvider?: IUserProvider,
) {
this.cache = cache;
this.networkMonitor = networkMonitor;
this.httpClient = new HttpClient(config, certificateManager, cache, networkMonitor, mtlsAdapter, userProvider);

this.httpClient = new HttpClient(
config,
certificateManager,
adapters.cache,
adapters.networkMonitor,
adapters.mtls,
userProvider
);

// Initialize resource managers
this.receipts = new ReceiptsAPI(this.httpClient);
this.receipts = new ReceiptsAPI(
this.httpClient,
new OfflineMaster(
adapters,
(data: ReceiptInput) => this.receipts.create(data)
)
);

this.cashiers = new CashiersAPI(this.httpClient);
this.pointOfSales = new PointOfSalesAPI(this.httpClient);
this.cashRegisters = new CashRegistersAPI(this.httpClient);
Expand Down Expand Up @@ -76,60 +86,4 @@ export class APIClient {
getHttpClient(): HttpClient {
return this.httpClient;
}

/**
* Get the cache adapter if available
*/
getCache(): ICacheAdapter | undefined {
return this.cache;
}

/**
* Check if the cache is available and enabled
*/
isCacheEnabled(): boolean {
return !!this.cache;
}

/**
* Get the network monitor if available
*/
getNetworkMonitor(): INetworkMonitor | undefined {
return this.networkMonitor;
}

/**
* Check if network monitoring is enabled
*/
isNetworkMonitorEnabled(): boolean {
return !!this.networkMonitor;
}

/**
* Get current network status
*/
getNetworkStatus(): { isOnline: boolean; hasMonitor: boolean } {
return this.httpClient.getNetworkStatus();
}

/**
* Check if currently online
*/
isOnline(): boolean {
return this.getNetworkStatus().isOnline;
}

/**
* Get mTLS adapter if available through HttpClient
*/
getMTLSAdapter(): IMTLSAdapter | null {
return this.httpClient.getMTLSAdapter();
}

/**
* Check if mTLS is ready
*/
async isMTLSReady(): Promise<boolean> {
return this.httpClient.isMTLSReady();
}
}
71 changes: 41 additions & 30 deletions src/core/api/receipts.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { HttpClient, CacheRequestConfig } from './http-client';
import {CacheRequestConfig, HttpClient} from './http-client';
import {
ReceiptInput,
ReceiptOutput,
ReceiptDetailsOutput,
ReceiptReturnOrVoidViaPEMInput,
ReceiptReturnOrVoidWithProofInput,
Page,
ReceiptListParams,
RECEIPT_READY
Page,
RECEIPT_READY,
ReceiptDetailsOutput,
ReceiptInput,
ReceiptListParams,
ReceiptOutput,
ReceiptReturnOrVoidViaPEMInput,
ReceiptReturnOrVoidWithProofInput
} from './types';
import {OfflineMaster} from "../../offline";

/**
* User role information for authentication routing
Expand All @@ -26,37 +27,24 @@ export class ReceiptsAPI {
private debugEnabled: boolean = false;
private userContext: UserContext | null = null;

constructor(private httpClient: HttpClient) {
constructor(
private httpClient: HttpClient,
private offlineMaster: OfflineMaster,
) {
this.debugEnabled = httpClient.isDebugEnabled || true;

if (this.debugEnabled) {
console.log('[RECEIPTS-API] Receipts API initialized with mTLS support');
}
}

/**
* Set user context for role-based authentication
*/
setUserContext(context: UserContext): void {
this.userContext = context;

if (this.debugEnabled) {
console.log('[RECEIPTS-API] User context set:', {
roles: context.roles,
userId: context.userId,
merchantId: context.merchantId
});
}
}


/**
* Create request configuration
* Let MTLSHandler determine the best authentication mode based on role/platform/method
*/
private createRequestConfig(config?: Partial<CacheRequestConfig>): CacheRequestConfig {
return {
authMode: 'auto', // Let MTLSHandler decide based on authentication matrix
authMode: 'auto', // Let MTLSHandler decide based on the authentication matrix
...config
};
}
Expand All @@ -68,10 +56,29 @@ export class ReceiptsAPI {
async create(receiptData: ReceiptInput): Promise<ReceiptOutput> {
if (this.debugEnabled) {
console.log('[RECEIPTS-API] Creating receipt');
console.log('[RECEIPTS-API] [OFFLINE MASTER]', this.offlineMaster);
}

const config = this.createRequestConfig();
return this.httpClient.post<ReceiptOutput>('/mf1/receipts', receiptData, config);
try {
const config = this.createRequestConfig();
return this.httpClient.post<ReceiptOutput>('/mf1/receipts', receiptData, config)
.then((result) => {
this.offlineMaster.successSendReceipt()
return result;
})
.catch(async (error) => {
throw error
});

}catch (error){
if (this.debugEnabled) {
console.log('[RECEIPTS-API] Error creating receipt:', error);
console.log('[RECEIPTS-API] [OFFLINE MASTER]', this.offlineMaster);
}
this.offlineMaster.beginOfflineOrEmergencyModeProcess();
await this.offlineMaster.saveData(receiptData);
throw error;
}
}

/**
Expand Down Expand Up @@ -123,7 +130,7 @@ export class ReceiptsAPI {
/**
* Get receipt details (JSON or PDF)
* Authentication mode determined by MTLSHandler
* PDF downloads now use mTLS with binary response support (expo-mutual-tls v1.0.3+)
* PDF downloads now use mTLS with binary response support (expo-mutual-tls v1.0.3+)
*/
async getDetails(
receiptUuid: string,
Expand Down Expand Up @@ -248,4 +255,8 @@ export class ReceiptsAPI {

return status;
}

getOfflineReceipts(): ReceiptInput[] {
return this.offlineMaster.getOfflineData();
}
}
Loading