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

@e12e/ts-omni

v2.0.3

Published

TypeScript-first core library for any application — request/response models, validation, type-safe i18n, and DTO transformation.

Readme

@e12e/ts-omni

TypeScript-first core library for any application — request/response models, validation, type-safe i18n, and DTO transformation.

Installation

pnpm add @e12e/ts-omni

Peer dependencies (must be installed in your project):

pnpm add class-transformer class-validator

Quick Start

// Import specific modules (tree-shaking friendly)
import { validateObject, validateObjectSync } from "@e12e/ts-omni/validation";
import { ApiResponse } from "@e12e/ts-omni/response";
import { PaginatedQueryDto } from "@e12e/ts-omni/request/dto";

TypeScript Config

Enable decorators in your tsconfig.json:

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

Required for class-validator, class-transformer, and custom decorators like @Match, @IsValidFilter.

Modules

| Module | Import Path | Description | |--------|-------------|-------------| | Request | @e12e/ts-omni/request | Query types, sort, search, filter | | Request DTOs | @e12e/ts-omni/request/dto | Validated DTO classes | | Response | @e12e/ts-omni/response | ApiResponse wrapper (framework-agnostic) | | Response/Express | @e12e/ts-omni/response/express | Express adapter for ApiResponse | | Validation | @e12e/ts-omni/validation | Validators & custom decorators | | i18n | @e12e/ts-omni/i18n | Type-safe translations | | Util | @e12e/ts-omni/util | DTO transformation helper |


Request

Standardized query interfaces and DTOs for CRUD operations.

Types

import type {
  BaseQuery,
  PaginatedQuery,
  SearchParams,
  SortParams,
  ObjectFilter,
  FindOptions,
  FindByIdOptions,
} from "@e12e/ts-omni/request";

Paginated Query

interface User {
  id: number;
  name: string;
  email: string;
  status: "active" | "inactive";
}

const query: PaginatedQuery<User> = {
  page: 1,
  limit: 20,
  search: { keyword: "john", fields: ["name", "email"] },
  filter: { status: { eq: "active" } },
  sort: [{ field: "name", order: "asc" }],
};

Object Filter

Type-safe filtering with logical operators:

const filter: ObjectFilter<User> = {
  status: { eq: "active" },
  name: { contains: "john" },
  age: { gte: 18 },
  OR: [
    { name: { startsWith: "J" } },
    { name: { startsWith: "j" } },
  ],
};

Operators:

  • Single: eq, neq, gt, gte, lt, lte, contains, notContains, startsWith, endsWith, matches, isNull, isNotNull, isEmpty, isNotEmpty
  • Range: between, notBetween
  • List: in, notIn, hasAny, hasAll, hasNone

Helpers

import { withTiebreak, resolvePageSize, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE } from "@e12e/ts-omni/request";

// Add tiebreak for deterministic sorting
withTiebreak([{ field: "name", order: "asc" }]);
// → [{ field: "name", order: "asc" }, { field: "id", order: "asc" }]

// Resolve page size with limits
resolvePageSize({ page: 1, limit: 200 }); // → 100 (capped)

// Custom page size options
resolvePageSize({ page: 1, limit: 200 }, { maxPageSize: 50 }); // → 50

Request DTOs

Validated DTO classes with class-validator decorators.

import { validateObject } from "@e12e/ts-omni/validation";
import { PaginatedQueryDto, SearchParamsDto, SortParamsDto } from "@e12e/ts-omni/request/dto";

// Async version
const { success, data, errors } = await validateObject(PaginatedQueryDto, {
  page: 1,
  limit: 20,
  search: { keyword: "john", fields: ["name"] },
  sort: [{ field: "name", order: "asc" }],
});

// Or sync version (no await needed)
const { success: syncSuccess, data: syncData } = validateObjectSync(PaginatedQueryDto, {
  page: 1,
  limit: 20,
  search: { keyword: "john", fields: ["name"] },
  sort: [{ field: "name", order: "asc" }],
});

if (!success) {
  console.log(errors);
  // [{ field: "page", errors: { is_int: "page must be an integer number" } }]
}

Response

ApiResponse — Standardized model for API responses. Framework-agnostic by default, with Express integration available via @e12e/ts-omni/response/express.

import { ApiResponse } from "@e12e/ts-omni/response";

JSON Response

// Basic
return ApiResponse.json({ success: true, data: user });

// With DTO transformation
return ApiResponse.json(
  { success: true, data: newUser },
  { status: 201, resDTO: UserResponseDto }
);

// With cookies
return ApiResponse.json(
  { success: true, data: { accessToken: "sk_abc123" } },
  {
    status: 200,
    cookies: [{
      name: "refresh_token",
      value: "rt_xyz789",
      options: { httpOnly: true, secure: true, maxAge: 7 * 24 * 60 * 60 * 1000 },
    }],
  }
);

Redirect & HTML

return ApiResponse.redirect("https://example.com/new", { status: 301 });
return ApiResponse.html("<h1>Welcome!</h1>");

Fluent Metadata

return ApiResponse.json({ success: true, data: products })
  .setMetadata({ total: "150", page: "1" })
  .setMetadata({ traceId: "abc-123" });

Express Integration

If you're using Express, import sendToExpress from the Express adapter:

import { sendToExpress } from "@e12e/ts-omni/response/express";

const response = ApiResponse.json({ success: true, data: user });
sendToExpress(response, res);

Note: express is an optional peer dependency. Only install it if you use the Express adapter.

Types

| Type | Description | |------|-------------| | JsonResponse<T> | { success?, status?, message?, data?, error?, metadata? } | | ResponseError | { message?, type?, fields? } | | ResponseInit | { status?, headers?, cookies? } | | Cookie | { name, value, options: CookieOptions } | | CookieOptions | { path?, domain?, maxAge?, secure?, httpOnly?, sameSite? } | | PaginatedResponse<T> | { items, page, limit, total } |


Validation

Utilities built on class-validator and class-transformer.

validateObject

import { validateObject } from "@e12e/ts-omni/validation";

class LoginDTO {
  @IsEmail()
  email: string;

  @IsString()
  @MinLength(6)
  password: string;
}

const { success, data, errors } = await validateObject(LoginDTO, {
  email: "invalid",
});

validateObjectSync

Synchronous version — same API, no await needed. Uses validateSync from class-validator.

import { validateObjectSync } from "@e12e/ts-omni/validation";

const { success, data, errors } = validateObjectSync(LoginDTO, {
  email: "invalid",
});

Note: Only use validateObjectSync when all validators are synchronous. If your DTOs use async validators, stick with validateObject.

Custom Decorators

@Match / @NotMatch

import { Match, NotMatch } from "@e12e/ts-omni/validation";

class RegisterDTO {
  @IsString()
  @MinLength(6)
  password: string;

  @Match("password")
  confirmPassword: string;
}

class ChangeEmailDTO {
  @IsEmail()
  oldEmail: string;

  @IsEmail()
  @NotMatch("oldEmail")
  newEmail: string;
}

@MatchesRegex

import { MatchesRegex } from "@e12e/ts-omni/validation";

const PHONE_REGEX = /^\+?[1-9]\d{1,14}$/;

class UserDTO {
  @MatchesRegex(PHONE_REGEX, "invalid_phone_format")
  phone: string;
}

@IsValidFilter

import { IsValidFilter } from "@e12e/ts-omni/validation";

const filterConfig = {
  fields: {
    status: { operators: ["eq", "neq"] },
    name: { operators: ["contains", "startsWith"] },
  },
  maxDepth: 3,
  maxConditions: 5,
};

class UserQueryDto {
  @IsValidFilter(filterConfig)
  filter: Record<string, any>;
}

validateObjectFilter

import { validateObjectFilter } from "@e12e/ts-omni/validation";

const result = validateObjectFilter(
  { status: { eq: "active" } },
  { fields: { status: { operators: ["eq", "neq"] } } }
);
// { valid: true, errors: [] }

i18n

Type-safe translation system with dot-notation keys.

import { initTranslations, TranslationSchema } from "@e12e/ts-omni/i18n";

// 1. Define default locale
const en = {
  common: { ok: "OK" },
  auth: {
    login: {
      title: "Sign in",
      welcome: "Welcome, {name}!",
    },
  },
};

type Schema = typeof en;

// 2. Define other locales
const vi: TranslationSchema<Schema> = {
  common: { ok: "Đồng ý" },
  auth: {
    login: {
      title: "Đăng nhập",
      welcome: "Chào mừng, {name}!",
    },
  },
};

// 3. Initialize
const { getTranslations } = initTranslations<Schema, ["en", "vi"]>({
  messages: { en, vi },
});

// 4. Use
const t = getTranslations("en");
t("common.ok");                              // "OK"
t("auth.login.welcome", { name: "Eddie" }); // "Welcome, Eddie!"

Features: Type-safe keys, string interpolation, missing key warnings, max 8 levels depth.


Util

transformObject

Wraps class-transformer's plainToInstance with safe defaults.

import { transformObject } from "@e12e/ts-omni/util";
import { Expose } from "class-transformer";

class UserResponseDto {
  @Expose()
  id: number;

  @Expose()
  fullName: string;
}

const raw = { id: 1, fullName: "John", password: "secret" };
transformObject(UserResponseDto, raw);
// { id: 1, fullName: "John" }  ← password excluded

Defaults: excludeExtraneousValues: true, enableImplicitConversion: true


Peer Dependencies

| Package | Version | Required | |---------|---------|----------| | class-transformer | ^0.5.1 | Yes | | class-validator | ^0.15.1 | Yes | | express | ^4.0.0 || ^5.0.0 | Optional (only for Express adapter) |

License

MIT