Plugins
Kanun supports installable plugins so framework-specific or optional validation behavior can live outside the core package.
This keeps the base validator small while allowing packages such as @kanun-hq/plugin-file to add new rules, messages, and runtime helpers.
Installing a Plugin
Install the core package and the plugin you need:
npm install kanun @kanun-hq/plugin-filepnpm add kanun @kanun-hq/plugin-fileyarn add kanun @kanun-hq/plugin-fileRegister the plugin once during app startup:
import { Validator } from 'kanun';
import { fileValidatorPlugin } from '@kanun-hq/plugin-file';
Validator.use(fileValidatorPlugin);Validator Context
Plugins can read extra runtime state through validator context.
const validator = Validator.make(data, rules).withContext({
request,
currentUser,
});Context is useful when a rule depends on request-bound information such as uploaded files, authenticated users, or framework services.
If you want to register request-scoped context once in middleware and let validators created later pick it up automatically, use the static API:
import { Validator } from 'kanun';
Validator.useContext({
request,
currentUser,
});File Validation Plugin
The file plugin adds these rules:
filefilesimageextensions:jpg,pngmimetypes:image/jpeg,video/mpegmimes:jpg,pngdimensions:min_width=256,min_height=256,max_width=2048,max_height=2048,ratio=1
It also extends the built-in min, max, and size rules so file values are measured in kilobytes.
Example:
const validator = Validator.make(
{
avatar: {
mimetype: 'image/png',
originalname: 'avatar.png',
size: 2048,
},
},
{
avatar:
'file|image|extensions:png|mimetypes:image/png|max:4|dimensions:min_width=1,min_height=1,max_width=512,max_height=512,ratio=1',
},
);
const passes = await validator.passes();Use extensions when you want to validate filename suffixes directly. mimes remains available when you want the same extension-style syntax in existing rule sets.
Wildcard Multi-file Rules
When you want to validate uploaded file arrays with wildcard rules such as attachments.*, you usually need two things:
- A collection rule for the parent field such as
attachments: files - Per-item rules for
attachments.*
@kanun-hq/plugin-file includes helpers for that pattern:
import {
createWildcardFileRules,
syncRequestFilesToData,
useExpressUploadContext,
} from '@kanun-hq/plugin-file';
useExpressUploadContext(req);
const validator = syncRequestFilesToData(
Validator.make(
{},
createWildcardFileRules('attachments', 'file|image|extensions:png,jpg'),
),
['attachments'],
);
const passes = await validator.passes();createWildcardFileRules() creates the parent and item rules together, and syncRequestFilesToData() mirrors context.requestFiles into validator data so wildcard expansion can discover each uploaded file.
Upload Adapters
@kanun-hq/plugin-file also ships adapters that populate .withContext() automatically by normalizing uploaded files into context.requestFiles.
Express
Use useExpressUploadContext() in middleware for requests populated by middleware such as Multer.
import { Validator } from 'kanun';
import {
fileValidatorPlugin,
useExpressUploadContext,
} from '@kanun-hq/plugin-file';
Validator.use(fileValidatorPlugin);
useExpressUploadContext(req);
const validator = Validator.make({}, { avatar: 'file|image|mimes:png,jpg' });
const passes = await validator.passes();Fastify
Use useFastifyUploadContext() with @fastify/multipart inside middleware or hooks.
import { Validator } from 'kanun';
import {
fileValidatorPlugin,
useFastifyUploadContext,
} from '@kanun-hq/plugin-file';
Validator.use(fileValidatorPlugin);
await useFastifyUploadContext(request);
const validator = Validator.make(
{},
{ attachments: 'files|image|mimes:png,jpg' },
);
const passes = await validator.passes();Hono
Use useHonoUploadContext() to consume files returned by c.req.parseBody() during middleware execution.
import { Validator } from 'kanun';
import {
fileValidatorPlugin,
useHonoUploadContext,
} from '@kanun-hq/plugin-file';
Validator.use(fileValidatorPlugin);
await useHonoUploadContext(c);
const validator = Validator.make(
{},
{ avatar: 'file|image|mimetypes:image/png' },
);
const passes = await validator.passes();H3
Use useH3UploadContext() in middleware or route setup. It can read files from event.context.requestFiles, request.formData(), or multipart parsing when available.
import { Validator } from 'kanun';
import { fileValidatorPlugin, useH3UploadContext } from '@kanun-hq/plugin-file';
Validator.use(fileValidatorPlugin);
await useH3UploadContext(event);
const validator = Validator.make(
{},
{ avatar: 'file|image|mimetypes:image/png' },
);
const passes = await validator.passes();If you only want to enrich one validator instance, the existing withExpressUploadContext(), withFastifyUploadContext(), withHonoUploadContext(), and withH3UploadContext() helpers are still available.
Writing Your Own Plugin
Kanun exposes a plugin API for packages that need to register rules or extend runtime behavior.
import { definePlugin } from 'kanun';
export const examplePlugin = definePlugin({
name: 'example-plugin',
install: ({ registerRule, extendTranslations }) => {
registerRule('starts_with_kanun', (value) => {
return typeof value === 'string' && value.startsWith('kanun');
});
extendTranslations({
en: {
starts_with_kanun: 'The :attribute must start with kanun.',
},
});
},
});Add Rule Autocomplete For Plugin Users
If your plugin adds custom rules, you can also augment Kanun's rule autocomplete so array-style rule definitions suggest your rule names in TypeScript.
declare module 'kanun' {
interface ValidationRuleAutocompleteMap {
starts_with_kanun: 'plain';
kanun_format: 'paramable';
}
}Use 'plain' for rules without parameters and 'paramable' for rules used like rule:value.
That makes plugin rules show up in array syntax such as:
const rules = {
name: ['required', 'starts_with_kanun', 'kanun_format:strict'],
};This only affects TypeScript autocomplete and typing. You still need to register the runtime rule implementation inside your plugin with registerRule(...).
If a plugin needs runtime state, document the expected shape of .withContext() and provide adapters when framework integration is common.