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

autotel-audit

v0.1.8

Published

Audit-focused helpers for Autotel (force-keep + structured audit instrumentation)

Readme

autotel-audit

Audit-focused helpers for autotel. Provides structured audit logging with automatic tail-sampling bypass and OpenTelemetry attribute normalization.

What it provides

  • withAudit(...) — Wraps an operation with audit metadata, automatic outcome tagging (success/failure), and optional immediate emit
  • forceKeepAuditEvent(...) — Marks the current trace to bypass tail-drop sampling for compliance/audit trails
  • setAuditAttributes(...) — Writes normalized audit.* attributes on the active span with automatic type conversion

Features

  • Structured Metadata — Enforce consistent audit schemas with AuditMetadata interface
  • Automatic Outcome Tagging — Operations auto-tagged as success or failure (override with explicit outcome field)
  • Sampling Bypass — Force critical audit events through tail-sampling with forceKeepAuditEvent() or options.forceKeep
  • Type-Safe Attributes — Automatic serialization of complex types (Objects, Dates, Arrays) to OpenTelemetry-compatible values
  • Request Context Integration — Propagates actor ID, resource, and action across structured logs
  • Compliance Ready — Emit audit events immediately (emitNow: true) for real-time compliance systems

Quick Start

import { trace } from 'autotel';
import { withAudit } from 'autotel-audit';

export const deleteUser = trace(async () => {
  return withAudit(
    { action: 'user.delete', resource: 'user', actorId: 'admin-42' },
    async (_ctx, log) => {
      // business logic
      log.info('User deleted successfully');
      return { ok: true };
    },
    { emitNow: true },
  );
});

API Reference

withAudit<T>(metadata, fn, options?)

Wraps an async operation with audit metadata and handles success/failure outcomes.

Parameters:

  • metadata: AuditMetadata — Audit event metadata (action, resource, actor, etc.)
  • fn: (ctx, logger) => Promise<T> — Async function receiving audit context and request logger
  • options?: WithAuditOptions — Optional configuration:
    • emitNow?: boolean — Immediately emit the audit event (default: false)
    • forceKeep?: boolean — Force event through tail-sampling (default: true)
    • ctx?: AuditContext — Provide custom audit context (auto-resolved from trace if omitted)
    • logger?: RequestLogger — Override the request logger instance

Example with custom context:

const ctx = {
  traceId: 'abc-123',
  spanId: 'def-456',
  correlationId: 'xyz-789',
  setAttribute: (k, v) => span.setAttribute(k, v),
  setAttributes: (attrs) => span.setAttributes(attrs),
};

await withAudit({ action: 'data.export' }, fn, { ctx, emitNow: true });

setAuditAttributes(metadata, ctx?)

Write audit metadata as normalized audit.* span attributes without wrapping an operation.

import { setAuditAttributes } from 'autotel-audit';

setAuditAttributes({
  action: 'config.update',
  resource: 'settings',
  actorId: 'user-123',
  category: 'admin',
});
// Sets: audit.action, audit.resource, audit.actorId, audit.category, autotel.audit=true

forceKeepAuditEvent(ctx?)

Mark the active trace to bypass tail-drop sampling. Called automatically by withAudit unless forceKeep: false.

import { trace } from 'autotel';
import { forceKeepAuditEvent } from 'autotel-audit';

export const readSecrets = trace(async (req) => {
  if (req.user.role !== 'admin') {
    forceKeepAuditEvent(); // Keep sensitive access attempts
    throw new Error('Unauthorized');
  }
  // ...
});

Type-Safe Metadata

Define audit schemas for different operations:

import type { AuditMetadata } from 'autotel-audit';

interface DeleteUserAudit extends AuditMetadata {
  action: 'user.delete';
  resource: 'user';
  actorId: string;
  reason?: string;
}

interface PermissionUpdate extends AuditMetadata {
  action: 'permission.update';
  resource: 'role';
  oldValue?: Record<string, boolean>;
  newValue?: Record<string, boolean>;
  actorId: string;
}

Common Patterns

Emit audit events only on errors

await withAudit(
  { action: 'account.suspend', resource: 'account', actorId: 'admin-1' },
  async (ctx, log) => {
    try {
      await suspendAccount();
    } catch (err) {
      log.error(err); // Auto-tagged with outcome: failure
      throw;
    }
  },
  { emitNow: true },
);

Track sensitive operations with context

await withAudit(
  {
    action: 'secret.access',
    resource: 'api-key',
    actorId: user.id,
    secretType: 'api-key',
    env: 'prod',
  },
  async () => {
    // Fetch secret...
  },
  { emitNow: true, forceKeep: true },
);

Nested audit context in complex flows

export const transferFunds = trace(async (transfer) => {
  return withAudit(
    {
      action: 'transfer.execute',
      resource: 'transaction',
      actorId: transfer.initiator,
      amount: transfer.amount,
      fromAccount: transfer.from,
      toAccount: transfer.to,
    },
    async (ctx, log) => {
      const debitResult = await debitAccount(transfer.from, transfer.amount);
      const creditResult = await creditAccount(transfer.to, transfer.amount);

      log.info('Transfer completed', {
        transactionId: debitResult.txId,
        debitStatus: debitResult.status,
        creditStatus: creditResult.status,
      });

      return { success: true, txId: debitResult.txId };
    },
    { emitNow: true },
  );
});

Compliance & Sampling

Why force-keep audit events?

Tail-sampling decisions are made after spans complete. Critical audit trails need guaranteed export regardless of sampling rate. forceKeepAuditEvent() marks spans as keeper-worthy, ensuring they bypass statistical sampling.

// Default: force-keep is enabled (critical for audit)
await withAudit(metadata, fn);

// Disable if audit backend has separate retention
await withAudit(metadata, fn, { forceKeep: false });

// Manual control for hybrid scenarios
if (isPrivilegedOperation) {
  forceKeepAuditEvent();
}

Integration with Observability Backends

Audit attributes are standard OpenTelemetry span attributes and work with any OTLP-compatible backend (Datadog, New Relic, Jaeger, etc.).

  • Attributes are stored as audit.action, audit.resource, audit.actorId, etc.
  • Root span contains autotel.audit: true for filtering
  • Use backend span filters to create audit dashboards and alerts

See Also