---
title: "@playstack/audit"
description: "Append-only, per-scope tamper-evident audit chains for Node and Workers."
tags: ["package","identity","audit","security","pro"]
---

{/* package-access:start */}

> **Pro.** Covered by the Playstack Pro License. Registry access is required; check preview availability before installing. See [package access](/docs/packages#access-policy).

{/* package-access:end */}

`@playstack/audit` records security- and administration-relevant activity in append-only, per-scope tamper-evident chains for Node and Workers.

## Install

```sh
npm install @playstack/audit @playstack/core @playstack/events
```

## Compose event-driven audit

```ts
import {
  bindAuditRegistry,
  createAuditService,
  Sha256AuditHash,
} from '@playstack/audit'

const audit = createAuditService({
  persistence,
  hash: new Sha256AuditHash(applicationCrypto),
  clock,
  ids,
  mapper: {
    map: (event, payload) => ({
      scopeType: event.context.scope?.type ?? 'system',
      scopeId: event.context.scope?.id ?? 'global',
      actorType: event.context.actor?.type ?? 'system',
      actorId: event.context.actor?.id,
      resourceType: payload.resourceType as string,
      resourceId: payload.resourceId as string,
    }),
  },
  retention: {
    months: 84,
    policyReference: 'docs/policies/audit-retention.md',
  },
})

const dispose = bindAuditRegistry(events, registry, audit)
events.assertReady()
```

The event definition chooses the audit tier and projected fields. The application mapper supplies scope, actor, resource, and impersonation facts because those cannot be inferred safely from arbitrary payload names. The recorded `action` defaults to the event name without its first (package) segment, so `accounts.member.joined` is audited as `member.joined`; a mapper may return `action` to override that, for example to keep the full event name when two packages share a suffix.

## Configuration reference

| `AuditServiceOptions` property | Required | Purpose |
| --- | --- | --- |
| `persistence` | Yes | Transactional append, locked chain-tail lookup, query, and integrity reads. |
| `hash` | Yes | `digest(value)` for canonical entry hashing. |
| `clock`, `ids` | Yes | Application-owned timestamps and entry identifiers. |
| `mapper` | Yes | Maps a typed event and projected payload to scope, actor, and resource facts. |
| `retention.months` | Yes | Positive immutable retention duration. |
| `retention.policyReference` | Yes | Application-owned policy document that justifies the duration. |

The validated retention policy is exposed as `audit.retention` so storage, scheduled partition maintenance, and framework adapters use the same decision.

## Audit entry properties

| Group | Properties |
| --- | --- |
| Identity | `id`, `at`, `scopeType`, `scopeId`. |
| Actor | `actorType`, optional `actorId`, `onBehalfOfId`, and `apiKeyId`. |
| Action | `action`, `resourceType`, `resourceId`. |
| Detail | Optional `changes` and `context`; secret- and PII-shaped keys are recursively redacted. |
| Chain | Optional `prevHash` and required `hash`. |

Queries always require `scopeType` and `scopeId`, with optional actor, resource, action, time range, cursor, and limit filters.

Built-in actor types are `user`, `apiKey`, `staff`, and `system`. The string
contract is intentionally extensible, so applications can record actors such
as `partner`, `service`, or another authenticated principal without converting
them into a user. Actor identifiers remain optional only for system activity.

## Persistence bridge

`AuditPersistence` must lock the `scopeType/scopeId` chain while reading its tail and appending the next record—even when the chain is empty. Transactional event handlers receive the emitting transaction and fail the mutation if audit storage fails. Queued handlers open their own transaction after outbox delivery.

`@playstack/audit/prisma` provides PostgreSQL advisory locking, append-only inserts, and stable time/ID cursor pagination. The managed Prisma fragment is composed by the CLI; the application owns migrations plus monthly partition creation and removal.

## Direct application routes

Package events are the authoritative audit path for security-critical domain operations. Use [`@playstack/nest-audit`](/docs/packages/identity/nest-audit) for explicitly declared application routes whose successful responses should be recorded on a best-effort basis.

## Boundary

Audit is not the general event store and does not record every event. The application owns retention policy, storage access control, operator workflows, partition operations, and the decision about which application-specific events are auditable.

{/* package-reference:start */}

## API entry points and requirements

Reference snapshot: `@playstack/audit@0.1.0-beta.1`. Import only the entry point your runtime needs. Paths below are relative to the installed package; use **Go to Definition** in your editor to inspect exact parameters, return types and overloads. Do not import the declaration-file paths directly.

| Public entry point | Declaration file |
| --- | --- |
| `@playstack/audit` | `./dist/index.d.ts` |
| `@playstack/audit/errors` | `./dist/errors.d.ts` |
| `@playstack/audit/prisma` | `./dist/prisma.d.ts` |
| `@playstack/audit/testing` | `./dist/testing.d.ts` |
| `@playstack/audit/playstack.artifacts.json` | No TypeScript declaration (asset or metadata export). |
| `@playstack/audit/package.json` | No TypeScript declaration (asset or metadata export). |

Node.js engine requirement: `>=20`. This is not a claim that every entry point works in browsers or Workers.

### Peer dependencies

This package declares no peer dependencies. Its ordinary dependencies are resolved by the package manager.

For a complete first program, start with [Getting started](/docs/getting-started). For API lookup and partial-example conventions, see [Reading the reference](/docs/packages#reading-the-reference). Provider failures, lifecycle requirements and application responsibilities remain described in the guide above; types alone do not establish production safety.

{/* package-reference:end */}
