Loading...
Loading...
Anders & A-Cube S.r.l. / July 15, 2025 ⢠5 min read
@a-cube-io/ereceipts-js-sdk is a production-ready TypeScript SDK for electronic receipt management, providing seamless multi-platform support across Browser, Node.js, and React Native environments. Built with modern tooling and strict type safety, it offers enterprise-grade reliability with an intuitive developer experience.
The SDK implements a layered architecture with platform-specific optimizations:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Application Layer (React/RN/Node) ā
ā Custom Hooks & Utility Functions ā
āāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā
āāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Core SDK Layer (TypeScript) ā
ā Receipt Management ⢠Validation ⢠Caching ā
āāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāā
ā ā
āāāāāāāā¼āāāāāāāāāā āāāāāāāāāāā¼āāāāāāāāāāā
ā Browser Layer ā ā Native Layer ā
ā - IndexedDB ā ā - AsyncStorage ā
ā - LocalStorage ā ā - SQLite ā
ā - Fetch API ā ā - Expo Modules ā
āāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāā
The SDK provides optimized entry points for each platform:
Package Exports (package.json):
{
"exports": {
".": {
"react-native": "./dist/index.native.js",
"browser": "./dist/index.esm.js",
"node": "./dist/index.cjs.js",
"import": "./dist/index.esm.js",
"require": "./dist/index.cjs.js",
"types": "./dist/index.d.ts"
},
"./react": {
"import": "./dist/react.esm.js",
"require": "./dist/react.cjs.js",
"types": "./dist/react.d.ts"
}
}
}Platform Resolution:
@a-cube-io/ereceipts-js-sdk/react)The SDK provides comprehensive receipt lifecycle management:
import { EReceiptsSDK } from '@a-cube-io/ereceipts-js-sdk'
// Initialize SDK
const sdk = new EReceiptsSDK({
apiUrl: 'https://api.acubeapi.com',
authToken: 'user-jwt-token',
enableCache: true,
cacheTTL: 3600000 // 1 hour
})
// Fetch receipts with automatic caching
const receipts = await sdk.getReceipts({
startDate: '2025-01-01',
endDate: '2025-12-31',
status: 'validated'
})
// Get single receipt (from cache if available)
const receipt = await sdk
import { useReceipts, useReceipt } from '@a-cube-io/ereceipts-js-sdk/react'
function ReceiptsList() {
const { receipts, loading, error, refresh } = useReceipts({
startDate: '2025-01-01',
endDate: '2025-12-31'
})
if (loading) return <LoadingSpinner />
if (error) return <ErrorMessage error={error} />
return (
<div>
{receipts.map(receipt => (
All API responses and data structures validated at runtime:
import { z } from 'zod'
// Receipt schema
const ReceiptSchema = z.object({
id: z.string().uuid(),
merchantName: z.string().min(1),
amount: z.number().positive(),
currency: z.enum(['EUR', 'USD', 'GBP']),
date: z.string().datetime(),
status: z.enum(['pending', 'validated', 'rejected'
Multi-layer caching strategy optimized for each platform:
class BrowserCacheManager {
private db: IDBDatabase
async initialize() {
this.db = await openDB('ereceipts-cache', 1, {
upgrade(db) {
// Receipts store
const receiptsStore = db.createObjectStore('receipts', {
keyPath: 'id'
})
receiptsStore.createIndex('date', 'date')
receiptsStore.createIndex('status', 'status')
receiptsStore.createIndex('merchantName', 'merchantName')
class NativeCacheManager {
private readonly CACHE_PREFIX = '@ereceipts:cache:'
async cacheReceipts(receipts: Receipt[]) {
const cacheEntries = receipts.map(receipt => [
`${this.CACHE_PREFIX}${receipt.id}`,
JSON.stringify(receipt)
])
await AsyncStorage.multiSet(cacheEntries)
await AsyncStorage.setItem(
`${this.CACHE_PREFIX}lastSync`,
Date
Seamless integration with @a-cube-io/expo-mutual-tls for secure API calls:
import ExpoMutualTls from '@a-cube-io/expo-mutual-tls'
import { EReceiptsSDK } from '@a-cube-io/ereceipts-js-sdk'
// Configure mTLS
await ExpoMutualTls.configureP12('ereceipts-app', true)
await ExpoMutualTls.storeP12(certificateData, password)
// SDK automatically uses mTLS for API calls
const sdk = new EReceiptsSDK({
apiUrl: 'https://api.acubeapi.com',
useMTLS: true, // Enable mTLS authentication
authToken: 'user-jwt-token'
})
// All API calls use client certificate authentication
const receipts = await sdk.getReceiptsSource Files (TypeScript)
ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Rollup Build System ā
ā - TypeScript Compilation ā
ā - Code Splitting ā
ā - Tree Shaking ā
ā - Type Generation ā
āāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāā
ā
āāāāāāāāā“āāāāāāāāā
ā¼ ā¼
āāāāāāāāāāā āāāāāāāāāāāā
ā ESM ā ā CJS ā
ā Browser ā ā Node.js ā
ā RN ā ā ā
āāāāāā¬āāāāā āāāāāā¬āāāāāā
ā ā
āāāāāāāā¬āāāāāāāā
ā¼
NPM Package (.tgz)
rollup.config.js:
import typescript from '@rollup/plugin-typescript'
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import replace from '@rollup/plugin-replace'
import dts from 'rollup-plugin-dts'
export default [
// Main bundle (Browser/Node.js)
{
input: 'src/index.ts',
output: [
{
file: 'dist/index.esm.js',
format: 'esm',
sourcemap: true
},
{
file: 'dist/index.cjs.js',
format: 'cjs',
sourcemap: true
package.json scripts:
{
"scripts": {
"build": "rollup -c",
"build:dev": "npm run build && npm pack",
"dev": "rollup -c -w",
"test": "jest --passWithNoTests --detectOpenHandles",
"test:watch": "npm run test -- --watch",
"lint": "eslint src --ext .ts,.tsx",
"typecheck": "npx tsc --noEmit",
"prepublishOnly": "npm run build"
}
}tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"declaration": true,
"declarationMap": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"jsx": "react"
},
| Operation | Browser | React Native | Node.js | Notes |
|---|---|---|---|---|
| SDK Initialization | 50ms | 80ms | 30ms | One-time setup |
| Cache Read (100 receipts) | 20ms | 40ms | 15ms | IndexedDB/AsyncStorage |
| Cache Write (100 receipts) | 100ms | 180ms | 50ms | Batch operations |
| API Fetch (100 receipts) | 800ms | 900ms |
# 1. Install dependencies
npm install
# 2. Start watch mode for development
npm run dev
# 3. Run tests
npm test
# 4. Type checking
npm run typecheck
# 5. Lint code
npm run lint
# 6. Build for production
npm run build# 1. Build SDK and create local package
cd acube-ereceipt
npm run build:dev # Creates .tgz file
# 2. Install in Pempel Dashboard
cd ../pempel-dashboard
npm install ../acube-ereceipt/a-cube-io-ereceipts-js-sdk-0.1.0.tgz
# 3. Start Pempel Dashboard
npm startUnit Tests (Jest):
import { EReceiptsSDK } from '../src'
describe('EReceiptsSDK', () => {
let sdk: EReceiptsSDK
beforeEach(() => {
sdk = new EReceiptsSDK({
apiUrl: 'https://test.api.com',
authToken: 'test-token'
})
})
test('should initialize correctly', () => {
expect(sdk).toBeDefined()
expect(sdk.apiUrl).toBe('https://test.api.com')
})
test('should validate receipt schema', ()
import React, { useEffect } from 'react'
import { View, FlatList, Text, Button } from 'react-native'
import { useReceipts } from '@a-cube-io/ereceipts-js-sdk/react'
import ExpoMutualTls from '@a-cube-io/expo-mutual-tls'
export default function ReceiptsScreen() {
const {
receipts,
loading,
error,
refresh,
downloadPDF
} = useReceipts({
startDate: '2025-01-01',
endDate: '2025-12-31'
})
useEffect(() =>
ā What Worked Well:
š Key Takeaways:
The SDK welcomes contributions in:
@a-cube-io/ereceipts-js-sdk demonstrates production-ready multi-platform SDK development with a focus on type safety, performance, and developer experience. The project successfully balances:
The SDK serves as an excellent reference for:
Repository: Internal A-Cube repository Package: @a-cube-io/ereceipts-js-sdk License: MIT
| 600ms |
| Network dependent |
| Receipt Validation (Zod) | 5ms | 7ms | 3ms | Per receipt |
| PDF Download | 1200ms | 1500ms | 800ms | Network + processing |