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 🙏

© 2025 – Pkg Stats / Ryan Hefner

rehydrator

v1.1.0

Published

Rehydrator lets you serialize otherwise unserializable values by capturing the function call that generated them.

Readme

Rehydrator

rehydrator lets you serialize otherwise unserializable values by capturing the function call that generated them -- not just the output.

Great for DSLs, schema systems, and anywhere you want portable, replayable intent.

Install

npm i -S rehydrator

Usage

import { serializable, createReviver } from "rehydrator";

const date = serializable("date", (iso: str) => new Date(iso));

const data = {
  name: "Gabe Newell",
  dob: date("1962-11-03"),
};

const json = JSON.stringify(data);

// json = '{name: "Gabe Newell", dob: {__fn: "date", input: ["1962-11-03"]}}'

const rehydrated = JSON.parse(json, createReviver([date]));

assert(rehydrated.dob instanceof Date); // works!

That's basically it!

Use for DSLs

This library is especially handy for DSLs, validators, or any structured function-based system.

For example, a simple zod-style validator:

function string() {
  return (obj: unknown): obj is string => typeof obj === "string";
}

const schema = string();

Since schema is a function, ordinarily it wouldn't be serializable, so we couldn't store a schema in a database for example.

However, with rehydrator, we can make it serializable:

const string = serializable(
  "string",
  () =>
    (obj: unknown): obj is string =>
      typeof obj === "string",
);

const schema = string();

const json = JSON.stringify(schema);

// json = '{"__fn": "string", "input": []}'

Now your schema is fully portable — you can store it in a database, share it across environments, or reconstruct it on-demand.

How does it work?

serializable wraps the function with another function that adds a toJSON method to the original function's return value. JSON.stringify automatically calls toJSON methods if they exist, which in this case will return a meta object describing the function call, rather than the value itself.

Formats

The default format is designed to minimize the chances of interpreting arbitrary JSON data as a function call to be deserialized. The default deserializer treats an object as a function call if it looks like the following:

{ "__fn": "myFunctionName", "input": ["arg1", "arg2"] }

This is a bit verbose though, so I also defined a "short format", which looks like this:

{ "$myFunctionName": ["arg1", "arg2"] }

If the data you're serializing contains arbitrary object keys that start with $ and might be arrays, then this format will not be suitable, as the deserializer will incorrectly guess that arbitrary data is a function call to be deserialized. Otherwise, to use:

import { createFormat, shortFormat } from "rehydrator";

const { serializable, createReviver } = createFormat(shortFormat);

// use as normal

As an example of when not to use this format, perhaps you're defining some sort of mongodb-style query language that uses special keys prefixed with $ signs:

const expr = serializable("expr", (options) => {
  /* ... */
});

// when this gets serialized, it will be:
// {"$expr": [{"$and": [1, 2]}]}
const data = expr({ $and: [1, 2] });

When this gets deserialized again, it will want to find a function called and, which is probably not what you want.

Custom formats

You can also create your own formats, by passing serializer and deserializer functions to createFormat.