← All @molecule/* packages · App templates

@molecule/api-audit

Core interface · audit · API (Node) · v1.0.1 · Apache-2.0

Audit trail core interface for molecule.dev — record, query, and export audit entries

npm install @molecule/api-audit

npm · Source on GitHub

How it works

@molecule/api-audit is the audit core interface on the API (Node) side: the API your app calls, with no vendor inside.

Choose the implementation by bonding one of its 2 providers: @molecule/api-audit-database, @molecule/api-audit-file.

import { setProvider, log, query } from '@molecule/api-audit'
import { provider } from '@molecule/api-audit-database'

// Wire the provider at startup
setProvider(provider)

// Record an audit entry
await log({ actor: 'user:1', action: 'create', resource: 'project', resourceId: 'proj-42' })

// Query audit records
const results = await query({ actor: 'user:1', page: 1, perPage: 20 })

Providers (2): @molecule/api-audit-database, @molecule/api-audit-file

Works with: @molecule/api-bond, @molecule/api-i18n

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Audit core interface for molecule.dev.

Provides the AuditProvider interface for recording and querying audit trail entries. Bond a concrete provider (e.g. @molecule/api-audit-database, @molecule/api-audit-file) at startup via setProvider().

Quick Start

import { setProvider, log, query } from '@molecule/api-audit'
import { provider } from '@molecule/api-audit-database'

// Wire the provider at startup
setProvider(provider)

// Record an audit entry
await log({ actor: 'user:1', action: 'create', resource: 'project', resourceId: 'proj-42' })

// Query audit records
const results = await query({ actor: 'user:1', page: 1, perPage: 20 })

Type

core

Installation

npm install @molecule/api-audit @molecule/api-bond @molecule/api-i18n

API

Interfaces

AuditEntry

An audit trail entry to be recorded.

interface AuditEntry {
  /** The entity performing the action (e.g. user ID, system identifier). */
  actor: string

  /** The action performed (e.g. `create`, `update`, `delete`, `login`). */
  action: string

  /** The type of resource acted upon (e.g. `project`, `user`, `setting`). */
  resource: string

  /** Optional identifier of the specific resource instance. */
  resourceId?: string

  /** Optional additional details about the action. */
  details?: Record<string, unknown>

  /** Optional IP address of the request origin. */
  ip?: string

  /** Optional user agent string of the request origin. */
  userAgent?: string
}

AuditProvider

Audit provider interface.

All audit providers must implement this interface to provide audit trail recording, querying, and export capabilities.

interface AuditProvider {
  /**
   * Records an audit trail entry.
   *
   * @param entry - The audit entry to record.
   */
  log(entry: AuditEntry): Promise<void>

  /**
   * Queries audit records with optional filtering and pagination.
   *
   * @param options - Query filters and pagination options.
   * @returns A paginated result set of audit records.
   */
  query(options: AuditQuery): Promise<PaginatedResult<AuditRecord>>

  /**
   * Exports audit records matching the query in the specified format.
   *
   * @param options - Query filters for the records to export.
   * @param format - The export format (`csv` or `json`).
   * @returns A `Buffer` containing the exported data.
   */
  export(options: AuditQuery, format: AuditExportFormat): Promise<Buffer>
}

AuditQuery

Query options for filtering and paginating audit records.

interface AuditQuery {
  /** Filter by actor identifier. */
  actor?: string

  /** Filter by action type. */
  action?: string

  /** Filter by resource type. */
  resource?: string

  /** Filter by specific resource instance identifier. */
  resourceId?: string

  /** Include only records created at or after this date. */
  startDate?: Date

  /** Include only records created at or before this date. */
  endDate?: Date

  /** Page number for pagination (1-based). */
  page?: number

  /** Number of records per page. */
  perPage?: number
}

AuditRecord

A persisted audit record with server-assigned metadata.

interface AuditRecord extends AuditEntry {
  /** Unique identifier for this audit record. */
  id: string

  /** Timestamp when the audit record was created. */
  timestamp: Date
}

PaginatedResult

Paginated result set for audit queries.

interface PaginatedResult<T> {
  /** The records for the current page. */
  data: T[]

  /** Total number of records matching the query. */
  total: number

  /** Current page number (1-based). */
  page: number

  /** Number of records per page. */
  perPage: number

  /** Total number of pages. */
  totalPages: number
}

Types

AuditExportFormat

Supported export formats for audit data.

type AuditExportFormat = 'csv' | 'json'

Functions

auditExport(options, format)

Exports audit records matching the query in the specified format.

function auditExport(
  options: AuditQuery,
  format: AuditExportFormat,
): Promise<Buffer<ArrayBufferLike>>
  • options — Query filters for the records to export.
  • format — The export format (csv or json).

Returns: A Buffer containing the exported data.

getProvider()

Retrieves the bonded audit provider, throwing if none is configured.

function getProvider(): AuditProvider

Returns: The bonded audit provider.

hasProvider()

Checks whether an audit provider is currently bonded.

function hasProvider(): boolean

Returns: true if an audit provider is bonded.

log(entry)

Records an audit trail entry.

function log(entry: AuditEntry): Promise<void>
  • entry — The audit entry to record.

Returns: Resolves when the bonded provider persists the entry.

query(options)

Queries audit records with optional filtering and pagination.

function query(options: AuditQuery): Promise<PaginatedResult<AuditRecord>>
  • options — Query filters and pagination options.

Returns: A paginated result set of audit records.

setProvider(provider)

Registers an audit provider as the active singleton. Called by bond packages during application startup.

function setProvider(provider: AuditProvider): void
  • provider — The audit provider implementation to bond.

Available Providers

ProviderPackage
Audit@molecule/api-audit-database
Audit@molecule/api-audit-file

Injection Notes

Requirements

Peer dependencies:

  • @molecule/api-bond ^1.0.1
  • @molecule/api-i18n ^1.0.1

Runtime Dependencies

  • @molecule/api-bond

  • @molecule/api-i18n

  • Decide failure behavior per call site. log() throws when no provider is bonded and rejects when the provider fails — await it where the audit record is a hard requirement (fail the operation), or .catch()-and-log where it is best-effort telemetry. Never leave a bare fire-and-forget promise.

  • The export function is auditExport(options, format) ('csv' | 'json', returns a Buffer) — named to avoid the reserved word export.

  • Record entries server-side, in the handler that performs the action — never from the client (an endpoint that writes caller-supplied entries lets anyone forge the trail). Gate query/auditExport endpoints behind admin-level permissions.

  • Log identifiers and outcomes, not payloads. details is persisted verbatim and readable by anyone who can query the trail — no secrets, tokens, or raw PII.

  • query() paginates with 1-based page + perPage and returns PaginatedResult (data, total, page, perPage).

E2E Tests

Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:

  • Every auditable action the app defines (login, permission/role change, delete, export, settings change) performed in the UI actually WRITES an entry — log() is called from the handler that does the work, not merely defined. Confirm the entry exists via the audit view or a query().
  • Each written entry captures the real action + resource (+ resourceId) and a server-assigned timestamp — not a placeholder or the wrong resource.
  • The recorded actor is the authenticated user from the server session: two different signed-in users produce two different actors, never a hardcoded/anonymous/client-supplied id.
  • The audit log view (if the app exposes one) lists entries with correct details, and filtering by actor/action/resource/date range (query) narrows the results as expected.
  • Reading or exporting the trail (query/auditExport) is admin-only — a normal user gets 403 / no UI and cannot read everyone else's activity.
  • History is append-only / tamper-evident: no endpoint edits or deletes a past entry to cover tracks (the interface exposes only log/query/export) — try to mutate one and confirm there is no route.