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

safe-to-json

v0.0.1

Published

Safely serialize any value to plain JSON: handles circular references, serializes Error (name, message, stack, cause), truncates long strings and large arrays. Zero dependencies, works in Cloudflare Workers, browsers and Node.

Readme

safe-to-json

Safe JSON stringify for logging and error reporting. toSafeJson turns any value — including caught Error objects, circular references and huge request/response objects — into plain, always-serializable JSON. It serializes errors with name, message, stack and cause chains, limits depth, truncates long strings and large arrays, and never throws. Zero dependencies, TypeScript, ESM, and runs in Cloudflare Workers (workerd), edge runtimes, browsers and Node.js.

Why

Plain JSON.stringify breaks in three ways when you log arbitrary values or send them to telemetry:

  1. It throws on circular references, so your logging code crashes while handling an error.
  2. It serializes everything: an error holding a request or response pulls in every header and token, which leaks sensitive data and bloats your logs.
  3. It drops error details: name, message, stack and cause are non-enumerable, so JSON.stringify(new Error("x")) gives "{}".

toSafeJson adds a circular-reference guard and caps on depth, string length and item count. For errors it reads the non-enumerable fields explicitly. The result is always plain JSON you can pass straight to JSON.stringify.

Install

npm install safe-to-json

Usage

import { toSafeJson } from "safe-to-json";

toSafeJson(anyValue); // default limits
toSafeJson(anyValue, { maxDepth: 3, maxStr: 1000, maxItems: 20 });

Log a caught error

try {
  await db.query("select 1");
} catch (e) {
  // name, message, stack, custom fields (code, status, ...) and the whole cause chain
  console.error(JSON.stringify({ msg: "query failed", err: toSafeJson(e) }));
}

Send an error to telemetry from a Cloudflare Worker

export default {
  async fetch(req, env, ctx) {
    try {
      return await handle(req, env);
    } catch (e) {
      ctx.waitUntil(
        fetch(env.LOG_URL, { method: "POST", body: JSON.stringify(toSafeJson(e)) }),
      );
      return new Response("Internal Error", { status: 500 });
    }
  },
};

Circular references

const a: Record<string, unknown> = { n: 1 };
a.self = a;
toSafeJson(a); // { n: 1, self: "[unserializable]" }

Other common uses: debug-logging state objects or user input of unknown size, and returning error details in an API response body.

API

toSafeJson(value: unknown, options?: SafeJsonOptions): unknown

Returns a JSON-safe copy of value. Call JSON.stringify on the result if you need a string.

| Option | Default | Meaning | | --- | --- | --- | | maxDepth | 5 | Maximum nesting depth, including cause chains | | maxStr | 4000 | Maximum string length; longer strings end with …(truncated) | | maxItems | 50 | Maximum number of array items or object keys |

Rules

  • Primitives (number, boolean, null, undefined) pass through. string and bigint are cut to maxStr.
  • Functions and symbols are dropped.
  • Error: name, message and stack are always included. cause is followed recursively, including the non-enumerable cause set by new Error(msg, { cause }). Own enumerable custom fields (code, status, query, ...) are kept.
  • Circular references and values past maxDepth become "[unserializable]". Nothing throws.

License

MIT