AbsoluteJS

@absolutejs/audit-postgres

@absolutejs/audit-postgresv0.1.4betaObservability

Postgres-backed AuditSink for @absolutejs/audit with first-class Drizzle and tagged-template adapters, native JSONB metadata, and indexed history.

#Installation

BASH
bun add @absolutejs/audit-postgres

#Capabilities

Overview

Postgres-backed AuditSink for @absolutejs/audit with first-class Drizzle and tagged-template adapters.

Durable, queryable, and uses the same metadata.__integrity field for tamper-evidence as the in-memory sink — jsonb preserves the chain through the round-trip.

Usage

Drizzle

Re-export the package-owned table from your application schema so your normal Drizzle migration workflow owns its lifecycle:

Then pass any Drizzle Postgres database:

Show 8 more

When the Drizzle database uses Bun SQL, opt into the Bun-native JSONB mapping and sink so object and array parameters are not pre-stringified:

auditBunSqlDrizzleSchema provides the same mapping as a schema object. The default auditEvents, auditDrizzleSchema, and createDrizzleAuditSink exports retain their existing postgres.js-compatible codec. Select the mapping from the configured database driver rather than the JavaScript runtime: postgres.js can itself run under Bun.

The Drizzle adapter deliberately never runs DDL at application runtime. It exports auditEvents and auditDrizzleSchema, uses native typed JSONB, and implements the same recent-window, actor, kind, time-range, and prune behavior as the tagged-template adapter.

If your application intentionally keeps package-owned tables out of its Drizzle schema, apply this adapter's migration through your existing PostgreSQL client instead:

The runner uses an atomic, digest-checked 0001_init migration for each validated table name and records it in audit_postgres_migrations. Concurrent runners serialize with a transaction-scoped advisory lock. Existing tables created through the lazy adapter are safely adopted by the first runner. Changing an applied migration's SQL fails closed. The runner never creates or closes the injected client. getAuditPostgresSchemaSql({ table? }) exposes the same deterministic, validated SQL for migration systems that apply SQL themselves, while auditPostgresMigrationPlan({ table? }) exposes the numbered ID, SQL, and SHA-256 digest.

postgres.js

Neon serverless (Lambda / Workers)

Same adapter; the only difference is the SQL tag template.

Schema

The adapter creates this lazily on first append / list / prune:

metadata is jsonb — the __integrity chain field rides here untouched

by the round-trip.

Show 5 more

All three indexes are partial-or-full to cover the common filter paths

(recent-first lists; per-kind filters; per-actor lookups).

The table name is customizable via the table option (strictly validated

against /^[a-zA-Z_][a-zA-Z0-9_]$/ and limited to 53 characters to defend against injection and PostgreSQL index-name truncation — the identifier has to be interpolated into the DDL, not parameterized).

Pass ensureSchema: false if you manage migrations yourself.

API

Returns a standard AuditSink implementing append, list (with kind / actor / since / until / limit filters), and prune(before).

Behavior notes

Lazy schema. First call to any method runs the DDL once; subsequent

calls skip.

Portable row counts. prune uses RETURNING id and counts the returned

Show 5 more

array, so it works the same on postgres-js (which exposes .count) and Neon serverless (which doesn't expose row count the same way).

bigint at column. Wall-clock Date.now() won't exceed

Number.MAX_SAFE_INTEGER for centuries; the row is normalized back to a JS number on read regardless of driver configuration.

metadata jsonb-as-string fallback. Some driver setups return jsonb as

a string; the sink parses on read so callers never see a string.

Test setup

The Drizzle adapter's PGlite suite is self-contained:

The tagged-template compatibility suite uses a real Postgres service:

Override the DSN via AUDIT_PG_TEST_URL to point at your own Postgres.

Outcomes

What you can build

Build on the supported package contract

Use @absolutejs/audit-postgres through its supported public entry points.

Hardening checklist

Production guidance

Make every external boundary explicitPin the deployed @absolutejs/audit-postgres version, replace example or memory-backed dependencies with durable implementations, bound external calls, protect credentials, and emit enough evidence to retry or recover safely.

Follow in order

Troubleshooting path

1
Trace from the first failed boundary
Reproduce the smallest canonical @absolutejs/audit-postgres example, confirm the supported entry point and version in the API explorer, then inspect the first boundary that did not produce its documented result.

#Test setup

Partial snippet

The Drizzle adapter's PGlite suite is self-contained:

SH
bun test tests/drizzleAuditSink.test.ts

#Drizzle

Partial snippet

Re-export the package-owned table from your application schema so your normal Drizzle migration workflow owns its lifecycle:

TS
export { auditEvents } from "@absolutejs/audit-postgres";

#Drizzle 2

Partial snippet

Re-export the package-owned table from your application schema so your normal Drizzle migration workflow owns its lifecycle:

TS
import { createAudit, withIntegrity } from "@absolutejs/audit";
import { createDrizzleAuditSink } from "@absolutejs/audit-postgres";

const audit = createAudit({
  sinks: [
    withIntegrity(createDrizzleAuditSink({ db }), {
      secret: process.env.AUDIT_SECRET,
      writerId: "shard-A",
    }),
  ],
});

#Public entry points

Supported entry points declared by this package manifest.

Package entry point declared in package.json.

@absolutejs/audit-postgres@absolutejs/audit-postgres/manifest@absolutejs/audit-postgres/manifest.json

#Package commands

Scripts declared by this package manifest.

bun run buildrm -rf dist && bun build src/index.ts src/manifest.ts --outdir dist --sourcemap --target=bun --external @absolutejs/audit --external drizzle-orm --external 'drizzle-orm/*' --external postgres --external @neondatabase/serverless && tsc --project tsconfig.build.json && absolute-manifest emit
bun run check:packagebun run typecheck && bun run verify-package && bun run build && bun run verify-package --artifacts && bun run test
bun run formatprettier --write "./**/*.{ts,json,md}"
bun run testbun test
bun run typechecktsc --noEmit

#API reference

Search the declarations exported by the current package type files. Expand a symbol to inspect its source-backed signature.

18 symbols
auditBunSqlDrizzleSchemaexportPermalinkSource
TS
auditBunSqlDrizzleSchema
Exported from @absolutejs/audit-postgres