payload-guard-filter 1.3.0 → 1.3.2
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 +14 -303
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# payload-guard
|
|
2
2
|
|
|
3
|
+
> Part of the [Professional Node.js Backend Toolkit](https://github.com/sannuk79/PROJECTS-AND-NPM-PACKAGES-)
|
|
4
|
+
|
|
3
5
|
<p align="center">
|
|
4
6
|
<strong>🛡️ Lightweight, zero-dependency shape-based payload filtering and sanitization</strong>
|
|
5
7
|
</p>
|
|
@@ -44,10 +46,6 @@ graph LR
|
|
|
44
46
|
|
|
45
47
|
```bash
|
|
46
48
|
npm install payload-guard
|
|
47
|
-
# or
|
|
48
|
-
yarn add payload-guard
|
|
49
|
-
# or
|
|
50
|
-
pnpm add payload-guard
|
|
51
49
|
```
|
|
52
50
|
|
|
53
51
|
---
|
|
@@ -79,318 +77,31 @@ const safeData = userShape(rawData);
|
|
|
79
77
|
// Result: { id: 1, name: 'John Doe', email: 'john@example.com' }
|
|
80
78
|
```
|
|
81
79
|
|
|
82
|
-
### Express Middleware
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
import express from 'express';
|
|
86
|
-
import { guard, guardMiddleware } from 'payload-guard';
|
|
87
|
-
|
|
88
|
-
const app = express();
|
|
89
|
-
app.use(express.json());
|
|
90
|
-
|
|
91
|
-
// Apply middleware
|
|
92
|
-
app.use(guardMiddleware({
|
|
93
|
-
sanitizeBody: true,
|
|
94
|
-
sensitiveFields: ['password', 'token'],
|
|
95
|
-
devMode: process.env.NODE_ENV === 'development',
|
|
96
|
-
}));
|
|
97
|
-
|
|
98
|
-
const userShape = guard.shape({
|
|
99
|
-
id: 'number',
|
|
100
|
-
name: 'string',
|
|
101
|
-
email: 'string',
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
app.post('/users', (req, res) => {
|
|
105
|
-
const user = createUser(req.body);
|
|
106
|
-
res.guardJson(userShape, user); // ✅ Filtered response
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
app.listen(3000);
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Frontend Usage
|
|
113
|
-
|
|
114
|
-
```typescript
|
|
115
|
-
import { validateShape } from 'payload-guard/client';
|
|
116
|
-
|
|
117
|
-
const userShape = { id: 'number', name: 'string', email: 'string' };
|
|
118
|
-
const validateUser = validateShape(userShape, { devMode: true });
|
|
119
|
-
|
|
120
|
-
// Fetch and validate
|
|
121
|
-
const user = await fetch('/api/user')
|
|
122
|
-
.then(r => r.json())
|
|
123
|
-
.then(validateUser);
|
|
124
|
-
|
|
125
|
-
// Dev mode warnings:
|
|
126
|
-
// ⚠️ Unexpected field "createdAt" in response
|
|
127
|
-
// ⚠️ Missing field "email" in response
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
## 📖 API Reference
|
|
133
|
-
|
|
134
|
-
### `guard.shape(descriptor, options?)`
|
|
135
|
-
|
|
136
|
-
Create a filter function from a shape descriptor.
|
|
137
|
-
|
|
138
|
-
```typescript
|
|
139
|
-
const userShape = guard.shape({
|
|
140
|
-
id: 'number',
|
|
141
|
-
name: 'string',
|
|
142
|
-
email: 'string',
|
|
143
|
-
role: { type: 'string', default: 'user' },
|
|
144
|
-
});
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
**Supported types:**
|
|
148
|
-
- `'string'` — String values (auto-trimmed)
|
|
149
|
-
- `'number'` — Numeric values
|
|
150
|
-
- `'boolean'` — Boolean values
|
|
151
|
-
- `'any'` — Any value (no transformation)
|
|
152
|
-
|
|
153
|
-
**Field config options:**
|
|
154
|
-
```typescript
|
|
155
|
-
{
|
|
156
|
-
type: 'string',
|
|
157
|
-
required: false, // Optional field
|
|
158
|
-
default: 'value', // Default value if missing
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### `guard.array(itemShape)`
|
|
163
|
-
|
|
164
|
-
Create an array filter.
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
const postsShape = guard.shape({
|
|
168
|
-
posts: guard.array({
|
|
169
|
-
id: 'number',
|
|
170
|
-
title: 'string',
|
|
171
|
-
}),
|
|
172
|
-
});
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### `guardMiddleware(options)`
|
|
176
|
-
|
|
177
|
-
Express middleware for automatic sanitization.
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
app.use(guardMiddleware({
|
|
181
|
-
sanitizeBody: true, // Filter req.body
|
|
182
|
-
requestShape: userShape, // Shape for request body
|
|
183
|
-
filterResponse: true, // Auto-filter all res.json()
|
|
184
|
-
sensitiveFields: [], // Extra sensitive field names
|
|
185
|
-
devMode: false, // Enable dev warnings
|
|
186
|
-
}));
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### `res.guardJson(shape, data)`
|
|
190
|
-
|
|
191
|
-
Added by middleware — send filtered JSON response.
|
|
192
|
-
|
|
193
|
-
```typescript
|
|
194
|
-
app.get('/user', (req, res) => {
|
|
195
|
-
res.guardJson(userShape, userData);
|
|
196
|
-
});
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### `validateShape(shape, options?)` (Client)
|
|
200
|
-
|
|
201
|
-
Create a validator for frontend use.
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
import { validateShape } from 'payload-guard/client';
|
|
205
|
-
|
|
206
|
-
const validate = validateShape(userShape, {
|
|
207
|
-
devMode: true, // Log warnings
|
|
208
|
-
strict: false, // Throw on errors
|
|
209
|
-
});
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
---
|
|
213
|
-
|
|
214
|
-
## 🔒 Security
|
|
215
|
-
|
|
216
|
-
### Default Sensitive Fields
|
|
217
|
-
|
|
218
|
-
These fields are **automatically removed** from all outputs:
|
|
219
|
-
|
|
220
|
-
- `password`, `password_hash`, `password_reset_token`, `pwd`
|
|
221
|
-
- `token`, `access_token`, `refresh_token`, `auth_token`
|
|
222
|
-
- `secret`, `api_key`, `private_key`, `encryption_key`
|
|
223
|
-
- `authorization`, `auth`, `session_id`
|
|
224
|
-
- `ssn`, `credit_card`, `cvv`, `card_number`
|
|
225
|
-
|
|
226
|
-
### Add Custom Sensitive Fields
|
|
227
|
-
|
|
228
|
-
```typescript
|
|
229
|
-
guard.config({
|
|
230
|
-
sensitiveFields: ['internal_id', 'admin_notes', 'salary'],
|
|
231
|
-
});
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
---
|
|
235
|
-
|
|
236
|
-
## 🏗️ Nested Objects & Arrays
|
|
237
|
-
|
|
238
|
-
```typescript
|
|
239
|
-
const postShape = guard.shape({
|
|
240
|
-
id: 'number',
|
|
241
|
-
title: 'string',
|
|
242
|
-
author: guard.shape({
|
|
243
|
-
id: 'number',
|
|
244
|
-
name: 'string',
|
|
245
|
-
// author.password, author.token auto-removed!
|
|
246
|
-
}),
|
|
247
|
-
tags: guard.array({
|
|
248
|
-
id: 'number',
|
|
249
|
-
name: 'string',
|
|
250
|
-
}),
|
|
251
|
-
comments: guard.array(
|
|
252
|
-
guard.shape({
|
|
253
|
-
id: 'number',
|
|
254
|
-
text: 'string',
|
|
255
|
-
user: guard.shape({
|
|
256
|
-
id: 'number',
|
|
257
|
-
name: 'string',
|
|
258
|
-
}),
|
|
259
|
-
})
|
|
260
|
-
),
|
|
261
|
-
});
|
|
262
|
-
```
|
|
263
|
-
|
|
264
80
|
---
|
|
265
81
|
|
|
266
82
|
## ⚡ Performance
|
|
267
83
|
|
|
268
|
-
|
|
|
269
|
-
|
|
270
|
-
|
|
|
271
|
-
|
|
|
272
|
-
|
|
|
273
|
-
| Bundle size | <8KB | 50KB+ | 70KB+ |
|
|
274
|
-
| Dependencies | 0 | 5+ | 10+ |
|
|
275
|
-
|
|
276
|
-
---
|
|
277
|
-
|
|
278
|
-
## 🏢 Enterprise Features (v1.2.0+)
|
|
279
|
-
|
|
280
|
-
Designed for high-performance production systems, Payload Guard includes enterprise-grade features for security, observability, and performance.
|
|
84
|
+
| Benchmark | ops/sec | avg (ms) |
|
|
85
|
+
|-----------|---------|----------|
|
|
86
|
+
| **Small payload** (5 fields) | 449,365 | **0.0022ms** |
|
|
87
|
+
| **Medium payload** (50 posts) | 7,791 | **0.1284ms** |
|
|
88
|
+
| **Large payload** (1000 users) | 246 | **4.0724ms** |
|
|
281
89
|
|
|
282
|
-
|
|
283
|
-
Automatically remove sensitive headers like `Authorization` or `Cookie` before your business logic handles the request.
|
|
284
|
-
```ts
|
|
285
|
-
app.use(guardMiddleware({
|
|
286
|
-
sanitizeHeaders: true,
|
|
287
|
-
sensitiveHeaders: ['x-api-key', 'session-id'] // optional extras
|
|
288
|
-
}));
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
### 🧠 2. Memory Safety (`maxArrayLength`)
|
|
292
|
-
Prevent DoS attacks via extremely large arrays by automatically truncating them to a safe limit.
|
|
293
|
-
```ts
|
|
294
|
-
const shape = guard.shape({ items: guard.array('string') }, { maxArrayLength: 1000 });
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
### ⚡ 3. Async Safety (`maxPayloadSize`)
|
|
298
|
-
Avoid processing massive JSON payloads that could block the event loop.
|
|
299
|
-
```ts
|
|
300
|
-
app.use(guardMiddleware({
|
|
301
|
-
maxPayloadSize: 1024 * 512, // 512KB
|
|
302
|
-
skipLargePayload: true // Skips filtering if too large
|
|
303
|
-
}));
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
### ⏱️ 4. Middleware Timing Stats
|
|
307
|
-
Track exactly how much time Payload Guard adds to your request cycle.
|
|
308
|
-
```
|
|
309
|
-
[payload-guard] [POST] /api/data: reduced 15KB -> 4KB (73%) in 0.12ms
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
### 📊 5. Human-Readable Metrics
|
|
313
|
-
Visibility into bandwidth savings with formatted byte sizes and percentages.
|
|
314
|
-
|
|
315
|
-
### 🛠️ 6. CLI Type Sync
|
|
316
|
-
Generate frontend TypeScript types from your backend shapes with one command.
|
|
317
|
-
```bash
|
|
318
|
-
npx payload-guard sync
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
### ⚠️ 7. Route-Aware Dev Warnings
|
|
322
|
-
Dev mode warnings now include the full method, path, and nested field locations (e.g., `user.profile.password`) for faster debugging.
|
|
323
|
-
|
|
324
|
-
### 🛣️ 8. Ignore Routes
|
|
325
|
-
Skip processing for high-volume or incompatible routes like file uploads or health checks.
|
|
326
|
-
```ts
|
|
327
|
-
app.use(guardMiddleware({ ignoreRoutes: ['/health', '/upload'] }));
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
### 🏗️ 9. Shared Schemas & Examples
|
|
331
|
-
Built-in support for reusable schemas across your monorepo and a `examples/real-world` project for reference.
|
|
332
|
-
|
|
333
|
-
### 🚀 10. Performance Benchmarks
|
|
334
|
-
A dedicated benchmark suite to verify sub-millisecond overhead. `npm run benchmark`.
|
|
90
|
+
> **Memory Usage**: ~121 MB Heap Used (Stable)
|
|
335
91
|
|
|
336
92
|
---
|
|
337
93
|
|
|
338
|
-
##
|
|
339
|
-
|
|
340
|
-
### 🛡️ Fail-Safe Mode (`failOpen`)
|
|
341
|
-
In production, we prioritize availability. If filtering fails for any reason, `failOpen: true` (default) ensures the original data is sent instead of breaking the request.
|
|
94
|
+
## 🛡️ Fail-Safe Design
|
|
342
95
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
### 🔍 Detailed Debug Logs
|
|
347
|
-
Enable `logRemovedFields: true` to see exactly which fields were stripped from your payloads:
|
|
348
|
-
`[payload-guard] /api/user Removed fields: password, token, internal_id`
|
|
96
|
+
Built for production reliability:
|
|
97
|
+
- **Isolation**: Monitoring failures **never** break your API responses. If a storage adapter or plugin crashes, the error is caught and logged, while the user's request continues normally.
|
|
98
|
+
- **Async-Only**: All processing is non-blocking to ensure zero impact on event loop latency.
|
|
349
99
|
|
|
350
100
|
---
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
The core is zero-dependency and framework-agnostic. Use it anywhere:
|
|
355
|
-
|
|
356
|
-
### Hono / Cloudflare Workers
|
|
357
|
-
```ts
|
|
358
|
-
app.post('/user', async (c) => {
|
|
359
|
-
const body = await c.req.json();
|
|
360
|
-
return c.json(userShape(body));
|
|
361
|
-
});
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
### Fastify
|
|
365
|
-
```ts
|
|
366
|
-
fastify.post('/user', (req, reply) => {
|
|
367
|
-
reply.send(userShape(req.body));
|
|
368
|
-
});
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
---
|
|
372
|
-
|
|
373
|
-
## 🛑 When NOT to use
|
|
374
|
-
|
|
375
|
-
Payload Guard is optimized for JSON APIs. It is **not** suitable for:
|
|
376
|
-
1. **Binary Data**: PDFs, Images, or raw Buffers.
|
|
377
|
-
2. **File Streams**: Use `multer` or similar for multipart data.
|
|
378
|
-
3. **Heavy Computation**: Don't use it on payloads > 10MB without adjusting `maxPayloadSize`.
|
|
101
|
+
### ⛑️ Maintained actively.
|
|
102
|
+
**Bug fixes usually within 24–48 hours.**
|
|
379
103
|
|
|
380
104
|
---
|
|
381
|
-
|
|
382
|
-
## 🛠️ CLI
|
|
383
|
-
|
|
384
|
-
```bash
|
|
385
|
-
npx payload-guard init
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
Creates example files in your project:
|
|
389
|
-
- `shapes.ts` — Example shape definitions
|
|
390
|
-
- `server-example.ts` — Express middleware setup
|
|
391
|
-
|
|
392
|
-
---
|
|
393
|
-
|
|
394
105
|
## 📄 License
|
|
395
106
|
|
|
396
107
|
MIT
|
package/package.json
CHANGED