pompelmi 0.17.0-dev.37 → 0.18.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
@@ -33,6 +33,7 @@
33
33
  <img alt="node" src="https://img.shields.io/badge/node-%3E%3D18-339933?logo=node.js&logoColor=white">
34
34
  <img alt="types" src="https://img.shields.io/badge/types-TypeScript-3178C6?logo=typescript&logoColor=white">
35
35
  <a href="https://github.com/pompelmi/pompelmi/blob/main/LICENSE"><img alt="license" src="https://img.shields.io/npm/l/pompelmi"></a>
36
+ <a href="https://securityscorecards.dev/viewer/?uri=github.com/pompelmi/pompelmi"><img alt="OpenSSF Scorecard" src="https://api.securityscorecards.dev/projects/github.com/pompelmi/pompelmi/badge"/></a>
36
37
  <a href="https://codecov.io/gh/pompelmi/pompelmi"><img alt="codecov" src="https://codecov.io/gh/pompelmi/pompelmi/branch/main/graph/badge.svg?flag=core"/></a>
37
38
  <a href="https://github.com/pompelmi/pompelmi/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/pompelmi/pompelmi?style=social"></a>
38
39
  <a href="https://github.com/pompelmi/pompelmi/actions/workflows/ci-release-publish.yml"><img alt="CI / Release / Publish" src="https://img.shields.io/github/actions/workflow/status/pompelmi/pompelmi/ci-release-publish.yml?branch=main&label=CI%20%2F%20Release%20%2F%20Publish"></a>
@@ -45,6 +46,7 @@
45
46
  <p align="center"><a href="https://pompelmi.github.io/pompelmi/">Documentation</a> ·
46
47
  <a href="#installation">Install</a> ·
47
48
  <a href="#quick-start">Quick‑start</a> ·
49
+ <a href="#minimal-node-usage">Minimal Node</a> ·
48
50
  <a href="#github-action">GitHub Action</a> ·
49
51
  <a href="#adapters">Adapters</a> ·
50
52
  <a href="#diagrams">Diagrams</a> ·
@@ -65,6 +67,7 @@
65
67
 
66
68
  - [Install](#installation)
67
69
  - [Quick‑start](#quick-start)
70
+ - [Minimal Node usage](#minimal-node-usage)
68
71
  - [GitHub Action](#github-action)
69
72
  - [Adapters](#adapters)
70
73
  - [Diagrams](#diagrams)
@@ -131,7 +134,6 @@
131
134
 
132
135
  ```bash
133
136
  # core library
134
- [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/pompelmi/pompelmi/badge)](https://securityscorecards.dev/viewer/?uri=github.com/pompelmi/pompelmi)
135
137
  npm i pompelmi
136
138
  # or
137
139
  pnpm add pompelmi
@@ -175,6 +177,21 @@ export const scanner = composeScanners(
175
177
  );
176
178
  ```
177
179
 
180
+ ### Minimal Node usage
181
+
182
+ ```ts
183
+ import { scanFile } from 'pompelmi';
184
+
185
+ const res = await scanFile('path/to/file.zip'); // or any file
186
+ console.log(res.verdict); // "clean" | "suspicious" | "malicious"
187
+ ```
188
+
189
+ > See `examples/scan-one-file.ts` for a runnable script:
190
+ >
191
+ > ```bash
192
+ > pnpm tsx examples/scan-one-file.ts ./path/to/file
193
+ > ```
194
+
178
195
  ### Express
179
196
 
180
197
  ```ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pompelmi",
3
- "version": "0.17.0-dev.37",
3
+ "version": "0.18.0",
4
4
  "description": "RFI-safe file uploads for Node.js — Express/Koa/Next.js middleware with deep ZIP inspection, MIME/size checks, and optional YARA scanning.",
5
5
  "main": "./dist/pompelmi.cjs",
6
6
  "module": "./dist/pompelmi.esm.js",
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "scripts": {
37
37
  "build": "rollup -c",
38
- "prepublishOnly": "npm run build",
38
+ "prepublishOnly": "npm run build && npm run pack:strict",
39
39
  "yara:node:smoke": "tsx scripts/yara-node-smoke.ts",
40
40
  "yara:int:smoke": "tsx scripts/yara-integration-smoke.ts",
41
41
  "dev:remote": "tsx examples/remote-yara-server.ts",
@@ -56,13 +56,14 @@
56
56
  "repo:audit": "node scripts/audit.mjs",
57
57
  "pack:check": "node scripts/pack-check.mjs",
58
58
  "pack:list": "pnpm -r --filter \"@pompelmi/*\" --if-present pack --json --dry-run",
59
- "pack:strict": "node scripts/pack-check.mjs --strict"
59
+ "pack:strict": "node scripts/pack-check.mjs --strict",
60
+ "clean": "rimraf dist"
60
61
  },
61
62
  "license": "MIT",
62
63
  "devDependencies": {
63
64
  "@biomejs/biome": "^2.2.4",
64
65
  "@pompelmi/core": "workspace:*",
65
- "@pompelmi/engine": "workspace:0.17.0-dev.37-dev.6",
66
+ "@pompelmi/engine": "workspace:*",
66
67
  "@pompelmi/engine-heuristics": "workspace:^0.1.0",
67
68
  "@rollup/plugin-commonjs": "^28.0.6",
68
69
  "@rollup/plugin-node-resolve": "^16.0.1",
@@ -89,9 +90,6 @@
89
90
  "typescript": "^5.9.2",
90
91
  "vitest": "2.1.9"
91
92
  },
92
- "dependencies": {
93
- "rollup": "^4.45.1"
94
- },
95
93
  "peerDependencies": {
96
94
  "react": "^18.0.0 || ^19.0.0",
97
95
  "react-dom": "^18.0.0 || ^19.0.0"
@@ -100,7 +98,12 @@
100
98
  "@litko/yara-x": "^0.2.1"
101
99
  },
102
100
  "exports": {
103
- ".": {},
101
+ ".": {
102
+ "import": "./dist/pompelmi.esm.js",
103
+ "require": "./dist/pompelmi.cjs",
104
+ "default": "./dist/pompelmi.esm.js",
105
+ "types": "./dist/types/index.d.ts"
106
+ },
104
107
  "./package.json": "./package.json"
105
108
  },
106
109
  "files": [
@@ -109,7 +112,8 @@
109
112
  "README.md",
110
113
  "LICENSE*",
111
114
  "package.json",
112
- "CHANGELOG*"
115
+ "CHANGELOG*",
116
+ "LICENSE"
113
117
  ],
114
118
  "keywords": [
115
119
  "security",
@@ -151,5 +155,6 @@
151
155
  },
152
156
  "publishConfig": {
153
157
  "access": "public"
154
- }
158
+ },
159
+ "types": "./dist/types/index.d.ts"
155
160
  }
package/dist/index.cjs.js DELETED
@@ -1,86 +0,0 @@
1
- 'use strict';
2
-
3
- var react = require('react');
4
-
5
- /**
6
- * Reads an array of File objects via FileReader and returns their text.
7
- */
8
- async function scanFiles(files) {
9
- const readText = file => new Promise((resolve, reject) => {
10
- const reader = new FileReader();
11
- reader.onload = () => resolve(reader.result);
12
- reader.onerror = () => reject(reader.error);
13
- reader.readAsText(file);
14
- });
15
- const results = [];
16
- for (const file of files) {
17
- const content = await readText(file);
18
- results.push({
19
- file,
20
- content
21
- });
22
- }
23
- return results;
24
- }
25
-
26
- /**
27
- * Validates a File by MIME type and size (max 5 MB).
28
- */
29
- function validateFile(file) {
30
- const maxSize = 5 * 1024 * 1024;
31
- const allowedTypes = ['text/plain', 'application/json', 'text/csv'];
32
- if (!allowedTypes.includes(file.type)) {
33
- return {
34
- valid: false,
35
- error: 'Unsupported file type'
36
- };
37
- }
38
- if (file.size > maxSize) {
39
- return {
40
- valid: false,
41
- error: 'File too large (max 5 MB)'
42
- };
43
- }
44
- return {
45
- valid: true
46
- };
47
- }
48
-
49
- /**
50
- * React Hook: handles <input type="file" onChange> with validation + scanning.
51
- */
52
- function useFileScanner() {
53
- const [results, setResults] = react.useState([]);
54
- const [errors, setErrors] = react.useState([]);
55
- const onChange = react.useCallback(async e => {
56
- const fileList = Array.from(e.target.files || []);
57
- const good = [];
58
- const bad = [];
59
- for (const file of fileList) {
60
- const {
61
- valid,
62
- error
63
- } = validateFile(file);
64
- if (valid) good.push(file);else bad.push({
65
- file,
66
- error: error
67
- });
68
- }
69
- setErrors(bad);
70
- if (good.length) {
71
- const scanned = await scanFiles(good);
72
- setResults(scanned);
73
- } else {
74
- setResults([]);
75
- }
76
- }, []);
77
- return {
78
- results,
79
- errors,
80
- onChange
81
- };
82
- }
83
-
84
- exports.scanFiles = scanFiles;
85
- exports.useFileScanner = useFileScanner;
86
- exports.validateFile = validateFile;
package/dist/index.esm.js DELETED
@@ -1,82 +0,0 @@
1
- import { useState, useCallback } from 'react';
2
-
3
- /**
4
- * Reads an array of File objects via FileReader and returns their text.
5
- */
6
- async function scanFiles(files) {
7
- const readText = file => new Promise((resolve, reject) => {
8
- const reader = new FileReader();
9
- reader.onload = () => resolve(reader.result);
10
- reader.onerror = () => reject(reader.error);
11
- reader.readAsText(file);
12
- });
13
- const results = [];
14
- for (const file of files) {
15
- const content = await readText(file);
16
- results.push({
17
- file,
18
- content
19
- });
20
- }
21
- return results;
22
- }
23
-
24
- /**
25
- * Validates a File by MIME type and size (max 5 MB).
26
- */
27
- function validateFile(file) {
28
- const maxSize = 5 * 1024 * 1024;
29
- const allowedTypes = ['text/plain', 'application/json', 'text/csv'];
30
- if (!allowedTypes.includes(file.type)) {
31
- return {
32
- valid: false,
33
- error: 'Unsupported file type'
34
- };
35
- }
36
- if (file.size > maxSize) {
37
- return {
38
- valid: false,
39
- error: 'File too large (max 5 MB)'
40
- };
41
- }
42
- return {
43
- valid: true
44
- };
45
- }
46
-
47
- /**
48
- * React Hook: handles <input type="file" onChange> with validation + scanning.
49
- */
50
- function useFileScanner() {
51
- const [results, setResults] = useState([]);
52
- const [errors, setErrors] = useState([]);
53
- const onChange = useCallback(async e => {
54
- const fileList = Array.from(e.target.files || []);
55
- const good = [];
56
- const bad = [];
57
- for (const file of fileList) {
58
- const {
59
- valid,
60
- error
61
- } = validateFile(file);
62
- if (valid) good.push(file);else bad.push({
63
- file,
64
- error: error
65
- });
66
- }
67
- setErrors(bad);
68
- if (good.length) {
69
- const scanned = await scanFiles(good);
70
- setResults(scanned);
71
- } else {
72
- setResults([]);
73
- }
74
- }, []);
75
- return {
76
- results,
77
- errors,
78
- onChange
79
- };
80
- }
81
-
82
- export { scanFiles, useFileScanner, validateFile };