import type { Applog, Attribute, Timestamp } from '../applog/datom-types.ts'; import type { Thread } from '../thread/basic.ts'; import type { WriteableThread } from '../thread/writeable.ts'; /** * An EpochSnapshot maps every {@link Attribute} present in a time window to the * array of {@link Applog}s (from any entity) that carry that attribute. * * This is **not** a flat array — logs are grouped by attribute first so that * consumers can answer questions like "which entities had their `movie/title` * updated in this window?" without re-filtering. * * @example * ```typescript * const snap = createEpochSnapshot(thread, { * start: '2024-01-01T00:00:00.000Z', * end: '2024-06-01T00:00:00.000Z', * }) * for (const [attr, logs] of snap) { * console.log(`${attr}: ${logs.length} logs`) * } * ``` */ export type EpochSnapshot = ReadonlyMap; /** * Options for {@link createEpochSnapshot}. */ export interface EpochSnapshotOptions { /** * Start of the time window (inclusive). ISO 8601 string matching the * {@link Timestamp} format used on every {@link Applog}. */ readonly start: Timestamp; /** * End of the time window (exclusive). ISO 8601 string. * Logs whose `ts` is **equal to** `end` are excluded. */ readonly end: Timestamp; } /** * Creates an {@link EpochSnapshot} — a point-in-time grouping of all app logs * within `[start, end)` grouped by their attribute name. * * The function is a **one-off (snapshot) computation**: it reads the current * state of the thread and returns a frozen map. If you need reactivity, wrap * the result in a reactive derivation or subscribe to thread changes and * re-compute. * * @param thread - The thread to snapshot. * @param options - Time range bounds. * @returns A `ReadonlyMap` keyed by attribute name. Each value is the * (chronologically sorted) array of applogs whose `at` matches that * key and whose `ts` falls inside `[start, end)`. * * @throws {Error} If `start` is lexically `>=` `end` (empty range). * * @example * ```typescript * const snap = createEpochSnapshot(thread, { * start: '2024-01-01T00:00:00.000Z', * end: '2025-01-01T00:00:00.000Z', * }) * // Iterate attribute groups: * for (const [attr, logs] of snap) { * console.log(attr, logs.length) * } * ``` */ export declare function createEpochSnapshot(thread: Thread, options: EpochSnapshotOptions): EpochSnapshot; /** * A flexible time specification used by {@link purgeHistory}. * * - `-1` (number) — the earliest log's timestamp in the thread ("beginning") * - `0` (number) — current time ("now") * - Positive number — treated as a Unix millisecond timestamp * - `'-1d'`, `'-2h'`, `'-30m'`, `'-5s'` — relative offset **before** now * - `'+1d'`, `'2h'` — relative offset **after** now (no sign = forward) * - ISO 8601 string — absolute timestamp, used as-is * - `'now'` — current time */ export type TimeSpec = number | string; /** * Resolve a {@link TimeSpec} to an absolute ISO {@link Timestamp}. * * @param spec - The time specification to resolve. * @param thread - The thread (used to find earliest log when spec is `-1`). * @param now - The reference "now" for relative specs. * @returns An ISO 8601 timestamp string. */ export declare function resolveTimeSpec(spec: TimeSpec, thread: Thread, now: Date): Timestamp; /** * A JSON-serializable representation of an {@link EpochSnapshot}, safe for * writing to disk, sending over the wire, or storing in IPFS. */ export interface SerializedEpochSnapshot { /** Format marker for versioning */ readonly format: 'wovin-epoch-snapshot-v1'; /** The attribute whose history was captured / purged */ readonly attribute: string; /** The time range this snapshot covers */ readonly timeRange: { readonly start: Timestamp; readonly end: Timestamp; }; /** When this snapshot was created */ readonly createdAt: Timestamp; /** Total number of applogs across all groups */ readonly logCount: number; /** * The grouped applogs. Each key is an attribute name; the value is the * array of applogs that carried that attribute within the time window. */ readonly groups: Record; } /** * Converts an {@link EpochSnapshot} into a {@link SerializedEpochSnapshot} * that can be persisted as JSON. * * @param snapshot - The live snapshot to serialize. * @param metadata - Identifying metadata to attach. * @returns A plain, JSON-safe object. */ export declare function serializeEpochSnapshot(snapshot: EpochSnapshot, metadata: { /** The attribute this purge targets */ readonly attribute: string; /** The time range of the snapshot */ readonly timeRange: { readonly start: Timestamp; readonly end: Timestamp; }; }): SerializedEpochSnapshot; /** * Options for {@link purgeHistory}. */ export interface PurgeHistoryOptions { /** * Callback invoked with the serialized snapshot **before** any logs are * purged. Use this to persist the snapshot to a file, database, IPFS, or * any other storage you choose. * * If omitted, the snapshot is created and returned in the result but not * automatically persisted anywhere. */ persistSnapshot?: (serialized: SerializedEpochSnapshot) => Promise | void; /** * Override "now" for deterministic tests. Defaults to `new Date()`. */ now?: Date; } /** * The result of a successful {@link purgeHistory} call. */ export interface PurgeHistoryResult { /** * The {@link EpochSnapshot} that was taken **before** the purge. * Contains all logs (across all attributes) within the time window, even * though only one attribute was purged. */ readonly snapshot: EpochSnapshot; /** Number of applogs that were removed from the thread. */ readonly purgedCount: number; /** Number of applogs kept as LWW winners for the purged attribute. */ readonly keptCount: number; /** The resolved time range that was processed. */ readonly timeRange: { readonly start: Timestamp; readonly end: Timestamp; }; } /** * For a given **attribute** and **time range**: * * 1. Creates an {@link EpochSnapshot} capturing all app logs within * `[start, end)` across **all** attributes. * 2. Calls `options.persistSnapshot` with a serialized copy of the snapshot * (so you can store the pre-purge state before any data is removed). * 3. For the target attribute, groups the captured logs by entity and keeps * only the **latest** (last-write-wins) applog per `(en, at)` pair. * All older logs for that pair are purged from the thread. * * Logs for **other** attributes are never touched. * * @param thread - A writable thread to purge from. * @param attribute - Only logs carrying this attribute are candidates for * removal. Logs with other attributes are left untouched. * @param start - Start of the time window (see {@link TimeSpec}). * @param end - End of the time window, exclusive (see {@link TimeSpec}). * @param options - Optional persistence callback and time override. * @returns A {@link PurgeHistoryResult} with the snapshot and counts. * * @throws {RangeError} If the resolved `start` is not before `end`. * * @example * ```typescript * // Purge all but the latest block/content per entity from the beginning * // up to yesterday, saving a snapshot first. * const result = await purgeHistory(thread, 'block/content', -1, '-1d', { * persistSnapshot: async (snap) => { * await writeFile('purge-archive.json', JSON.stringify(snap, null, 2)) * }, * }) * console.log(`Purged ${result.purgedCount}, kept ${result.keptCount}`) * ``` */ export declare function purgeHistory(thread: WriteableThread, attribute: Attribute, start: TimeSpec, end: TimeSpec, options?: PurgeHistoryOptions): Promise; //# sourceMappingURL=epoch-snapshot.d.ts.map