AbsoluteJS

@absolutejs/errors-postgres

@absolutejs/errors-postgresv0.2.0-beta.0betaObservability

Postgres-backed, Effect-native IssueStore for @absolutejs/errors with first-class Drizzle and tagged-template adapters.

#Installation

BASH
bun add @absolutejs/errors-postgres

#Capabilities

Overview

Postgres-backed, Effect-native IssueStore for @absolutejs/errors — the durable "Issues" surface (Sentry's product core), self-hosted on your own Postgres.

Durable grouped issues + an append-only event timeline, with new vs. regression detection resolved in a single atomic CTE upsert — one round-trip, no transaction, so it works over Neon's HTTP driver too.

Usage

Drizzle

Re-export the package tables from your application schema and manage them with your normal migration workflow:

The Drizzle store uses transactions for atomic event/group updates, portable native JSONB for tags and extra context, row locking for regression detection, and the same Effect error channel as the tagged-template adapter. JSONB values are passed to Drizzle drivers as native objects (rather than pre-serialized strings), preventing Bun SQL from storing them as JSON strings.

Show 2 more

Tagged-template compatibility

Works identically with @neondatabase/serverless:

What it implements

Every method returns an Effect with a typed IssueStoreError channel (IssueStoreSchemaError / IssueStoreQueryError / IssueStoreSerializationError) — failures are values, not throws.

Method — Effect

record(event) — atomic upsert (one event) → { issue, isNew, isRegression }

Show 10 more

recordCoalesced(group) — count-aware upsert + bulk unnest insert — one round-trip per herd

listIssues(filter?) — dashboard list (project / environment / state / ILIKE title), newest-first

getIssue(project, fingerprint) — Option<IssueRecord>

setState(project, fingerprint, state) — resolve / ignore / unresolve

assign(project, fingerprint, who \ — null) — triage

listEvents(project, fingerprint, limit?) — occurrence timeline, newest-first

Grouping semantics (mirrors createMemoryIssueStore exactly)

new vs. regression — detected in one statement: xmax = 0 ⇒ the row

was inserted (new); a CTE captures the pre-update state, so a resolved issue seen again is a regression and flips back to unresolved. ignored issues stay muted.

severity escalates, never de-escalates — fatal > error > warning > info.

Schema (lazy, idempotent)

Created on first use (set ensureSchema: false to manage it via migrations). tablePrefix defaults to error → error_issues + error_events.

Indexes: (project, last_seen DESC) and (project, state) on issues; (project, fingerprint, at DESC) on events.

trace_id / span_id (→ @absolutejs/telemetry) and replay_id (→ @absolutejs/replay) are stored per event so a dashboard can cross-link an issue to its exact trace and DOM replay.

Show 2 more

error_issues also carries the resolution trail — resolved_at, resolved_by, resolved_release, resolution_note — which the triage board writes when an issue is closed. ensureSchema adds them to an existing table; an application that owns its schema through migrations must add them itself before upgrading, because the store writes every column it knows about.

Choose the schema-derived Drizzle store for application-managed databases or the raw tagged-template compatibility store for lightweight and Neon HTTP integrations.

Triage

The store answers "what broke and how often". A board on top of it has to answer what a person actually asks in front of it: what is breaking now, who is on it, did the fix hold, which release introduced this. createIssueTriage is those queries, bound to one project.

A regression is derived, not stored: the ingest upsert flips a resolved issue back to unresolved when it recurs but leaves resolved_at in place, so unresolved + a resolution stamp + activity after it means the fix did not hold. setState clears the trail on reopen, because a manual reopen is a decision rather than a failed fix — and a surviving stamp would make the next recurrence look like one.

releaseStats is the per-release rollup a deployments ledger needs: for each release, how many issues were introduced under it, carried in from before it, came back in it, or were declared fixed in it — split by severity, because a deploy that introduced three warnings is not the same news as one that introduced three errors. Each issue lands in exactly one bucket per release.

Outcomes

What you can build

Build on the supported package contract

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

Hardening checklist

Production guidance

Make every external boundary explicitPin the deployed @absolutejs/errors-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/errors-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.

#Drizzle

Partial snippet

Re-export the package tables from your application schema and manage them with your normal migration workflow:

TS
export { errorEvents, errorIssues } from "@absolutejs/errors-postgres";

#Drizzle 2

Partial snippet

Re-export the package tables from your application schema and manage them with your normal migration workflow:

TS
import { createDrizzleIssueStore } from "@absolutejs/errors-postgres";

const store = createDrizzleIssueStore({ db });

#Public entry points

Supported entry points declared by this package manifest.

Package entry point declared in package.json.

@absolutejs/errors-postgres@absolutejs/errors-postgres/manifest@absolutejs/errors-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/errors --external drizzle-orm --external 'drizzle-orm/*' --external effect --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