payload-guard-filter 1.6.3 → 1.8.1

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
@@ -1,174 +1,277 @@
1
- # payload-guard
2
-
3
- > Part of the [Professional Node.js Backend Toolkit](https://github.com/sannuk79/PROJECTS-AND-NPM-PACKAGES-)
4
-
5
- <p align="center">
6
- <strong>🛡️ Lightweight, zero-dependency shape-based payload filtering and sanitization</strong>
7
- </p>
8
-
9
- <p align="center">
10
- <img src="https://img.shields.io/badge/bundle%20size-%3C8KB-brightgreen" alt="Bundle Size">
11
- <img src="https://img.shields.io/badge/dependencies-0-blue" alt="Zero Dependencies">
12
- <img src="https://img.shields.io/badge/TypeScript-100%25-blue" alt="TypeScript">
13
- <img src="https://img.shields.io/badge/Node.js-18%2B-green" alt="Node.js 18+">
14
- </p>
15
-
16
- ---
17
-
18
- ## 🛡️ Workflow
19
-
20
- ```mermaid
21
- graph LR
22
- A[Request] --> B(Gatekeeper)
23
- B --> C{Shape Check}
24
- C -- Valid --> D[Redact & Clean]
25
- C -- Invalid --> E[Strict Error / Fail Safe]
26
- D --> F[Secure Response]
27
- E --> F
28
- F --> G((Metrics))
29
- ```
30
-
31
- ---
32
-
33
- ## ✨ Features
34
-
35
- - **Shape-based filtering** — Define what you want, auto-remove everything else
36
- - **Sensitive field protection** — `password`, `token`, `secret` automatically removed
37
- - **Zero dependencies** — Pure TypeScript, no external packages
38
- - **Universal** — Works in Node.js, Browser, React Native
39
- - **TypeScript-first** — Full type inference from shape definitions
40
- - **Blazing fast** — Compiled schemas for production performance
41
- - **Never crashes** — Graceful failure mode, production-safe
42
-
43
- ---
44
-
45
- ## 📦 Installation
46
-
47
- ```bash
48
- npm install payload-guard
49
- ```
50
-
51
- ---
52
-
53
- ## 🚀 Quick Start
54
-
55
- ### Basic Usage
56
-
57
- ```typescript
58
- import { guard } from 'payload-guard';
59
-
60
- // Define a shape
61
- const userShape = guard.shape({
62
- id: 'number',
63
- name: 'string',
64
- email: 'string',
65
- });
66
-
67
- // Filter data
68
- const rawData = {
69
- id: 1,
70
- name: 'John Doe',
71
- email: 'john@example.com',
72
- password: 'secret123', // ❌ Will be removed
73
- internalNotes: 'VIP user', // ❌ Will be removed
74
- };
75
-
76
- const safeData = userShape(rawData);
77
- // Result: { id: 1, name: 'John Doe', email: 'john@example.com' }
78
- ```
79
-
80
- ### Advanced Validation (v1.4+)
81
-
82
- ```typescript
83
- const userShape = guard.shape({
84
- email: guard.string().email().toLowerCase().trim(),
85
- age: guard.number().min(18).max(100).default(18),
86
- tags: guard.array(guard.string().min(2)),
87
- role: guard.string().validate(v => ['admin', 'user'].includes(v)).default('user'),
88
- bio: guard.string().max(200).optional(),
89
- });
90
- ```
91
-
92
- ---
93
-
94
- ## 📖 API Reference
95
-
96
- ### `guard.string()`
97
- Creates a string builder with chained constraints:
98
- - `.min(length)` — Minimum character length
99
- - `.max(length)` — Maximum character length
100
- - `.email()` — Basic email validation
101
- - `.regex(pattern)` — Regex pattern match
102
- - `.trim()` — Auto-trim whitespace (Transformation)
103
- - `.toLowerCase()` / `.toUpperCase()` — Case transformation
104
-
105
- ### `guard.number()`
106
- - `.min(value)` / `.max(value)` — Range validation
107
- - `.integer()` — Ensure number is an integer
108
- - `.positive()` — Shortcut for `.min(0)`
109
-
110
- ### Common Builder Methods
111
- - `.required()` / `.optional()` — Toggle requirement
112
- - `.default(value)` — Value to use if field is missing or invalid
113
- - `.transform(fn)` — Custom transformation function
114
- - `.validate(fn)` — Custom validation function (return `false` to fail)
115
-
116
- ### Field Aliasing & Mapping (v1.6+)
117
-
118
- Rename fields from your database to match your frontend API:
119
-
120
- ```typescript
121
- const userShape = guard.shape({
122
- id: guard.string().from('_id'), // Map DB _id to id
123
- workTime: guard.number().from('totalWorkTimeMs').transform(v => v / 1000),
124
- name: 'string',
125
- });
126
-
127
- // Input: { _id: '123', totalWorkTimeMs: 5000, name: 'Sannu' }
128
- // Output: { id: '123', workTime: 5, name: 'Sannu' }
129
- ```
130
-
131
- ---
132
-
133
- ## 🛡️ "Never Crash" Policy
134
-
135
- Payload Guard is designed for mission-critical enterprise environments where uptime is non-negotiable.
136
-
137
- - **Circular Reference Safety**: Automatically detects and handles circular objects without infinite loops or stack overflows.
138
- - **Hook Isolation**: Custom `.transform()` and `.validate()` callbacks are wrapped in internal try/catch blocks. If your code fails, the library logs the error and safely continues using fallback values.
139
- - **Middleware Fail-Open**: If internal filtering logic hits an unexpected edge case, `failOpen: true` ensures the original request/response still reaches its destination.
140
-
141
- ---
142
-
143
- ## ⚡ Performance
144
-
145
- | Benchmark | ops/sec | avg (ms) |
146
- |-----------|---------|----------|
147
- | **Small payload** (5 fields) | 449,365 | **0.0022ms** |
148
- | **Medium payload** (50 posts) | 7,791 | **0.1284ms** |
149
- | **Large payload** (1000 users) | 246 | **4.0724ms** |
150
-
151
- > **Memory Usage**: ~121 MB Heap Used (Stable)
152
-
153
- ---
154
-
155
- ## 🛡️ Fail-Safe Design
156
-
157
- Built for production reliability:
158
- - **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.
159
- - **Async-Only**: All processing is non-blocking to ensure zero impact on event loop latency.
160
-
161
- ---
162
- ### ⛑️ Maintained actively.
163
- **Bug fixes usually within 24–48 hours.**
164
-
165
- ---
166
- ## 📄 License
167
-
168
- MIT
169
-
170
- ---
171
-
172
- <p align="center">
173
- Made with ❤️ for safer APIs
174
- </p>
1
+ # payload-guard
2
+
3
+ > Part of the [Professional Node.js Backend Toolkit](https://github.com/sannuk79/PROJECTS-AND-NPM-PACKAGES-)
4
+
5
+ <p align="center">
6
+ <strong>🛡️ Lightweight, zero-dependency shape-based payload filtering and sanitization</strong>
7
+ </p>
8
+
9
+ <p align="center">
10
+ <img src="https://img.shields.io/badge/bundle%20size-%3C8KB-brightgreen" alt="Bundle Size">
11
+ <img src="https://img.shields.io/badge/dependencies-0-blue" alt="Zero Dependencies">
12
+ <img src="https://img.shields.io/badge/TypeScript-100%25-blue" alt="TypeScript">
13
+ <img src="https://img.shields.io/badge/Node.js-18%2B-green" alt="Node.js 18+">
14
+ </p>
15
+
16
+ ---
17
+
18
+ ## 🛡️ Workflow
19
+
20
+ ```mermaid
21
+ graph LR
22
+ A[Request] --> B(Gatekeeper)
23
+ B --> C{Shape Check}
24
+ C -- Valid --> D[Redact & Clean]
25
+ C -- Invalid --> E[Strict Error / Fail Safe]
26
+ D --> F[Secure Response]
27
+ E --> F
28
+ F --> G((Metrics))
29
+ ```
30
+
31
+ ---
32
+
33
+ ## ✨ Features
34
+
35
+ - **Shape-based filtering** — Define what you want, auto-remove everything else
36
+ - **Sensitive field protection** — `password`, `token`, `secret` automatically removed
37
+ - **Zero dependencies** — Pure TypeScript, no external packages
38
+ - **Universal** — Works in Node.js, Browser, React Native
39
+ - **TypeScript-first** — Full type inference from shape definitions
40
+ - **Blazing fast** — Compiled schemas for production performance
41
+ - **Never crashes** — Graceful failure mode, production-safe
42
+
43
+ ---
44
+
45
+ ## 📦 Installation
46
+
47
+ ```bash
48
+ npm install payload-guard
49
+ ```
50
+
51
+ ---
52
+
53
+ ## 🚀 Quick Start
54
+
55
+ ### Basic Usage
56
+
57
+ ```typescript
58
+ import { guard } from 'payload-guard';
59
+
60
+ // Define a shape
61
+ const userShape = guard.shape({
62
+ id: 'number',
63
+ name: 'string',
64
+ email: 'string',
65
+ });
66
+
67
+ // Filter data
68
+ const rawData = {
69
+ id: 1,
70
+ name: 'John Doe',
71
+ email: 'john@example.com',
72
+ password: 'secret123', // ❌ Will be removed
73
+ internalNotes: 'VIP user', // ❌ Will be removed
74
+ };
75
+
76
+ const safeData = userShape(rawData);
77
+ // Result: { id: 1, name: 'John Doe', email: 'john@example.com' }
78
+ ```
79
+
80
+ ### Advanced Validation (v1.4+)
81
+
82
+ ```typescript
83
+ const userShape = guard.shape({
84
+ email: guard.string().email().toLowerCase().trim(),
85
+ age: guard.number().min(18).max(100).default(18),
86
+ tags: guard.array(guard.string().min(2)),
87
+ role: guard.string().validate(v => ['admin', 'user'].includes(v)).default('user'),
88
+ bio: guard.string().max(200).optional(),
89
+ });
90
+ ```
91
+
92
+ ### Nested Object Validation (v1.7+)
93
+
94
+ Define nested shapes for deep object validation:
95
+
96
+ ```typescript
97
+ const userShape = guard.shape({
98
+ id: 'number',
99
+ profile: {
100
+ name: 'string',
101
+ email: guard.string().email(),
102
+ age: guard.number().min(18),
103
+ address: {
104
+ street: 'string',
105
+ city: 'string',
106
+ zipCode: guard.string().regex(/^\d{5}(-\d{4})?$/),
107
+ },
108
+ },
109
+ posts: guard.array({
110
+ id: 'number',
111
+ title: 'string',
112
+ tags: guard.array('string'),
113
+ }),
114
+ });
115
+
116
+ const input = {
117
+ id: 1,
118
+ profile: {
119
+ name: 'John',
120
+ email: 'john@example.com',
121
+ age: 30,
122
+ address: {
123
+ street: '123 Main St',
124
+ city: 'NYC',
125
+ zipCode: '10001',
126
+ },
127
+ },
128
+ posts: [
129
+ { id: 1, title: 'Hello', tags: ['intro'] },
130
+ ],
131
+ };
132
+
133
+ const result = userShape(input);
134
+ // Filters all nested levels automatically
135
+ ```
136
+
137
+ ### Custom Error Messages (v1.7+)
138
+
139
+ Add per-field custom error messages:
140
+
141
+ ```typescript
142
+ const userShape = guard.shape({
143
+ email: guard
144
+ .string()
145
+ .email()
146
+ .error('Please provide a valid email address'),
147
+
148
+ username: guard
149
+ .string()
150
+ .min(5)
151
+ .error((value, field) => `${field} must be at least 5 characters`),
152
+
153
+ age: guard
154
+ .number()
155
+ .min(18)
156
+ .max(100)
157
+ .errorCodes({ min: 'AGE_TOO_YOUNG', max: 'AGE_TOO_OLD' }),
158
+ });
159
+
160
+ // Collect validation errors
161
+ const { compile } = require('payload-guard');
162
+ const errors = [];
163
+ const validator = compile(
164
+ { email: { type: 'string', email: true } },
165
+ { collectErrors: true, _errors: errors }
166
+ );
167
+
168
+ validator({ email: 'invalid' });
169
+ // errors: [{ field: 'email', message: '...', code: 'email' }]
170
+ ```
171
+
172
+ ---
173
+
174
+ ## 📖 API Reference
175
+
176
+ ### `guard.string()`
177
+ Creates a string builder with chained constraints:
178
+ - `.min(length)` — Minimum character length
179
+ - `.max(length)` — Maximum character length
180
+ - `.email()` — Basic email validation
181
+ - `.regex(pattern)` — Regex pattern match
182
+ - `.trim()` — Auto-trim whitespace (Transformation)
183
+ - `.toLowerCase()` / `.toUpperCase()` — Case transformation
184
+
185
+ ### `guard.number()`
186
+ - `.min(value)` / `.max(value)` — Range validation
187
+ - `.integer()` — Ensure number is an integer
188
+ - `.positive()` — Shortcut for `.min(0)`
189
+
190
+ ### Common Builder Methods
191
+ - `.required()` / `.optional()` — Toggle requirement
192
+ - `.default(value)` — Value to use if field is missing or invalid
193
+ - `.transform(fn)` — Custom transformation function
194
+ - `.validate(fn)` — Custom validation function (return `false` to fail)
195
+ - `.error(message)` — Custom error message (string or function) **(v1.7+)**
196
+ - `.errorCodes(codes)` — Custom error codes for validations **(v1.7+)**
197
+
198
+ ### New in v1.7+
199
+
200
+ **Nested Object Support:**
201
+ - Define nested shapes as plain objects: `{ profile: { name: 'string', email: 'string' } }`
202
+ - Arrays with nested objects: `guard.array({ id: 'number', name: 'string' })`
203
+ - Deep nesting supported at any level
204
+
205
+ **Custom Error Messages:**
206
+ - `.error('Custom message')` — Static error message
207
+ - `.error((value, field) => \`${field} is invalid\`)` — Dynamic error message
208
+ - `.errorCodes({ min: 'TOO_SHORT', email: 'BAD_EMAIL' })` — Error codes
209
+
210
+ **Error Collection:**
211
+ ```typescript
212
+ const { compile } = require('payload-guard');
213
+ const errors = [];
214
+ const validator = compile(shape, { collectErrors: true, _errors: errors });
215
+ validator(data);
216
+ // errors array populated with { field, message, code, value }
217
+ ```
218
+
219
+ ### Field Aliasing & Mapping (v1.6+)
220
+
221
+ Rename fields from your database to match your frontend API:
222
+
223
+ ```typescript
224
+ const userShape = guard.shape({
225
+ id: guard.string().from('_id'), // Map DB _id to id
226
+ workTime: guard.number().from('totalWorkTimeMs').transform(v => v / 1000),
227
+ name: 'string',
228
+ });
229
+
230
+ // Input: { _id: '123', totalWorkTimeMs: 5000, name: 'Sannu' }
231
+ // Output: { id: '123', workTime: 5, name: 'Sannu' }
232
+ ```
233
+
234
+ ---
235
+
236
+ ## 🛡️ "Never Crash" Policy
237
+
238
+ Payload Guard is designed for mission-critical enterprise environments where uptime is non-negotiable.
239
+
240
+ - **Circular Reference Safety**: Automatically detects and handles circular objects without infinite loops or stack overflows.
241
+ - **Hook Isolation**: Custom `.transform()` and `.validate()` callbacks are wrapped in internal try/catch blocks. If your code fails, the library logs the error and safely continues using fallback values.
242
+ - **Middleware Fail-Open**: If internal filtering logic hits an unexpected edge case, `failOpen: true` ensures the original request/response still reaches its destination.
243
+
244
+ ---
245
+
246
+ ## ⚡ Performance
247
+
248
+ | Benchmark | ops/sec | avg (ms) |
249
+ |-----------|---------|----------|
250
+ | **Small payload** (5 fields) | 449,365 | **0.0022ms** |
251
+ | **Medium payload** (50 posts) | 7,791 | **0.1284ms** |
252
+ | **Large payload** (1000 users) | 246 | **4.0724ms** |
253
+
254
+ > **Memory Usage**: ~121 MB Heap Used (Stable)
255
+
256
+ ---
257
+
258
+ ## 🛡️ Fail-Safe Design
259
+
260
+ Built for production reliability:
261
+ - **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.
262
+ - **Async-Only**: All processing is non-blocking to ensure zero impact on event loop latency.
263
+
264
+ ---
265
+ ### ⛑️ Maintained actively.
266
+ **Bug fixes usually within 24–48 hours.**
267
+
268
+ ---
269
+ ## 📄 License
270
+
271
+ MIT
272
+
273
+ ---
274
+
275
+ <p align="center">
276
+ Made with ❤️ for safer APIs
277
+ </p>
@@ -0,0 +1,157 @@
1
+ /**
2
+ * payload-guard — Async Buffering System
3
+ * Batch payload processing for reduced overhead
4
+ *
5
+ * @packageDocumentation
6
+ */
7
+ import type { ValidationMetrics } from './types';
8
+ /**
9
+ * Async Buffer for batching payload validations
10
+ * Reduces overhead by processing multiple payloads together
11
+ */
12
+ export declare class AsyncBuffer<T = unknown> {
13
+ private buffer;
14
+ private maxSize;
15
+ private maxTime;
16
+ private flushCallback;
17
+ private timer;
18
+ private isFlushing;
19
+ private pendingResolves;
20
+ constructor(options?: {
21
+ maxSize?: number;
22
+ maxTime?: number;
23
+ flushCallback?: (items: T[]) => Promise<void>;
24
+ });
25
+ /**
26
+ * Add item to buffer
27
+ * Returns promise that resolves when item is processed
28
+ */
29
+ add(item: T, priority?: number): Promise<void>;
30
+ /**
31
+ * Force flush the buffer
32
+ */
33
+ flush(): Promise<void>;
34
+ /**
35
+ * Get current buffer size
36
+ */
37
+ size(): number;
38
+ /**
39
+ * Clear buffer without processing
40
+ */
41
+ clear(): void;
42
+ /**
43
+ * Get buffer statistics
44
+ */
45
+ getStats(): {
46
+ size: number;
47
+ maxSize: number;
48
+ isFlushing: boolean;
49
+ avgWaitTime: number;
50
+ };
51
+ private startTimer;
52
+ private stopTimer;
53
+ private generateId;
54
+ }
55
+ /**
56
+ * Circular Buffer for memory-efficient storage
57
+ * Fixed size, overwrites oldest entries when full
58
+ */
59
+ export declare class CircularBuffer<T> {
60
+ private buffer;
61
+ private capacity;
62
+ private head;
63
+ private tail;
64
+ private size;
65
+ constructor(capacity?: number);
66
+ /**
67
+ * Add item to buffer
68
+ * Overwrites oldest item if full
69
+ */
70
+ push(item: T): void;
71
+ /**
72
+ * Get all items in order (oldest to newest)
73
+ */
74
+ toArray(): T[];
75
+ /**
76
+ * Get item at index (0 = oldest)
77
+ */
78
+ get(index: number): T | null;
79
+ /**
80
+ * Get latest item
81
+ */
82
+ latest(): T | null;
83
+ /**
84
+ * Get oldest item
85
+ */
86
+ oldest(): T | null;
87
+ /**
88
+ * Clear buffer
89
+ */
90
+ clear(): void;
91
+ /**
92
+ * Get current size
93
+ */
94
+ length(): number;
95
+ /**
96
+ * Check if buffer is full
97
+ */
98
+ isFull(): boolean;
99
+ /**
100
+ * Check if buffer is empty
101
+ */
102
+ isEmpty(): boolean;
103
+ /**
104
+ * Get buffer statistics
105
+ */
106
+ getStats(): {
107
+ capacity: number;
108
+ size: number;
109
+ utilization: number;
110
+ };
111
+ }
112
+ /**
113
+ * Validation result buffer item
114
+ */
115
+ interface ValidationBufferItem {
116
+ path: string;
117
+ method: string;
118
+ inputSize: number;
119
+ outputSize: number;
120
+ filteredFields: string[];
121
+ duration: number;
122
+ timestamp: number;
123
+ }
124
+ /**
125
+ * Metrics buffer for batching validation metrics
126
+ */
127
+ export declare class MetricsBuffer {
128
+ private buffer;
129
+ private asyncBuffer;
130
+ private metricsCallback;
131
+ constructor(capacity?: number, metricsCallback?: (metrics: ValidationMetrics) => void);
132
+ /**
133
+ * Record a validation result
134
+ */
135
+ record(result: {
136
+ path: string;
137
+ method: string;
138
+ inputSize: number;
139
+ outputSize: number;
140
+ filteredFields: string[];
141
+ duration: number;
142
+ }): void;
143
+ /**
144
+ * Get aggregated metrics
145
+ */
146
+ getMetrics(): ValidationMetrics;
147
+ /**
148
+ * Get recent validation results
149
+ */
150
+ getRecent(limit?: number): ValidationBufferItem[];
151
+ /**
152
+ * Clear all metrics
153
+ */
154
+ clear(): void;
155
+ private recordBatch;
156
+ }
157
+ export {};