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

@uon/model

v1.2.0

Published

A decorator-based schema/model library with json and binary (de)serialization

Readme

@uon/model

A decorator-based schema/model library with JSON and binary (de)serialization, validation, formatting and mutation tracking.

Installation

npm i @uon/model

@uon/model builds on @uon/core (peer dependency) and relies on emitted decorator metadata. Your tsconfig.json must enable:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

and reflect-metadata must be imported once at your app entry point (it is imported by @uon/core).

Defining a model

import { Model, Member, ArrayMember } from '@uon/model';

@Model()
export class MyModel {

    // Generic member — supports String, Boolean, Number and Date
    @Member()
    myStringField: string;

    // Array members must specify the element type (TS does not emit it)
    @ArrayMember(String)
    myArrayField: string[];
}

Supported member value types: String, Boolean, Number (treated as Float64), Date, the typed-number wrappers below, other @Model types (embedded models) and plain Object.

Identity — @ID

Marks the primary key of a model. An ID is "forever clean" (it never registers as a mutation) and is used to decide how embedded models are assigned/merged.

@Model()
export class User {
    @ID() id: string;
    @Member() name: string;
}

TypedNumber

For compact binary serialization, number types are provided. Generic Number members are treated as Float64.

import { Model, NumberMember, ArrayMember, Uint8, Uint32 } from '@uon/model';

@Model()
export class MyModel {
    // Int8, Int16, Int32, Uint8, Uint16, Uint32, Float32, Float64 (no (U)Int64 yet)
    @NumberMember(Uint8) myByte: number;

    // a TypedNumber can also be an array element type
    @ArrayMember(Uint32) myNumberArray: number[];
}

Modelizing an external type

To let the serializers support a type you don't own, "modelize" it:

import { Modelize, NumberMember, Float32 } from '@uon/model';
import { Vec2 } from 'some-math-lib';

Modelize(Vec2, {
    x: NumberMember(Float32),
    y: NumberMember(Float32),
});

Instantiation helpers

import { Model } from '@uon/model';

// create + populate
const u = Model.New(User, { id: '1', name: 'Ann' });

// merge values into an existing instance (embedded models are merged, not replaced)
Model.Assign(u, { name: 'Annie' });

JSON serialization

Serialize either manually via JsonSerializer or by passing the instance to JSON.stringify() (each @Model gets a generated toJSON).

import { JsonSerializer } from '@uon/model';

const serializer = new JsonSerializer(MyModel);

// serialize returns a plain JS object (String/Number/Boolean/Array/Object/Date),
// not a string
const plain = serializer.serialize(obj);

// pass mutationsOnly = true to serialize only fields changed since the last clean
const partial = serializer.serialize(obj, true);

// deserialize back to a typed instance
const obj2 = serializer.deserialize(JSON.parse(jsonString));

Binary serialization

BinarySerializer (de)serializes a model to/from an ArrayBuffer. Note: null values are treated as undefined (omitted), and a model may have at most 256 members (member indices are stored as a byte). Deserialization validates lengths and throws a descriptive error on a malformed/truncated buffer.

import { BinarySerializer } from '@uon/model';

const bin = new BinarySerializer(MyModel);
const buffer = bin.serialize(obj);     // ArrayBuffer
const obj2 = bin.deserialize(buffer);  // MyModel

Validation

Attach validators per member and run Validate():

import { Model, Member, Validate, Required, ValidateRange, ValidateEmail } from '@uon/model';

@Model()
export class Signup {
    @Member({ validators: [Required(), ValidateEmail()] }) email: string;
    @Member({ validators: [ValidateRange(13, 120)] }) age: number;
}

const result = await Validate(Model.New(Signup, { email: 'bad', age: 5 }));

if (!result.valid) {
    // result is a ModelValidationResult<T>
    const flat = result.flatten(); // [{ path, errors }, ...]
}

Built-in validators: Required, Prohibited, ValidateOneOf, ValidateRange, ValidatePattern, ValidateMongoId, MinLength, MaxLength, ValidateEmail, ValidatePhone, and ValidateModel (validate an embedded @Model). Validators are plain functions (model, key, value, injector?) => value, so you can write your own; throw a ValidationFailure to signal an error.

Validate() returns a ModelValidationResult<T>:

| Member | Description | |--------|-------------| | valid | true when there are no failures and no invalid children | | failures | ValidationFailure[] for this node | | children | per-field ValidationResult / ModelValidationResult | | flatten(out?, path?) | flatten the tree into { path, errors }[] | | filter(ignored) | a copy with the given validators removed |

Formatting

Formatters transform field values in place. Run ApplyFormatting():

import { Model, Member, ApplyFormatting } from '@uon/model';

@Model()
export class Account {
    @Member({ formatters: [(t, k, v) => String(v).trim().toLowerCase()] })
    handle: string;
}

const a = Model.New(Account, { handle: '  ALICE ' });
ApplyFormatting(a); // a.handle === 'alice'

Formatters run for every present field value, including falsy ones (0, false, ''); only undefined/null are skipped.

Mutation tracking

Decorated members are backed by getters/setters that flag changed fields. This powers serialize(obj, true) (serialize only what changed).

import { Model } from '@uon/model';

const u = Model.New(User, { id: '1', name: 'Ann' });
Model.MakeClean(u);          // clear all flags
u.name = 'Annie';            // flags `name` dirty
Model.HasMutations(u);       // true
Model.GetMutations(u);       // { name: true }
Model.MakeDirty(u, 'name');  // flag a field manually
Model.MakeClean(u, ['name']); // clear specific fields

API reference (barrel exports)

  • Decorators: Model, Member, ID, ArrayMember, NumberMember, Modelize
  • Number types: TypedNumber, Int8/Int16/Int32/Uint8/Uint16/Uint32/Float32/Float64
  • Serializers: JsonSerializer, BinarySerializer
  • Validation: Validate, ValidationResult, ModelValidationResult, ValidationFailure, Validator, and the built-in validators listed above
  • Formatting: ApplyFormatting, Formatter
  • Mutation: Model.MakeClean/MakeDirty/GetMutations/HasMutations, Mutations, ArrayMutation
  • Utilities: FindModelAnnotation, GetModelMembers, GetModelMembersMap, GetMemberForKey, Utf8ToBase64, Base64ToUtf8
  • Regex constants: MONGO_ID_REGEX, EMAIL_REGEXP, AMERICA_REGEXP

Limitations

  • Array members are limited to 1 dimension (n-dimensional arrays may come later).
  • Binary serialization: no (U)Int64; built-in typed arrays (Uint8Array, …) are not yet supported; a model is limited to 256 members.

License

MIT