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

@krishanmarco/epizod

v0.0.3

Published

Isomorphic (browser + Node.js) TypeScript library, published as dual CJS + ESM.

Downloads

499

Readme

@krishanmarco/epizod

Serialize Zod schemas to JSON and back, and render them to TypeScript source. The same source runs unchanged in the browser and in Node.js, and ships as dual CJS + ESM.

What it does

epizod does two things with a Zod schema:

  1. Serialize and deserialize. epizodSerialize turns a schema into a JSON-safe value you can store in a text or jsonb column; epizodDeserialize rebuilds an equivalent schema from it. The round-trip preserves both .parse behaviour and the TypeScript render.
  2. Render to TypeScript. epizodZodToTypescript turns a schema into its TypeScript type source — objects, unions, tuples, function signatures, the exotic types (date/bigint/map/set/promise/…), and recursive schemas (emitted as named Auxiliary_N aliases).

The serialized form is branded (EpiSerializable), so a raw object — or another library's serialized schema, such as a JSON Schema — cannot reach epizodDeserialize. Produce one with epizodSerialize, or validate untrusted input (a database read) with epizodAsSerializable.

Install

pnpm add @krishanmarco/epizod zod

zod is a peer dependency, so epizod uses the schema library you already have. The only runtime dependency is typescript, which the renderer calls at runtime.

Usage

Store a schema and read it back

import { epizodSerialize, epizodAsSerializable, epizodDeserialize } from '@krishanmarco/epizod';
import { z } from 'zod';

const contract = z.object({
  name: z.string().describe('A human label'),
  startedAt: z.date(),
  retryIds: z.set(z.string()),
  total: z.bigint(),
  mode: z.enum(['fast', 'slow']),
});

// Serialize to a JSON-safe value and persist it.
const stored = epizodSerialize(contract); // EpiSerializable
await db.save(JSON.stringify(stored));

// Later: validate the untrusted read, then rebuild the schema.
const serialized = epizodAsSerializable(JSON.parse(await db.load()));
const schema = epizodDeserialize(serialized);
schema.parse({ name: 'x', startedAt: new Date(), retryIds: new Set(), total: 1n, mode: 'fast' });

Render a schema to TypeScript

import { epizodZodToTypescript } from '@krishanmarco/epizod';
import { z } from 'zod';

epizodZodToTypescript(z.object({ a: z.string(), b: z.number().optional() }));
// {
//     a: string;
//     b?: number;
// }

API

| Function | Signature | Purpose | |----------|-----------|---------| | epizodSerialize | (schema, options?) => EpiSerializable | Zod schema → JSON-safe branded value. Throws on a construct it cannot carry. | | epizodDeserialize | (serialized, options?) => z.ZodType | EpiSerializable → equivalent Zod schema. | | epizodAsSerializable | (value) => EpiSerializable | Validate an untrusted value as a serialized schema — the only sanctioned way to brand outside input. Throws otherwise. | | epizodZodToTypescript | (schema, options?) => string | Zod schema → TypeScript type source. |

DeserializeOptions carries transforms — re-supplied implementations for any transform captured in the schema, because a function body is never serialized. ZodToTypescriptOptions carries optionalPropertyStyle ('question-mark' or 'undefined-union') and singleLineComments.

Nomenclature

The vocabulary of the domain. Add a row the moment a term earns a name, before it drifts into three synonyms.

| Term | Meaning | |------|---------| | serialize | Turn a Zod schema into an EpiSerializable (epizodSerialize). | | deserialize | Rebuild an equivalent Zod schema from an EpiSerializable (epizodDeserialize). | | render | Turn a Zod schema into TypeScript type source (epizodZodToTypescript). | | round-trip | serialize → deserialize; faithful in both .parse and render. | | EpiSerializable | The branded, JSON-safe serialized form of a schema — the stored format. | | auxiliary type | A generated type Auxiliary_N = … alias standing in for a recursive schema in the render. |

Package shape

  • Isomorphic — the same source runs in the browser and in Node.js.
  • Dual formattsup emits ESM (dist/index.mjs) and CJS (dist/index.js) from one source, with per-format type declarations (.d.mts and .d.ts).
  • zod and typescript stay externalzod resolves against your install (the peer), typescript against epizod's own.

Development

| Script | What it does | |--------|--------------| | pnpm build | Bundle CJS + ESM + type declarations into dist/ (tsup) | | pnpm typecheck | tsc --noEmit over the source | | pnpm test | Run the mocha + chai suite (src/**/*.test.ts) via tsx | | pnpm lint | ESLint (with dprint formatting) using the vendored SDK config | | pnpm lint:fix | Same, applying autofixes |

src/index.test.ts pins the public surface by snapshot: the serialized JSON is a stored format and the rendered TypeScript is generated code, so both are asserted whole and cannot drift silently.

Repository layout

| Path | Purpose | |------|---------| | src/index.ts | The public barrel — the only published entry point. | | src/serializer/ | epizodSerialize / epizodDeserialize / epizodAsSerializable and the EpiSerializable brand. | | src/to-typescript/ | epizodZodToTypescript. | | src/modules/zodex/ | Vendored schema ↔ JSON codec (zerialize / dezerialize), adapted to Zod 4. | | src/modules/zod-to-ts/ | Vendored schema → TypeScript renderer, adapted to Zod 4. | | sdk/ | Vendored slice of the Epilogo SDK's src/dev/ — the ESLint config, import-boundary plugin, and expect test helper — so @epilogo/sdk/dev/... imports resolve without depending on the SDK. | | dev/ | Test infrastructure (the snapshot helper and its __snapshots__). Never bundled or published. | | patches/ | pnpm patch disabling dprint's Dockerfile formatter. | | tsup.config.ts | Dual CJS/ESM build configuration. |

Linting and formatting

ESLint is wired through .eslintrc.js, which loads the vendored config at sdk/dev/eslint/eslintrc.js — the same configuration and custom import-boundary plugin the SDK uses, copied in because epizod has no SDK dependency. Refresh it by re-copying from the SDK's src/dev/eslint/.