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

@fluojs/serialization

v1.0.0-beta.6

Published

Class-based response serialization and output shaping interceptors for Fluo.

Readme

@fluojs/serialization

Class-based response serialization and output shaping for fluo with decorator-aware recursive object walking.

Table of Contents

Installation

pnpm add @fluojs/serialization

When to Use

  • when you need output DTOs to expose only a controlled subset of fields
  • when sensitive values such as password hashes or internal identifiers must never leave the response boundary
  • when response data needs lightweight synchronous transforms during serialization
  • when you want an HTTP interceptor to apply the same serialization rules automatically

Quick Start

import { Exclude, Expose, Transform, serialize } from '@fluojs/serialization';

class UserEntity {
  @Expose()
  id = '';

  @Expose()
  @Transform((value) => value.toUpperCase())
  username = '';

  @Exclude()
  passwordHash = '';
}

const user = Object.assign(new UserEntity(), {
  id: '1',
  username: 'fluo',
  passwordHash: 'secret',
});

console.log(serialize(user));
// { id: '1', username: 'FLUO' }

Common Patterns

Expose-only output DTOs

import { Expose } from '@fluojs/serialization';

@Expose({ excludeExtraneous: true })
class SecureDto {
  @Expose()
  publicData = 'visible';

  internalData = 'hidden';
}

Value transforms

import { Transform } from '@fluojs/serialization';

class ProductDto {
  @Transform((price) => `$${price.toFixed(2)}`)
  price = 0;
}

When the same field is decorated in a base class and a derived class, transforms run in declaration order from base to derived.

HTTP response shaping with an interceptor

import { Controller, Get, UseInterceptors } from '@fluojs/http';
import { SerializerInterceptor } from '@fluojs/serialization';

@Controller('/users')
@UseInterceptors(SerializerInterceptor)
class UsersController {
  @Get('/')
  findAll() {
    return [new UserEntity()];
  }
}

SerializerInterceptor only serializes values that still belong to the normal HTTP response writer. If a handler or response helper commits RequestContext.response directly, such as an SSE stream, the interceptor returns that handler-owned value unchanged so the request pipeline preserves response ownership.

Cycle-safe serialization

The serializer cuts active cyclic references safely instead of recursing forever, so complex object graphs can still be turned into plain response-shaped objects without unbounded recursion. Completed shared references are reused in the serialized graph rather than dropped: if two sibling fields point at the same source object, both serialized fields point at the same serialized object. Only an object that is encountered again while it is already being serialized is cut to undefined.

Inherited decorator contracts

Serialization metadata declared on a base class is inherited by derived DTOs. @Expose(), @Exclude(), and @Transform() rules applied to shared base fields still take effect when you serialize subclass instances.

Class-level excludeExtraneous also follows normal inheritance. A derived class with @Expose() and no options keeps the nearest inherited setting, so an expose-only base DTO remains expose-only in subclasses. Use @Expose({ excludeExtraneous: false }) on the derived class only when you intentionally want to re-enable ordinary enumerable fields while still honoring inherited field-level @Exclude() metadata.

Undecorated class instances are still traversed recursively, so decorated nested descendants are respected even when the parent object has no serialization metadata.

Plain-object safety

serialize() treats plain objects and null-prototype records as data containers, not decorated class instances. Enumerable symbol keys are serialized, own __proto__, constructor, and prototype keys are treated as data rather than prototype mutations, and objects with custom or unsafe constructor fields are walked safely without throwing.

Non-JSON leaf values

serialize() applies decorator metadata and recursively walks arrays/plain objects, but it does not coerce every leaf into strict JSON types. Opaque built-ins such as Date, Map, Set, URL, URLSearchParams, RegExp, Error, ArrayBuffer, typed arrays, WeakMap, WeakSet, and Promise pass through unchanged instead of being flattened as DTO-like class instances. Values such as bigint, functions, and symbols can also pass through unchanged unless you normalize them with @Transform(...) or before writing the final HTTP response.

Public API Overview

  • Decorators: Expose, Exclude, Transform
  • Engine: serialize(value)
  • HTTP integration: SerializerInterceptor

Expose can be applied to classes and fields. Exclude and Transform apply to fields.

Related Packages

  • @fluojs/http: applies SerializerInterceptor to HTTP handlers
  • @fluojs/validation: handles input-side DTO materialization and validation

Example Sources

  • packages/serialization/src/serialize.test.ts
  • packages/serialization/src/serializer-interceptor.test.ts