Skip to content

File Validation Plugin ​

@kanun-hq/plugin-file adds first-class file rules, request-context helpers, framework adapters, and wildcard utilities for upload-heavy validation flows.

Installation ​

bash
npm install kanun @kanun-hq/plugin-file
bash
pnpm add kanun @kanun-hq/plugin-file
bash
yarn add kanun @kanun-hq/plugin-file

Register the plugin once during app startup:

ts
import { Validator } from 'kanun';
import { fileValidatorPlugin } from '@kanun-hq/plugin-file';

Validator.use(fileValidatorPlugin);

If you need custom file lookup behavior, register your own instance instead:

ts
import { Validator } from 'kanun';
import { createFileValidatorPlugin } from '@kanun-hq/plugin-file';

Validator.use(
  createFileValidatorPlugin({
    resolveFiles: ({ attribute, context, value }) => {
      if (typeof value !== 'undefined') {
        return value;
      }

      return context.requestFiles?.[attribute];
    },
  }),
);

Rules ​

The file plugin adds these rules:

  • file
  • files
  • image
  • extensions:jpg,png
  • mimetypes:image/jpeg,video/mpeg
  • mimes:jpg,png
  • dimensions: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.

ts
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.

Supported File Shapes ​

The plugin accepts file-like values that expose one or more of these properties:

  • buffer
  • filename
  • originalname
  • name
  • path
  • mimetype
  • type
  • size
  • width
  • height

That means these input styles work:

  • Multer-style file objects
  • Fastify multipart parts after normalization
  • plain objects with path, size, and mimetype
  • File and Blob values from FormData
  • arrays of any supported file shape

Validating Files Passed Directly In Data ​

If your application already has file objects on the data payload, you can validate them without any context helpers.

ts
const validator = Validator.make(
  {
    avatar: {
      buffer,
      mimetype: 'image/png',
      originalname: 'avatar.png',
      size: 2048,
    },
  },
  {
    avatar: 'file|image|extensions:png|mimetypes:image/png|max:4',
  },
);

const validated = await validator.validate();

validated.avatar will be the resolved file object.

Request-Scoped Uploads ​

If files are not part of the data object, attach them through validator context.

ts
const validator = Validator.make(
  {},
  { avatar: 'file|image|mimes:png' },
).withContext({
  requestFiles: {
    avatar,
  },
});

const validated = await validator.validate();

validated will include the file:

ts
{
  avatar,
}

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:

ts
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 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.

ts
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' });

Fastify ​

Use useFastifyUploadContext() with @fastify/multipart inside middleware or hooks.

ts
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' },
);

Hono ​

Use useHonoUploadContext() to consume files returned by c.req.parseBody() during middleware execution.

ts
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' },
);

H3 ​

Use useH3UploadContext() in middleware or route setup. It can read files from event.context.requestFiles, request.formData(), or multipart parsing when available.

ts
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' },
);

If you only want to enrich one validator instance, the existing withExpressUploadContext(), withFastifyUploadContext(), withHonoUploadContext(), and withH3UploadContext() helpers are still available.