pompelmi 1.13.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -73,6 +73,9 @@ Most integrations require parsing ClamAV's stdout with regex, managing a clamd d
73
73
  ## Features
74
74
 
75
75
  - Standalone CLI — scan files from any terminal with `npx pompelmi scan`
76
+ - HTML security dashboard — generate beautiful scan reports with `--report` ([docs](./docs/dashboard.html))
77
+ - SVG share card — shareable scan result card with `--share-card` ([docs](./docs/dashboard.html#share-card))
78
+ - GitHub App — one-click installation for organizations, zero-config PR scanning ([docs](./docs/github-app.html))
76
79
  - Single `scan(filePath, [options])` function — works locally or against a remote clamd instance
77
80
  - `scanBuffer(buffer, [options])` — scan in-memory Buffers directly, no temp file required in TCP mode
78
81
  - `scanStream(stream, [options])` — scan a Readable stream directly. In TCP mode, streamed to clamd with no disk I/O.
@@ -86,11 +89,15 @@ Most integrations require parsing ClamAV's stdout with regex, managing a clamd d
86
89
  - Symbol-based verdicts (`Verdict.Clean` / `Verdict.Malicious` / `Verdict.ScanError`) — typo-proof comparisons
87
90
  - Full clamd support via the INSTREAM protocol — TCP (`host`/`port`) or UNIX socket (`socket`) with configurable timeout
88
91
  - Built-in helpers to install ClamAV and update virus definitions programmatically
89
- - Works with Express, Fastify, NestJS, and any other Node.js HTTP framework
92
+ - Works with Express, Fastify, NestJS, Hono, and any other Node.js HTTP framework
93
+ - Works with Node.js and Bun — uses `Bun.file()` for faster file reading when available
94
+ - Interactive demo at [pompelmi.app/demo](https://pompelmi.app/demo.html) — try before you install
90
95
  - Zero runtime dependencies — ships nothing but source code
91
96
  - Tested with EICAR standard antivirus test files
92
97
  - CommonJS module; TypeScript type declarations available inline
93
98
 
99
+ See [how pompelmi compares](./docs/comparison.html) to other Node.js ClamAV integrations.
100
+
94
101
  ---
95
102
 
96
103
  ## Framework Integrations
@@ -101,6 +108,8 @@ Official integration packages for popular frameworks:
101
108
  |---------|-----------|---------|
102
109
  | [@pompelmi/nestjs](./packages/nestjs/) | NestJS | `npm i @pompelmi/nestjs` |
103
110
  | [@pompelmi/fastify](./packages/fastify/) | Fastify | `npm i @pompelmi/fastify` |
111
+ | [@pompelmi/hono](./packages/hono/) | Hono | `npm i @pompelmi/hono` |
112
+ | [@pompelmi/testing](./packages/testing/) | Jest/Vitest/Node | `npm i -D @pompelmi/testing` |
104
113
 
105
114
  ### NestJS
106
115
 
@@ -129,11 +138,29 @@ const result = await fastify.pompelmi.scanBuffer(buffer);
129
138
  fastify.post('/upload', { preHandler: fastify.pompelmi.preHandler({ field: 'file' }) }, handler);
130
139
  ```
131
140
 
141
+ ### Hono (Node.js, Bun, Cloudflare Workers)
142
+
143
+ ```js
144
+ import { Hono } from 'hono'
145
+ import { pompelmiMiddleware } from '@pompelmi/hono'
146
+
147
+ const app = new Hono()
148
+
149
+ app.use('/upload/*', pompelmiMiddleware({
150
+ host: 'localhost',
151
+ port: 3310,
152
+ onInfected: (c, filename) => c.json({ error: 'Malware detected' }, 422),
153
+ }))
154
+
155
+ app.post('/upload', async (c) => c.json({ ok: true }))
156
+ ```
157
+
132
158
  ---
133
159
 
134
160
  ## Requirements
135
161
 
136
162
  - **Node.js** — any LTS release (no native addons, no C++ bindings)
163
+ - **Bun** — fully supported; uses `Bun.file()` for faster file reading
137
164
  - **ClamAV** — must be installed on the host or reachable over TCP
138
165
 
139
166
  pompelmi does not bundle or automatically download ClamAV. Install it once per machine (see [Installing ClamAV](#installing-clamav)).
@@ -153,6 +180,9 @@ yarn add pompelmi
153
180
 
154
181
  # pnpm
155
182
  pnpm add pompelmi
183
+
184
+ # bun
185
+ bun add pompelmi
156
186
  ```
157
187
 
158
188
  ### Docker
@@ -503,6 +533,8 @@ Scan any repository for viruses on every push or pull request — ClamAV is bund
503
533
 
504
534
  A ready-to-copy workflow is available at [`.github/workflows/action-example.yml`](./.github/workflows/action-example.yml). Full reference — inputs, outputs, layer caching, and more examples — in **[docs/github-action.md](./docs/github-action.md)**.
505
535
 
536
+ > **For organizations:** install the [pompelmi GitHub App](./docs/github-app.html) for zero-config scanning on every PR — no workflow file needed.
537
+
506
538
  ---
507
539
 
508
540
  ## Contributing
package/bin/pompelmi.js CHANGED
@@ -67,6 +67,10 @@ function parseArgs(argv) {
67
67
  quiet: false,
68
68
  delete: false,
69
69
  recursive: true,
70
+ report: false,
71
+ reportOutput: null,
72
+ shareCard: false,
73
+ shareCardOutput: null,
70
74
  };
71
75
 
72
76
  let i = 0;
@@ -92,6 +96,14 @@ function parseArgs(argv) {
92
96
  opts.timeout = parseInt(args[++i], 10);
93
97
  } else if (a === '--retries') {
94
98
  opts.retries = parseInt(args[++i], 10);
99
+ } else if (a === '--report') {
100
+ opts.report = true;
101
+ } else if (a === '--share-card') {
102
+ opts.shareCard = true;
103
+ } else if (a === '--output') {
104
+ const next = args[++i];
105
+ if (next && next.endsWith('.svg')) opts.shareCardOutput = next;
106
+ else opts.reportOutput = next;
95
107
  } else if (!a.startsWith('-') && opts.command && !opts.target) {
96
108
  opts.target = a;
97
109
  }
@@ -276,6 +288,26 @@ async function cmdScan(opts) {
276
288
 
277
289
  printResults(results, elapsed, opts);
278
290
 
291
+ if (opts.report) {
292
+ const { generateDashboard } = require('../src/Dashboard.js');
293
+ const outPath = opts.reportOutput || 'pompelmi-report.html';
294
+ generateDashboard(results, {
295
+ elapsed,
296
+ host: opts.host,
297
+ port: opts.port,
298
+ socket: opts.socket,
299
+ outputPath: outPath,
300
+ });
301
+ if (!opts.quiet) console.log(`\n Report saved: ${outPath}`);
302
+ }
303
+
304
+ if (opts.shareCard) {
305
+ const { generateShareCard } = require('../src/ShareCard.js');
306
+ const outPath = opts.shareCardOutput || 'pompelmi-scan-card.svg';
307
+ generateShareCard(results, { outputPath: outPath });
308
+ if (!opts.quiet) console.log(` Share card saved: ${outPath}`);
309
+ }
310
+
279
311
  const hasInfected = results.some(r => r.verdict === 'infected');
280
312
  const hasError = results.some(r => r.verdict === 'error');
281
313
  const clamdDown = results.some(r => r._clamdUnreachable);
@@ -361,6 +393,10 @@ SCAN OPTIONS
361
393
  --json Output results as JSON (no logo, no colors)
362
394
  --quiet, -q Only print infected files and summary
363
395
  --delete Delete infected files after confirmation
396
+ --report Generate an HTML security dashboard report
397
+ --share-card Generate a shareable SVG scan result card
398
+ --output <file> Output path for --report (default: pompelmi-report.html)
399
+ or --share-card (default: pompelmi-scan-card.svg)
364
400
 
365
401
  WATCH OPTIONS
366
402
  --host, --port, --socket, --timeout (same as scan)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pompelmi",
3
- "version": "1.13.0",
3
+ "version": "1.15.0",
4
4
  "description": "ClamAV for humans — scan any file and get back Clean, Malicious, or ScanError. No daemons. No cloud. No native bindings.",
5
5
  "license": "ISC",
6
6
  "author": "pompelmi contributors",
@@ -37,7 +37,7 @@
37
37
  "pompelmi": "./bin/pompelmi.js"
38
38
  },
39
39
  "scripts": {
40
- "test": "node --test test/unit.test.js && node --test packages/nestjs/test/index.test.js && node --test packages/fastify/test/index.test.js && node test/scan.test.js",
40
+ "test": "node --test test/unit.test.js && node --test packages/nestjs/test/index.test.js && node --test packages/fastify/test/index.test.js && node --test packages/nextjs/test/index.test.js && node --test packages/hono/test/index.test.js && node --test packages/testing/test/index.test.js && node test/scan.test.js",
41
41
  "lint": "eslint src/"
42
42
  },
43
43
  "publishConfig": {
@@ -0,0 +1,160 @@
1
+ # @pompelmi/hono
2
+
3
+ Hono middleware for [pompelmi](https://pompelmi.app) — in-process ClamAV virus scanning with zero extra dependencies.
4
+
5
+ Works on **Node.js**, **Bun**, and **Cloudflare Workers** (simulation mode).
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @pompelmi/hono pompelmi
11
+ # or
12
+ bun add @pompelmi/hono pompelmi
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```js
18
+ import { Hono } from 'hono'
19
+ import { pompelmiMiddleware } from '@pompelmi/hono'
20
+
21
+ const app = new Hono()
22
+
23
+ app.use('/upload/*', pompelmiMiddleware({
24
+ host: 'localhost',
25
+ port: 3310,
26
+ }))
27
+
28
+ app.post('/upload', async (c) => {
29
+ // file is guaranteed clean here
30
+ return c.json({ ok: true })
31
+ })
32
+
33
+ export default app
34
+ ```
35
+
36
+ ## Custom infected handler
37
+
38
+ ```js
39
+ app.use('/upload/*', pompelmiMiddleware({
40
+ host: 'localhost',
41
+ port: 3310,
42
+ field: 'file',
43
+ onInfected: (c, filename) => {
44
+ console.warn(`Blocked malicious upload: ${filename}`)
45
+ return c.json({ error: 'Malware detected', filename }, 422)
46
+ },
47
+ }))
48
+ ```
49
+
50
+ ## Hono on Node.js
51
+
52
+ ```js
53
+ const { serve } = require('@hono/node-server')
54
+ const { Hono } = require('hono')
55
+ const { pompelmiMiddleware } = require('@pompelmi/hono')
56
+
57
+ const app = new Hono()
58
+
59
+ app.use('/upload/*', pompelmiMiddleware({
60
+ host: '127.0.0.1',
61
+ port: 3310,
62
+ }))
63
+
64
+ app.post('/upload', async (c) => {
65
+ const body = await c.req.parseBody()
66
+ const file = body['file']
67
+ return c.json({ name: file.name, size: file.size, ok: true })
68
+ })
69
+
70
+ serve({ fetch: app.fetch, port: 3000 }, () => {
71
+ console.log('Server running on http://localhost:3000')
72
+ })
73
+ ```
74
+
75
+ ## Hono on Bun
76
+
77
+ ```ts
78
+ import { Hono } from 'hono'
79
+ import { pompelmiMiddleware } from '@pompelmi/hono'
80
+
81
+ const app = new Hono()
82
+
83
+ app.use('/upload/*', pompelmiMiddleware({
84
+ socket: '/run/clamav/clamd.sock', // UNIX socket — faster on Bun
85
+ }))
86
+
87
+ app.post('/upload', async (c) => {
88
+ return c.json({ ok: true })
89
+ })
90
+
91
+ export default {
92
+ port: 3000,
93
+ fetch: app.fetch,
94
+ }
95
+ ```
96
+
97
+ ## Hono on Cloudflare Workers
98
+
99
+ > Note: clamd is not available inside Workers. Use pompelmi in a Node.js / Bun sidecar
100
+ > service and call it over HTTP, or use the UNIX socket approach with a co-located daemon.
101
+ >
102
+ > For Workers deployments without a sidecar, the middleware skips scanning gracefully
103
+ > and calls `next()` — you can gate the behaviour with an environment variable.
104
+
105
+ ```ts
106
+ import { Hono } from 'hono'
107
+ import { pompelmiMiddleware } from '@pompelmi/hono'
108
+
109
+ const app = new Hono<{ Bindings: { SCAN_HOST: string; SCAN_PORT: string } }>()
110
+
111
+ app.use('/upload/*', async (c, next) => {
112
+ if (!c.env.SCAN_HOST) return next() // skip if no clamd configured
113
+ return pompelmiMiddleware({
114
+ host: c.env.SCAN_HOST,
115
+ port: Number(c.env.SCAN_PORT) || 3310,
116
+ })(c, next)
117
+ })
118
+
119
+ app.post('/upload', async (c) => {
120
+ return c.json({ ok: true })
121
+ })
122
+
123
+ export default app
124
+ ```
125
+
126
+ ## Configuration Reference
127
+
128
+ All options are forwarded to pompelmi's `ScanOptions`:
129
+
130
+ | Option | Type | Default | Description |
131
+ |--------|------|---------|-------------|
132
+ | `field` | `string` | `'file'` | Form field name containing the uploaded file |
133
+ | `host` | `string` | — | clamd hostname (enables TCP mode) |
134
+ | `port` | `number` | `3310` | clamd port |
135
+ | `socket` | `string` | — | UNIX domain socket path |
136
+ | `timeout` | `number` | `15000` | Socket idle timeout in ms |
137
+ | `retries` | `number` | `0` | Number of retry attempts |
138
+ | `retryDelay` | `number` | `1000` | Delay between retries in ms |
139
+ | `onInfected` | `Function` | — | Called with `(c, filename)` when malware is detected |
140
+
141
+ ## TypeScript
142
+
143
+ ```ts
144
+ import { Hono } from 'hono'
145
+ import { pompelmiMiddleware } from '@pompelmi/hono'
146
+ import { Verdict } from 'pompelmi'
147
+
148
+ const app = new Hono()
149
+
150
+ app.use('/upload/*', pompelmiMiddleware({
151
+ host: 'localhost',
152
+ port: 3310,
153
+ onInfected: (c, filename) =>
154
+ c.json({ error: `${filename} is infected` }, 422),
155
+ }))
156
+ ```
157
+
158
+ ## License
159
+
160
+ ISC — see root [LICENSE](../../LICENSE).
@@ -0,0 +1,29 @@
1
+ import type { MiddlewareHandler, Context } from 'hono';
2
+ import type { ScanOptions } from 'pompelmi';
3
+
4
+ export interface PompelmiHonoOptions extends ScanOptions {
5
+ /** Form field name that contains the uploaded file (default: 'file') */
6
+ field?: string;
7
+ /**
8
+ * Called with (c, filename) when a malicious file is detected.
9
+ * Must return a Response (or Promise<Response>).
10
+ * If omitted, responds with HTTP 422 { error: 'Malware detected' }.
11
+ */
12
+ onInfected?: (c: Context, filename: string) => Response | Promise<Response>;
13
+ }
14
+
15
+ /**
16
+ * Hono middleware that scans an uploaded file before the route handler runs.
17
+ * Reads the file from the parsed multipart body field (default: 'file').
18
+ *
19
+ * @example
20
+ * import { Hono } from 'hono'
21
+ * import { pompelmiMiddleware } from '@pompelmi/hono'
22
+ *
23
+ * const app = new Hono()
24
+ * app.use('/upload/*', pompelmiMiddleware({ host: 'localhost', port: 3310 }))
25
+ * app.post('/upload', (c) => c.json({ ok: true }))
26
+ */
27
+ export function pompelmiMiddleware(options?: PompelmiHonoOptions): MiddlewareHandler;
28
+
29
+ export { Verdict } from 'pompelmi';
@@ -0,0 +1,74 @@
1
+ 'use strict';
2
+
3
+ const { scanBuffer, Verdict } = require('pompelmi');
4
+
5
+ const SCAN_KEYS = ['host', 'port', 'socket', 'timeout', 'retries', 'retryDelay'];
6
+
7
+ function buildScanOptions(options) {
8
+ const out = {};
9
+ for (const k of SCAN_KEYS) {
10
+ if (options[k] !== undefined) out[k] = options[k];
11
+ }
12
+ return out;
13
+ }
14
+
15
+ async function toBuffer(raw) {
16
+ if (Buffer.isBuffer(raw)) return raw;
17
+ if (raw instanceof Uint8Array) return Buffer.from(raw);
18
+ // Web API File / Blob (Hono on Bun, Cloudflare Workers, Node 20+)
19
+ if (raw && typeof raw.arrayBuffer === 'function') {
20
+ return Buffer.from(await raw.arrayBuffer());
21
+ }
22
+ if (typeof raw === 'string') return Buffer.from(raw);
23
+ return null;
24
+ }
25
+
26
+ /**
27
+ * Hono middleware that scans an uploaded file with pompelmi before the route
28
+ * handler runs. The file is read from the parsed multipart body.
29
+ *
30
+ * @param {object} [options]
31
+ * @param {string} [options.field='file'] - Form field name containing the file.
32
+ * @param {string} [options.host] - clamd hostname (enables TCP mode).
33
+ * @param {number} [options.port=3310] - clamd port.
34
+ * @param {string} [options.socket] - UNIX domain socket path.
35
+ * @param {number} [options.timeout=15000] - Socket idle timeout in ms.
36
+ * @param {number} [options.retries=0] - Number of retry attempts.
37
+ * @param {number} [options.retryDelay=1000] - Delay between retries in ms.
38
+ * @param {Function} [options.onInfected] - Called with (c, filename) when malware
39
+ * is detected; must return a Response.
40
+ * Defaults to 422 JSON error.
41
+ */
42
+ function pompelmiMiddleware(options) {
43
+ const { field = 'file', onInfected } = options || {};
44
+ const scanOptions = buildScanOptions(options || {});
45
+
46
+ return async function pompelmiHonoMiddleware(c, next) {
47
+ let body;
48
+ try {
49
+ body = await c.req.parseBody();
50
+ } catch {
51
+ return next();
52
+ }
53
+
54
+ const raw = body[field];
55
+ if (raw == null) return next();
56
+
57
+ const buffer = await toBuffer(raw);
58
+ if (!buffer || buffer.length === 0) return next();
59
+
60
+ const result = await scanBuffer(buffer, scanOptions);
61
+
62
+ if (result === Verdict.Malicious) {
63
+ const filename = (raw && typeof raw.name === 'string') ? raw.name : field;
64
+ if (typeof onInfected === 'function') {
65
+ return onInfected(c, filename);
66
+ }
67
+ return c.json({ error: 'Malware detected' }, 422);
68
+ }
69
+
70
+ return next();
71
+ };
72
+ }
73
+
74
+ module.exports = { pompelmiMiddleware, Verdict };
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@pompelmi/hono",
3
+ "version": "1.0.0",
4
+ "description": "Hono middleware for pompelmi — in-process ClamAV virus scanning with zero extra dependencies",
5
+ "license": "ISC",
6
+ "author": "pompelmi contributors",
7
+ "homepage": "https://pompelmi.app",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/pompelmi/pompelmi.git",
11
+ "directory": "packages/hono"
12
+ },
13
+ "keywords": [
14
+ "hono",
15
+ "middleware",
16
+ "clamav",
17
+ "antivirus",
18
+ "virus-scan",
19
+ "malware",
20
+ "file-upload",
21
+ "security",
22
+ "pompelmi",
23
+ "bun",
24
+ "edge",
25
+ "cloudflare-workers"
26
+ ],
27
+ "main": "./index.js",
28
+ "types": "./index.d.ts",
29
+ "scripts": {
30
+ "test": "node --test test/index.test.js"
31
+ },
32
+ "peerDependencies": {
33
+ "hono": ">=3",
34
+ "pompelmi": ">=1.14.0"
35
+ },
36
+ "publishConfig": {
37
+ "registry": "https://registry.npmjs.org/",
38
+ "access": "public"
39
+ }
40
+ }
@@ -0,0 +1,83 @@
1
+ # @pompelmi/nextjs
2
+
3
+ Next.js middleware for [pompelmi](https://pompelmi.app) — in-process ClamAV virus scanning with zero extra dependencies.
4
+
5
+ Supports both the **App Router** (Next.js 13+) and the **Pages Router** (Next.js ≤ 12).
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install pompelmi @pompelmi/nextjs
11
+ ```
12
+
13
+ ClamAV must be available on the server — either via the system `clamscan` binary or a running `clamd` daemon.
14
+
15
+ ## App Router (Next.js 13+)
16
+
17
+ ```js
18
+ // app/api/upload/route.js
19
+ import { withPompelmi } from '@pompelmi/nextjs'
20
+
21
+ export const POST = withPompelmi(async (req) => {
22
+ const formData = await req.formData()
23
+ const file = formData.get('file')
24
+ // req.pompelmiVerdict is set — Verdict.Clean is guaranteed here
25
+ return Response.json({ ok: true })
26
+ }, {
27
+ host: 'localhost',
28
+ port: 3310,
29
+ })
30
+ ```
31
+
32
+ With TypeScript:
33
+
34
+ ```ts
35
+ // app/api/upload/route.ts
36
+ import { withPompelmi } from '@pompelmi/nextjs'
37
+
38
+ export const POST = withPompelmi(async (req: Request) => {
39
+ return Response.json({ ok: true })
40
+ }, { host: 'localhost', port: 3310 })
41
+ ```
42
+
43
+ ## Pages Router (Next.js ≤ 12)
44
+
45
+ ```js
46
+ // pages/api/upload.js
47
+ import { withPompelmiHandler } from '@pompelmi/nextjs'
48
+
49
+ async function handler(req, res) {
50
+ // req.pompelmiVerdict is set — Verdict.Clean is guaranteed here
51
+ res.json({ ok: true })
52
+ }
53
+
54
+ export default withPompelmiHandler(handler, {
55
+ host: 'localhost',
56
+ port: 3310,
57
+ })
58
+ ```
59
+
60
+ ## Options
61
+
62
+ All options are forwarded to `pompelmi.scanBuffer()`:
63
+
64
+ | Option | Type | Default | Description |
65
+ |---|---|---|---|
66
+ | `host` | `string` | — | clamd hostname (TCP mode) |
67
+ | `port` | `number` | `3310` | clamd port |
68
+ | `socket` | `string` | — | UNIX socket path |
69
+ | `timeout` | `number` | `15000` | Connection timeout in ms |
70
+ | `retries` | `number` | `0` | Auto-retry count on failure |
71
+
72
+ When neither `host` nor `socket` is provided, pompelmi falls back to the local `clamscan` binary.
73
+
74
+ ## Behaviour
75
+
76
+ - The raw request body is buffered and scanned **before** your handler runs.
77
+ - If the body is malicious, a **400 JSON** response is returned immediately: `{ "error": "Malicious file detected" }`.
78
+ - `req.pompelmiVerdict` is set to the `Verdict` symbol so your handler can inspect it if needed.
79
+ - Scan errors (e.g. clamd unreachable) are **not** blocking — the request proceeds with `Verdict.ScanError`.
80
+
81
+ ## License
82
+
83
+ ISC
@@ -0,0 +1,45 @@
1
+ import type { VerdictValue, ScanOptions } from 'pompelmi';
2
+
3
+ /** Options accepted by withPompelmi / withPompelmiHandler */
4
+ export interface PompelmiNextOptions extends ScanOptions {}
5
+
6
+ /**
7
+ * App Router (Next.js 13+) wrapper.
8
+ * Scans the raw request body before the handler runs.
9
+ * Returns HTTP 400 if the body is malicious.
10
+ *
11
+ * @example
12
+ * // app/api/upload/route.ts
13
+ * import { withPompelmi } from '@pompelmi/nextjs'
14
+ *
15
+ * export const POST = withPompelmi(async (req) => {
16
+ * return Response.json({ ok: true })
17
+ * }, { host: 'localhost', port: 3310 })
18
+ */
19
+ export declare function withPompelmi(
20
+ handler: (req: Request, ctx?: unknown) => Promise<Response>,
21
+ options?: PompelmiNextOptions
22
+ ): (req: Request, ctx?: unknown) => Promise<Response>;
23
+
24
+ /**
25
+ * Pages Router (Next.js ≤ 12) wrapper.
26
+ * Scans the raw request body before the handler runs.
27
+ * Sends HTTP 400 if the body is malicious.
28
+ *
29
+ * @example
30
+ * // pages/api/upload.ts
31
+ * import { withPompelmiHandler } from '@pompelmi/nextjs'
32
+ * import type { NextApiRequest, NextApiResponse } from 'next'
33
+ *
34
+ * async function handler(req: NextApiRequest, res: NextApiResponse) {
35
+ * res.json({ ok: true })
36
+ * }
37
+ *
38
+ * export default withPompelmiHandler(handler, { host: 'localhost', port: 3310 })
39
+ */
40
+ export declare function withPompelmiHandler(
41
+ handler: (req: import('http').IncomingMessage, res: import('http').ServerResponse) => void | Promise<void>,
42
+ options?: PompelmiNextOptions
43
+ ): (req: import('http').IncomingMessage, res: import('http').ServerResponse) => Promise<void>;
44
+
45
+ export { Verdict } from 'pompelmi';