import type { AuditService } from '@pikku/core/services'; import type { AuditEvent, AuditEventBatch } from '@pikku/core/services'; import type { AuditFacets, AuditQuery, AuditQueryResult } from '@pikku/core/services'; import type { Kysely } from 'kysely'; /** * Durable {@link AuditService} that persists AuditEvents to an `audit` table * via Kysely — the companion sink to {@link createAuditedKysely}. * * The column mapping matches a platform audit-queue consumer, so a locally-run * project and a deployed stage write identical rows (the read side relies only * on `type`, `occurred_at`, `user_id`, and the `data` JSON that holds * `metadata`). The `audit` table is an optional per-project migration (not in * the generated schema), so rows are inserted untyped; all columns are TEXT on * every engine and ON CONFLICT DO NOTHING keeps writes idempotent on retries. */ export declare class KyselyAuditService implements AuditService { private db; private initialized; constructor(db: Kysely); /** * Creates the `audit` table if the database has none. * * Optional — a project that migrates the table itself can skip it, and the * declaration is written to match the documented shape either way. Calling it * on a database that already has the table is a no-op, so two instances * booting cold do not race each other into a half-applied schema. */ init(): Promise; audit(event: AuditEvent): Promise; write(batch: AuditEventBatch): Promise; /** * A page of the trail, newest first. * * Offset paging, matching the rest of the console. The trail is append-only * and ordered by `occurred_at DESC`, so events written *while* a reader is * paging shift the window and can repeat a row across pages. That is visible * but harmless for browsing; anything that must not miss a row should page by * a bounded `from`/`to` window instead of scrolling. * * Ties on `occurred_at` are broken by `audit_id` so the order is total — * without it a batch flushed in one call shares a timestamp and the engine is * free to order it differently per query, which drops or repeats rows at a * page boundary. */ query(query?: AuditQuery): Promise; facets(): Promise; /** * An empty array means "match nothing" and is applied as such. Treating it as * "no filter" would turn a reader's deselect-everything into a full-trail * read, which is the opposite of what they asked for. */ private applyFilters; }