import { Logger } from 'pino'; import { Dispatcher } from 'undici-types'; import { Fetch, FlagsmithTraitValue, FlagsmithValue } from './types.js'; /** The only `$`-prefixed event name an SDK is allowed to send. **/ export declare const FLAG_EXPOSURE_EVENT = "$flag_exposure"; /** URL of Flagsmith's public events API. **/ export declare const DEFAULT_EVENTS_API_URL = "https://events.api.flagsmith.com/"; /** Options for an {@link EventProcessor}. **/ export interface EventProcessorOptions { /** Client-side or server-side key of the environment that events will be recorded for. **/ environmentKey: string; /** {@link fetch} implementation to use for API requests. **/ fetch: Fetch; /** Custom {@link Dispatcher} to use when making HTTP requests. **/ agent?: Dispatcher; /** Custom headers to send with every request. The SDK's own headers take precedence. **/ customHeaders?: { [key: string]: string; }; /** URL of the Flagsmith events API. Defaults to {@link DEFAULT_EVENTS_API_URL}. **/ eventsApiUrl?: string; /** Number of events the buffer holds before it drops its oldest event. Defaults to {@link DEFAULT_MAX_BUFFER}. **/ maxBuffer?: number; /** Duration in milliseconds between automatic flushes. 0 disables the timer. Defaults to {@link DEFAULT_FLUSH_INTERVAL_MS}. **/ flushInterval?: number; /** Duration in milliseconds to wait for API requests to complete before timing out. Defaults to {@link DEFAULT_REQUEST_TIMEOUT_MS}. **/ requestTimeoutMs?: number; /** Upper bound in milliseconds of the wait before the first retry of a batch, doubled for each retry after it. Defaults to {@link DEFAULT_RETRY_BACKOFF_MS}. **/ retryBackoffMs?: number; /** Logger for dropped batches and other failures. Defaults to a new pino logger. **/ logger?: Logger; } /** * A single event as sent to the Flagsmith events API. */ export interface FlagsmithEvent { /** The event name, e.g. `purchase` or {@link FLAG_EXPOSURE_EVENT}. **/ event: string; /** The feature this event relates to. Required for {@link FLAG_EXPOSURE_EVENT}. **/ feature_name: string | null; /** The identity this event relates to, used to reconcile exposures with conversions. **/ identifier: string | null; /** The event's value, always stringified by the SDK. **/ value: string | null; /** A flat map of resolved trait values. **/ traits: Record | null; /** Caller metadata, merged with the SDK version. **/ metadata: Record; /** Epoch milliseconds at which this event was buffered. **/ timestamp: number; } /** * Buffers events and posts them to the Flagsmith events API. * * Events are flushed every {@link EventProcessorOptions.flushInterval} milliseconds, or by calling * {@link flush}. Flushes run one after the other, so a single batch is in flight at a time, and a * timer tick is skipped while a flush is running or queued. An event tracked while * {@link EventProcessorOptions.maxBuffer} events are buffered flushes them, unless a batch is * already in flight or kept from a failed flush: the new event then drops the oldest one instead. * * Exposure events are deduplicated within a flush window. A batch that fails with a network error, * a timeout or a 408, 429, 500, 502, 503 or 504 response is retried after a backoff with full * jitter, up to {@link MAX_ATTEMPTS} attempts in a flush. If its last attempt finds the events API * unavailable (anything but a 500), the batch is kept and sent with the next flush, ahead of the * events buffered since. Otherwise a failing batch is dropped. A 401 or 403 response means the * environment key is refused: the processor then drops every event and stops tracking. * * {@link stop} is terminal: events tracked or flushes requested after it are ignored. * * Recording events must never fail the calling application, so all errors are logged and * swallowed. */ export declare class EventProcessor { private eventsUrl; private environmentKey; private customFetch; private agent?; private customHeaders; private maxBuffer; private flushInterval; private requestTimeoutMs; private retryBackoffMs; private logger; private buffer; /** Deduplication keys of the exposures in {@link buffer}, kept in sync with it. **/ private seenExposures; /** The last flush requested, which every new flush runs after. Never rejects. **/ private flushing; /** Number of flushes running or queued. **/ private pendingFlushes; /** Set while the buffer starts with a batch kept from a failed flush. **/ private hasKeptBatch; /** Set once {@link stop} has been called. **/ private closed; private interval?; /** Set once the events API refuses the environment key. **/ private unauthorised; /** Aborts the request and backoff in flight when {@link stop} times out. **/ private abortController; constructor(opts: EventProcessorOptions); /** * Buffer a custom event. */ trackEvent(args: { event: string; identifier: string | null; value: FlagsmithValue; traits: Record | null; metadata: Record | null; }): void; /** * Buffer a {@link FLAG_EXPOSURE_EVENT} for a feature. * * Exposures that are identical to one already buffered in this flush window are discarded. */ trackExposureEvent(args: { featureName: string; identifier: string; value: FlagsmithValue; traits: Record | null; metadata: Record | null; }): void; /** * Post all buffered events to the Flagsmith events API. * * Runs after the flushes requested before it, so it resolves once every event tracked before * the call has been sent, dropped, or kept for the next flush because the events API is * unavailable. Never rejects. Does nothing once the processor is stopped. */ flush(): Promise; /** * Queue a flush after the flushes already requested. With none, it takes the buffer at once. */ private queueFlush; /** * Start flushing events every {@link EventProcessorOptions.flushInterval} milliseconds. * * The timer is unref'd, so it never keeps the process alive on its own. */ start(): void; /** * Stop the flush timer and post any remaining events. The processor ignores events tracked and * flushes requested afterwards. * * @param timeoutMs? how long to wait for the events to be sent. Once it has passed, the request * in flight is aborted, its events are lost, and this resolves. Waits for the flush to complete * if not set. */ stop(timeoutMs?: number): Promise; private bufferEvent; /** * Post the buffered events as one batch, and keep them for the next flush if the events API is * unavailable. */ private sendBuffer; /** * Put a kept batch back ahead of the events tracked since, within the buffer's capacity. * * An exposure tracked during the flush may duplicate one in the batch: the batch's copy is kept. */ private restoreKeptBatch; /** Stop deduplicating against exposures that have left the buffer without being sent. **/ private forgetExposures; /** * Post a batch, retrying it after a network error, a timeout or a {@link RETRYABLE_STATUSES} status. */ private postEvents; }