import type { TelemetryConfig, TelemetryDimensions, TelemetryEventDimensions, TelemetryEventName, TelemetryState } from "./types.js"; type TrackArgs = keyof TelemetryEventDimensions extends never ? [dimensions?: TelemetryEventDimensions] : [dimensions: TelemetryEventDimensions]; export declare class TelemetryClient { private queue; private readonly config; private readonly caps; private readonly stateFactory; private readonly version; private readonly random; private state; private flushInterval; private pending; private readonly retryTimers; constructor(config: TelemetryConfig, stateFactory: () => TelemetryState, version: string, random?: () => number); /** * Tracks first-party Paperclip telemetry events registered in the generated * backend event schema. */ track(eventName: K, ...args: TrackArgs): void; /** * Whether `track` would enqueue this first-party event name rather than drop * it as unregistered. Lets a caller with an expensive payload (e.g. one that * needs database reads) skip building dimensions for a proposed event the * client would discard anyway. */ isRegisteredEventName(eventName: string): boolean; /** * Tracks plugin telemetry bridge events whose names are built dynamically * from third-party plugin input. The backend accepts only explicitly * registered plugin events. */ trackDynamic(eventName: string, dimensions?: TelemetryDimensions): void; private enqueue; flush(): Promise; /** * Partitions a drained event list into wire-compliant chunks: first by * `maxEventsPerBatch` (count), then recursively byte-splits any chunk whose * serialized envelope still exceeds `maxBodyBytes` (halving). A single event * that alone exceeds `maxBodyBytes` is dropped-and-logged (fail loudly) rather * than sent over-limit. */ private chunkForSend; private splitByBytes; private buildEnvelope; /** * Deterministic, salt-free content-hash idempotency key. Hashes * `{installId, events}` (scopes the key per install, matching the * server's `contentSha256` scope so cross-install batches never collide on the * server ledger key) and truncates to 128 bits. Identical input always * yields the same id, so a retried batch replays idempotently (202) instead of * double-counting; different events/install yield a different id. */ private deriveBatchId; private serializedBytes; /** * Sends one batch (its current `attempt`). On a retryable failure the EXACT * same events + `batchId` are re-queued with capped, jittered backoff; on a * terminal failure or after `maxAttempts` the batch is dropped-and-logged. */ private attemptSend; private classifyOutcome; private isRetryableStatus; /** * Capped exponential backoff with symmetric jitter: * `min(maxDelayMs, baseDelayMs * 2^(attempt-1)) * (1 ± jitterRatio)`, using the * injected RNG. `attempt` is the failed attempt (1-based). */ private computeBackoffMs; /** * Pushes a batch onto the pending store (bounded), then schedules its retry * wake-up. On overflow the OLDEST batches (front) are evicted first — newest * prioritized — and each eviction is logged so no batch is lost silently. */ private enqueuePending; /** Cancels a pending batch's scheduled retry wake-up, if it has one. */ private cancelRetryTimer; private scheduleDrain; /** Re-sends every pending batch whose `nextAttemptAt` is due. */ private drainPending; /** * POSTs a serialized envelope, trying each endpoint in order. Returns the * definitive outcome: `ok` on a 2xx; the HTTP `status` on a definitive non-2xx * response (4xx incl. 429, which the shared API gateway fronts for every * endpoint, so it is authoritative — stop here); or `network` when every * endpoint threw. A transient upstream 5xx (502/503/504) does NOT stop the * loop: a sibling endpoint may be healthy, so we fall through to it and only * surface the last transient status if every endpoint returns one — matching * the pre-retry loop's endpoint-fallback behavior. */ private postEnvelope; /** Upstream 5xx that a healthy sibling endpoint may still be able to serve. */ private isTransientServerStatus; private warn; startPeriodicFlush(intervalMs?: number): void; stop(): void; hashPrivateRef(value: string): string; private getState; private resolveEndpoints; } export {}; //# sourceMappingURL=client.d.ts.map