import { M as MaybePromise, D as Duration } from "../packem_shared/types.d-CcjfiGpo.d-DuZME7ry.js"; import '@standard-schema/spec'; /** A single event buffered inside a digest window. */ interface DigestEvent { /** Stable id of this event within the window. */ id: string; /** The event payload. */ payload: PayloadT; /** Epoch ms the event was added. */ time: number; } /** An open digest window: the events collected so far for a key, and when it closes. */ interface DigestWindow { events: DigestEvent[]; key: string; /** Epoch ms at which the window is due to flush. */ wakeAt: number; } /** * Durability contract for `createDigester`. Implementations own the buffered * windows and the "what is due" query; the digester stays storage-agnostic. * * `read` and `remove` are separate (rather than a single destructive `drain`) so * the digester can flush a window's events *before* removing it — a failed flush * leaves the window in place to be retried (at-least-once). */ interface DigestStore { /** * Append an event to the window for `key`, opening it (with `wakeAt`) if absent. * The window's `wakeAt` is fixed when it opens — later events do not extend it. * @returns `true` if this call opened a new window. */ append: (key: string, event: DigestEvent, wakeAt: number) => Promise; /** Keys whose window `wakeAt` is at or before `now`, up to `limit`. */ due: (now: number, limit: number) => Promise; /** Return the window for `key` without removing it, or `undefined` if none. */ read: (key: string) => Promise | undefined>; /** Permanently remove the window for `key`. */ remove: (key: string) => Promise; } /** Options for `createDigester`. */ interface DigesterOptions { /** Group events into windows by this key (e.g. `subscriberId` or `subscriberId:postId`). */ key: (event: PayloadT) => string; /** * Called once per window when it closes, with every event collected. Delivery is * **at-least-once**: the window is removed only after `onFlush` resolves, so a * throwing `onFlush` is retried on the next sweep (and may run again if removal * later fails). Make it idempotent. */ onFlush: (events: DigestEvent[], key: string) => MaybePromise; /** The durable store; defaults to an in-memory store. */ store?: DigestStore; /** How long a window stays open from its first event (a {@link Duration} or a per-event function). */ window: ((event: PayloadT) => Duration) | Duration; } /** Aggregates many events into windowed batches, flushing each as one notification. */ interface Digester { /** Buffer an event; returns `true` if it opened a new window for its key. */ add: (event: PayloadT) => Promise; /** Flush every window whose wake-at has passed; returns the number flushed. */ sweep: (now?: number, limit?: number) => Promise; } /** * Create a {@link Digester} that batches events into time/cron windows keyed by * `options.key`, flushing each closed window once via `options.onFlush` — turning * a burst of N events into a single notification. * * Windows close on a poll: call {@link Digester.sweep} from a cron job, a * Cloudflare alarm, or any timer (alongside a workflow runtime's `sweep`). * @param options Key function, window duration, flush handler and optional store. * @returns A {@link Digester}. * @example * ```ts * const digester = createDigester<{ subscriberId: string; postId: string }>({ * key: (event) => `${event.subscriberId}:${event.postId}`, * window: { amount: 10, unit: "minutes" }, * onFlush: (events) => runtime.trigger(summaryWorkflow, { count: events.length, events }), * }); * * await digester.add({ subscriberId: "u1", postId: "p1" }); // opens a 10-minute window * // …later, on a timer: * await digester.sweep(); * ``` */ declare const createDigester: (options: DigesterOptions) => Digester; /** * In-process {@link DigestStore}. Ideal for tests and single-instance apps; swap * for the unstorage adapter for durability across restarts and instances. */ declare class MemoryDigestStore implements DigestStore { #private; append(key: string, event: DigestEvent, wakeAt: number): Promise; read(key: string): Promise | undefined>; remove(key: string): Promise; due(now: number, limit: number): Promise; } /** * Minimal structural view of an [unstorage](https://unstorage.unjs.io) instance, * declared locally so the package needs no hard `unstorage` dependency. */ interface UnstorageLike { getItem: (key: string) => Promise; getKeys: (base?: string) => Promise; removeItem: (key: string) => Promise; setItem: (key: string, value: unknown) => Promise; } /** * {@link DigestStore} backed by [unstorage](https://unstorage.unjs.io), for durable, * edge-friendly digest windows over any unstorage driver. * * Each window is a single self-contained document keyed by `digest:w:` plus the * digest key; there is no shared index, so concurrent `add`s for different keys cannot * lose-update each other. `due` scans the window documents under the prefix — fine for the * transient, bounded set of open windows. Individual reads/writes are still not * transactional, so concurrent writers on the *same* key (or a sweep racing an * `add` for that key) can drop an event or double-flush; for that level of * contention prefer a store with atomic guarantees, or sweep from one instance. */ declare class UnstorageDigestStore implements DigestStore { #private; constructor(storage: UnstorageLike); append(key: string, event: DigestEvent, wakeAt: number): Promise; read(key: string): Promise | undefined>; remove(key: string): Promise; due(now: number, limit: number): Promise; } export { type DigestEvent, type DigestStore, type DigestWindow, type Digester, type DigesterOptions, MemoryDigestStore, UnstorageDigestStore, createDigester };