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 +277 -174
- package/dist/core/buffer.d.ts +157 -0
- package/dist/core/buffer.js +312 -0
- package/dist/core/compiler.d.ts +5 -1
- package/dist/core/compiler.js +130 -12
- package/dist/core/filter.js +2 -0
- package/dist/core/sampler.d.ts +125 -0
- package/dist/core/sampler.js +222 -0
- package/dist/core/sourcemap.d.ts +74 -0
- package/dist/core/sourcemap.js +272 -0
- package/dist/core/types.d.ts +87 -1
- package/dist/core/worker.d.ts +76 -0
- package/dist/core/worker.js +271 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +30 -1
- package/dist/shapes.d.ts +54 -0
- package/dist/shapes.js +46 -0
- package/package.json +2 -1
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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 {};
|