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

@vita-mojo/audit-logs

v0.1.9

Published

NestJS building blocks for capturing an audit trail of HTTP requests/responses per `x-audit-id`, shipping them to SQS, and storing/querying them against a TypeORM-backed `audit_logs` table.

Downloads

3,843

Readme

@vita-mojo/audit-logs

NestJS building blocks for capturing an audit trail of HTTP requests/responses per x-audit-id, shipping them to SQS, and storing/querying them against a TypeORM-backed audit_logs table.

How it fits together

  • AuditMiddleware reads the x-audit-id request header and binds it to an async-local-storage scope (AuditContext) for the lifetime of the request, so any code downstream — including code outside Nest's request object, e.g. background subscribers — can recover the current audit id via AuditContext.getAuditId().
  • AuditInterceptor (wired up automatically by AuditModule as a global APP_INTERCEPTOR) fires once on the way in and once on the way out of every request that carries an x-audit-id header. It builds an AuditLog entry (service, tenant, user, path, headers/body or response, timestamp, and an optional scope) and pushes it onto the audit-logs SQS queue via @ssut/nestjs-sqs. Requests without x-audit-id are skipped, and any error while building/sending a log is swallowed (logged via console.warn) so audit logging can never break the actual request.
  • AuditScope is an optional method decorator consumers can attach to a controller handler to attach extra structured context (stores, settings, entities) to that endpoint's audit log entries. The interceptor reads it back via Reflector and merges the return value into AuditLog.scope.
  • AuditController exposes GET /audit/:auditId and DELETE /audit/:auditId, guarded by AuditGuard, which checks the request's Authorization: Bearer <token> header against options.serviceAccountToken.
  • AuditService runs the raw SELECT/DELETE queries behind those two endpoints against the audit_logs table, through the connection described below.
  • addAuditLogTable / addAuditLogTrigger are TypeORM migration helpers: the former creates the audit_logs table (+ an index on audit_id), the latter installs/removes per-entity MySQL triggers that populate it on INSERT/UPDATE/DELETE, driven by the @AuditTrigger() class decorator (see below).

Setup

import { AuditModule } from '@vita-mojo/audit-logs';
import { getConnectionToken } from '@nestjs/typeorm';

@Module({
  imports: [
    AuditModule.register({
      queueUrl: process.env.AUDIT_LOGS_QUEUE_URL,
      region: process.env.AWS_REGION,
      serviceAccountToken: process.env.AUDIT_SERVICE_ACCOUNT_TOKEN,
      service: 'my-service',
      connectionToken: getConnectionToken(), // getDataSourceToken() for typorm version  >= 0.3.x
    }),
  ],
})
export class AppModule {}

Why connectionToken is required

AuditService needs the app's TypeORM connection injected, but the class that connection is registered under differs by TypeORM major version: Connection on 0.2.x, DataSource from 0.3.x onwards (0.2.x never exported DataSource; 1.x removed Connection entirely). NestJS's implicit, type-based DI can only resolve a concrete class reference — an interface or any parameter type erases to Object at compile time and can't be resolved at all — so there is no single TypeScript type that works across every supported TypeORM version.

Instead, AuditModule.register() takes the DI token the connection is already registered under in your app (connectionToken) and rebinds it internally to this package's own token (AUDIT_DATA_SOURCE) via useExisting. AuditService and the migration helpers only depend on a narrow structural type (AuditConnection: query() + getMetadata()) that has been stable across TypeORM 0.2.x–1.1.x, so the package itself never imports a TypeORM class.

The easiest way to get the right value regardless of your TypeORM version is @nestjs/typeorm's own getConnectionToken() (deprecated alias) / getDataSourceToken() helper — it already resolves to whichever class your installed TypeORM version actually exports. Passing the class directly (Connection or DataSource) also works if you don't use @nestjs/typeorm's default connection name.

Supported TypeORM range: >=0.2.0 (peer dependency), verified against 0.2.45, 0.3.x, and 1.1.x.

Other options

| Option | Description | | ---------------------- | ---------------------------------------------------------------------------- | | queueUrl | SQS queue URL audit logs are sent to. No producer is registered if falsy. | | region | AWS region for the SQS producer. | | serviceAccountToken | Bearer token required to call the AuditController endpoints. | | service | Label stamped on every AuditLog entry (AuditLog.service). | | connectionToken | DI token for the app's TypeORM connection — see above. |

Tracking a table with triggers

import { AuditTrigger } from '@vita-mojo/audit-logs';

@AuditTrigger({ trackOldValuesOnUpdate: ['status'] })
@Entity()
export class Order {
  /* ... */
}

trackOldValuesOnUpdate is optional; listed columns get both col (new value) and old_col (previous value) recorded on UPDATE, everything else just gets the new value. Wire the triggers up per-entity in a migration:

import { addAuditLogTrigger } from '@vita-mojo/audit-logs';
import { Order } from '../entities/Order';

export class AddOrderAuditTrigger implements MigrationInterface {
  up(queryRunner: QueryRunner) {
    return addAuditLogTrigger.up(queryRunner, Order);
  }
  down(queryRunner: QueryRunner) {
    return addAuditLogTrigger.down(queryRunner, Order);
  }
}

Run addAuditLogTable.up(queryRunner) once (e.g. in an initial migration) to create the audit_logs table these triggers write into.

Building

Run nx build audit-logs to build the library.

Testing

Run nx test audit-logs. Coverage includes AuditService, AuditModule's connection-token wiring, AuditInterceptor (audit-id gating, tenant/user resolution, the superadmin tenant fallback, scope resolution and its error handling, and the swallow-all-errors behavior), AuditContext/ AuditMiddleware, decodeAuthorizationToken, the @AuditTrigger decorator and Trigger SQL rendering, and both migration helpers (addAuditLogTable, addAuditLogTrigger).