JSPM

nox-mongo-driver

1.3.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 18
  • Score
    100M100P100Q77086F
  • License MIT

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

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 and validator 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.

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", min: 18 },
};

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

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

Features

  • Three processing modes — strict, transform, validate
  • 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

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

{
  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,
}

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 Style

const schema = {
  profile: {
    age: { type: "Number", required: true },
    email: { type: "String", match: /^[^@]+@[^@]+$/ },
  },
};

Explicit Object Schema

const schema = {
  profile: {
    type: "Object",
    required: true,
    schema: {
      age: { type: "Number", required: true },
    },
  },
};

Bare Object (type-only validation)

When you only need to check that a value is an object without validating its internal structure, use type: "Object" without a schema property. The value passes through as-is:

const schema = {
  metadata: { type: "Object" },
};

// Input:  { metadata: { anything: "goes", nested: { deep: true } } }
// Output: { metadata: { anything: "goes", nested: { deep: true } } }

Arrays

Array of Primitives

tags: [{ type: "String" }]

Inline Array of Objects

items: [
  {
    name: { type: "String", required: true },
  },
];

Explicit Array Schema

items: {
  type: "Array",
  required: true,
  minItems: 1,
  maxItems: 50,
  schema: {
    name: { type: "String", required: true },
    value: { type: "Number", min: 0 }
  }
}

Bare Array (type-only validation)

When you only need to check that a value is an array without validating its items, use type: "Array" without a schema property:

const schema = {
  tags: { type: "Array" },
};

// Input:  { tags: ["anything", 42, { mixed: true }] }
// Output: { tags: ["anything", 42, { mixed: true }] }

minItems / maxItems

Available on explicit Array schemas:

items: {
  type: "Array",
  minItems: 1,
  maxItems: 10,
  schema: { name: { type: "String" } }
}

Recursive Schemas (Lazy)

Self-referencing schemas using functions:

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

const schema = { modules: [MenuItemSchema] };

Also works with explicit style:

children: {
  type: "Array",
  schema: MenuItemSchema
}

Setter (set)

Transform a value before type coercion and validation. Runs in strict and transform modes, skipped in validate mode:

const schema = {
  slug: {
    type: "String",
    set: (value) => value.toLowerCase().replace(/\s+/g, "-"),
  },
};

// Input:  { slug: "My Blog Post" }
// Output: { slug: "my-blog-post" }

The setter receives context as the second argument:

set: (value, context) => {
  return context.tenant === "admin" ? value : value.trim();
};

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";
  }
}

Pass context via options:

await sanitize(payload, schema, { context: { db } });

Immutable Fields

Prevent specific fields from being modified during updates (partial mode):

const schema = {
  email: { type: "String", immutable: true },
  name: { type: "String" },
};

// On create (partial: false) — both fields are accepted
// On update (partial: true) — email is rejected with IMMUTABLE_FIELD error

Auto Timestamps

Automatically add createdAt and updatedAt fields:

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

// Create → adds createdAt + updatedAt
// Update (partial: true) → adds updatedAt only

Custom field names:

await sanitize(payload, schema, {
  timestamps: true,
  timestampFields: {
    createdAt: "created_at",
    updatedAt: "updated_at",
  },
});

Unknown Field Handling

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

Cleanup Options

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

Partial Mode (For Updates)

await sanitize(updatePayload, schema, { partial: true });

Skips required validation and default assignment for missing fields. Ideal for PATCH / update APIs.

Stop On First Error

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

Returns immediately on the first validation failure for better performance on large payloads.

Bulk Sanitization

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

const result = await sanitizeBulk(payloads, schema, {
  concurrency: 5,
});

console.log(result.valid);   // successfully sanitized items
console.log(result.invalid); // items with errors + index + partial values

i18n / Custom Messages

await sanitize(payload, schema, {
  language: "nl",
  messages: {
    nl: {
      FIELD_REQUIRED: "Veld is verplicht",
      EXPECTED_OBJECT: "Object verwacht",
    },
  },
});

Error Format

{
  path: "profile.age",
  code: "MIN_VIOLATION",
  message: "Minimum allowed is 18",
  meta: { min: 18, received: 15 }
}

Error Codes

FIELD_REQUIRED · INVALID_TYPE · INVALID_NUMBER · INVALID_BOOLEAN · INVALID_DATE · INVALID_OBJECT_ID · 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

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.

License

MIT — NOX Team