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

@mikael_tenshio/schema-guardian

v1.1.2

Published

A TypeScript-first schema validator with built-in multilingual error messages and RTL-aware locale detection.

Readme

schema-guardian

schema-guardian is a TypeScript-first validation library for global products. It ships with built-in translations, locale negotiation, and RTL-aware errors so teams can validate once and return user-facing messages in the right language without maintaining a huge error-message catalog by hand.

Highlights

  • Built-in i18n for validation messages
  • Automatic locale negotiation from explicit locale, browser hints, or Accept-Language
  • dir metadata for clean RTL rendering
  • Context-aware messages using field labels and schema paths
  • Structured errors with issues and flatten()
  • Immutable-style schema builders for safer reuse
  • Production scripts and CI workflows for build, typecheck, test, and pack validation

Installation

npm install schema-guardian

Quick start

import { S } from 'schema-guardian';

const signupSchema = S.object({
  name: S.string().label('Name').trim().min(5),
  email: S.string().label('Email').trim().email(),
  age: S.number().label('Age').integer().min(18).optional(),
  roles: S.array(S.enum(['admin', 'editor', 'viewer'] as const)).min(1),
  acceptedTerms: S.boolean().label('Terms').refine((value) => value, 'Terms must be accepted'),
}).strict();

const result = signupSchema.safeParse(
  {
    name: 'Aya',
    email: 'invalid-email',
    roles: [],
    acceptedTerms: false,
  },
  {
    acceptLanguage: 'ja-JP,fr;q=0.8,en;q=0.7',
  },
);

if (!result.success) {
  console.log(result.error.message);
  console.log(result.error.locale);
  console.log(result.error.dir);
  console.log(result.error.flatten());
}

API overview

import { S } from 'schema-guardian';

S.string().trim().min(3).max(20).email().optional();
S.number().integer().min(0).max(100);
S.boolean();
S.enum(['draft', 'published'] as const);
S.array(S.string()).min(1).max(10);
S.object({
  id: S.string(),
  tags: S.array(S.string()).optional(),
});

All schemas support:

  • .label('Field name')
  • .optional()
  • .refine((value) => boolean, message?)
  • .parse(value, options?)
  • .safeParse(value, options?)

Locale resolution

Locales are resolved in this order:

  1. safeParse(..., { locale })
  2. i18n.setLocale(...)
  3. safeParse(..., { browserLanguages })
  4. safeParse(..., { acceptLanguage })
  5. Runtime browser languages from navigator.languages
  6. Default locale, which is English by default
import { i18n } from 'schema-guardian';

i18n.setDefaultLocale('fr');
i18n.setLocale('ar');

Built-in locales

The package currently ships with these bundled locales:

  • ar
  • de
  • en
  • es
  • fr
  • he
  • hi
  • id
  • it
  • ja
  • ko
  • nl
  • pt
  • ru
  • tl with fil alias support
  • tr
  • vi
  • zh-CN
  • zh-TW

You can import all locale exports:

import { es, fr, ja, zhCN } from 'schema-guardian/locales';

Or import a specific locale file:

import { pt } from 'schema-guardian/locales/pt';

Custom locales

import { i18n, type LocaleDefinition } from 'schema-guardian';

const pirate: LocaleDefinition = {
  code: 'pirate',
  dir: 'ltr',
  messages: {
    common: {
      required: (context) => context.label ? `${context.label} be required` : 'This field be required',
      invalidType: (context) => `${context.label ?? 'This field'} must be ${context.expected ?? 'valid cargo'}`,
      objectType: (context) => `${context.label ?? 'This field'} must be an object`,
      arrayType: (context) => `${context.label ?? 'This field'} must be an array`,
      unknownKey: (context) => `${context.label ?? 'This field'} be forbidden`,
      custom: (context) => `${context.label ?? 'This field'} be invalid`,
    },
    array: {
      min: (context) => `${context.label ?? 'This field'} must contain at least ${context.minimum} items`,
      max: (context) => `${context.label ?? 'This field'} must contain at most ${context.maximum} items`,
    },
    string: {
      min: (context) => `${context.label ?? 'This field'} must be at least ${context.minimum} characters`,
      max: (context) => `${context.label ?? 'This field'} must be at most ${context.maximum} characters`,
      email: (context) => `${context.label ?? 'This field'} must be a valid email address`,
    },
    enum: {
      invalid: (context) => `${context.label ?? 'This field'} must be one of: ${(context.options ?? []).join(', ')}`,
    },
    number: {
      min: (context) => `${context.label ?? 'This field'} must be greater than or equal to ${context.minimum}`,
      max: (context) => `${context.label ?? 'This field'} must be less than or equal to ${context.maximum}`,
      integer: (context) => `${context.label ?? 'This field'} must be a whole number`,
    },
  },
};

i18n.register(pirate);

Production workflow

npm run validate
npm run pack:check

Those commands run:

  • typecheck
  • tests
  • build
  • npm pack --dry-run

GitHub Actions are included for CI and publish flows under .github/workflows.