Package Exports
- nox-mongo-driver
- nox-mongo-driver/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (nox-mongo-driver) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
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.
Interactive Docs & Playground: nox-sanitizer.nowonlinetech.in
Installation
npm install nox-mongo-driverQuick 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: "sahil@test.com" },
schema,
{ mode: "strict" }
);
// value → { name: "Sahil", age: 25, email: "sahil@test.com" }
// 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 —
_refto compare against sibling, parent, or root fields - Conditional validation —
whento 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_FIELDAuto 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 fieldsBulk 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 fieldCleanup 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