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

@svene/redact

v0.1.1

Published

Tiny TypeScript wrapper that redacts sensitive values from logs, JSON, and inspection.

Readme

@svene/redact

Tiny TypeScript wrapper for values that should not leak through logs, JSON, string coercion, or Node.js inspection.

Inspired by Dillon Mulroy's Redacted module and Effect's Redacted.

It helps prevent accidental exposure. It is not encryption, a secret manager, a sandbox, or a security boundary. Code that can call revealRedacted() can read the value.

install

npm install @svene/redact

basic use

import { redact, revealRedacted } from "@svene/redact";

const apiKey = redact("sk_live_123");

console.log(apiKey);       // <redacted>
String(apiKey);             // <redacted>
JSON.stringify({ apiKey }); // {"apiKey":"<redacted>"}

const raw = revealRedacted(apiKey); // sk_live_123

copy or install?

This package is small. If you only need it in one app, copying the code into your own utils is fine.

Install it if you want the tested version, the types, the examples, and the same behavior across projects.

why use it

Secrets leak through boring paths: debug logs, request dumps, JSON snapshots, test failures, console.log, and util.inspect.

@svene/redact makes the safe path the default. Raw access stays explicit.

The value is stored in an internal WeakMap, not on the wrapper object.

import { redact } from "@svene/redact";

const token = redact("secret");

Object.keys(token);                      // []
Reflect.ownKeys(token);                  // []
Object.getOwnPropertyDescriptors(token); // {}

type-safe secrets

Use Brand when two secrets share the same runtime type but must not be mixed.

import {
  createRedacted,
  revealRedacted,
  type Brand,
  type Redacted,
} from "@svene/redact";

type ApiKey = string & Brand<"ApiKey">;
type DbPassword = string & Brand<"DbPassword">;

const apiKey = "sk_live_123" as ApiKey;
const dbPassword = "password" as DbPassword;

const redactedApiKey: Redacted<ApiKey> = createRedacted(apiKey);
const redactedDbPassword: Redacted<DbPassword> = createRedacted(dbPassword);

const fetchUser = (key: Redacted<ApiKey>) => {
  const raw: ApiKey = revealRedacted(key);
  return raw;
};

fetchUser(redactedApiKey);     // ok
fetchUser(redactedDbPassword); // TypeScript error

disposal

Disposal removes the wrapper from the internal registry. After that, revealRedacted() throws.

import { disposeRedacted, redact, revealRedacted } from "@svene/redact";

const secret = redact("sensitive");

revealRedacted(secret); // sensitive
disposeRedacted(secret);
revealRedacted(secret); // throws TypeError

In runtimes where Symbol.dispose exists, wrappers also expose a runtime dispose hook. The public Redacted<T> type does not require ESNext.Disposable; ordinary TypeScript consumers can use disposeRedacted().

Disposal does not wipe memory. JavaScript does not provide reliable memory wiping for strings, and other references to the original value may still exist.

esm and commonjs

Both ESM and CommonJS entrypoints are published. In one JavaScript realm, wrappers created through import and require share the same registry, so either entrypoint can reveal or dispose wrappers created by the other.

api

redact(value)

Creates a Redacted<T> wrapper. Alias of createRedacted(value).

const secret = redact("value");

createRedacted(value)

Creates a Redacted<T> wrapper.

const secret = createRedacted("value");

revealRedacted(redacted)

Returns the wrapped value. Throws TypeError if the wrapper is invalid or disposed.

const raw = revealRedacted(secret);

isRedacted(value)

Returns true for live wrappers created by this module. Disposed wrappers return false.

if (isRedacted(value)) {
  revealRedacted(value);
}

disposeRedacted(redacted)

Removes the wrapper from the internal registry.

disposeRedacted(secret);

createEqRedacted(eq)

Builds equality for redacted values from equality for the wrapped value.

import { createEqRedacted, redact, type Brand } from "@svene/redact";

type ApiKey = string & Brand<"ApiKey">;

const eqApiKey = createEqRedacted<ApiKey>((a, b) => a === b);

const a = redact("x" as ApiKey);
const b = redact("x" as ApiKey);

eqApiKey(a, b); // true

types

type Redacted<T> // opaque wrapper for T
type Brand<Name extends string | symbol> // type-only nominal marker
type Eq<T> = (self: T, that: T) => boolean
type Unredact<T> // extracts T from Redacted<T>

output behavior

| path | output | | --- | --- | | String(secret) | <redacted> | | `${secret}` | <redacted> | | JSON.stringify(secret) | "<redacted>" | | JSON.stringify({ secret }) | {"secret":"<redacted>"} | | console.log(secret) in Node.js | <redacted> | | util.inspect(secret) in Node.js | <redacted> | | Object spread | no secret | | Reflect.ownKeys(secret) | [] |

limits

This package does not protect against code that can reveal the value.

const secret = redact("sk_live_123");
revealRedacted(secret); // sk_live_123

It also does not replace logger-level redaction. Keep redaction rules for authorization headers, cookies, tokens, database URLs, and request bodies.

console.dir() in Node.js bypasses custom inspect hooks. The raw value still is not stored on the wrapper, but Node controls the output shape.

references

license

MIT