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

@philiprehberger/safe-json

v0.3.0

Published

Safe JSON parsing and serialization with circular detection and depth limiting

Readme

@philiprehberger/safe-json

CI npm version Last updated

Safe JSON parsing and serialization with circular detection and depth limiting

Installation

npm install @philiprehberger/safe-json

Usage

Safe Parse

import { safeParse } from '@philiprehberger/safe-json';

const { ok, data, error } = safeParse<User>(jsonString);
if (ok) {
  console.log(data.name); // typed as User
} else {
  console.error(error.message);
}

Safe Stringify

import { safeStringify } from '@philiprehberger/safe-json';

// Handles circular references
const obj: any = { name: 'test' };
obj.self = obj;
safeStringify(obj);
// {"name":"test","self":"[Circular]"}

// Depth limiting
safeStringify(deeplyNested, { maxDepth: 3 });
// Objects beyond depth 3 become "[MaxDepth]"

// Pretty print
safeStringify(data, { space: 2 });

Custom Type Serialization Hooks

import {
  safeParse,
  safeStringify,
  createTypeHooks,
  builtInSerializers,
} from '@philiprehberger/safe-json';

// Create hooks with built-in serializers for Date, BigInt, Set, and Map
const hooks = createTypeHooks();

const data = {
  createdAt: new Date('2025-01-15'),
  bigNum: BigInt('99999999999999999'),
  tags: new Set(['a', 'b']),
  meta: new Map([['key', 'value']]),
};

const json = safeStringify(data, { hooks });
const { ok, data: restored } = safeParse(json, { hooks });
// restored.createdAt is a Date instance
// restored.tags is a Set instance

Deep Clone with Type Preservation

import { safeJsonClone, createTypeHooks } from '@philiprehberger/safe-json';

const hooks = createTypeHooks();
const original = { date: new Date(), items: new Set([1, 2, 3]) };

const cloned = safeJsonClone(original, { hooks });
// cloned.date is a new Date instance with the same value
// cloned.items is a new Set with the same values

Deep Merge

import { safeJsonMerge } from '@philiprehberger/safe-json';

const target = { a: 1, nested: { x: 10 }, tags: ['a'] };
const source = { b: 2, nested: { y: 20 }, tags: ['b'] };

const merged = safeJsonMerge(target, source);
// { a: 1, b: 2, nested: { x: 10, y: 20 }, tags: ['a', 'b'] }

Structural Equality

import { safeJsonEqual, createTypeHooks } from '@philiprehberger/safe-json';

safeJsonEqual({ a: 1, items: [1, 2] }, { a: 1, items: [1, 2] }); // true

// Date / BigInt / Set / Map equality via hooks
const hooks = createTypeHooks();
safeJsonEqual({ at: new Date('2026-01-01') }, { at: new Date('2026-01-01') }, { hooks }); // true

// Circular references are tolerated
const a: any = { x: 1 }; a.self = a;
const b: any = { x: 1 }; b.self = b;
safeJsonEqual(a, b); // true

Configurable Error Handler

import { safeParse, safeStringify, safeJsonClone } from '@philiprehberger/safe-json';

const onError = (err: Error) => console.error('JSON error:', err.message);

safeParse('invalid json', { onError });
safeStringify(value, { onError });
safeJsonClone(value, { onError });

API

| Export | Description | |--------|-------------| | safeParse<T>(input, options?) | Parse JSON string, returns { ok, data?, error? } | | safeStringify(value, options?) | Stringify with circular/depth protection | | safeJsonClone<T>(value, options?) | Deep clone via serialize/deserialize | | safeJsonMerge<T>(target, source, options?) | Deep merge two objects safely | | safeJsonEqual(a, b, options?) | Structural JSON-aware equality with circular safety and optional type hooks | | createTypeHooks(serializers?) | Create a TypeHooks config (defaults to built-in serializers) | | builtInSerializers | Array of built-in serializers for Date, BigInt, Set, Map | | dateSerializer | Type serializer for Date | | bigIntSerializer | Type serializer for BigInt | | setSerializer | Type serializer for Set | | mapSerializer | Type serializer for Map |

SafeParseResult<T>

| Property | Type | Description | |----------|------|-------------| | ok | boolean | Whether parsing succeeded | | data | T | Parsed value (if ok) | | error | Error | Parse error (if not ok) |

StringifyOptions

| Option | Type | Default | Description | |--------|------|---------|-------------| | maxDepth | number | — | Max nesting depth before "[MaxDepth]" | | replacer | (key, value) => unknown | — | Custom replacer function | | space | number | — | Indentation spaces | | onError | (error: Error) => void | — | Error callback instead of silent failure | | hooks | TypeHooks | — | Custom type serialization hooks |

SafeParseOptions

| Option | Type | Default | Description | |--------|------|---------|-------------| | hooks | TypeHooks | — | Custom type deserialization hooks | | onError | (error: Error) => void | — | Error callback |

TypeSerializer<T>

| Property | Type | Description | |----------|------|-------------| | type | string | Unique type identifier | | test | (value: unknown) => boolean | Returns true if value matches this type | | serialize | (value: T) => unknown | Convert value to JSON-safe representation | | deserialize | (value: unknown) => T | Restore value from JSON representation |

Development

npm install
npm run build
npm test

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT