BigInt-safe JSON serialization and deserialization for Web3 data.
pnpm add json-web3
# or
npm i json-web3
# or
yarn add json-web3import jsonWeb3 from 'json-web3'
const payload = {
balance: 1234567890123456789n,
decimals: 18n,
u8Array: new Uint8Array([1, 2, 3, 255]),
u16Array: new Uint16Array([1, 2, 3, 255]),
bigIntArray: new BigInt64Array([18446744073709551615n, 2n, 3n, 255n]),
createdAt: new Date('2020-01-02T03:04:05.006Z'),
ids: new Set([123, 456]),
headers: new Map([['hello', 'world']]),
re: /([^\s]+)/g,
url: new URL('https://example.com/'),
fn: function echo(arg) {
return arg
},
}
const text = jsonWeb3.stringify(payload)
// => {"balance":{"__@json.bigint__":"1234567890123456789"},"decimals":{"__@json.bigint__":"18"},"u8Array":{"__@json.typedarray__":{"type":"Uint8Array","bytes":"0x010203ff"}},"u16Array":{"__@json.typedarray__":{"type":"Uint16Array","bytes":"0x010002000300ff00"}},"bigIntArray":{"__@json.typedarray__":{"type":"BigInt64Array","bytes":"0xffffffffffffffff02000000000000000300000000000000ff00000000000000"}}}
const restored = jsonWeb3.parse(text)
/* =>
{
balance: 1234567890123456789n,
decimals: 18n,
u8Array: Uint8Array(4) [1, 2, 3, 255]...,
u16Array: Uint16Array(4)...,
bigIntArray: BigInt64Array(4)...,
createdAt: Date(...),
ids: Set(2) {...},
headers: Map(1) {...},
re: /([^\s]+)/g,
url: URL(...),
fn: undefined
}
*/
const textUnsafe = jsonWeb3.stringify_UNSAFE(payload)
const restoredUnsafe = jsonWeb3.parse_UNSAFE(textUnsafe)
// restoredUnsafe.fn is a callable functionimport jsonWeb3 from 'json-web3'
window.JSON = jsonWeb3 // Yes, you can replace it directly; it is fully compatible.stringify(value, replacer?, space?)parse(text, reviver?)stringify_UNSAFE(value, replacer?, space?)(serializesFunctionpayloads)parse_UNSAFE(text, reviver?)(revivesFunctionpayloads vianew Function(...))
| type | supported by standard JSON? | supported by json-web3? |
|---|---|---|
string |
✅ | ✅ |
number |
✅ | ✅ |
boolean |
✅ | ✅ |
null |
✅ | ✅ |
Array |
✅ | ✅ |
Object |
✅ | ✅ |
undefined |
❌ | ❌ |
Infinity |
❌ | ✅ |
-Infinity |
❌ | ✅ |
NaN |
❌ | ✅ |
BigInt |
❌ | ✅ |
Date |
❌ | ✅ |
RegExp |
❌ | ✅ |
Set |
❌ | ✅ |
Map |
❌ | ✅ |
URL |
❌ | ✅ |
ArrayBuffer |
❌ | ✅ |
Uint8Array |
❌ | ✅ |
Uint8ClampedArray |
❌ | ✅ |
Uint16Array |
❌ | ✅ |
Uint32Array |
❌ | ✅ |
Int8Array |
❌ | ✅ |
Int16Array |
❌ | ✅ |
Int32Array |
❌ | ✅ |
Float16Array |
❌ | ✅ |
Float32Array |
❌ | ✅ |
Float64Array |
❌ | ✅ |
BigInt64Array |
❌ | ✅ |
BigUint64Array |
❌ | ✅ |
Function |
❌ | ✅ |
bigintvalues are encoded as objects:{"__@json.bigint__":"<value>"}.- Non-finite numbers (
NaN,Infinity,-Infinity) are encoded as{"__@json.number__":"<value>"}. Datevalues are encoded as{"__@json.date__":<timestamp>}.Mapvalues are encoded as{"__@json.map__":[[k,v],...]}andSetvalues as{"__@json.set__":[...]}.RegExpvalues are encoded as{"__@json.regexp__":{"source":"...","flags":"..."}}.URLvalues are encoded as{"__@json.url__":"..."}.Functionvalues are encoded as{"__@json.function__":"<source>"}bystringify_UNSAFEand are only revived byparse_UNSAFEusingnew Function(...)(using the UNSAFE function pair is dangerous; make sure your data is trusted).ArrayBuffervalues are encoded as{"__@json.arraybuffer__":{"bytes":"0x..."}}and decoded back toArrayBuffer.- Node
BufferJSON shapes and typed arrays are encoded as{"__@json.typedarray__":{"type":"<Name>","bytes":"0x..."}}and decoded back to the original typed array (Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array,Int8Array,Int16Array,Int32Array,Float32Array,Float64Array,BigInt64Array,BigUint64Array).
Compared to libraries that require eval-based parsing (for example, serialize-javascript), this approach is generally safer and more efficient.
To enable cross-language interoperability, the serialization format is specified in RFC.md. It defines the canonical tag objects, payload shapes, validation rules, and UNSAFE function handling.