Package Exports
- @codeimplants/app-core
- @codeimplants/app-core/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@codeimplants/app-core) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@codeimplants/app-core
Platform-agnostic App Foundation / Core SDK for building robust, production-ready applications across Web (React), React Native, Ionic, and Capacitor. Single shared packageβimported by every app. No app overrides core behavior.
π Table of Contents
- Overview
- App Foundation Checklist
- Features
- Installation
- Copy-Paste Setup
- Quick Start
- Core Concepts
- API Reference
- Platform Integration
- Integration with Related Packages
- Global Error Boundary Integration
- Best Practices
- Full Application Integration
- Examples
- Contributing
- License
π― Overview
@codeimplants/app-core is the platform-agnostic App Foundation / Core SDK that provides shared business logic and infrastructure independent of UI and platform. It acts as the single shared foundation for all applicationsβevery app imports it, and core behavior is not overridden by apps.
What it Does
- Global Error Boundary - Unified error handling, retry & circuit breaker, central support
- Environment and configuration management - Centralized config with feature flags
- API layer abstraction - HTTP client, interceptors, error normalization
- Authentication logic - Login, logout, token refresh, session handling
- Storage abstraction - Unified interface for web and native storage
- App lifecycle hooks - init, pause, resume, destroy
- Logging system - Dev and production support with configurable levels
- Integration layer - Offline/network status monitoring
- Shared constants, types, and utilities - Type-safe interfaces
What it Doesn't Do
- β No UI components or styling (use
@codeimplants/ui-kitfor screens) - β No platform-specific code (no direct localStorage, AsyncStorage, DOM usage)
- β No framework-specific dependencies
β App Foundation Checklist
| Requirement | API / Feature |
|---|---|
| Global Error Boundary | handleError(error, context), reportCrash(context) + Error Boundary integration |
| Unified fallback UI | showFallback(type) returns fallback config; emit fallback_requested |
| Retry & circuit breaker | executeWithRetry(), RetryManager, CircuitBreaker |
| Support | Use @codeimplants/support with ui-kit for WhatsApp/Email/Phone buttons |
| App lifecycle hooks | onInit(), onPause(), onResume(), destroy() |
| Config & feature flags | getConfig(), updateConfig(), getFeatureFlag(key) |
Required APIs (Must Provide)
appCore.handleError(error, context) // Error classification + decision
appCore.showFallback(type) // Unified fallback config
appCore.reportCrash(context) // Crash reporting
// Support: use @codeimplants/support + ui-kit for WhatsApp/Email/Phone buttons⨠Features
- π Authentication Manager - Complete token management, auto-refresh, session handling
- πΎ Storage Abstraction - Unified interface for Web, React Native, and Ionic storage
- π Robust API Client - Http client with interceptors, error normalization, and types
- π Intelligent Retry Logic - Exponential backoff, circuit breakers, configurable strategies
- π‘οΈ Robust Error Handling - Error classification, automatic recovery, support escalation
- π App State Management - Health monitoring, connectivity tracking, degraded state handling
- π― Support Integration - Contextual support, frustration detection, multi-channel
- π§ Recovery Strategies - Clear cache, reset state, reload app, safe mode
- π Comprehensive Logging - Configurable levels, namespace support, production-ready
- πͺ Event System - Type-safe event emitter for cross-module communication
- β Full TypeScript Support - Complete type definitions and inference
- π§ͺ Testable - Dependency injection, mockable interfaces
- π¦ Zero Dependencies - No runtime dependencies, minimal bundle size
π¦ Installation
npm install @codeimplants/app-coreor
yarn add @codeimplants/app-coreπ Copy-Paste Setup
Copy these blocks into your app to enable core features.
1. AppCore init (src/init.ts or appCore.ts)
import {
AppCore,
MemoryStorage,
Logger,
} from '@codeimplants/app-core'
const appCore = new AppCore({
errorConfig: {
maxRetries: 3,
supportThreshold: 2,
recoveryThreshold: 5,
},
featureFlags: {
// your flags
},
})
// Optional: global uncaught error handler (call early in bootstrap)
if (typeof window !== 'undefined') {
window.onerror = (message, source, lineno, colno, error) => {
appCore.reportCrash({
message: String(message),
stack: error?.stack,
metadata: { source, lineno, colno },
})
}
}
export { appCore }2. React β root wrap (App.tsx)
import React, { Component, ErrorInfo, ReactNode } from 'react'
import { appCore } from './init'
interface Props { children: ReactNode }
class AppErrorBoundary extends Component<Props, { hasError: boolean }> {
state = { hasError: false }
static getDerivedStateFromError() {
return { hasError: true }
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
appCore.reportCrash({
message: error.message,
stack: error.stack,
component: errorInfo.componentStack,
})
}
render() {
if (this.state.hasError) {
const fallback = appCore.showFallback('generic_error')
return (
<div>
<h1>{fallback.title}</h1>
<p>{fallback.message}</p>
<button onClick={() => { appCore.resetErrorState(); this.setState({ hasError: false }) }}>
Try Again
</button>
<button>Contact Support</button> {/* Wire to @codeimplants/support */}
</div>
)
}
return this.props.children
}
}
function App() {
return (
<AppErrorBoundary>
{/* Your app */}
</AppErrorBoundary>
)
}3. React Native β root wrap + lifecycle
import React, { Component, ErrorInfo, ReactNode } from 'react'
import { View, Text, Button, AppState, AppStateStatus } from 'react-native'
import { appCore } from './init'
// Error boundary
interface Props { children: ReactNode }
class AppErrorBoundary extends Component<Props, { hasError: boolean }> {
state = { hasError: false }
static getDerivedStateFromError() {
return { hasError: true }
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
appCore.reportCrash({
message: error.message,
stack: error.stack,
component: errorInfo.componentStack,
})
}
render() {
if (this.state.hasError) {
const fallback = appCore.showFallback('generic_error')
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 }}>
<Text>{fallback.title}</Text>
<Text>{fallback.message}</Text>
<Button title="Try Again" onPress={() => { appCore.resetErrorState(); this.setState({ hasError: false }) }} />
<Button title="Contact Support" /> {/* Wire to @codeimplants/support */}
</View>
)
}
return this.props.children
}
}
// Lifecycle sync (use in root component)
export function useAppLifecycle() {
React.useEffect(() => {
const sub = AppState.addEventListener('change', (state: AppStateStatus) => {
if (state === 'active') appCore.onResume()
else if (state === 'background') appCore.onPause()
})
return () => sub.remove()
}, [])
}
// Usage in App.tsx
export default function App() {
useAppLifecycle()
return (
<AppErrorBoundary>
{/* Your app */}
</AppErrorBoundary>
)
}4. Error handling in async code
import { appCore } from './init'
async function fetchData() {
try {
const data = await appCore.executeWithRetry(() => fetch('/api/data').then(r => r.json()), {
maxAttempts: 3,
onRetry: (attempt) => console.log(`Retry ${attempt}`),
})
return data
} catch (error) {
const decision = appCore.handleError(error as Error, { action: 'fetch_data', component: 'DataScreen' })
if (decision.action === 'show_support') { /* Show ui-kit screen with support buttons */ }
else if (decision.screenData) appCore.showFallback(decision.screen ?? 'generic_error', decision.screenData)
throw error
}
}5. Connectivity sync (with @codeimplants/app-network)
import { useEffect } from 'react'
import { OfflineProvider, OfflineBanner, useOffline } from '@codeimplants/app-network'
import { appCore } from './init'
function ConnectivitySync() {
const { isOnline } = useOffline()
useEffect(() => { appCore.updateConnectivity(isOnline) }, [isOnline])
return null
}
export function App() {
return (
<OfflineProvider>
<ConnectivitySync />
<OfflineBanner />
{/* Your app */}
</OfflineProvider>
)
}6. Version check before render (with @codeimplants/version-control)
import { VersionSDK } from '@codeimplants/version-control'
import { appCore } from './init'
export async function bootstrap() {
const decision = await VersionSDK.check('https://api.yourapp.com', 'your-api-key')
if (['FORCE_UPDATE', 'KILL_SWITCH', 'MAINTENANCE'].includes(decision.action)) {
appCore.showFallback('maintenance', { message: decision.message })
return false
}
appCore.onInit()
return true
}π Quick Start
Basic Setup
import {
AppCore,
AuthManager,
ApiClient,
MemoryStorage,
Logger,
AppCoreEventEmitter,
} from '@codeimplants/app-core'
// 1. Initialize dependencies
const logger = new Logger('App')
const eventEmitter = new AppCoreEventEmitter()
const storage = new MemoryStorage() // Use platform-specific adapter in production
// 2. Initialize AppCore
const appCore = new AppCore({
errorConfig: {
maxRetries: 3,
},
// ... other config
})
// 3. Initialize AuthManager
const authManager = new AuthManager(
storage,
eventEmitter,
{
tokenKey: 'app_token',
autoRefresh: true,
},
logger
)
// 4. Initialize ApiClient
const apiClient = new ApiClient(
{
baseURL: 'https://api.yourapp.com',
timeout: 30000,
},
logger
)
export { appCore, authManager, apiClient }Making Authenticated Requests
import { AuthInterceptor } from '@codeimplants/app-core'
import { apiClient, authManager } from './init'
// Add auth interceptor to automatically inject token
apiClient.addInterceptor(
new AuthInterceptor(async () => {
return await authManager.getToken()
})
)
async function fetchUserProfile() {
try {
// Typed response
const response = await apiClient.get<UserProfile>('/api/me')
return response.data
} catch (error) {
// Error is automatically normalized
throw error
}
}Error Handling
import { appCore } from './init'
async function safeFetch() {
try {
// ... operation
} catch (error) {
// Get intelligent decision on how to handle the error
const decision = appCore.handleError(error as Error, {
action: 'fetch_data',
component: 'UserProfile',
})
switch (decision.action) {
case 'retry':
// ...
break
// ... handle other actions
}
}
}Retry with Automatic Backoff
import appCore from './appCore'
async function fetchWithRetry() {
try {
const data = await appCore.executeWithRetry(
async () => {
const response = await fetch('/api/data')
if (!response.ok) throw new Error('API Error')
return response.json()
},
{
maxAttempts: 3,
exponentialBackoff: true,
timeout: 5000,
onRetry: (attempt, delay) => {
console.log(`Retry attempt ${attempt}, waiting ${delay}ms`)
},
}
)
return data
} catch (error) {
console.error('All retries exhausted', error)
throw error
}
}App State Monitoring
import appCore from './appCore'
// Get current app state
const state = appCore.getAppState()
console.log('Current state:', state.state) // 'healthy' | 'degraded' | 'critical' | 'offline' | 'maintenance'
console.log('Can make API calls:', state.allowedActions.canMakeApiCalls)
console.log('Can use cache:', state.allowedActions.canUseCache)
// Listen to state changes
appCore.on('state_changed', (event) => {
console.log('State changed:', event.payload.previousState, '->', event.payload.newState)
// Update UI based on new state
if (event.payload.newState === 'offline') {
showOfflineBanner()
}
})
// Update connectivity manually
window.addEventListener('online', () => appCore.updateConnectivity(true))
window.addEventListener('offline', () => appCore.updateConnectivity(false))π§© Core Concepts
Managers
The package is organized into specialized managers:
ErrorManager - Classifies errors, tracks error history, determines recovery strategies
RetryManager - Handles retry logic with backoff strategies and circuit breakers
AppStateManager - Monitors app health, connectivity, and determines allowed actions
RecoveryManager - Executes recovery strategies when errors persist
Event System
All managers emit events through a centralized event emitter:
// Listen to all events
appCore.on('*', (event) => {
console.log('Event:', event.type, event.payload)
})
// Listen to specific events
appCore.on('error_occurred', (event) => {
// Send to analytics
analytics.track('error', event.payload)
})
appCore.on('retry_attempted', (event) => {
console.log(`Retry ${event.payload.attemptNumber}/${event.payload.maxAttempts}`)
})Error Classification
Errors are automatically classified into types:
network- Network connectivity issuestimeout- Request timeoutsserver- 5xx server errorsclient- 4xx client errorsauth- Authentication/authorization errorsnot_found- 404 errorsrate_limit- Rate limiting errorsvalidation- Input validation errorscritical- Critical system errorsunknown- Unclassified errors
Retry Strategies
Built-in retry strategies:
- ExponentialBackoff - Delay doubles with each retry (1s, 2s, 4s, 8s...)
- LinearBackoff - Fixed delay between retries
- CircuitBreaker - Prevents cascading failures by opening circuit after threshold
π API Reference
AppCore
Constructor
new AppCore(config: AppCoreConfig)Methods
| Method | Description |
|---|---|
handleError(error, context?) |
Handle error, return ErrorDecision (retry, show_error, show_support, recover) |
showFallback(type, overrides?) |
Return unified fallback config; emit fallback_requested |
reportCrash(context) |
Report crash; emit crash_reported; track in ErrorManager |
executeWithRetry(operation, options?) |
Execute with retry & circuit breaker |
getAppState() |
Current app state (healthy, degraded, critical, offline, maintenance) |
updateConnectivity(isOnline) |
Update network status |
resetErrorState() |
Reset consecutive error count |
getFeatureFlag(key) |
Get feature flag value |
onInit(metadata?) |
App lifecycle: init |
onPause(metadata?) |
App lifecycle: pause (background) |
onResume(metadata?) |
App lifecycle: resume (foreground) |
on(eventType, callback) |
Subscribe to events |
getConfig() / updateConfig() |
Config access |
destroy() |
Cleanup |
Fallback Types
showFallback(type) accepts: offline, api_error, maintenance, slow_connection, permission, rate_limit, generic_error, loading, empty_state, session_expired.
Event Types
error_occurred- When an error is handledfallback_requested- WhenshowFallback()is calledcrash_reported- WhenreportCrash()is calledretry_attempted,state_changed,recovery_startedapp_init,app_pause,app_resume,app_destroy- Lifecyclecircuit_breaker_opened,circuit_breaker_closed
π Platform Integration
React
// hooks/useAppCore.ts
import { useEffect, useState } from 'react';
import appCore from '../appCore';
export function useAppState() {
const [state, setState] = useState(appCore.getAppState());
useEffect(() => {
const unsubscribe = appCore.on('state_changed', () => {
setState(appCore.getAppState());
});
return unsubscribe;
}, []);
return state;
}
// Component usage
function App() {
const appState = useAppState();
if (appState.state === 'offline') {
return <OfflineBanner />;
}
return <YourApp />;
}React Native
import NetInfo from '@react-native-community/netinfo'
import appCore from './appCore'
// Monitor network connectivity
NetInfo.addEventListener((state) => {
appCore.updateConnectivity(state.isConnected ?? false)
})Ionic/Capacitor
import { Network } from '@capacitor/network'
import appCore from './appCore'
// Monitor network status
Network.addListener('networkStatusChange', (status) => {
appCore.updateConnectivity(status.connected)
})π Integration with Related Packages
App-core is the foundation; integrate with these packages for full-stack resilience:
@codeimplants/version-control
Version checks (soft/force updates, maintenance, kill switch). Call before rendering the app.
import { VersionSDK } from '@codeimplants/version-control'
import { appCore } from './init'
async function bootstrap() {
const decision = await VersionSDK.check('https://api.yourapp.com', 'your-api-key')
switch (decision.action) {
case 'FORCE_UPDATE':
case 'KILL_SWITCH':
appCore.showFallback('maintenance', { message: decision.message })
return
case 'MAINTENANCE':
appCore.showFallback('maintenance', { message: decision.message })
return
}
appCore.onInit()
// Render app
}@codeimplants/app-network
Connectivity monitoring + OfflineBanner. Feed status into app-core.
import { OfflineProvider, OfflineBanner, useOffline } from '@codeimplants/app-network'
import { useEffect } from 'react'
import { appCore } from './init'
// Sync connectivity to app-core (must be inside OfflineProvider)
function ConnectivitySync() {
const { isOnline } = useOffline()
useEffect(() => {
appCore.updateConnectivity(isOnline)
}, [isOnline])
return null
}
function App() {
return (
<OfflineProvider>
<ConnectivitySync />
<OfflineBanner />
<YourApp />
</OfflineProvider>
)
}React Native: Use @react-native-community/netinfo; app-network detects RN and uses it. Add the same ConnectivitySync component.
@codeimplants/ui-kit
Error screens (ApiErrorScreen, NetworkOfflineScreen, etc.) map to showFallback / handleError results.
import {
ApiErrorScreen,
NetworkOfflineScreen,
ErrorBoundaryScreen,
} from '@codeimplants/ui-kit'
import { appCore, type FallbackData } from '@codeimplants/app-core'
// Map fallback type to ui-kit screens
function FallbackRenderer({ fallback }: { fallback: FallbackData }) {
switch (fallback.type) {
case 'offline':
return <NetworkOfflineScreen onRetry={() => appCore.resetErrorState()} />
case 'api_error':
case 'generic_error':
return (
<ApiErrorScreen
onRetry={() => appCore.resetErrorState()}
support={{ whatsapp: { number: '...' }, email: { address: '...' } }}
/>
)
default:
return <ErrorBoundaryScreen message={fallback.message} />
}
}@codeimplants/support
Support logic (WhatsApp, Email, Phone). Use with ui-kit error screensβui-kit shows support buttons; on click, use useSupport().openWhatsApp() etc.
import { SupportProvider } from '@codeimplants/support'
// Wrap app; ui-kit screens use useSupport for button actions
<SupportProvider config={{ whatsapp: { number: '...' }, email: { address: '...' } }}>
<YourApp />
</SupportProvider>π‘οΈ Global Error Boundary Integration
App-core provides logic; your app provides the UI error boundary. Wire them together:
React
import React, { Component, ErrorInfo, ReactNode } from 'react'
import { appCore } from './init'
interface Props {
children: ReactNode
fallback?: ReactNode
}
export class AppErrorBoundary extends Component<Props, { hasError: boolean; error?: Error }> {
state = { hasError: false, error: undefined as Error | undefined }
static getDerivedStateFromError(error: Error) {
return { hasError: true, error }
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
appCore.reportCrash({
message: error.message,
stack: error.stack,
component: errorInfo.componentStack,
metadata: { errorInfo },
})
appCore.showFallback('generic_error', { message: error.message })
}
render() {
if (this.state.hasError) {
return this.props.fallback ?? <div>Something went wrong.</div>
}
return this.props.children
}
}React Native
import React, { Component, ErrorInfo, ReactNode } from 'react'
import { View, Text, Button } from 'react-native'
import { appCore } from './init'
// Optional: use @codeimplants/ui-kit ErrorBoundaryScreen
// import { ErrorBoundaryScreen } from '@codeimplants/ui-kit'
interface Props {
children: ReactNode
}
export class AppErrorBoundary extends Component<Props, { hasError: boolean; error?: Error }> {
state = { hasError: false, error: undefined as Error | undefined }
static getDerivedStateFromError(error: Error) {
return { hasError: true, error }
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
appCore.reportCrash({
message: error.message,
stack: error.stack,
component: errorInfo.componentStack,
})
appCore.showFallback('generic_error', { message: error.message })
}
handleRetry = () => {
appCore.resetErrorState()
this.setState({ hasError: false, error: undefined })
}
render() {
if (this.state.hasError) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 }}>
<Text>Something went wrong.</Text>
<Button title="Try Again" onPress={this.handleRetry} />
<Button title="Contact Support" /> {/* Wire to @codeimplants/support */}
</View>
)
}
return this.props.children
}
}Wire global uncaught errors
// index.tsx or App.tsx (early in bootstrap)
window.onerror = (message, source, lineno, colno, error) => {
appCore.reportCrash({
message: String(message),
stack: error?.stack,
metadata: { source, lineno, colno },
})
}
// React Native: use ErrorUtils
if (typeof ErrorUtils !== 'undefined') {
const originalHandler = ErrorUtils.getGlobalHandler()
ErrorUtils.setGlobalHandler((error, isFatal) => {
appCore.reportCrash({
message: error.message,
stack: error.stack,
metadata: { isFatal },
})
originalHandler?.(error, isFatal)
})
}π‘ Best Practices
1. Initialize Early
Initialize AppCore as early as possible in your application lifecycle:
// index.ts or App.tsx
import appCore from './appCore'
// Configure logger for development
if (process.env.NODE_ENV === 'development') {
Logger.configure({ minLevel: 'debug' })
}2. Centralize Error Handling
Use the core APIsβnever bypass app-core:
// errorHandler.ts
import { appCore } from './init'
export function globalErrorHandler(error: Error, context?: ErrorContext) {
const decision = appCore.handleError(error, context)
switch (decision.action) {
case 'retry':
return appCore.executeWithRetry(() => /* retry logic */)
case 'show_error':
return appCore.showFallback(decision.screen ?? 'generic_error', decision.screenData)
case 'show_support':
return appCore.showFallback(decision.screen ?? 'generic_error', {
...decision.screenData,
supportAvailable: true,
}) // ui-kit screen shows support buttons; use @codeimplants/support for actions
case 'recover':
return /* trigger recovery via RecoveryManager */
}
}3. Use Type Guards
Leverage TypeScript for type safety:
import { NetworkError, APIError } from '@codeimplants/app-core'
function handleError(error: Error) {
if (error instanceof NetworkError) {
// Handle network error
} else if (error instanceof APIError) {
// Handle API error
}
}4. Monitor Events
Set up analytics tracking:
appCore.on('*', (event) => {
// Send to analytics service
analytics.track(`app_core_${event.type}`, event.payload)
})5. Clean Up
Always clean up when unmounting:
useEffect(() => {
const unsubscribe = appCore.on('error_occurred', handleError)
return () => {
unsubscribe()
}
}, [])π Full Application Integration
Recommended bootstrap order:
- Initialize
AppCore(single instance) - Run
VersionSDK.check()β show maintenance/update fallback if needed - Wrap app with
OfflineProvider+ConnectivitySync(app-network) - Wrap app with
AppErrorBoundary(callsreportCrash,showFallback) - Set global
window.onerror/ErrorUtils.setGlobalHandler - Wrap with
SupportProvider(@codeimplants/support) if using support - Call
appCore.onInit()when app is ready - Use
appCore.onPause()/appCore.onResume()on app state changes (React Native: AppState)
React Native lifecycle example:
import { AppState, AppStateStatus } from 'react-native'
useEffect(() => {
const sub = AppState.addEventListener('change', (state: AppStateStatus) => {
if (state === 'active') appCore.onResume()
else if (state === 'background') appCore.onPause()
})
return () => sub.remove()
}, [])π Examples
See the examples directory for complete examples:
- React SPA integration
- React Native app integration
- Ionic/Capacitor integration
- API client wrapper
- Custom error handling
π License
MIT Β© Code Implants Software Technologies Pvt. Ltd.
π Related Packages
| Package | Purpose |
|---|---|
@codeimplants/version-control |
Version checks, force/soft updates, maintenance, kill switch |
@codeimplants/app-network |
Connectivity monitoring, OfflineBanner, resilient API client |
@codeimplants/ui-kit |
Error screens (ApiErrorScreen, NetworkOfflineScreen, etc.) |
@codeimplants/support |
Support logic (WhatsApp, Email, Phone); use with ui-kit error screens |