npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@txfence/audit

v0.1.2

Published

Append-only audit log for txfence agents. Captures every policy evaluation, simulation, approval, and execution outcome.

Readme

@txfence/audit

Append-only audit log for txfence agent decisions. Captures every policy evaluation, simulation, approval request, and execution outcome — including rejections that never reach the chain.

Why audit vs. receipt storage?

@txfence/core's ReceiptStore only records successful on-chain transactions. The audit log captures everything:

| | ReceiptStore | @txfence/audit | |---|---|---| | Successful transactions | ✓ | ✓ | | Policy rejections | ✗ | ✓ | | Simulation failures | ✗ | ✓ | | Approval requests / decisions | ✗ | ✓ | | Execution failures | ✗ | ✓ |

Use @txfence/audit for compliance, debugging, and monitoring. Use ReceiptStore for querying confirmed on-chain state.

Installation

pnpm add @txfence/audit

Usage

import { createMemoryAuditLog, createFileAuditLog } from '@txfence/audit'
import { runPipeline } from '@txfence/core'

// In-memory — development and testing
const auditLog = createMemoryAuditLog()

// File-backed NDJSON — production
const auditLog = createFileAuditLog('./audit.jsonl')

// Pass as the last argument to runPipeline
const result = await runPipeline(action, policy, adapters, rpcUrls, executor,
  undefined, undefined, undefined, undefined, auditLog)

// Query entries
const rejections = await auditLog.query({ status: 'policy_rejected' })
const ethTransfers = await auditLog.query({ chain: 'ethereum', actionKind: 'transfer' })
const recent = await auditLog.query({ from: Date.now() - 86_400_000 })

AuditEntry shape

type AuditEntry = {
  id: string                      // UUID generated per pipeline call
  timestamp: number               // Date.now() at time of recording
  action: Action                  // The action that was submitted
  policySnapshot: Policy          // Deep clone of the policy at evaluation time
  evaluation: PolicyEvaluation    // Result of policy checks
  simulation?: SimulationResult   // Present when requireSimulation: true
  approvalRequest?: ApprovalRequest  // Present when human approval was triggered
  approvalDecision?: ApprovalDecision  // 'approved' | 'rejected' | absent on timeout
  outcome: AuditOutcome           // Final result of the pipeline run
}

AuditOutcome variants

| { status: 'success'; txHash: string; confirmedAtBlock: number; gasUsed: string }
| { status: 'policy_rejected'; reason: PolicyRejectionReason | undefined }
| { status: 'simulation_failed' }
| { status: 'approval_timeout' }
| { status: 'execution_failed'; reason: string }
| { status: 'dry_run'; stoppedAt: 'policy' | 'simulation' | 'approval' | 'execution' }

gasUsed is stored as a decimal string — not a bigint — because the audit log is serialized to JSON and bigint values are not JSON-native. The ReceiptStore's SuccessReceipt stores gasUsed as bigint; the audit log intentionally keeps it as a string for interoperability.

Filtering

type AuditFilter = {
  chain?: ChainId              // filter by action chain
  from?: number                // timestamp >= from (milliseconds)
  to?: number                  // timestamp <= to (milliseconds)
  status?: AuditOutcome['status']  // filter by outcome status
  actionKind?: Action['kind']  // 'transfer' | 'swap' | 'contract_call'
}

Implementations

Memory (development)

const log = createMemoryAuditLog()

Stores entries in a plain array. Not persisted across process restarts. Ideal for tests and development.

File (production)

const log = createFileAuditLog('./audit.jsonl')

Appends one JSON line per entry to an NDJSON file. The directory is created automatically. The file is never rewritten — only appended — making it safe under concurrent reads.

NDJSON format: one JSON object per line, each terminated with \n. Standard tools like jq work on NDJSON:

# Show all policy rejections
cat audit.jsonl | jq 'select(.outcome.status == "policy_rejected")'

# Count outcomes by status
cat audit.jsonl | jq -r '.outcome.status' | sort | uniq -c

Bigint serialization

Policy, Action, and SimulationResult contain bigint fields (token amounts, gas estimates). These are serialized as decimal strings in the NDJSON file and revived back to bigint on read. The policySnapshot is deep-cloned on record() to prevent mutation after the fact.

Known limitation: no tamper evidence in v1

The file backend is append-only but does not chain entries with hashes. A determined attacker with filesystem access can edit historical entries. Teams with strict tamper-evidence requirements should use a write-once storage backend (e.g. S3 with object lock) for the NDJSON file. Hash chaining is a planned future addition.