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

nox-mongo-driver

v1.4.0

Published

A fast runtime schema-driven sanitizer & validator for dynamic schemas — alternative to Mongoose validation for multi-tenant apps.

Downloads

257

Readme

nox-mongo-driver

A fast, async-first, schema-driven payload sanitizer, validator & composable rule engine for Node.js and MongoDB applications. Built as a lightweight alternative to Mongoose validation — ideal for multi-tenant systems where schemas are defined dynamically at runtime.

npm version License: MIT

Interactive Docs & Playground: nox-sanitizer.nowonlinetech.in

Installation

npm install nox-mongo-driver

Quick Start

import { sanitize } from "nox-mongo-driver";

const schema = {
  name: { type: "String", required: true, trim: true },
  age: { type: "Number", validation: { _between: [18, 65] } },
  email: {
    type: "String",
    validation: {
      _and: [
        { _regex: "^[^@]+@[^@]+\\.[a-zA-Z]{2,}$" },
        { _not: { _contains: "spam" } },
      ],
    },
  },
};

const { value, errors } = await sanitize(
  { name: "  Sahil ", age: "25", email: "[email protected]" },
  schema,
  { mode: "strict" }
);

// value → { name: "Sahil", age: 25, email: "[email protected]" }
// errors → []

Try this example live in the Playground

Features

Schema Sanitizer

  • Three processing modes — strict, transform, validate (docs)
  • Type coercion — strings to numbers, booleans, dates, ObjectIds
  • Rule validation — required, min/max, enum, regex, minLength/maxLength
  • Nested objects & arrays — inline and explicit styles
  • Bare Object / Array types — type-only validation without nested schema
  • Recursive schemas — self-referencing via lazy functions
  • Custom validators — sync and async with context injection
  • Setter functions — transform values before coercion
  • Immutable fields — prevent updates on specific fields
  • Auto timestamps — createdAt / updatedAt with customizable field names
  • Partial mode — skip required checks for PATCH / update operations
  • Bulk sanitization — process arrays of payloads with concurrency control
  • Cleanup options — strip nulls, empty objects, empty arrays, undefined
  • Unknown field handling — strip, keep, or error
  • Prototype pollution protection — blocks __proto__, constructor, prototype
  • i18n support — custom error messages per language
  • Stop on first error — bail early for performance

Composable Rule Engine

  • 20 comparison operators_eq, _neq, _lt, _lte, _gt, _gte, _in, _nin, _contains, _contains_i, _starts_with, _starts_with_i, _ends_with, _ends_with_i, _is_null, _regex, _between, _length, _empty, _not_empty (operator reference)
  • 3 logical operators_and, _or, _not (unlimited nesting)
  • Cross-field references_ref to compare against sibling, parent, or root fields
  • Conditional validationwhen to apply rules based on another field's value
  • Per-operator error codes — each operator produces its own specific error code and message (error codes)
  • i18n per operator — translate each operator message independently

Documentation

Full interactive documentation with live playground, operator reference, schema options, and error codes:

nox-sanitizer.nowonlinetech.in

  • Playground — edit schemas, payloads, and options live with 34 preset examples
  • Operator Reference — all 23 operators with descriptions, examples, and error codes
  • Features — detailed docs for every feature with code examples
  • Schema Options — searchable table of all 21 schema field options
  • Error Codes — all 37 error codes with triggers and default messages

Modes

| Mode | Type Validation | Rule Validation | Transformation | | ----------- | --------------- | --------------- | -------------- | | strict | Yes | Yes | Yes | | transform | Yes | No | Yes | | validate | Yes | Yes | No |

await sanitize(payload, schema, { mode: "transform" });

Schema Field Options

Full searchable reference: Schema Options

{
  type: "String" | "Number" | "Boolean" | "Date" | "ObjectId" | "Object" | "Array" | "Mixed",
  required: boolean,
  default: any | (() => any),
  enum: any[],
  match: RegExp,
  min: number,
  max: number,
  minLength: number,
  maxLength: number,
  trim: boolean,
  lowercase: boolean,
  uppercase: boolean,
  immutable: boolean,
  set: (value, context) => any,
  validate: (value, context) => boolean | string,
  asyncValidate: async (value, context) => boolean | string,
  validation: { /* composable rule engine */ },
  when: { field, is, then, otherwise },
}

Composable Rule Engine (validation key)

Interactive examples: Playground > Operators

The validation key on any schema field accepts a composable rule tree. Rules can be nested with _and, _or, and _not.

Comparison Operators

Full reference with error codes: Operator Reference

| Operator | Description | Example | |---|---|---| | _eq | Equals | { _eq: "active" } | | _neq | Not equals | { _neq: "deleted" } | | _lt | Less than | { _lt: 100 } | | _lte | Less than or equal | { _lte: 65 } | | _gt | Greater than | { _gt: 0 } | | _gte | Greater than or equal | { _gte: 18 } | | _in | Value in array | { _in: ["admin", "editor"] } | | _nin | Value not in array | { _nin: ["banned"] } | | _contains | String contains | { _contains: "hello" } | | _contains_i | Contains (case insensitive) | { _contains_i: "Hello" } | | _starts_with | Starts with | { _starts_with: "admin" } | | _starts_with_i | Starts with (case insensitive) | { _starts_with_i: "Admin" } | | _ends_with | Ends with | { _ends_with: ".pdf" } | | _ends_with_i | Ends with (case insensitive) | { _ends_with_i: ".PDF" } | | _is_null | Is null/undefined | { _is_null: true } | | _regex | Regex match | { _regex: "^[A-Z]" } or { _regex: { pattern: "^[a-z]", flags: "i" } } | | _between | Value in range (inclusive) | { _between: [18, 65] } | | _length | Check string/array length | { _length: { _gte: 3, _lte: 50 } } | | _empty | Is empty (string/array/object/null) | { _empty: true } | | _not_empty | Is not empty | { _not_empty: true } |

Logical Operators

// _and — all conditions must pass
validation: {
  _and: [
    { _gte: 18 },
    { _lte: 65 }
  ]
}

// _or — at least one must pass
validation: {
  _or: [
    { _eq: "active" },
    { _eq: "pending" }
  ]
}

// _not — negation
validation: {
  _not: { _contains: "admin" }
}

// deep nesting
validation: {
  _and: [
    { _starts_with: "user_" },
    { _not: { _in: ["user_banned", "user_suspended"] } },
    { _or: [
      { _ends_with: "_admin" },
      { _ends_with: "_editor" }
    ]}
  ]
}

Cross-Field References (_ref)

Try it live: Playground > Cross-Field

Compare a field's value against another field anywhere in the payload.

const schema = {
  password: { type: "String", required: true },
  confirmPassword: {
    type: "String",
    validation: { _eq: { _ref: "password" } },
  },
  startDate: { type: "Date" },
  endDate: {
    type: "Date",
    validation: { _gt: { _ref: "startDate" } },
  },
};

Path Resolution

| Syntax | Resolves To | |---|---| | { _ref: "fieldName" } | Sibling field in same parent object | | { _ref: "$root.path.to.field" } | Absolute path from root payload | | { _ref: "$parent.field" } | One level up | | { _ref: "$parent.$parent.field" } | Two levels up |

Works at Any Nesting Depth

const schema = {
  maxQuantity: { type: "Number" },
  orders: [{
    items: [{
      quantity: {
        type: "Number",
        validation: { _lte: { _ref: "$root.maxQuantity" } },
      },
    }],
  }],
};

Conditional Validation (when)

Try it live: Playground > Conditional

Apply different validation rules based on another field's value.

const schema = {
  type: { type: "String", enum: ["individual", "company"] },
  companyName: {
    type: "String",
    when: {
      field: "type",
      is: { _eq: "company" },
      then: { required: true },
      otherwise: { required: false },
    },
  },
};

when with Validation Rules

const schema = {
  country: { type: "String" },
  taxId: {
    type: "String",
    when: {
      field: "country",
      is: { _eq: "NL" },
      then: { required: true, validation: { _starts_with: "NL" } },
    },
  },
};

when with $root Reference (Inside Arrays)

const schema = {
  currency: { type: "String" },
  items: [{
    price: {
      type: "Number",
      when: {
        field: "$root.currency",
        is: { _eq: "EUR" },
        then: { validation: { _gte: 0.01 } },
      },
    },
  }],
};

Type Coercion

In strict or transform mode, values are automatically coerced to the declared type:

const schema = {
  age: { type: "Number" },
  isActive: { type: "Boolean" },
  createdAt: { type: "Date" },
};

// Input:  { age: "25", isActive: "true", createdAt: "2024-01-01" }
// Output: { age: 25, isActive: true, createdAt: Date("2024-01-01") }

Nested Objects

// Inline nested
{ profile: { age: { type: "Number" }, email: { type: "String" } } }

// Explicit with type
{ profile: { type: "Object", schema: { age: { type: "Number" } } } }

// Bare (type-only, pass-through)
{ metadata: { type: "Object" } }

Arrays

// Inline array of objects
items: [{ name: { type: "String", required: true } }]

// Explicit with bounds
items: { type: "Array", minItems: 1, maxItems: 50, schema: { name: { type: "String" } } }

// Bare (type-only)
{ tags: { type: "Array" } }

Recursive Schemas (Lazy)

const MenuItemSchema = () => ({
  id: { type: "String", required: true },
  children: [MenuItemSchema],
});

const schema = { modules: [MenuItemSchema] };

Setter (set)

{
  slug: {
    type: "String",
    set: (value) => value.toLowerCase().replace(/\s+/g, "-"),
  }
}
// Input: "My Blog Post" → Output: "my-blog-post"

Custom Validation

// Sync
username: {
  type: "String",
  validate: (value) => value.length >= 3 || "Too short"
}

// Async
email: {
  type: "String",
  asyncValidate: async (value, context) => {
    const exists = await context.db.findUser(value);
    return !exists || "Email already exists";
  }
}

Immutable Fields

{ email: { type: "String", immutable: true } }
// On create (partial: false) — accepted
// On update (partial: true) — rejected with IMMUTABLE_FIELD

Auto Timestamps

await sanitize(payload, schema, { timestamps: true });
// Create → { createdAt: Date, updatedAt: Date }
// Update (partial: true) → { updatedAt: Date }

Partial Mode (For Updates)

await sanitize(payload, schema, { partial: true });
// Skips required + default for missing fields

Bulk Sanitization

import { sanitizeBulk } from "nox-mongo-driver";
const result = await sanitizeBulk(payloads, schema, { concurrency: 5 });

Unknown Field Handling

unknownFields: "strip"   // default — removes unknown fields
unknownFields: "keep"    // preserves unknown fields
unknownFields: "error"   // adds error for each unknown field

Cleanup Options

await sanitize(payload, schema, {
  removeNull: true,
  removeUndefined: true,
  removeEmptyObjects: true,
  removeEmptyArrays: true,
});

Stop On First Error

await sanitize(payload, schema, { stopOnFirstError: true });

Error Format

Full error code reference: Error Codes

{
  path: "profile.age",
  code: "VALIDATION_GTE",
  message: "Must be greater than or equal to 18",
  meta: { operator: "_gte", expected: 18, received: 15 }
}

Error Codes

Schema rules: FIELD_REQUIRED · INVALID_TYPE · ENUM_MISMATCH · REGEX_MISMATCH · MIN_VIOLATION · MAX_VIOLATION · MIN_LENGTH_VIOLATION · MAX_LENGTH_VIOLATION · MIN_ITEMS_VIOLATION · MAX_ITEMS_VIOLATION · EXPECTED_ARRAY · EXPECTED_OBJECT · UNKNOWN_FIELD · IMMUTABLE_FIELD · CUSTOM_VALIDATION · CUSTOM_ASYNC_VALIDATION

Validation operators: VALIDATION_EQ · VALIDATION_NEQ · VALIDATION_LT · VALIDATION_LTE · VALIDATION_GT · VALIDATION_GTE · VALIDATION_IN · VALIDATION_NIN · VALIDATION_CONTAINS · VALIDATION_CONTAINS_I · VALIDATION_STARTS_WITH · VALIDATION_STARTS_WITH_I · VALIDATION_ENDS_WITH · VALIDATION_ENDS_WITH_I · VALIDATION_IS_NULL · VALIDATION_REGEX · VALIDATION_BETWEEN · VALIDATION_LENGTH · VALIDATION_EMPTY · VALIDATION_NOT_EMPTY · VALIDATION_NOT


i18n / Custom Messages

await sanitize(payload, schema, {
  language: "nl",
  messages: {
    nl: {
      FIELD_REQUIRED: "Veld is verplicht",
      VALIDATION_CONTAINS: (expected) => `Moet "${expected}" bevatten`,
      VALIDATION_GTE: (expected) => `Moet minimaal ${expected} zijn`,
    },
  },
});

Conflict Resolution

When a validation key is present, conflicting schema rules are automatically skipped:

| Skipped Schema Rule | Use Instead | |---|---| | enum | _in / _nin | | match (regex) | _regex, _contains, _starts_with, _ends_with | | min / max | _gt, _gte, _lt, _lte, _between |

Non-conflicting rules always run: required, minLength, maxLength, validate, asyncValidate.


Recommended Usage Patterns

// Create — full validation + coercion
await sanitize(payload, schema, { mode: "strict" });

// Update — skip required, reject immutable
await sanitize(payload, schema, { mode: "strict", partial: true });

// Data transformation layer — coerce types only
await sanitize(payload, schema, { mode: "transform" });

// Validation gate — check without mutating
await sanitize(payload, schema, { mode: "validate" });

Security

Automatically strips prototype pollution vectors (__proto__, constructor, prototype) from both schema keys and input data when unknownFields is set to keep.


Links

License

MIT — NOX Team