Repository files navigation

@imqueue/validation

Build Statusnpm versionLicense

Zod-backed, field- and method-level validation via native (TC39) decorators for Node.js & TypeScript back-ends — the input-validation layer of the @imqueue framework. Declare a validator next to a class field with @validate, seal the class with @validatable, and validate method arguments with @validated.

Documentation: full guides, tutorial and API reference at imqueue.org. Commercial licensing & support for closed-source products at imqueue.com.

Using an AI assistant? Point it at imqueue.org/llms.txt for a machine-readable index of the docs, or see AGENTS.md. Current version, licence and Node floor for every package: imqueue.org/status.json.

Related packages:

  • @imqueue/core - Fast JSON message queue over Redis for inter-service communication.
  • @imqueue/rpc - RPC-like client/service implementation over @imqueue/core.
  • @imqueue/pg-prisma - Prisma/Postgres toolkit for @imqueue services.

Features

  • Native TC39 decorators — no experimentalDecorators, no reflect-metadata. Works under the standard TypeScript decorator emit.
  • Zod schemas — reuse any zod schema as a field or argument validator.
  • Composable — a @validatable class can be used as a validator for a field or argument on another class, so nested input shapes validate recursively.
  • Method-argument validation@validated(...) checks positional arguments left-to-right; a null/undefined entry skips that position.
  • TypeScript included!

Requirements

Node.js ≥ 22.12. zod v4 is a runtime dependency.

Install

npm i --save @imqueue/validation

Usage

import{z}from'zod';import{validatable,validate,validated,schemaOf,}from'@imqueue/validation';
@validatable()classCredentials{
@validate(z.string().min(3))identifier!: string;
@validate(z.string().min(8))secret!: string;}// A schema assembled from the field validators (or `null` if the class has none)constschema=schemaOf(Credentials);// z.object({ identifier, secret })classAuthService{// Validate positional arguments before the method body runs.// Pass a Zod schema, a `@validatable` class, or `null`/`undefined` to skip.
@validated(Credentials)authenticate(creds: Credentials): string{returncreds.identifier;}}newAuthService().authenticate({identifier: 'ab',secret: 'short'});// → throws ZodError (identifier too short, secret too short)

How it works

TC39 decorator metadata (Symbol.metadata) is not populated by every build tool (esbuild/tsx), so field validators are buffered as each class body evaluates and sealed onto the class by the @validatable() class decorator. Field decorators run before the class decorator and class bodies evaluate sequentially, so the buffer reaches the right class — provided that class is decorated. schemaOf(Class) then assembles the sealed field validators into a z.object(...).

Three things to know

  • @validatable() is not optional. Nothing flushes the buffer when a class body merely ends, so a class using @validate without @validatable() hands its fields to the next class that is sealed. That class then rejects valid input over a property it never declared, while the class with the actual mistake validates nothing — the error surfaces on the innocent one.
  • @validated checks arguments, it does not replace them. The method body receives exactly what the caller passed, so a transforming schema validates as expected and changes nothing downstream: z.coerce.number() accepts '42' and the parameter is still the string, .trim() hands over the untrimmed original, .default(...) fills nothing in, and object schemas leave undeclared properties in place. Parse in the body where the converted value is what you need.
  • Inherited fields are not inherited rules.@validatable() seals the fields declared in that class body only, and schemaOf does not walk the prototype chain, so a subclass validates a parent's field only by re-declaring it.

Running Unit Tests

Tests run on the native Node.js test runner (node:test) with node:assert and no external test framework:

git clone git@github.com:imqueue/validation.git
cd validation
npm install
npm test

To produce a coverage report use:

npm run test-coverage # prints coverage summary to the console
npm run test-lcov # writes coverage/lcov.info

License

This project is licensed under the GNU General Public License v3.0. See the LICENSE

About

Zod-backed field- and method-level validation via native TC39 decorators for the @imqueue framework

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

@imqueue/validation

Build Statusnpm versionLicense

Zod-backed, field- and method-level validation via native (TC39) decorators for Node.js & TypeScript back-ends — the input-validation layer of the @imqueue framework. Declare a validator next to a class field with @validate, seal the class with @validatable, and validate method arguments with @validated.

Documentation: full guides, tutorial and API reference at imqueue.org. Commercial licensing & support for closed-source products at imqueue.com.

Using an AI assistant? Point it at imqueue.org/llms.txt for a machine-readable index of the docs, or see AGENTS.md. Current version, licence and Node floor for every package: imqueue.org/status.json.

Related packages:

  • @imqueue/core - Fast JSON message queue over Redis for inter-service communication.
  • @imqueue/rpc - RPC-like client/service implementation over @imqueue/core.
  • @imqueue/pg-prisma - Prisma/Postgres toolkit for @imqueue services.

Features

  • Native TC39 decorators — no experimentalDecorators, no reflect-metadata. Works under the standard TypeScript decorator emit.
  • Zod schemas — reuse any zod schema as a field or argument validator.
  • Composable — a @validatable class can be used as a validator for a field or argument on another class, so nested input shapes validate recursively.
  • Method-argument validation@validated(...) checks positional arguments left-to-right; a null/undefined entry skips that position.
  • TypeScript included!

Requirements

Node.js ≥ 22.12. zod v4 is a runtime dependency.

Install

npm i --save @imqueue/validation

Usage

import{z}from'zod';import{validatable,validate,validated,schemaOf,}from'@imqueue/validation';
@validatable()classCredentials{
@validate(z.string().min(3))identifier!: string;
@validate(z.string().min(8))secret!: string;}// A schema assembled from the field validators (or `null` if the class has none)constschema=schemaOf(Credentials);// z.object({ identifier, secret })classAuthService{// Validate positional arguments before the method body runs.// Pass a Zod schema, a `@validatable` class, or `null`/`undefined` to skip.
@validated(Credentials)authenticate(creds: Credentials): string{returncreds.identifier;}}newAuthService().authenticate({identifier: 'ab',secret: 'short'});// → throws ZodError (identifier too short, secret too short)

How it works

TC39 decorator metadata (Symbol.metadata) is not populated by every build tool (esbuild/tsx), so field validators are buffered as each class body evaluates and sealed onto the class by the @validatable() class decorator. Field decorators run before the class decorator and class bodies evaluate sequentially, so the buffer reaches the right class — provided that class is decorated. schemaOf(Class) then assembles the sealed field validators into a z.object(...).

Three things to know

  • @validatable() is not optional. Nothing flushes the buffer when a class body merely ends, so a class using @validate without @validatable() hands its fields to the next class that is sealed. That class then rejects valid input over a property it never declared, while the class with the actual mistake validates nothing — the error surfaces on the innocent one.
  • @validated checks arguments, it does not replace them. The method body receives exactly what the caller passed, so a transforming schema validates as expected and changes nothing downstream: z.coerce.number() accepts '42' and the parameter is still the string, .trim() hands over the untrimmed original, .default(...) fills nothing in, and object schemas leave undeclared properties in place. Parse in the body where the converted value is what you need.
  • Inherited fields are not inherited rules.@validatable() seals the fields declared in that class body only, and schemaOf does not walk the prototype chain, so a subclass validates a parent's field only by re-declaring it.

Running Unit Tests

Tests run on the native Node.js test runner (node:test) with node:assert and no external test framework:

git clone git@github.com:imqueue/validation.git
cd validation
npm install
npm test

To produce a coverage report use:

npm run test-coverage # prints coverage summary to the console
npm run test-lcov # writes coverage/lcov.info

License

This project is licensed under the GNU General Public License v3.0. See the LICENSE

About

Zod-backed field- and method-level validation via native TC39 decorators for the @imqueue framework

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

@imqueue/validation

Build Statusnpm versionLicense

Zod-backed, field- and method-level validation via native (TC39) decorators for Node.js & TypeScript back-ends — the input-validation layer of the @imqueue framework. Declare a validator next to a class field with @validate, seal the class with @validatable, and validate method arguments with @validated.

Documentation: full guides, tutorial and API reference at imqueue.org. Commercial licensing & support for closed-source products at imqueue.com.

Using an AI assistant? Point it at imqueue.org/llms.txt for a machine-readable index of the docs, or see AGENTS.md. Current version, licence and Node floor for every package: imqueue.org/status.json.

Related packages:

  • @imqueue/core - Fast JSON message queue over Redis for inter-service communication.
  • @imqueue/rpc - RPC-like client/service implementation over @imqueue/core.
  • @imqueue/pg-prisma - Prisma/Postgres toolkit for @imqueue services.

Features

  • Native TC39 decorators — no experimentalDecorators, no reflect-metadata. Works under the standard TypeScript decorator emit.
  • Zod schemas — reuse any zod schema as a field or argument validator.
  • Composable — a @validatable class can be used as a validator for a field or argument on another class, so nested input shapes validate recursively.
  • Method-argument validation@validated(...) checks positional arguments left-to-right; a null/undefined entry skips that position.
  • TypeScript included!

Requirements

Node.js ≥ 22.12. zod v4 is a runtime dependency.

Install

npm i --save @imqueue/validation

Usage

import{z}from'zod';import{validatable,validate,validated,schemaOf,}from'@imqueue/validation';
@validatable()classCredentials{
@validate(z.string().min(3))identifier!: string;
@validate(z.string().min(8))secret!: string;}// A schema assembled from the field validators (or `null` if the class has none)constschema=schemaOf(Credentials);// z.object({ identifier, secret })classAuthService{// Validate positional arguments before the method body runs.// Pass a Zod schema, a `@validatable` class, or `null`/`undefined` to skip.
@validated(Credentials)authenticate(creds: Credentials): string{returncreds.identifier;}}newAuthService().authenticate({identifier: 'ab',secret: 'short'});// → throws ZodError (identifier too short, secret too short)

How it works

TC39 decorator metadata (Symbol.metadata) is not populated by every build tool (esbuild/tsx), so field validators are buffered as each class body evaluates and sealed onto the class by the @validatable() class decorator. Field decorators run before the class decorator and class bodies evaluate sequentially, so the buffer reaches the right class — provided that class is decorated. schemaOf(Class) then assembles the sealed field validators into a z.object(...).

Three things to know

  • @validatable() is not optional. Nothing flushes the buffer when a class body merely ends, so a class using @validate without @validatable() hands its fields to the next class that is sealed. That class then rejects valid input over a property it never declared, while the class with the actual mistake validates nothing — the error surfaces on the innocent one.
  • @validated checks arguments, it does not replace them. The method body receives exactly what the caller passed, so a transforming schema validates as expected and changes nothing downstream: z.coerce.number() accepts '42' and the parameter is still the string, .trim() hands over the untrimmed original, .default(...) fills nothing in, and object schemas leave undeclared properties in place. Parse in the body where the converted value is what you need.
  • Inherited fields are not inherited rules.@validatable() seals the fields declared in that class body only, and schemaOf does not walk the prototype chain, so a subclass validates a parent's field only by re-declaring it.

Running Unit Tests

Tests run on the native Node.js test runner (node:test) with node:assert and no external test framework:

git clone git@github.com:imqueue/validation.git
cd validation
npm install
npm test

To produce a coverage report use:

npm run test-coverage # prints coverage summary to the console
npm run test-lcov # writes coverage/lcov.info

License

This project is licensed under the GNU General Public License v3.0. See the LICENSE

About

Zod-backed field- and method-level validation via native TC39 decorators for the @imqueue framework

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

@imqueue/validation

Build Statusnpm versionLicense

Zod-backed, field- and method-level validation via native (TC39) decorators for Node.js & TypeScript back-ends — the input-validation layer of the @imqueue framework. Declare a validator next to a class field with @validate, seal the class with @validatable, and validate method arguments with @validated.

Documentation: full guides, tutorial and API reference at imqueue.org. Commercial licensing & support for closed-source products at imqueue.com.

Using an AI assistant? Point it at imqueue.org/llms.txt for a machine-readable index of the docs, or see AGENTS.md. Current version, licence and Node floor for every package: imqueue.org/status.json.

Related packages:

  • @imqueue/core - Fast JSON message queue over Redis for inter-service communication.
  • @imqueue/rpc - RPC-like client/service implementation over @imqueue/core.
  • @imqueue/pg-prisma - Prisma/Postgres toolkit for @imqueue services.

Features

  • Native TC39 decorators — no experimentalDecorators, no reflect-metadata. Works under the standard TypeScript decorator emit.
  • Zod schemas — reuse any zod schema as a field or argument validator.
  • Composable — a @validatable class can be used as a validator for a field or argument on another class, so nested input shapes validate recursively.
  • Method-argument validation@validated(...) checks positional arguments left-to-right; a null/undefined entry skips that position.
  • TypeScript included!

Requirements

Node.js ≥ 22.12. zod v4 is a runtime dependency.

Install

npm i --save @imqueue/validation

Usage

import{z}from'zod';import{validatable,validate,validated,schemaOf,}from'@imqueue/validation';
@validatable()classCredentials{
@validate(z.string().min(3))identifier!: string;
@validate(z.string().min(8))secret!: string;}// A schema assembled from the field validators (or `null` if the class has none)constschema=schemaOf(Credentials);// z.object({ identifier, secret })classAuthService{// Validate positional arguments before the method body runs.// Pass a Zod schema, a `@validatable` class, or `null`/`undefined` to skip.
@validated(Credentials)authenticate(creds: Credentials): string{returncreds.identifier;}}newAuthService().authenticate({identifier: 'ab',secret: 'short'});// → throws ZodError (identifier too short, secret too short)

How it works

TC39 decorator metadata (Symbol.metadata) is not populated by every build tool (esbuild/tsx), so field validators are buffered as each class body evaluates and sealed onto the class by the @validatable() class decorator. Field decorators run before the class decorator and class bodies evaluate sequentially, so the buffer reaches the right class — provided that class is decorated. schemaOf(Class) then assembles the sealed field validators into a z.object(...).

Three things to know

  • @validatable() is not optional. Nothing flushes the buffer when a class body merely ends, so a class using @validate without @validatable() hands its fields to the next class that is sealed. That class then rejects valid input over a property it never declared, while the class with the actual mistake validates nothing — the error surfaces on the innocent one.
  • @validated checks arguments, it does not replace them. The method body receives exactly what the caller passed, so a transforming schema validates as expected and changes nothing downstream: z.coerce.number() accepts '42' and the parameter is still the string, .trim() hands over the untrimmed original, .default(...) fills nothing in, and object schemas leave undeclared properties in place. Parse in the body where the converted value is what you need.
  • Inherited fields are not inherited rules.@validatable() seals the fields declared in that class body only, and schemaOf does not walk the prototype chain, so a subclass validates a parent's field only by re-declaring it.

Running Unit Tests

Tests run on the native Node.js test runner (node:test) with node:assert and no external test framework:

git clone git@github.com:imqueue/validation.git
cd validation
npm install
npm test

To produce a coverage report use:

npm run test-coverage # prints coverage summary to the console
npm run test-lcov # writes coverage/lcov.info

License

This project is licensed under the GNU General Public License v3.0. See the LICENSE

About

Zod-backed field- and method-level validation via native TC39 decorators for the @imqueue framework

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

@imqueue/validation

Build Statusnpm versionLicense

Zod-backed, field- and method-level validation via native (TC39) decorators for Node.js & TypeScript back-ends — the input-validation layer of the @imqueue framework. Declare a validator next to a class field with @validate, seal the class with @validatable, and validate method arguments with @validated.

Documentation: full guides, tutorial and API reference at imqueue.org. Commercial licensing & support for closed-source products at imqueue.com.

Using an AI assistant? Point it at imqueue.org/llms.txt for a machine-readable index of the docs, or see AGENTS.md. Current version, licence and Node floor for every package: imqueue.org/status.json.

Related packages:

  • @imqueue/core - Fast JSON message queue over Redis for inter-service communication.
  • @imqueue/rpc - RPC-like client/service implementation over @imqueue/core.
  • @imqueue/pg-prisma - Prisma/Postgres toolkit for @imqueue services.

Features

  • Native TC39 decorators — no experimentalDecorators, no reflect-metadata. Works under the standard TypeScript decorator emit.
  • Zod schemas — reuse any zod schema as a field or argument validator.
  • Composable — a @validatable class can be used as a validator for a field or argument on another class, so nested input shapes validate recursively.
  • Method-argument validation@validated(...) checks positional arguments left-to-right; a null/undefined entry skips that position.
  • TypeScript included!

Requirements

Node.js ≥ 22.12. zod v4 is a runtime dependency.

Install

npm i --save @imqueue/validation

Usage

import{z}from'zod';import{validatable,validate,validated,schemaOf,}from'@imqueue/validation';
@validatable()classCredentials{
@validate(z.string().min(3))identifier!: string;
@validate(z.string().min(8))secret!: string;}// A schema assembled from the field validators (or `null` if the class has none)constschema=schemaOf(Credentials);// z.object({ identifier, secret })classAuthService{// Validate positional arguments before the method body runs.// Pass a Zod schema, a `@validatable` class, or `null`/`undefined` to skip.
@validated(Credentials)authenticate(creds: Credentials): string{returncreds.identifier;}}newAuthService().authenticate({identifier: 'ab',secret: 'short'});// → throws ZodError (identifier too short, secret too short)

How it works

TC39 decorator metadata (Symbol.metadata) is not populated by every build tool (esbuild/tsx), so field validators are buffered as each class body evaluates and sealed onto the class by the @validatable() class decorator. Field decorators run before the class decorator and class bodies evaluate sequentially, so the buffer reaches the right class — provided that class is decorated. schemaOf(Class) then assembles the sealed field validators into a z.object(...).

Three things to know

  • @validatable() is not optional. Nothing flushes the buffer when a class body merely ends, so a class using @validate without @validatable() hands its fields to the next class that is sealed. That class then rejects valid input over a property it never declared, while the class with the actual mistake validates nothing — the error surfaces on the innocent one.
  • @validated checks arguments, it does not replace them. The method body receives exactly what the caller passed, so a transforming schema validates as expected and changes nothing downstream: z.coerce.number() accepts '42' and the parameter is still the string, .trim() hands over the untrimmed original, .default(...) fills nothing in, and object schemas leave undeclared properties in place. Parse in the body where the converted value is what you need.
  • Inherited fields are not inherited rules.@validatable() seals the fields declared in that class body only, and schemaOf does not walk the prototype chain, so a subclass validates a parent's field only by re-declaring it.

Running Unit Tests

Tests run on the native Node.js test runner (node:test) with node:assert and no external test framework:

git clone git@github.com:imqueue/validation.git
cd validation
npm install
npm test

To produce a coverage report use:

npm run test-coverage # prints coverage summary to the console
npm run test-lcov # writes coverage/lcov.info

License

This project is licensed under the GNU General Public License v3.0. See the LICENSE

About

Zod-backed field- and method-level validation via native TC39 decorators for the @imqueue framework

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

@imqueue/validation

Build Statusnpm versionLicense

Zod-backed, field- and method-level validation via native (TC39) decorators for Node.js & TypeScript back-ends — the input-validation layer of the @imqueue framework. Declare a validator next to a class field with @validate, seal the class with @validatable, and validate method arguments with @validated.

Documentation: full guides, tutorial and API reference at imqueue.org. Commercial licensing & support for closed-source products at imqueue.com.

Using an AI assistant? Point it at imqueue.org/llms.txt for a machine-readable index of the docs, or see AGENTS.md. Current version, licence and Node floor for every package: imqueue.org/status.json.

Related packages:

  • @imqueue/core - Fast JSON message queue over Redis for inter-service communication.
  • @imqueue/rpc - RPC-like client/service implementation over @imqueue/core.
  • @imqueue/pg-prisma - Prisma/Postgres toolkit for @imqueue services.

Features

  • Native TC39 decorators — no experimentalDecorators, no reflect-metadata. Works under the standard TypeScript decorator emit.
  • Zod schemas — reuse any zod schema as a field or argument validator.
  • Composable — a @validatable class can be used as a validator for a field or argument on another class, so nested input shapes validate recursively.
  • Method-argument validation@validated(...) checks positional arguments left-to-right; a null/undefined entry skips that position.
  • TypeScript included!

Requirements

Node.js ≥ 22.12. zod v4 is a runtime dependency.

Install

npm i --save @imqueue/validation

Usage

import{z}from'zod';import{validatable,validate,validated,schemaOf,}from'@imqueue/validation';
@validatable()classCredentials{
@validate(z.string().min(3))identifier!: string;
@validate(z.string().min(8))secret!: string;}// A schema assembled from the field validators (or `null` if the class has none)constschema=schemaOf(Credentials);// z.object({ identifier, secret })classAuthService{// Validate positional arguments before the method body runs.// Pass a Zod schema, a `@validatable` class, or `null`/`undefined` to skip.
@validated(Credentials)authenticate(creds: Credentials): string{returncreds.identifier;}}newAuthService().authenticate({identifier: 'ab',secret: 'short'});// → throws ZodError (identifier too short, secret too short)

How it works

TC39 decorator metadata (Symbol.metadata) is not populated by every build tool (esbuild/tsx), so field validators are buffered as each class body evaluates and sealed onto the class by the @validatable() class decorator. Field decorators run before the class decorator and class bodies evaluate sequentially, so the buffer reaches the right class — provided that class is decorated. schemaOf(Class) then assembles the sealed field validators into a z.object(...).

Three things to know

  • @validatable() is not optional. Nothing flushes the buffer when a class body merely ends, so a class using @validate without @validatable() hands its fields to the next class that is sealed. That class then rejects valid input over a property it never declared, while the class with the actual mistake validates nothing — the error surfaces on the innocent one.
  • @validated checks arguments, it does not replace them. The method body receives exactly what the caller passed, so a transforming schema validates as expected and changes nothing downstream: z.coerce.number() accepts '42' and the parameter is still the string, .trim() hands over the untrimmed original, .default(...) fills nothing in, and object schemas leave undeclared properties in place. Parse in the body where the converted value is what you need.
  • Inherited fields are not inherited rules.@validatable() seals the fields declared in that class body only, and schemaOf does not walk the prototype chain, so a subclass validates a parent's field only by re-declaring it.

Running Unit Tests

Tests run on the native Node.js test runner (node:test) with node:assert and no external test framework:

git clone git@github.com:imqueue/validation.git
cd validation
npm install
npm test

To produce a coverage report use:

npm run test-coverage # prints coverage summary to the console
npm run test-lcov # writes coverage/lcov.info

License

This project is licensed under the GNU General Public License v3.0. See the LICENSE

About

Zod-backed field- and method-level validation via native TC39 decorators for the @imqueue framework

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

@imqueue/validation

Build Statusnpm versionLicense

Zod-backed, field- and method-level validation via native (TC39) decorators for Node.js & TypeScript back-ends — the input-validation layer of the @imqueue framework. Declare a validator next to a class field with @validate, seal the class with @validatable, and validate method arguments with @validated.

Documentation: full guides, tutorial and API reference at imqueue.org. Commercial licensing & support for closed-source products at imqueue.com.

Using an AI assistant? Point it at imqueue.org/llms.txt for a machine-readable index of the docs, or see AGENTS.md. Current version, licence and Node floor for every package: imqueue.org/status.json.

Related packages:

  • @imqueue/core - Fast JSON message queue over Redis for inter-service communication.
  • @imqueue/rpc - RPC-like client/service implementation over @imqueue/core.
  • @imqueue/pg-prisma - Prisma/Postgres toolkit for @imqueue services.

Features

  • Native TC39 decorators — no experimentalDecorators, no reflect-metadata. Works under the standard TypeScript decorator emit.
  • Zod schemas — reuse any zod schema as a field or argument validator.
  • Composable — a @validatable class can be used as a validator for a field or argument on another class, so nested input shapes validate recursively.
  • Method-argument validation@validated(...) checks positional arguments left-to-right; a null/undefined entry skips that position.
  • TypeScript included!

Requirements

Node.js ≥ 22.12. zod v4 is a runtime dependency.

Install

npm i --save @imqueue/validation

Usage

import{z}from'zod';import{validatable,validate,validated,schemaOf,}from'@imqueue/validation';
@validatable()classCredentials{
@validate(z.string().min(3))identifier!: string;
@validate(z.string().min(8))secret!: string;}// A schema assembled from the field validators (or `null` if the class has none)constschema=schemaOf(Credentials);// z.object({ identifier, secret })classAuthService{// Validate positional arguments before the method body runs.// Pass a Zod schema, a `@validatable` class, or `null`/`undefined` to skip.
@validated(Credentials)authenticate(creds: Credentials): string{returncreds.identifier;}}newAuthService().authenticate({identifier: 'ab',secret: 'short'});// → throws ZodError (identifier too short, secret too short)

How it works

TC39 decorator metadata (Symbol.metadata) is not populated by every build tool (esbuild/tsx), so field validators are buffered as each class body evaluates and sealed onto the class by the @validatable() class decorator. Field decorators run before the class decorator and class bodies evaluate sequentially, so the buffer reaches the right class — provided that class is decorated. schemaOf(Class) then assembles the sealed field validators into a z.object(...).

Three things to know

  • @validatable() is not optional. Nothing flushes the buffer when a class body merely ends, so a class using @validate without @validatable() hands its fields to the next class that is sealed. That class then rejects valid input over a property it never declared, while the class with the actual mistake validates nothing — the error surfaces on the innocent one.
  • @validated checks arguments, it does not replace them. The method body receives exactly what the caller passed, so a transforming schema validates as expected and changes nothing downstream: z.coerce.number() accepts '42' and the parameter is still the string, .trim() hands over the untrimmed original, .default(...) fills nothing in, and object schemas leave undeclared properties in place. Parse in the body where the converted value is what you need.
  • Inherited fields are not inherited rules.@validatable() seals the fields declared in that class body only, and schemaOf does not walk the prototype chain, so a subclass validates a parent's field only by re-declaring it.

Running Unit Tests

Tests run on the native Node.js test runner (node:test) with node:assert and no external test framework:

git clone git@github.com:imqueue/validation.git
cd validation
npm install
npm test

To produce a coverage report use:

npm run test-coverage # prints coverage summary to the console
npm run test-lcov # writes coverage/lcov.info

License

This project is licensed under the GNU General Public License v3.0. See the LICENSE

About

Zod-backed field- and method-level validation via native TC39 decorators for the @imqueue framework

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

@imqueue/validation

Build Statusnpm versionLicense

Zod-backed, field- and method-level validation via native (TC39) decorators for Node.js & TypeScript back-ends — the input-validation layer of the @imqueue framework. Declare a validator next to a class field with @validate, seal the class with @validatable, and validate method arguments with @validated.

Documentation: full guides, tutorial and API reference at imqueue.org. Commercial licensing & support for closed-source products at imqueue.com.

Using an AI assistant? Point it at imqueue.org/llms.txt for a machine-readable index of the docs, or see AGENTS.md. Current version, licence and Node floor for every package: imqueue.org/status.json.

Related packages:

  • @imqueue/core - Fast JSON message queue over Redis for inter-service communication.
  • @imqueue/rpc - RPC-like client/service implementation over @imqueue/core.
  • @imqueue/pg-prisma - Prisma/Postgres toolkit for @imqueue services.

Features

  • Native TC39 decorators — no experimentalDecorators, no reflect-metadata. Works under the standard TypeScript decorator emit.
  • Zod schemas — reuse any zod schema as a field or argument validator.
  • Composable — a @validatable class can be used as a validator for a field or argument on another class, so nested input shapes validate recursively.
  • Method-argument validation@validated(...) checks positional arguments left-to-right; a null/undefined entry skips that position.
  • TypeScript included!

Requirements

Node.js ≥ 22.12. zod v4 is a runtime dependency.

Install

npm i --save @imqueue/validation

Usage

import{z}from'zod';import{validatable,validate,validated,schemaOf,}from'@imqueue/validation';
@validatable()classCredentials{
@validate(z.string().min(3))identifier!: string;
@validate(z.string().min(8))secret!: string;}// A schema assembled from the field validators (or `null` if the class has none)constschema=schemaOf(Credentials);// z.object({ identifier, secret })classAuthService{// Validate positional arguments before the method body runs.// Pass a Zod schema, a `@validatable` class, or `null`/`undefined` to skip.
@validated(Credentials)authenticate(creds: Credentials): string{returncreds.identifier;}}newAuthService().authenticate({identifier: 'ab',secret: 'short'});// → throws ZodError (identifier too short, secret too short)

How it works

TC39 decorator metadata (Symbol.metadata) is not populated by every build tool (esbuild/tsx), so field validators are buffered as each class body evaluates and sealed onto the class by the @validatable() class decorator. Field decorators run before the class decorator and class bodies evaluate sequentially, so the buffer reaches the right class — provided that class is decorated. schemaOf(Class) then assembles the sealed field validators into a z.object(...).

Three things to know

  • @validatable() is not optional. Nothing flushes the buffer when a class body merely ends, so a class using @validate without @validatable() hands its fields to the next class that is sealed. That class then rejects valid input over a property it never declared, while the class with the actual mistake validates nothing — the error surfaces on the innocent one.
  • @validated checks arguments, it does not replace them. The method body receives exactly what the caller passed, so a transforming schema validates as expected and changes nothing downstream: z.coerce.number() accepts '42' and the parameter is still the string, .trim() hands over the untrimmed original, .default(...) fills nothing in, and object schemas leave undeclared properties in place. Parse in the body where the converted value is what you need.
  • Inherited fields are not inherited rules.@validatable() seals the fields declared in that class body only, and schemaOf does not walk the prototype chain, so a subclass validates a parent's field only by re-declaring it.

Running Unit Tests

Tests run on the native Node.js test runner (node:test) with node:assert and no external test framework:

git clone git@github.com:imqueue/validation.git
cd validation
npm install
npm test

To produce a coverage report use:

npm run test-coverage # prints coverage summary to the console
npm run test-lcov # writes coverage/lcov.info

License

This project is licensed under the GNU General Public License v3.0. See the LICENSE

About

Zod-backed field- and method-level validation via native TC39 decorators for the @imqueue framework

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages