@jsonzen/core
v1.0.0
Published
Pure-TypeScript JSON engine: format, validate, diff, query, convert. The library behind jsonzen.dev and the jsonzen CLI.
Maintainers
Readme
Install
pnpm add @jsonzen/coreor npm i @jsonzen/core · yarn add @jsonzen/core · bun add @jsonzen/core
Why
Every JSON tool you reach for in an editor — parse, format, validate, diff,
query, convert, encrypt — wrapped in one tree-shakable package with
Result<T, E> instead of throws and zero browser coupling. Runs in Node, edge
runtimes, workers, or the browser. The same code powers
jsonzen.dev and the
jsonzen CLI.
What's in the box
@jsonzen/core/json
Parse, format, minify, validate, diff, equal, flatten, mutate.
parseJson · validateJson · diffJson
@jsonzen/core/jwt
Decode header, payload, and claims. No signature verification.
decodeJwt
@jsonzen/core/query
JSONPath and JMESPath behind a single API.
runQuery · pathToJsonPath
@jsonzen/core/convert
YAML, CSV, TypeScript, Zod, Pydantic, JSON Schema (both directions).
jsonToYaml · jsonToSchema · jsonFromSchema
@jsonzen/core/crypto
Argon2id key derivation + XChaCha20-Poly1305 envelopes.
deriveMasterKey · encryptSnippet · decryptSnippet
@jsonzen/core/share
URL-fragment share links, plain or password-protected. Zero server state.
encodeShare · encodePasswordShare
@jsonzen/core/tools
Canonical tool registry shared with the web app and CLI.
NAV_TOOLS · groupedNavTools
@jsonzen/core/types
Result<T, E> discriminated union plus ok and err constructors.
Result · ok · err
@jsonzen/core/config
Per-tool config shapes and their DEFAULTS literal.
FormatConfig · CsvConfig · YamlConfig
Every subpath is tree-shakable. Import only what you need: import { parseJson } from '@jsonzen/core/json'.
Quick start
Parse and format a JSON document. Five lines. No exceptions thrown.
import { formatJson } from '@jsonzen/core/json';
const result = formatJson('{"port":8080,"host":"localhost"}', { indent: 2 });
if (result.ok) {
console.log(result.value);
}Every operation that can fail returns a Result<T, E> —
{ ok: true, value } on success, { ok: false, error } on failure. Type
narrowing does the rest.
Examples
import { runQuery } from '@jsonzen/core/query';
const result = runQuery({
language: 'jsonpath',
query: '$.users[*].email',
jsonText: JSON.stringify({ users: [{ email: 'a@x' }, { email: 'b@x' }] }),
});
if (result.ok) {
console.log(result.value.matches); // ['a@x', 'b@x']
}JMESPath users pass language: 'jmespath' and write the expression in
JMESPath syntax. Same Result shape.
import { validateJson } from '@jsonzen/core/json';
const result = validateJson(
'{"port": 8080}',
JSON.stringify({
$schema: 'https://json-schema.org/draft/2020-12/schema',
type: 'object',
properties: { port: { type: 'integer' } },
required: ['port'],
}),
);
if (result.ok) {
console.log(result.value.valid); // true
}Draft-07 and Draft-2019-09 are auto-detected from the schema's $schema
header. Schemas above the depth/node caps short-circuit with a typed
error before Ajv ever sees them.
import {
deriveMasterKey,
encryptSnippet,
decryptSnippet,
generateSalt,
} from '@jsonzen/core/crypto';
const salt = generateSalt();
const masterKey = deriveMasterKey('correct horse battery staple', salt);
const envelope = encryptSnippet(masterKey, JSON.stringify({ secret: 1 }));
const plaintext = decryptSnippet(masterKey, envelope);
// plaintext === '{"secret":1}'Argon2id derivation, XChaCha20-Poly1305 ciphertext, per-snippet data keys wrapped with the master key so passphrase rotation only rewrites the small wrapper — not every ciphertext.
import { jsonToTypeScript } from '@jsonzen/core/convert';
const result = jsonToTypeScript('{"name":"alice","age":30,"roles":["admin","editor"]}', {
topLevelName: 'User',
exportType: 'interface',
});
if (result.ok) {
console.log(result.value);
// export interface User { name: string; age: number; roles: string[]; }
}The same module ships jsonToZodSchema, jsonToPydantic, and
jsonToSchema for JSON Schema inference.
import { diffJson } from '@jsonzen/core/json';
const result = diffJson('{"a":1,"b":2}', '{"a":1,"b":3,"c":4}');
if (result.ok) {
for (const change of result.value.changes) {
console.log(change.kind, change.path, change.before, '→', change.after);
// modified /b 2 → 3
// added /c undefined → 4
}
}kind is 'added' | 'removed' | 'modified'. path is a JSON Pointer.
arrayMatching: 'value' switches array diffs from index-by-index to
LCS-style.
Design rules
Pure logic only. Every public function is deterministic and
side-effect-free. No fetch, no localStorage, no console.log. Safe in the
browser, Node, edge runtimes, or workers.
Result types over throws. Operations that can fail return Result<T, E> —
the ok: boolean-discriminated union from @jsonzen/core/types — instead of
throwing. Crypto is the one exception: it throws on tampered ciphertext because
there is nothing the caller can usefully do besides treat the input as hostile.
No DOM, no React, no globals. Build once, run anywhere.
Enforced by an ESLint rule set with complexity ≤ 8, no any, no non-null assertions, no console.log, 95 % line and branch coverage on every file, and JSDoc on every public export. See CONTRIBUTING.md.
API reference
Every public export ships JSDoc — hover any symbol in your editor for a
summary, @param list, @returns shape, and @example block on the
primary entry points. Start with the subpath entry point:
- json —
parseJson,formatJson,validateJson,diffJson,jsonDeepEqual,flattenJson,mutate - jwt —
decodeJwt - query —
runQuery,pathToJsonPath,pathToJmesPath - convert — yaml · csv · typescript · zod · pydantic · json-schema (both directions)
- crypto —
deriveMasterKey,encryptSnippet,decryptSnippet, recovery flow - share —
encodeShare,decodeShareAuto, password-protected variants - types —
Result<T, E>,ok,err
Versioning
Semver. The current major is 1. Breaking changes — exports removed,
return-shape changes — only land on a major bump.
Contributing
See CONTRIBUTING.md. pnpm validate must be green
before any PR (format + lint + typecheck + 95 % coverage + build).
License
MIT © JSONZen.
