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

@effectful/serialization

v2.0.12

Published

References-aware JS values serialization library

Readme

@effectful/serialization

Extensible, references aware, schemaless JavaScript values serialization.

Usage

Install from npm:

$ npm install --save @effectful/serialization

In code:

import * as S from "@effectful/serialization"

const json = S.stringify(value)

// ....

const value = S.parse(str)

Writing JavaScript values

Function S.write takes JS objects and returns it encoded as JSON.stringify serializable value. It can deal with multiple references to same values, including recursive references.

The root value must always be a plain object. Its properties values may have any type if there is its format description registered.

The library contains descriptors for Array/Set/Map/Symbol types and can be extended to support any other type if can be serialized.

Library's S.stringify function is a write followed by JSON.stringify.

Reading functions

The reverse direction is done by S.read function. It takes a serializable object returned by write and returns its original value.

Function S.parse is JSON.parse followed by S.read.

Extension

There is a descriptor structure used to specify how to write and read values.

When writing, the descriptor is looked up in [S.descriptorSymbol] value's property or in the library's internal map. The write routine is responsible to output a string for type's name in "#type" property of output object. It is used to lookup corresponding descriptor for reading.

The descriptor is registered using S.regDescriptor function.

The library will generate unique names based on the name property in descriptor if there are collisions. This means sending and receiving sides must call the register function in the same order if there are names collisions chances.

More information in API docs.

Opaque values

Some values cannot be serialized, e.g. Promise, Function, WeakMap etc. They may be registered as opaque values. This way if there is a reference to such opaque value in serialized value the library outputs the reference name rather than the value. This works if same (corresponding) objects registered with the same name on sending and receiving sides. Typically they are module's top-level variables with functions or classes declarations.

To register opaque values call S.regOpaqueObject or S.regOpaquePrim. With their first argument is the value, and the second argument is its name. The name may be omitted for S.regOpaqueObject the library will try to guess it. If it is a function declaration, it will use its name, for example.

The third argument specifies additional options (see DescriptorOpts type in the API).

By default the output will contain properties set or changed in object after S.regOpaqueObject call. This can be disabled by setting {props:false} in the third argument to disable any property output. Or {propsSnapshot:false} to disable storing the original values snapshot (thus all properties will be output). Reads mutate the registered objects.

Calling S.regOpaqueObject will set [S.descriptorSymbol] property in the object, while S.regOpaquePrim will store the value in a library's internal map.

Prototypes based inheritance

Use S.regConstructor to make objects with JS prototype inheritance serializable. It gets constructor function as its first argument and optional name as the second. The constructor function's name will be used if the name argument isn't specified.

It will register the constructor's prototype as an opaque object. This way if all the method are only referenced in prototype and all the data referenced in the object is serializable the object is serializable.

Functions serialization

The function's source code in JS is simple to write to a string (with toString method) and simple to read (using Function constructor), however, there are two significant issues.

De-serializing functions by calling new Function(...) is apparently very dangerous. Developers must be absolutely sure there is absolutely no data received from outside. And it is quite difficult to guarantee.

Even if the security isn't a concern for the project, this way of reading/writing function will lose all information about closure captured variables. It is not even possible to serialize a result of Function.prototype.bind. This way the function can only get state data either from global variables (obviously not an option) or using this reference if the function is some object's method.

If these limitations are too heavy, there is a closure conversion transform pass. It converts closures into objects with call method. This may solve all the limitations. There are no needs to store function's text. Some unique identifier, say SHA1 is enough. And since there are no closures after conversions object's translation will work well.

The transform is in Proof Of Concept state name, but will be moved into a separate library SOON.

DOM serialization

The package contains proof-of-concept DOM serialization. It is disabled by default. To enable:

import * as SDOM "@effectful/serialization/dom"
SDOM.track()

This monkey patches some DOM functions to get access to internal platform state which is not accessible by JavaScript otherwise.

It is very limited for now, requires deeper wrapping. It will store/restore elements, events and document with all children, attributes, and properties of DOM values with some limitations. Events will keep only their initialization options with calculated properties (such as target) not initialized.

TODO:

  • Validation
  • Data versioning

LICENSE

Distributed under the terms of The MIT License (MIT).