@appss/sdk-core
v0.4.8
Published
Core module for APPSS analytics SDK
Downloads
324
Readme
@appss/sdk-core
Core module for APPSS analytics SDK. Provides the abstract client, configuration, batching, retry logic, and platform-agnostic interfaces.
This package is not used directly. Install @appss/sdk-browser or @appss/sdk-node instead.
What's inside
AbstractAppssClient
Base class that browser and node packages extend. Handles the full event lifecycle:
init(config)— validate config, create transport/queue/logger, start flush timertrack(distinctId, event, properties?)— enrich event with super properties, enqueue, auto-flush on thresholdsetUserProperty(distinctId, key, value)— send user property to serversetUserProperties(distinctId, properties)— send multiple user propertiessetSuperProperties(properties)— set properties attached to every event automaticallyresetSuperProperties()— clear all super propertiesflush()— force send all queued events (deduplicated)destroy()— flush + stop timers + unregister lifecycle handlers
Subclasses must implement:
protected abstract createTransport(config: ResolvedConfig): ITransport;
protected abstract createQueue(config: ResolvedConfig): IEventQueue;
protected abstract createLogger(config: ResolvedConfig): ILogger;
protected abstract registerLifecycleHandlers(): void;
protected abstract unregisterLifecycleHandlers(): void;Ports (interfaces)
ITransport
interface ITransport {
send(path: string, body: unknown, headers: Record<string, string>): Promise<TransportResponse>;
}IEventQueue
interface IEventQueue {
enqueue(event: AppssEvent): void;
drain(maxCount: number): AppssEvent[];
peek(maxCount: number): AppssEvent[];
size(): number;
isEmpty(): boolean;
clear(): void;
}All methods are synchronous. If your backing store is async, use a local buffer with background sync.
ILogger
interface ILogger {
debug(message: string, context?: Record<string, unknown>): void;
info(message: string, context?: Record<string, unknown>): void;
warn(message: string, context?: Record<string, unknown>): void;
error(message: string, context?: Record<string, unknown>): void;
}Configuration
interface AppssConfig {
apiKey: string; // required
endpoint?: string; // default: APPSS production endpoint
flushInterval?: number; // ms, default: 10000
batchSize?: number; // default: 50
maxQueueSize?: number; // default: 10000
requestTimeout?: number; // ms, default: 30000
debug?: boolean; // default: false
retry?: {
maxRetries?: number; // default: 5
baseBackoffMs?: number; // default: 1000
maxBackoffMs?: number; // default: 16000
};
logger?: ILogger; // custom logger
queue?: IEventQueue; // custom queue
onError?: (error: AppssError) => void;
}Types
DistinctId
type DistinctId = string | number;Accepted by track, setUserProperty, setUserProperties. Numbers are converted to strings internally via resolveDistinctId(). NaN, Infinity, and empty strings are silently rejected.
AppssEvent
interface AppssEvent {
event: string;
distinctId: string;
insertId: string;
timestamp: Date;
properties?: Record<string, unknown>;
}Internal event format used by IEventQueue. Generated by buildEvent(), converted to wire format by eventToPayload().
Error handling
All errors extend AppssError:
class AppssError extends Error {
readonly code: ErrorCode;
readonly severity: 'warn' | 'error';
readonly retryable: boolean;
}Error codes:
| Code | When |
|------|------|
| NOT_INITIALIZED | Method called before init() |
| INVALID_API_KEY | Empty or missing API key |
| NETWORK_ERROR | Transport failure or 5xx response |
| RATE_LIMITED | 429 response |
| API_KEY_REVOKED | 401 response — SDK stops sending |
| PROTOCOL_ERROR | 400 or unexpected status |
| QUEUE_OVERFLOW | Queue exceeded max size |
| MAX_RETRIES_EXCEEDED | All retry attempts failed |
Batching and retry
- Events are queued and sent in batches (
batchSize, default 50) - Flush triggers on timer (
flushInterval, default 10s) or when batch is full - Failed batches are retried with exponential backoff + jitter
- 413 responses trigger recursive batch splitting
- 401 response stops all future sends (API key revoked)
- 429 response respects
Retry-Afterheader (clamped tomaxBackoffMs)
EventEnricher
Manages super properties that are automatically merged into every tracked event:
class EventEnricher {
set(key: string, value: unknown): void;
setAll(properties: Record<string, unknown>): void;
remove(key: string): void;
reset(): void;
enrich(eventProperties?: EventProperties): EventProperties;
}Super properties override event properties with the same key. Used internally by AbstractAppssClient — platform packages call setSuperProperties() to set $lib and other metadata.
FlushPolicy
Manages the flush timer and flush deduplication:
- Starts an interval timer that triggers flush
flush()ensures only one flush runs at a time (promise deduplication)reset()restarts the timer after a successful flushstop()clears the timer and pending flush
Implementing a new platform
To add support for a new platform (e.g., React Native, Deno):
- Create a new package that depends on
@appss/sdk-core - Extend
AbstractAppssClient - Implement the five abstract methods
- Create a constants file with
SDK_PLATFORM - Call
this.setSuperProperties({ $lib: SDK_PLATFORM })ininit()
import { AbstractAppssClient } from '@appss/sdk-core';
class MyPlatformClient extends AbstractAppssClient {
override init(config) {
super.init(config);
this.setSuperProperties({ $lib: 'my-platform' });
}
protected createTransport(config) { /* ... */ }
protected createQueue(config) { /* ... */ }
protected createLogger(config) { /* ... */ }
protected registerLifecycleHandlers() { /* ... */ }
protected unregisterLifecycleHandlers() { /* ... */ }
}License
Apache-2.0
