Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@suaveplan/json - Safe JSON parse/stringify with prototype-pollution protection, circular-ref detection, and OTel instrumentation
Summary
Safe, enterprise-grade JSON utilities with prototype-pollution protection, circular-reference detection, and OpenTelemetry instrumentation.
Documentation tree
- errors — (no submodules)
- json-error — (no submodules)
- safe-json — (no submodules)
- safe-json — (no submodules)
- types — (no submodules)
- types — (no submodules)
Install
bun add @suaveplan/json
Quick start
import { safeParse, safeStringify, tryParse, isValidJSON, getStringifySize } from "@suaveplan/json";
// Safe parse — throws JsonError on invalid JSON or forbidden keys
const obj = safeParse<{ a: number }>('{"a": 1}');
// Safe stringify — throws JsonError on circular references
const json = safeStringify(obj);
// Non-throwing parse
const val = tryParse("bad input"); // undefined
// Validity check (handles "null" correctly)
isValidJSON("null"); // true
isValidJSON("bad"); // false
// UTF-8 byte size of JSON representation
getStringifySize({ hello: "world" }); // 15
Modules
| Module | Description |
|---|---|
@suaveplan/json |
Main entry — all public exports |
@suaveplan/json/safe-json |
safeParse, safeStringify, tryParse, isValidJSON, getStringifySize |
@suaveplan/json/errors |
JsonError, JSON_CODES, JsonCode |
Error handling
Every failure is a structured JsonError with a stable code:
| Code | Trigger |
|---|---|
JSON.PARSE.FAILED |
Invalid JSON syntax or aborted AbortSignal |
JSON.PARSE.PROTOTYPE_POLLUTION |
Forbidden key (__proto__, constructor, prototype) |
JSON.STRINGIFY.CIRCULAR |
True circular reference detected |
JSON.STRINGIFY.FAILED |
Aborted signal or non-serialisable value (e.g. BigInt) |
import { safeParse, JsonError, JSON_CODES } from "@suaveplan/json";
try {
safeParse('{"__proto__": {}}');
} catch (err) {
if (err instanceof JsonError && err.code === JSON_CODES["PARSE.PROTOTYPE_POLLUTION"]) {
console.error("Prototype pollution blocked");
}
}
Options
ParseOptions
interface ParseOptions {
forbiddenKeys?: string[]; // default: ["__proto__", "constructor", "prototype"]
maxDepth?: number; // default: 50
signal?: AbortSignal;
}
StringifyOptions
interface StringifyOptions {
space?: number;
signal?: AbortSignal;
maxDepth?: number; // default: 100
}
Benchmarks
Measured on Intel Xeon E5-2696 v4 @ 2.20 GHz, Bun 1.3.13:
benchmark avg (min … max)
-------------------------------------------
safeParse small 9.84 µs/iter
JSON.parse small 592.70 ns/iter
safeStringify small 1.99 µs/iter
JSON.stringify small 212.99 ns/iter
safeParse medium 42.11 µs/iter
safeStringify medium 11.92 µs/iter
The overhead relative to the native functions comes from the OTel span creation, reviver/replacer function calls, and ancestor-stack tracking. In production with a no-op tracer the spans cost ~0 ns.
Links
src/safe-json/safe-json.md— implementation notessrc/errors/json-error.md— error codessrc/types/types.md— option types