feat: TypeScript telemetry client SDK v0.1.0

Standalone npm package (@mosaicstack/telemetry-client) for reporting
task-completion telemetry and querying predictions from the Mosaic
Stack Telemetry server.

- TelemetryClient with setInterval-based background flush
- EventQueue (bounded FIFO array)
- BatchSubmitter with native fetch, exponential backoff, Retry-After
- PredictionCache (Map + TTL)
- EventBuilder with auto-generated event_id/timestamp
- Zero runtime dependencies (Node 18+ native APIs)
- 43 tests, 86% branch coverage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 23:25:31 -06:00
commit 177720e523
26 changed files with 5643 additions and 0 deletions

62
src/config.ts Normal file
View File

@@ -0,0 +1,62 @@
export interface TelemetryConfig {
/** Base URL of the telemetry server (e.g., "https://tel.mosaicstack.dev") */
serverUrl: string;
/** API key for authentication (64-char hex string) */
apiKey: string;
/** Instance UUID for this client */
instanceId: string;
/** Whether telemetry collection is enabled. Default: true */
enabled?: boolean;
/** Interval between automatic batch submissions in ms. Default: 300_000 (5 min) */
submitIntervalMs?: number;
/** Maximum number of events held in queue. Default: 1000 */
maxQueueSize?: number;
/** Maximum events per batch submission. Default: 100 */
batchSize?: number;
/** HTTP request timeout in ms. Default: 10_000 */
requestTimeoutMs?: number;
/** TTL for cached predictions in ms. Default: 21_600_000 (6 hours) */
predictionCacheTtlMs?: number;
/** If true, log events instead of sending them. Default: false */
dryRun?: boolean;
/** Maximum number of retries on failure. Default: 3 */
maxRetries?: number;
/** Optional callback invoked on errors */
onError?: (error: Error) => void;
}
export interface ResolvedConfig {
serverUrl: string;
apiKey: string;
instanceId: string;
enabled: boolean;
submitIntervalMs: number;
maxQueueSize: number;
batchSize: number;
requestTimeoutMs: number;
predictionCacheTtlMs: number;
dryRun: boolean;
maxRetries: number;
onError: (error: Error) => void;
}
const DEFAULT_ON_ERROR = (_error: Error): void => {
// Silent by default
};
export function resolveConfig(config: TelemetryConfig): ResolvedConfig {
return {
serverUrl: config.serverUrl.replace(/\/+$/, ''),
apiKey: config.apiKey,
instanceId: config.instanceId,
enabled: config.enabled ?? true,
submitIntervalMs: config.submitIntervalMs ?? 300_000,
maxQueueSize: config.maxQueueSize ?? 1000,
batchSize: config.batchSize ?? 100,
requestTimeoutMs: config.requestTimeoutMs ?? 10_000,
predictionCacheTtlMs: config.predictionCacheTtlMs ?? 21_600_000,
dryRun: config.dryRun ?? false,
maxRetries: config.maxRetries ?? 3,
onError: config.onError ?? DEFAULT_ON_ERROR,
};
}