Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [3.2.0] - 2026-09-19

Optional second-argument unpack option `{ lazy: true }` wraps maps and arrays
as accessors so nested values are not converted until they are read. See `#40`.

### Added

- `unpack(buf, { lazy: true })` keeps the decoder zone alive and returns maps
as objects with accessor own-properties and arrays as array-likes with
indexed accessors (`length`, `in`, `Object.keys`). Nested maps and arrays
stay lazy until a property is read.
- `toJSON` and `util.inspect.custom` materialize through the eager converter,
so `JSON.stringify` and `util.inspect` match eager unpack. `pack()` of a
lazy value also round-trips because it calls `toJSON`.
- Primitives, incomplete buffers, trailing `bytes_remaining`, and the DoS
limits are unchanged. `__proto__` / `constructor` stay own properties.
- Lazy unpack copies the input before decode so str/bin do not alias the
caller's Buffer. Transferring that Buffer after unpack cannot dangle
later property reads.

## [3.1.0] - 2026-09-19

Optional second-argument pack hints force a MessagePack wire type or family
Expand Down Expand Up @@ -108,7 +128,8 @@ GitHub Actions tests Node 18/20/22 on Ubuntu, macOS, and Windows 2022.
- Pack throw paths free or return pooled sbuffers on every exit.
- msgpack-c c-7.0.2 includes unpacker buffer-expansion overflow checks.

[Unreleased]: https://github.com/msgpack/msgpack-node/compare/v3.1.0...HEAD
[Unreleased]: https://github.com/msgpack/msgpack-node/compare/v3.2.0...HEAD
[3.2.0]: https://github.com/msgpack/msgpack-node/compare/v3.1.0...v3.2.0
[3.1.0]: https://github.com/msgpack/msgpack-node/compare/v3.0.0...v3.1.0
[3.0.0]: https://github.com/msgpack/msgpack-node/compare/e04c9b55f98d64512174d6e859b8294b729659a2...HEAD
[2.0.0]: https://github.com/msgpack/msgpack-node/commit/e04c9b55f98d64512174d6e859b8294b729659a2
16 changes: 12 additions & 4 deletions COVERAGE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Coverage — msgpack 3.1.0
# Coverage — msgpack 3.2.0

`npm run coverage` runs both halves and fails the build under 95%.

Expand All @@ -8,9 +8,9 @@
| `lib/` + `bin/` (c8) | branches | **100%** | ≥ 95% |
| `lib/` + `bin/` (c8) | functions | **100%** | ≥ 95% |
| `lib/` + `bin/` (c8) | lines | **100%** | ≥ 95% |
| `src/` (gcovr) | lines | **95.2%** (902/947) | ≥ 95% |
| `src/` (gcovr) | branches | **95.4%** (836/876) | ≥ 95% |
| `src/` (gcovr) | functions | 100% (59/59) | — |
| `src/` (gcovr) | lines | **95.7%** (1002/1047) | ≥ 95% |
| `src/` (gcovr) | branches | **95.5%** (976/1022) | ≥ 95% |
| `src/` (gcovr) | functions | 100% (66/66) | — |

`deps/` is excluded from the native report; the vendored msgpack-c is not our
code. `build/` is rebuilt without instrumentation at the end of
Expand Down Expand Up @@ -146,6 +146,14 @@ gcovr --root . --filter src/ --exclude deps/ --no-markers --txt-metric branch --
`kMaxPackDepth`) are marked `GCOVR_EXCL_*`, not deleted. Native overall
stays above the 95% gate (`pack_hints.inc` itself is 91% branches because
switch `default:` edges sit on the same line as covered cases).
- `test/lazy.test.js` — `#40` `unpack(buf, { lazy: true })`: one-arg eager
identity, nested `o.c[1]` without reading siblings, `__proto__` /
`constructor` as own properties, oversized headers still throw, incomplete
buffers still return `null`, `toJSON` / `JSON.stringify` / `util.inspect`
match eager unpack, nested BigInt, non-object second args, toJSON
`this` checks, and str/bin reads after the caller Buffer is transferred.
Lazy OOM / empty-Maybe / ObjectTemplate-failure / CopyBuffer-failure arms
are marked `GCOVR_EXCL_*`, not deleted.
- `test/cli.test.js` (12 tests) — the exit-1 paths of both CLIs: invalid JSON,
empty stdin, a pack rejection reachable from real JSON, an unparseable byte,
an oversized header, incomplete input both alone and after a good frame, and
Expand Down
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
and de-serializes JavaScript values with [MessagePack](https://msgpack.org).
Packed output is a `Buffer` and is typically much smaller than JSON.

Version 3.1 requires **Node.js 18+**, vendors **msgpack-c c-7.0.2**, unpacks
64-bit integers outside `Number.MAX_SAFE_INTEGER` as `bigint`, and accepts
optional pack type/family hints. See [`SECURITY.md`](SECURITY.md).
Version 3.2 requires **Node.js 18+**, vendors **msgpack-c c-7.0.2**, unpacks
64-bit integers outside `Number.MAX_SAFE_INTEGER` as `bigint`, accepts
optional pack type/family hints, and can unpack maps and arrays lazily
(`unpack(buf, { lazy: true })`). See [`SECURITY.md`](SECURITY.md).

### Usage

Expand Down Expand Up @@ -79,6 +80,17 @@ is that same `bigint`.
`unpack.bytes_remaining` is the number of unused trailing bytes after the last
successful (or attempted) unpack. Stream uses that to splice leftover data.

`unpack(buf, { lazy: true })` wraps maps as objects with accessor
own-properties and arrays as array-likes with indexed accessors. Nested
values are not converted until they are read, which is useful for large
payloads when only a few keys are needed. The decoder copies `buf` so later
reads do not depend on the caller's backing store (transfer / detach is
safe). `JSON.stringify` and `util.inspect` materialize via `toJSON` /
`inspect.custom`. Lazy arrays are not real `Array`s (`Array.isArray` is
false); `pack()` still round-trips them because it calls `toJSON`.
Primitives unpack eagerly even when `lazy` is set. `__proto__` and
`constructor` keys stay own properties, same as eager unpack.

### Pack type hints (3.1)

`pack(value, options)` takes an optional last-argument options object when
Expand Down
11 changes: 9 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Type definitions for msgpack 3.1.0
// Type definitions for msgpack 3.2.0
// Project: https://github.com/msgpack/msgpack-node

/// <reference types="node" />
Expand Down Expand Up @@ -74,8 +74,15 @@ export function pack(...values: any[]): Buffer;
* Returns `null` when the buffer holds an incomplete value, in which case
* `unpack.bytes_remaining` equals `buf.length`. Throws on malformed input or
* when a container/string/bin header exceeds the decoder's limits.
*
* Pass `{ lazy: true }` to wrap maps as objects with accessor own-properties
* and arrays as array-likes with indexed accessors. Nested values are not
* converted until read. `JSON.stringify` and `util.inspect` materialize via
* `toJSON` / `inspect.custom`. Lazy arrays are not real `Array`s
* (`Array.isArray` is false); `pack()` still round-trips them because it
* calls `toJSON`. Primitives unpack eagerly even when `lazy` is set.
*/
export function unpack(buf: Buffer): any;
export function unpack(buf: Buffer, opts?: { lazy?: boolean }): any;

export namespace unpack {
/**
Expand Down
4 changes: 2 additions & 2 deletions lib/msgpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ function pack() {
return bpack.apply(null, arguments);
}

function unpack(buf) {
const result = rawUnpack(buf);
function unpack(buf, opts) {
const result = arguments.length < 2 ? rawUnpack(buf) : rawUnpack(buf, opts);
unpack.bytes_remaining = mpBindings.bytesRemaining();
return result;
}
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "msgpack",
"description": "A space-efficient object serialization library for Node.js",
"version": "3.1.0",
"version": "3.2.0",
"homepage": "https://github.com/msgpack/msgpack-node",
"author": "Peter Griess <pg@std.in>",
"contributors": [
Expand Down Expand Up @@ -34,7 +34,7 @@
"nan": "^2.23.1"
},
"scripts": {
"test": "node --test test/bigint.test.js test/cli.test.js test/coverage-native.test.js test/msgpack.test.js test/pack-hints.test.js test/regression.test.js test/security.test.js test/worker.test.js",
"test": "node --test test/bigint.test.js test/cli.test.js test/coverage-native.test.js test/lazy.test.js test/msgpack.test.js test/pack-hints.test.js test/regression.test.js test/security.test.js test/worker.test.js",
"bench": "node test/benchmark/benchmark.js",
"rebuild": "node-gyp rebuild",
"coverage": "npm run coverage:js && npm run coverage:native",
Expand Down
Loading
Loading