payload-guard-filter 1.8.0 → 1.8.3

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,4 +1,4 @@
1
- # payload-guard
1
+ # payload-guard-filter
2
2
 
3
3
  > Part of the [Professional Node.js Backend Toolkit](https://github.com/sannuk79/PROJECTS-AND-NPM-PACKAGES-)
4
4
 
@@ -45,7 +45,7 @@ graph LR
45
45
  ## 📦 Installation
46
46
 
47
47
  ```bash
48
- npm install payload-guard
48
+ npm install payload-guard-filter
49
49
  ```
50
50
 
51
51
  ---
@@ -55,7 +55,7 @@ npm install payload-guard
55
55
  ### Basic Usage
56
56
 
57
57
  ```typescript
58
- import { guard } from 'payload-guard';
58
+ import { guard } from 'payload-guard-filter';
59
59
 
60
60
  // Define a shape
61
61
  const userShape = guard.shape({
@@ -158,7 +158,7 @@ const userShape = guard.shape({
158
158
  });
159
159
 
160
160
  // Collect validation errors
161
- const { compile } = require('payload-guard');
161
+ const { compile } = require('payload-guard-filter');
162
162
  const errors = [];
163
163
  const validator = compile(
164
164
  { email: { type: 'string', email: true } },
@@ -209,7 +209,7 @@ Creates a string builder with chained constraints:
209
209
 
210
210
  **Error Collection:**
211
211
  ```typescript
212
- const { compile } = require('payload-guard');
212
+ const { compile } = require('payload-guard-filter');
213
213
  const errors = [];
214
214
  const validator = compile(shape, { collectErrors: true, _errors: errors });
215
215
  validator(data);
@@ -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 {};
@@ -0,0 +1,312 @@
1
+ "use strict";
2
+ /**
3
+ * payload-guard — Async Buffering System
4
+ * Batch payload processing for reduced overhead
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.MetricsBuffer = exports.CircularBuffer = exports.AsyncBuffer = void 0;
10
+ /**
11
+ * Async Buffer for batching payload validations
12
+ * Reduces overhead by processing multiple payloads together
13
+ */
14
+ class AsyncBuffer {
15
+ constructor(options = {}) {
16
+ this.buffer = [];
17
+ this.timer = null;
18
+ this.isFlushing = false;
19
+ this.pendingResolves = [];
20
+ this.maxSize = options.maxSize ?? 100;
21
+ this.maxTime = options.maxTime ?? 1000; // 1 second
22
+ this.flushCallback = options.flushCallback ?? (async () => { });
23
+ }
24
+ /**
25
+ * Add item to buffer
26
+ * Returns promise that resolves when item is processed
27
+ */
28
+ add(item, priority = 0) {
29
+ return new Promise((resolve) => {
30
+ const bufferItem = {
31
+ data: item,
32
+ timestamp: Date.now(),
33
+ priority,
34
+ id: this.generateId(),
35
+ };
36
+ this.buffer.push(bufferItem);
37
+ this.pendingResolves.push(resolve);
38
+ // Start timer if not already running
39
+ if (!this.timer && this.buffer.length > 0) {
40
+ this.startTimer();
41
+ }
42
+ // Flush if buffer is full
43
+ if (this.buffer.length >= this.maxSize) {
44
+ this.flush();
45
+ }
46
+ });
47
+ }
48
+ /**
49
+ * Force flush the buffer
50
+ */
51
+ async flush() {
52
+ if (this.isFlushing || this.buffer.length === 0) {
53
+ return;
54
+ }
55
+ this.isFlushing = true;
56
+ this.stopTimer();
57
+ // Sort by priority (higher first)
58
+ this.buffer.sort((a, b) => b.priority - a.priority);
59
+ // Extract data
60
+ const items = this.buffer.map(item => item.data);
61
+ const resolves = this.pendingResolves;
62
+ // Clear buffer
63
+ this.buffer = [];
64
+ this.pendingResolves = [];
65
+ try {
66
+ // Process in background
67
+ await this.flushCallback(items);
68
+ }
69
+ catch (error) {
70
+ console.error('[AsyncBuffer] Flush error:', error);
71
+ }
72
+ finally {
73
+ // Resolve all pending promises
74
+ resolves.forEach(resolve => resolve());
75
+ this.isFlushing = false;
76
+ }
77
+ }
78
+ /**
79
+ * Get current buffer size
80
+ */
81
+ size() {
82
+ return this.buffer.length;
83
+ }
84
+ /**
85
+ * Clear buffer without processing
86
+ */
87
+ clear() {
88
+ this.buffer = [];
89
+ this.pendingResolves = [];
90
+ this.stopTimer();
91
+ }
92
+ /**
93
+ * Get buffer statistics
94
+ */
95
+ getStats() {
96
+ const now = Date.now();
97
+ const avgWaitTime = this.buffer.length > 0
98
+ ? this.buffer.reduce((sum, item) => sum + (now - item.timestamp), 0) / this.buffer.length
99
+ : 0;
100
+ return {
101
+ size: this.buffer.length,
102
+ maxSize: this.maxSize,
103
+ isFlushing: this.isFlushing,
104
+ avgWaitTime,
105
+ };
106
+ }
107
+ startTimer() {
108
+ this.timer = setTimeout(() => {
109
+ this.flush();
110
+ }, this.maxTime);
111
+ }
112
+ stopTimer() {
113
+ if (this.timer) {
114
+ clearTimeout(this.timer);
115
+ this.timer = null;
116
+ }
117
+ }
118
+ generateId() {
119
+ return `buf_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
120
+ }
121
+ }
122
+ exports.AsyncBuffer = AsyncBuffer;
123
+ /**
124
+ * Circular Buffer for memory-efficient storage
125
+ * Fixed size, overwrites oldest entries when full
126
+ */
127
+ class CircularBuffer {
128
+ constructor(capacity = 1000) {
129
+ this.capacity = capacity;
130
+ this.buffer = new Array(capacity).fill(null);
131
+ this.head = 0;
132
+ this.tail = 0;
133
+ this.size = 0;
134
+ }
135
+ /**
136
+ * Add item to buffer
137
+ * Overwrites oldest item if full
138
+ */
139
+ push(item) {
140
+ this.buffer[this.tail] = item;
141
+ this.tail = (this.tail + 1) % this.capacity;
142
+ if (this.size === this.capacity) {
143
+ // Buffer is full, move head forward
144
+ this.head = (this.head + 1) % this.capacity;
145
+ }
146
+ else {
147
+ this.size++;
148
+ }
149
+ }
150
+ /**
151
+ * Get all items in order (oldest to newest)
152
+ */
153
+ toArray() {
154
+ const result = [];
155
+ for (let i = 0; i < this.size; i++) {
156
+ const index = (this.head + i) % this.capacity;
157
+ const item = this.buffer[index];
158
+ if (item !== null) {
159
+ result.push(item);
160
+ }
161
+ }
162
+ return result;
163
+ }
164
+ /**
165
+ * Get item at index (0 = oldest)
166
+ */
167
+ get(index) {
168
+ if (index < 0 || index >= this.size) {
169
+ return null;
170
+ }
171
+ const idx = (this.head + index) % this.capacity;
172
+ return this.buffer[idx];
173
+ }
174
+ /**
175
+ * Get latest item
176
+ */
177
+ latest() {
178
+ if (this.size === 0)
179
+ return null;
180
+ const idx = (this.tail - 1 + this.capacity) % this.capacity;
181
+ return this.buffer[idx];
182
+ }
183
+ /**
184
+ * Get oldest item
185
+ */
186
+ oldest() {
187
+ if (this.size === 0)
188
+ return null;
189
+ return this.buffer[this.head];
190
+ }
191
+ /**
192
+ * Clear buffer
193
+ */
194
+ clear() {
195
+ this.buffer = new Array(this.capacity).fill(null);
196
+ this.head = 0;
197
+ this.tail = 0;
198
+ this.size = 0;
199
+ }
200
+ /**
201
+ * Get current size
202
+ */
203
+ length() {
204
+ return this.size;
205
+ }
206
+ /**
207
+ * Check if buffer is full
208
+ */
209
+ isFull() {
210
+ return this.size === this.capacity;
211
+ }
212
+ /**
213
+ * Check if buffer is empty
214
+ */
215
+ isEmpty() {
216
+ return this.size === 0;
217
+ }
218
+ /**
219
+ * Get buffer statistics
220
+ */
221
+ getStats() {
222
+ return {
223
+ capacity: this.capacity,
224
+ size: this.size,
225
+ utilization: this.size / this.capacity,
226
+ };
227
+ }
228
+ }
229
+ exports.CircularBuffer = CircularBuffer;
230
+ /**
231
+ * Metrics buffer for batching validation metrics
232
+ */
233
+ class MetricsBuffer {
234
+ constructor(capacity = 1000, metricsCallback) {
235
+ this.buffer = new CircularBuffer(capacity);
236
+ this.metricsCallback = metricsCallback ?? (() => { });
237
+ this.asyncBuffer = new AsyncBuffer({
238
+ maxSize: 50,
239
+ maxTime: 5000,
240
+ flushCallback: async (items) => {
241
+ this.recordBatch(items);
242
+ }
243
+ });
244
+ }
245
+ /**
246
+ * Record a validation result
247
+ */
248
+ record(result) {
249
+ const item = {
250
+ ...result,
251
+ timestamp: Date.now(),
252
+ };
253
+ this.buffer.push(item);
254
+ this.asyncBuffer.add(item);
255
+ }
256
+ /**
257
+ * Get aggregated metrics
258
+ */
259
+ getMetrics() {
260
+ const items = this.buffer.toArray();
261
+ const totalValidations = items.length;
262
+ if (totalValidations === 0) {
263
+ return {
264
+ totalValidations: 0,
265
+ totalFiltered: 0,
266
+ avgInputSize: 0,
267
+ avgOutputSize: 0,
268
+ avgReductionPercent: 0,
269
+ avgDuration: 0,
270
+ slowestDuration: 0,
271
+ };
272
+ }
273
+ const totalFiltered = items.filter(i => i.filteredFields.length > 0).length;
274
+ const totalInputSize = items.reduce((sum, i) => sum + i.inputSize, 0);
275
+ const totalOutputSize = items.reduce((sum, i) => sum + i.outputSize, 0);
276
+ const totalDuration = items.reduce((sum, i) => sum + i.duration, 0);
277
+ const slowestDuration = Math.max(...items.map(i => i.duration));
278
+ const avgInputSize = totalInputSize / totalValidations;
279
+ const avgOutputSize = totalOutputSize / totalValidations;
280
+ const avgReductionPercent = ((totalInputSize - totalOutputSize) / totalInputSize) * 100;
281
+ const avgDuration = totalDuration / totalValidations;
282
+ return {
283
+ totalValidations,
284
+ totalFiltered,
285
+ avgInputSize,
286
+ avgOutputSize,
287
+ avgReductionPercent,
288
+ avgDuration,
289
+ slowestDuration,
290
+ };
291
+ }
292
+ /**
293
+ * Get recent validation results
294
+ */
295
+ getRecent(limit = 10) {
296
+ const items = this.buffer.toArray();
297
+ return items.slice(-limit);
298
+ }
299
+ /**
300
+ * Clear all metrics
301
+ */
302
+ clear() {
303
+ this.buffer.clear();
304
+ this.asyncBuffer.clear();
305
+ }
306
+ recordBatch(items) {
307
+ // Aggregate batch metrics
308
+ const metrics = this.getMetrics();
309
+ this.metricsCallback(metrics);
310
+ }
311
+ }
312
+ exports.MetricsBuffer = MetricsBuffer;
@@ -0,0 +1,125 @@
1
+ /**
2
+ * payload-guard — Adaptive Sampling System
3
+ * Dynamic sampling rate adjustment based on traffic
4
+ *
5
+ * @packageDocumentation
6
+ */
7
+ /**
8
+ * Sampling result
9
+ */
10
+ export interface SamplingResult {
11
+ shouldSample: boolean;
12
+ rate: number;
13
+ reason: string;
14
+ }
15
+ /**
16
+ * Adaptive Sampler
17
+ * Automatically adjusts sampling rate based on traffic volume
18
+ */
19
+ export declare class AdaptiveSampler {
20
+ private baseRate;
21
+ private currentRate;
22
+ private minRate;
23
+ private maxRate;
24
+ private requestCounts;
25
+ private windowSize;
26
+ private lastAdjustment;
27
+ private adjustmentInterval;
28
+ constructor(options?: {
29
+ baseRate?: number;
30
+ minRate?: number;
31
+ maxRate?: number;
32
+ windowSize?: number;
33
+ adjustmentInterval?: number;
34
+ });
35
+ /**
36
+ * Check if a request should be sampled
37
+ */
38
+ shouldSample(priority?: number): SamplingResult;
39
+ /**
40
+ * Record a request
41
+ */
42
+ recordRequest(sampled: boolean): void;
43
+ /**
44
+ * Get current sampling rate
45
+ */
46
+ getRate(): number;
47
+ /**
48
+ * Get request statistics
49
+ */
50
+ getStats(): {
51
+ currentRate: number;
52
+ baseRate: number;
53
+ avgRequestsPerWindow: number;
54
+ totalRequests: number;
55
+ };
56
+ /**
57
+ * Reset to base rate
58
+ */
59
+ reset(): void;
60
+ /**
61
+ * Manually set sampling rate
62
+ */
63
+ setRate(rate: number): void;
64
+ private getWindowIndex;
65
+ private adjustRate;
66
+ }
67
+ /**
68
+ * Time-based sampler
69
+ * Samples requests at specific time intervals
70
+ */
71
+ export declare class TimeBasedSampler {
72
+ private interval;
73
+ private lastSample;
74
+ private sampleDuration;
75
+ constructor(options?: {
76
+ interval?: number;
77
+ sampleDuration?: number;
78
+ });
79
+ /**
80
+ * Check if currently in sampling window
81
+ */
82
+ shouldSample(): boolean;
83
+ /**
84
+ * Get time until next sample
85
+ */
86
+ getTimeUntilNextSample(): number;
87
+ }
88
+ /**
89
+ * Error-based sampler
90
+ * Increases sampling rate when errors are detected
91
+ */
92
+ export declare class ErrorBasedSampler {
93
+ private baseRate;
94
+ private errorRate;
95
+ private errorMultiplier;
96
+ private errorCount;
97
+ private requestCount;
98
+ private windowMs;
99
+ private windowStart;
100
+ constructor(options?: {
101
+ baseRate?: number;
102
+ errorMultiplier?: number;
103
+ windowMs?: number;
104
+ });
105
+ /**
106
+ * Check if should sample
107
+ */
108
+ shouldSample(): SamplingResult;
109
+ /**
110
+ * Record a request
111
+ */
112
+ recordRequest(isError: boolean): void;
113
+ /**
114
+ * Get error statistics
115
+ */
116
+ getStats(): {
117
+ errorRate: number;
118
+ baseRate: number;
119
+ errorCount: number;
120
+ requestCount: number;
121
+ errorPercent: number;
122
+ };
123
+ private checkWindow;
124
+ private updateErrorRate;
125
+ }