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

data-struct

v0.1.0

Published

Schema-driven binary serialization between JS objects and Node Buffers

Readme

data-struct

CI npm

Schema-driven binary serialization between JavaScript values and Node Buffers.

  • Tiny. No runtime dependencies.
  • Typed. A schema infers the exact TypeScript shape of the decoded value via Infer<S>.
  • Fast. Two-pass encoder allocates the output buffer exactly once.
  • Dual-format. Ships ESM + CommonJS + .d.ts for both.
  • Wire-stable. Big-endian by default, byte-identical with prior 0.0.x releases.

Install

npm install data-struct

Requires Node >=20.9.

Usage

import { struct, t, type Infer } from 'data-struct';

const Hero = struct({
  id: t.u32,
  name: t.string,
  hp: t.i16,
  skills: [{ id: t.u16, description: t.string }],
  playable: t.bool,
  experience: t.u32,
  position: { x: t.u16, y: t.u16 },
});

type Hero = Infer<typeof Hero.schema>;

const buf = Hero.encode({
  id: 9,
  name: 'CirnoBaka',
  hp: 146,
  skills: [
    { id: 34, description: 'freezing frogs' },
    { id: 16, description: 'perfect math' },
  ],
  playable: false,
  experience: 99_999_999,
  position: { x: 2, y: 3 },
});

const hero = Hero.decode(buf); // typed as Hero

Functional form, when you don't want to keep a compiled struct around:

import { encode, decode, t } from 'data-struct';

const Map2D = [[t.u8]];
const buf = encode([[0, 1, 0], [1, 0, 1]], Map2D);
const map = decode(buf, Map2D); // number[][]

API

Codec tokens — t

| Token | Bytes | TS type | Notes | | ---------------- | ---------- | ------------ | ------------------------------------------- | | t.bool | 1 | boolean | | | t.i8 / t.u8 | 1 | number | | | t.i16 / t.u16| 2 | number | big-endian | | t.i32 / t.u32| 4 | number | big-endian | | t.f32 / t.f64| 4 / 8 | number | big-endian | | t.i64 / t.u64| 8 | bigint | big-endian | | t.string | 2 + utf-8 | string | uint16 length prefix, max 65535 utf-8 bytes | | t.shortBytes | 2 + n | Uint8Array | uint16 length prefix, max 65535 bytes | | t.bytes | 4 + n | Uint8Array | uint32 length prefix, max 4294967295 bytes |

Little-endian variants live under t.le.* (e.g. t.le.u32, t.le.f64, t.le.string).

Schema shape

A schema is one of:

  • A codec token (t.u32).
  • A single-element array [Schema] — encodes as a uint16 length prefix followed by N child encodings.
  • A plain object — fields encoded in declared key order.
type Schema = Codec<unknown> | Schema[] | { [k: string]: Schema };
type Infer<S> = /* recursively maps each leaf to its TS type */;

Functions

struct<S extends Schema>(schema: S): {
  schema: S;
  encode(value: Infer<S>): Buffer;
  decode(input: Uint8Array): Infer<S>;
  sizeOf(value: Infer<S>): number;
};

encode<S extends Schema>(value: Infer<S>, schema: S): Buffer;
decode<S extends Schema>(input: Uint8Array, schema: S): Infer<S>;

struct(schema) compiles the schema tree once and reuses the compiled codec across calls — prefer it in hot paths.

Errors

Validation throws DataStructError with a code:

| Code | When | | --------------------- | ------------------------------------------------- | | VALUE_OUT_OF_RANGE | Numeric value outside the leaf's range or non-int | | STRING_TOO_LONG | UTF-8 byte length exceeds 65535 | | BYTES_TOO_LONG | Bytes value exceeds the leaf's length cap | | ARRAY_TOO_LONG | Array length exceeds 65535 | | BUFFER_UNDERFLOW | Decode would read past the end of the input | | SCHEMA_MISMATCH | Value shape does not match the schema | | INVALID_SCHEMA | Schema itself is malformed |

Every error carries path (e.g. $.skills[1].description) and, for decode errors, offset.

Wire format

bool          : 1 byte               0x00 = false, anything else = true
i8/u8         : 1 byte
i16/u16       : 2 bytes BE
i32/u32       : 4 bytes BE
f32/f64       : 4 / 8 bytes BE
i64/u64       : 8 bytes BE
string        : uint16 BE length || utf-8 bytes
shortBytes    : uint16 BE length || raw bytes
bytes         : uint32 BE length || raw bytes
array [E]     : uint16 BE length || N encoded elements
object {…}    : fields encoded in declared key order, no header

LE variants (t.le.*) swap the byte order of length prefixes and the numeric payload.

Migration from 0.0.x

The 0.1.0 release is a full rewrite with a new API surface. The wire format is preserved, so buffers produced by older versions decode correctly under the new codecs.

| Old | New | | ------------------------- | ------------------------- | | DataTypes.boolean | t.bool | | DataTypes.int8 / uint8| t.i8 / t.u8 | | DataTypes.int16/uint16| t.i16 / t.u16 | | DataTypes.int32/uint32| t.i32 / t.u32 | | DataTypes.float | t.f32 | | DataTypes.double | t.f64 | | DataTypes.string | t.string | | DataTypes.shortBuffer | t.shortBytes | | DataTypes.buffer | t.bytes | | DataWriter(obj, scheme) | encode(obj, schema) | | DataReader(buf, scheme) | decode(buf, schema) |

The legacy DataTypes / DataReader / DataWriter exports are removed.

Development

npm install
npm run typecheck
npm run lint
npm test
npm run bench
npm run build

License

MIT