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

@hy_ong/zod-kit

v0.2.1

Published

A comprehensive TypeScript library providing pre-built Zod validation schemas with full internationalization support for common data types and Taiwan-specific formats

Readme

Zod Kit

npm version License: MIT TypeScript

A comprehensive TypeScript library that provides pre-built validation schemas on top of Zod with full internationalization support. Streamline your form validation with battle-tested schemas for common data types and Taiwan-specific formats.

✨ Features

  • 🔍 Pre-built schemas - Common validation patterns ready to use
  • 🌐 i18n support - English and Traditional Chinese localization
  • 📝 TypeScript-first - Full type safety and IntelliSense support
  • Lightweight - Minimal dependencies with Zod as peer dependency
  • 🎯 Highly configurable - Flexible options for every use case
  • 🇹🇼 Taiwan-specific - National ID, business ID, phone numbers, postal codes, etc.
  • Date/Time support - Comprehensive datetime, time, and date validation
  • 📎 File validation - MIME type filtering, size constraints, and file type checking
  • 🧪 Battle-tested - Comprehensive test suite with 700+ tests

📦 Installation

npm install @hy_ong/zod-kit zod
yarn add @hy_ong/zod-kit zod
pnpm add @hy_ong/zod-kit zod

Note: Zod is a peer dependency (^4.3.6) and must be installed separately.

🚀 Quick Start

import { email, password, text, mobile, datetime, time, postalCode } from '@hy_ong/zod-kit'

// Simple email validation (required by default)
const emailSchema = email(true)
emailSchema.parse('[email protected]') // ✅ "[email protected]"

// Optional email
const optionalEmail = email(false)
optionalEmail.parse(null) // ✅ null

// Password with complexity requirements
const passwordSchema = password(true, {
  minLength: 8,
  requireUppercase: true,
  requireDigits: true,
  requireSpecialChars: true
})

// Taiwan mobile phone validation
const phoneSchema = mobile(true)
phoneSchema.parse('0912345678') // ✅ "0912345678"

// DateTime validation
const datetimeSchema = datetime(true)
datetimeSchema.parse('2024-03-15 14:30') // ✅ "2024-03-15 14:30"

// Time validation
const timeSchema = time(true)
timeSchema.parse('14:30') // ✅ "14:30"

// Taiwan postal code validation
const postalSchema = postalCode(true)
postalSchema.parse('100001') // ✅ "100001"

📚 API Reference

Common Validators

email(required?, options?)

Validates email addresses with comprehensive format checking.

Parameters:

  • required (boolean, optional): Whether the field is required. Default: false
  • options (object, optional): Configuration options
import { email } from '@hy_ong/zod-kit'

// Required email (recommended)
const requiredEmail = email(true)

// Optional email
const optionalEmail = email(false)
optionalEmail.parse(null) // ✅ null

// With options
const advancedEmail = email(true, {
  allowedDomains: ['gmail.com', 'company.com'],
  minLength: 5,
  maxLength: 100,
  transform: (val) => val.toLowerCase(),
  defaultValue: '[email protected]',
  i18n: {
    en: { invalid: 'Please enter a valid email' },
    'zh-TW': { invalid: '請輸入有效的電子郵件' }
  }
})

password(required?, options?)

Validates passwords with customizable complexity requirements.

Parameters:

  • required (boolean, optional): Whether the field is required. Default: false
  • options (object, optional): Configuration options
import { password } from '@hy_ong/zod-kit'

// Required password with complexity rules
const passwordSchema = password(true, {
  minLength: 8,             // Minimum length
  maxLength: 128,           // Maximum length
  requireUppercase: true,   // Require A-Z
  requireLowercase: true,   // Require a-z
  requireDigits: true,      // Require 0-9
  requireSpecialChars: true,// Require !@#$%^&*
  customPatterns: [
    { pattern: /[A-Z]/, message: 'Need uppercase' }
  ]
})

// Optional password
const optionalPassword = password(false)

text(required?, options?)

General text validation with length and pattern constraints.

import { text } from '@hy_ong/zod-kit'

const nameSchema = text(true, {
  minLength: 2,
  maxLength: 50,
  pattern: /^[a-zA-Z\s]+$/,
  transform: (val) => val.trim()
})

const optionalText = text(false)

number(required?, options?)

Validates numeric values with range and type constraints.

import { number } from '@hy_ong/zod-kit'

const ageSchema = number(true, {
  min: 0,
  max: 150,
  integer: true,
  positive: true
})

const optionalNumber = number(false)

url(required?, options?)

URL validation with protocol and domain restrictions.

import { url } from '@hy_ong/zod-kit'

const urlSchema = url(true, {
  protocols: ['https'],         // Only HTTPS allowed
  allowedDomains: ['safe.com'], // Domain whitelist
  requireTLD: true             // Require top-level domain
})

const optionalUrl = url(false)

boolean(required?, options?)

Boolean validation with flexible input handling.

import { boolean } from '@hy_ong/zod-kit'

const consentSchema = boolean(true, {
  trueValues: ['yes', '1', 'true'],  // Custom truthy values
  falseValues: ['no', '0', 'false'] // Custom falsy values
})

const optionalBoolean = boolean(false)

datetime(required?, options?)

Validates datetime with comprehensive format support and timezone handling.

import { datetime } from '@hy_ong/zod-kit'

// Basic datetime validation
const basicSchema = datetime(true)
basicSchema.parse('2024-03-15 14:30') // ✓ Valid

// Business hours validation
const businessHours = datetime(true, {
  format: 'YYYY-MM-DD HH:mm',
  minHour: 9,
  maxHour: 17,
  weekdaysOnly: true
})

// Timezone-aware validation
const timezoneSchema = datetime(true, {
  timezone: 'Asia/Taipei',
  mustBeFuture: true
})

// Multiple format support
const flexibleSchema = datetime(true, {
  format: 'DD/MM/YYYY HH:mm'
})
flexibleSchema.parse('15/03/2024 14:30') // ✓ Valid

// Optional datetime
const optionalDatetime = datetime(false)

time(required?, options?)

Time validation with multiple formats and constraints.

import { time } from '@hy_ong/zod-kit'

// Basic time validation (24-hour format)
const basicSchema = time(true)
basicSchema.parse('14:30') // ✓ Valid

// 12-hour format with AM/PM
const ampmSchema = time(true, { format: 'hh:mm A' })
ampmSchema.parse('02:30 PM') // ✓ Valid

// Business hours validation
const businessHours = time(true, {
  format: 'HH:mm',
  minHour: 9,
  maxHour: 17,
  minuteStep: 15 // Only :00, :15, :30, :45
})

// Time range validation
const timeRangeSchema = time(true, {
  min: '09:00',
  max: '17:00'
})

// Optional time
const optionalTime = time(false)

date(required?, options?)

Date validation with range and format constraints.

import { date } from '@hy_ong/zod-kit'

const birthdateSchema = date(true, {
  format: 'YYYY-MM-DD',
  minDate: '1900-01-01',
  maxDate: new Date(),
  timezone: 'Asia/Taipei'
})

const optionalDate = date(false)

file(required?, options?)

File validation with MIME type filtering and size constraints.

import { file } from '@hy_ong/zod-kit'

// Basic file validation
const basicSchema = file(true)
basicSchema.parse(new File(['content'], 'test.txt'))

// Size restrictions
const sizeSchema = file(true, {
  maxSize: 1024 * 1024, // 1MB
  minSize: 1024 // 1KB
})

// Extension restrictions
const imageSchema = file(true, {
  extension: ['.jpg', '.png', '.gif'],
  maxSize: 5 * 1024 * 1024 // 5MB
})

// MIME type restrictions
const documentSchema = file(true, {
  type: ['application/pdf', 'application/msword'],
  maxSize: 10 * 1024 * 1024 // 10MB
})

// Image files only
const imageOnlySchema = file(true, { imageOnly: true })

// Optional file
const optionalFile = file(false)

id(required?, options?)

Flexible ID validation supporting multiple formats.

import { id } from '@hy_ong/zod-kit'

const userIdSchema = id(true, {
  type: 'uuid',              // 'uuid', 'nanoid', 'objectId', 'auto', etc.
  allowedTypes: ['uuid', 'nanoid'], // Multiple allowed types
  customRegex: /^USR_[A-Z0-9]+$/    // Custom pattern
})

const optionalId = id(false)

Taiwan-Specific Validators

nationalId(required?, options?)

Validates Taiwan National ID (身份證字號).

import { nationalId } from '@hy_ong/zod-kit'

const idSchema = nationalId(true, {
  normalize: true,  // Convert to uppercase
  whitelist: ['A123456789'] // Allow specific IDs
})

idSchema.parse('A123456789') // ✅ Valid Taiwan National ID

const optionalId = nationalId(false)

businessId(required?, options?)

Validates Taiwan Business ID (統一編號).

import { businessId } from '@hy_ong/zod-kit'

const bizSchema = businessId(true)
bizSchema.parse('12345675') // ✅ Valid business ID with checksum

const optionalBizId = businessId(false)

mobile(required?, options?)

Validates Taiwan mobile phone numbers.

import { mobile } from '@hy_ong/zod-kit'

const phoneSchema = mobile(true, {
  allowInternational: true,  // Allow +886 prefix
  allowSeparators: true,     // Allow 0912-345-678
  operators: ['09']          // Restrict to specific operators
})

const optionalMobile = mobile(false)

tel(required?, options?)

Validates Taiwan landline telephone numbers.

import { tel } from '@hy_ong/zod-kit'

const landlineSchema = tel(true, {
  allowSeparators: true,     // Allow 02-1234-5678
  areaCodes: ['02', '03']    // Restrict to specific areas
})

const optionalTel = tel(false)

fax(required?, options?)

Validates Taiwan fax numbers (same format as landline).

import { fax } from '@hy_ong/zod-kit'

const faxSchema = fax(true)
faxSchema.parse('02-2345-6789') // ✅ Valid fax number

const optionalFax = fax(false)

postalCode(required?, options?)

Validates Taiwan postal codes with support for 3-digit, 5-digit, and 6-digit formats.

import { postalCode } from '@hy_ong/zod-kit'

// Accept 3-digit or 6-digit formats (recommended)
const modernSchema = postalCode(true)
modernSchema.parse('100')     // ✅ Valid 3-digit
modernSchema.parse('100001')  // ✅ Valid 6-digit

// Accept all formats
const flexibleSchema = postalCode(true, { format: 'all' })
flexibleSchema.parse('100')     // ✅ Valid
flexibleSchema.parse('10001')   // ✅ Valid (5-digit legacy)
flexibleSchema.parse('100001')  // ✅ Valid

// Only 6-digit format (current standard)
const modernOnlySchema = postalCode(true, { format: '6' })
modernOnlySchema.parse('100001') // ✅ Valid
modernOnlySchema.parse('100')    // ❌ Invalid

// With dashes allowed
const dashSchema = postalCode(true, { allowDashes: true })
dashSchema.parse('100-001')  // ✅ Valid (normalized to '100001')

// Specific areas only
const taipeiSchema = postalCode(true, {
  allowedPrefixes: ['100', '103', '104', '105', '106']
})
taipeiSchema.parse('100001') // ✅ Valid (Taipei area)
taipeiSchema.parse('200001') // ❌ Invalid (not in allowlist)

// Optional postal code
const optionalPostal = postalCode(false)

🌐 Internationalization

Zod Kit supports multiple languages for error messages:

import { setLocale } from '@hy_ong/zod-kit'

// Set global locale
setLocale('zh-TW') // Traditional Chinese
setLocale('en')    // English (default)

// Or use custom messages per validator
const emailSchema = email(true, {
  i18n: {
    en: {
      required: 'Email is required',
      invalid: 'Please enter a valid email address'
    },
    'zh-TW': {
      required: '請輸入電子郵件',
      invalid: '請輸入有效的電子郵件格式'
    }
  }
})

🎨 Advanced Usage

Optional Fields

Make any field optional by passing false as the first argument:

const optionalEmail = email(false)

optionalEmail.parse(null)      // ✅ null
optionalEmail.parse('')        // ✅ null
optionalEmail.parse('[email protected]') // ✅ "[email protected]"

Custom Transformations

Transform values during validation:

const trimmedText = text(true, {
  transform: (val) => val.trim().toLowerCase(),
  minLength: 1
})

trimmedText.parse('  HELLO  ') // ✅ "hello"

Default Values

Provide default values for empty inputs:

const emailWithDefault = email(true, {
  defaultValue: '[email protected]'
})

emailWithDefault.parse('')   // ✅ "[email protected]"
emailWithDefault.parse(null) // ✅ "[email protected]"

Whitelist Validation

Allow specific values regardless of format:

const flexibleId = id(true, {
  type: 'uuid',
  whitelist: ['admin', 'system', 'test-user']
})

flexibleId.parse('admin')                    // ✅ "admin"
flexibleId.parse('550e8400-e29b-41d4-a716-446655440000') // ✅ Valid UUID

Combining Validators

Use with Zod's composition features:

import { z } from 'zod'
import { email, password } from '@hy_ong/zod-kit'

const userSchema = z.object({
  email: email(true),
  password: password(true, { minLength: 8 }),
  confirmPassword: z.string()
}).refine(data => data.password === data.confirmPassword, {
  message: "Passwords don't match"
})

🛠️ Development

# Clone the repository
git clone https://github.com/hy-ong/zod-kit.git
cd zod-kit

# Install dependencies
npm install

# Run tests
npm test

# Build the package
npm run build

# Run tests in watch mode
npx vitest --watch

🧪 Testing

The library includes comprehensive tests covering:

  • ✅ All validator functions
  • ✅ Edge cases and error conditions
  • ✅ Internationalization
  • ✅ TypeScript type safety
  • ✅ Taiwan-specific format validation
npm test                    # Run all tests
npx vitest --coverage      # Run with coverage report

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📊 Project Stats

GitHub stars GitHub forks GitHub issues

🙏 Acknowledgments

  • Built on top of the amazing Zod library
  • Inspired by real-world validation needs in Taiwan's tech ecosystem
  • Thanks to all contributors and users

Made with ❤️ by Ong Hoe Yuan

For questions or support, please open an issue on GitHub.