veryfront 0.0.3 → 0.0.5

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.
@@ -0,0 +1,922 @@
1
+ // src/core/errors/veryfront-error.ts
2
+ function createError(error) {
3
+ return error;
4
+ }
5
+ function toError(veryfrontError) {
6
+ const error = new Error(veryfrontError.message);
7
+ error.name = `VeryfrontError[${veryfrontError.type}]`;
8
+ Object.defineProperty(error, "context", {
9
+ value: veryfrontError,
10
+ enumerable: false,
11
+ configurable: true
12
+ });
13
+ return error;
14
+ }
15
+
16
+ // src/ai/production/rate-limit/limiter.ts
17
+ var FixedWindowLimiter = class {
18
+ constructor(config) {
19
+ this.requests = /* @__PURE__ */ new Map();
20
+ this.config = config;
21
+ }
22
+ check(identifier) {
23
+ const now = Date.now();
24
+ const entry = this.requests.get(identifier);
25
+ if (!entry || now >= entry.resetAt) {
26
+ const resetAt = now + this.config.windowMs;
27
+ this.requests.set(identifier, {
28
+ count: 1,
29
+ resetAt
30
+ });
31
+ return {
32
+ allowed: true,
33
+ remaining: this.config.maxRequests - 1,
34
+ resetAt
35
+ };
36
+ }
37
+ if (entry.count < this.config.maxRequests) {
38
+ entry.count++;
39
+ return {
40
+ allowed: true,
41
+ remaining: this.config.maxRequests - entry.count,
42
+ resetAt: entry.resetAt
43
+ };
44
+ }
45
+ return {
46
+ allowed: false,
47
+ remaining: 0,
48
+ resetAt: entry.resetAt,
49
+ retryAfter: Math.ceil((entry.resetAt - now) / 1e3)
50
+ };
51
+ }
52
+ reset(identifier) {
53
+ this.requests.delete(identifier);
54
+ }
55
+ clear() {
56
+ this.requests.clear();
57
+ }
58
+ };
59
+ var TokenBucketLimiter = class {
60
+ constructor(config) {
61
+ this.buckets = /* @__PURE__ */ new Map();
62
+ this.config = config;
63
+ this.refillRate = config.maxRequests / config.windowMs;
64
+ }
65
+ check(identifier) {
66
+ const now = Date.now();
67
+ let bucket = this.buckets.get(identifier);
68
+ if (!bucket) {
69
+ bucket = {
70
+ tokens: this.config.maxRequests - 1,
71
+ lastRefill: now
72
+ };
73
+ this.buckets.set(identifier, bucket);
74
+ return {
75
+ allowed: true,
76
+ remaining: bucket.tokens,
77
+ resetAt: now + this.config.windowMs
78
+ };
79
+ }
80
+ const timePassed = now - bucket.lastRefill;
81
+ const tokensToAdd = timePassed * this.refillRate;
82
+ bucket.tokens = Math.min(
83
+ this.config.maxRequests,
84
+ bucket.tokens + tokensToAdd
85
+ );
86
+ bucket.lastRefill = now;
87
+ if (bucket.tokens >= 1) {
88
+ bucket.tokens--;
89
+ return {
90
+ allowed: true,
91
+ remaining: Math.floor(bucket.tokens),
92
+ resetAt: now + this.config.windowMs
93
+ };
94
+ }
95
+ const timeUntilToken = (1 - bucket.tokens) / this.refillRate;
96
+ return {
97
+ allowed: false,
98
+ remaining: 0,
99
+ resetAt: now + this.config.windowMs,
100
+ retryAfter: Math.ceil(timeUntilToken / 1e3)
101
+ };
102
+ }
103
+ reset(identifier) {
104
+ this.buckets.delete(identifier);
105
+ }
106
+ clear() {
107
+ this.buckets.clear();
108
+ }
109
+ };
110
+ function createRateLimiter(config) {
111
+ let limiter;
112
+ switch (config.strategy) {
113
+ case "fixed-window":
114
+ limiter = new FixedWindowLimiter(config);
115
+ break;
116
+ case "token-bucket":
117
+ limiter = new TokenBucketLimiter(config);
118
+ break;
119
+ case "sliding-window":
120
+ limiter = new TokenBucketLimiter(config);
121
+ break;
122
+ default:
123
+ limiter = new FixedWindowLimiter(config);
124
+ }
125
+ return {
126
+ /**
127
+ * Check if request is allowed
128
+ */
129
+ check(context) {
130
+ const identifier = config.identify ? config.identify(context) : "default";
131
+ return limiter.check(identifier);
132
+ },
133
+ /**
134
+ * Reset rate limit for identifier
135
+ */
136
+ reset(context) {
137
+ const identifier = config.identify ? config.identify(context) : "default";
138
+ limiter.reset(identifier);
139
+ },
140
+ /**
141
+ * Clear all rate limits
142
+ */
143
+ clear() {
144
+ limiter.clear();
145
+ }
146
+ };
147
+ }
148
+ function rateLimitMiddleware(config) {
149
+ const limiter = createRateLimiter(config);
150
+ return (context, next) => {
151
+ const result = limiter.check(context);
152
+ if (!result.allowed) {
153
+ throw toError(createError({
154
+ type: "agent",
155
+ message: config.errorMessage || `Rate limit exceeded. Try again in ${result.retryAfter} seconds.`
156
+ }));
157
+ }
158
+ return next();
159
+ };
160
+ }
161
+
162
+ // src/ai/production/cache/cache.ts
163
+ var MemoryCache = class {
164
+ constructor() {
165
+ this.cache = /* @__PURE__ */ new Map();
166
+ }
167
+ set(key, response) {
168
+ this.cache.set(key, {
169
+ response,
170
+ cachedAt: Date.now(),
171
+ accessCount: 0,
172
+ lastAccessedAt: Date.now()
173
+ });
174
+ }
175
+ get(key) {
176
+ const entry = this.cache.get(key);
177
+ if (!entry)
178
+ return null;
179
+ entry.accessCount++;
180
+ entry.lastAccessedAt = Date.now();
181
+ return entry.response;
182
+ }
183
+ has(key) {
184
+ return this.cache.has(key);
185
+ }
186
+ delete(key) {
187
+ this.cache.delete(key);
188
+ }
189
+ clear() {
190
+ this.cache.clear();
191
+ }
192
+ size() {
193
+ return this.cache.size;
194
+ }
195
+ };
196
+ var LRUCache = class {
197
+ constructor(maxSize = 100) {
198
+ this.cache = /* @__PURE__ */ new Map();
199
+ this.maxSize = maxSize;
200
+ }
201
+ set(key, response) {
202
+ if (this.cache.has(key)) {
203
+ this.cache.delete(key);
204
+ }
205
+ if (this.cache.size >= this.maxSize) {
206
+ const firstKey = this.cache.keys().next().value;
207
+ if (firstKey !== void 0) {
208
+ this.cache.delete(firstKey);
209
+ }
210
+ }
211
+ this.cache.set(key, {
212
+ response,
213
+ cachedAt: Date.now(),
214
+ accessCount: 0,
215
+ lastAccessedAt: Date.now()
216
+ });
217
+ }
218
+ get(key) {
219
+ const entry = this.cache.get(key);
220
+ if (!entry)
221
+ return null;
222
+ this.cache.delete(key);
223
+ entry.accessCount++;
224
+ entry.lastAccessedAt = Date.now();
225
+ this.cache.set(key, entry);
226
+ return entry.response;
227
+ }
228
+ has(key) {
229
+ return this.cache.has(key);
230
+ }
231
+ delete(key) {
232
+ this.cache.delete(key);
233
+ }
234
+ clear() {
235
+ this.cache.clear();
236
+ }
237
+ size() {
238
+ return this.cache.size;
239
+ }
240
+ };
241
+ var TTLCache = class {
242
+ constructor(ttl = 3e5) {
243
+ this.cache = /* @__PURE__ */ new Map();
244
+ this.ttl = ttl;
245
+ this.startCleanup();
246
+ }
247
+ set(key, response) {
248
+ const now = Date.now();
249
+ this.cache.set(key, {
250
+ response,
251
+ cachedAt: now,
252
+ expiresAt: now + this.ttl,
253
+ accessCount: 0,
254
+ lastAccessedAt: now
255
+ });
256
+ }
257
+ get(key) {
258
+ const entry = this.cache.get(key);
259
+ if (!entry)
260
+ return null;
261
+ if (entry.expiresAt && Date.now() >= entry.expiresAt) {
262
+ this.cache.delete(key);
263
+ return null;
264
+ }
265
+ entry.accessCount++;
266
+ entry.lastAccessedAt = Date.now();
267
+ return entry.response;
268
+ }
269
+ has(key) {
270
+ const entry = this.cache.get(key);
271
+ if (!entry)
272
+ return false;
273
+ if (entry.expiresAt && Date.now() >= entry.expiresAt) {
274
+ this.cache.delete(key);
275
+ return false;
276
+ }
277
+ return true;
278
+ }
279
+ delete(key) {
280
+ this.cache.delete(key);
281
+ }
282
+ clear() {
283
+ this.cache.clear();
284
+ }
285
+ size() {
286
+ return this.cache.size;
287
+ }
288
+ startCleanup() {
289
+ setInterval(() => {
290
+ const now = Date.now();
291
+ for (const [key, entry] of this.cache.entries()) {
292
+ if (entry.expiresAt && now >= entry.expiresAt) {
293
+ this.cache.delete(key);
294
+ }
295
+ }
296
+ }, 6e4);
297
+ }
298
+ };
299
+ function createCache(config) {
300
+ let cache;
301
+ switch (config.strategy) {
302
+ case "memory":
303
+ cache = new MemoryCache();
304
+ break;
305
+ case "lru":
306
+ cache = new LRUCache(config.maxSize || 100);
307
+ break;
308
+ case "ttl":
309
+ cache = new TTLCache(config.ttl || 3e5);
310
+ break;
311
+ default:
312
+ cache = new MemoryCache();
313
+ }
314
+ const keyGenerator = config.keyGenerator || ((input) => `cache_${hashString(input)}`);
315
+ return {
316
+ /**
317
+ * Get cached response
318
+ */
319
+ get(input, context) {
320
+ const key = keyGenerator(input, context);
321
+ return cache.get(key);
322
+ },
323
+ /**
324
+ * Set cached response
325
+ */
326
+ set(input, response, context) {
327
+ const key = keyGenerator(input, context);
328
+ cache.set(key, response);
329
+ },
330
+ /**
331
+ * Check if cached
332
+ */
333
+ has(input, context) {
334
+ const key = keyGenerator(input, context);
335
+ return cache.has(key);
336
+ },
337
+ /**
338
+ * Delete cached entry
339
+ */
340
+ delete(input, context) {
341
+ const key = keyGenerator(input, context);
342
+ cache.delete(key);
343
+ },
344
+ /**
345
+ * Clear all cache
346
+ */
347
+ clear() {
348
+ cache.clear();
349
+ },
350
+ /**
351
+ * Get cache size
352
+ */
353
+ size() {
354
+ return cache.size();
355
+ }
356
+ };
357
+ }
358
+ function hashString(str) {
359
+ let hash = 0;
360
+ for (let i = 0; i < str.length; i++) {
361
+ const char = str.charCodeAt(i);
362
+ hash = (hash << 5) - hash + char;
363
+ hash = hash & hash;
364
+ }
365
+ return Math.abs(hash).toString(36);
366
+ }
367
+ function cacheMiddleware(config) {
368
+ const cache = createCache(config);
369
+ return async (context, next) => {
370
+ const inputString = typeof context.input === "string" ? context.input : JSON.stringify(context.input);
371
+ const cached = cache.get(inputString, context);
372
+ if (cached) {
373
+ return {
374
+ ...cached,
375
+ metadata: {
376
+ ...cached.metadata,
377
+ fromCache: true,
378
+ cachedAt: Date.now()
379
+ }
380
+ };
381
+ }
382
+ const result = await next();
383
+ cache.set(inputString, result, context);
384
+ return result;
385
+ };
386
+ }
387
+
388
+ // src/core/utils/runtime-guards.ts
389
+ function hasDenoRuntime(global) {
390
+ return typeof global === "object" && global !== null && "Deno" in global && typeof global.Deno?.env?.get === "function";
391
+ }
392
+ function hasNodeProcess(global) {
393
+ return typeof global === "object" && global !== null && "process" in global && typeof global.process?.env === "object";
394
+ }
395
+
396
+ // src/core/utils/logger/env.ts
397
+ function getEnvironmentVariable(name) {
398
+ try {
399
+ if (typeof Deno !== "undefined" && hasDenoRuntime(globalThis)) {
400
+ const value = globalThis.Deno?.env.get(name);
401
+ return value === "" ? void 0 : value;
402
+ }
403
+ if (hasNodeProcess(globalThis)) {
404
+ const value = globalThis.process?.env[name];
405
+ return value === "" ? void 0 : value;
406
+ }
407
+ } catch (error) {
408
+ console.debug(`Failed to get environment variable ${name}:`, error);
409
+ return void 0;
410
+ }
411
+ return void 0;
412
+ }
413
+
414
+ // src/core/utils/logger/logger.ts
415
+ var cachedLogLevel;
416
+ function resolveLogLevel(force = false) {
417
+ if (force || cachedLogLevel === void 0) {
418
+ cachedLogLevel = getDefaultLevel();
419
+ }
420
+ return cachedLogLevel;
421
+ }
422
+ var ConsoleLogger = class {
423
+ constructor(prefix, level = resolveLogLevel()) {
424
+ this.prefix = prefix;
425
+ this.level = level;
426
+ }
427
+ setLevel(level) {
428
+ this.level = level;
429
+ }
430
+ getLevel() {
431
+ return this.level;
432
+ }
433
+ debug(message, ...args) {
434
+ if (this.level <= 0 /* DEBUG */) {
435
+ console.debug(`[${this.prefix}] DEBUG: ${message}`, ...args);
436
+ }
437
+ }
438
+ info(message, ...args) {
439
+ if (this.level <= 1 /* INFO */) {
440
+ console.log(`[${this.prefix}] ${message}`, ...args);
441
+ }
442
+ }
443
+ warn(message, ...args) {
444
+ if (this.level <= 2 /* WARN */) {
445
+ console.warn(`[${this.prefix}] WARN: ${message}`, ...args);
446
+ }
447
+ }
448
+ error(message, ...args) {
449
+ if (this.level <= 3 /* ERROR */) {
450
+ console.error(`[${this.prefix}] ERROR: ${message}`, ...args);
451
+ }
452
+ }
453
+ async time(label, fn) {
454
+ const start = performance.now();
455
+ try {
456
+ const result = await fn();
457
+ const end = performance.now();
458
+ this.debug(`${label} completed in ${(end - start).toFixed(2)}ms`);
459
+ return result;
460
+ } catch (_error) {
461
+ const end = performance.now();
462
+ this.error(`${label} failed after ${(end - start).toFixed(2)}ms`, _error);
463
+ throw _error;
464
+ }
465
+ }
466
+ };
467
+ function parseLogLevel(levelString) {
468
+ if (!levelString)
469
+ return void 0;
470
+ const upper = levelString.toUpperCase();
471
+ switch (upper) {
472
+ case "DEBUG":
473
+ return 0 /* DEBUG */;
474
+ case "WARN":
475
+ return 2 /* WARN */;
476
+ case "ERROR":
477
+ return 3 /* ERROR */;
478
+ case "INFO":
479
+ return 1 /* INFO */;
480
+ default:
481
+ return void 0;
482
+ }
483
+ }
484
+ var getDefaultLevel = () => {
485
+ const envLevel = getEnvironmentVariable("LOG_LEVEL");
486
+ const parsedLevel = parseLogLevel(envLevel);
487
+ if (parsedLevel !== void 0)
488
+ return parsedLevel;
489
+ const debugFlag = getEnvironmentVariable("VERYFRONT_DEBUG");
490
+ if (debugFlag === "1" || debugFlag === "true")
491
+ return 0 /* DEBUG */;
492
+ return 1 /* INFO */;
493
+ };
494
+ var trackedLoggers = /* @__PURE__ */ new Set();
495
+ function createLogger(prefix) {
496
+ const logger2 = new ConsoleLogger(prefix);
497
+ trackedLoggers.add(logger2);
498
+ return logger2;
499
+ }
500
+ var cliLogger = createLogger("CLI");
501
+ var serverLogger = createLogger("SERVER");
502
+ var rendererLogger = createLogger("RENDERER");
503
+ var bundlerLogger = createLogger("BUNDLER");
504
+ var agentLogger = createLogger("AGENT");
505
+ var logger = createLogger("VERYFRONT");
506
+
507
+ // src/ai/production/cost-tracking/tracker.ts
508
+ var CostTracker = class {
509
+ constructor(config) {
510
+ this.records = [];
511
+ this.dailyTotal = 0;
512
+ this.monthlyTotal = 0;
513
+ this.lastDayReset = Date.now();
514
+ this.lastMonthReset = Date.now();
515
+ this.config = config;
516
+ this.startPeriodicReset();
517
+ }
518
+ /**
519
+ * Track an agent response
520
+ */
521
+ track(agentId, model, response, userId) {
522
+ if (!response.usage) {
523
+ agentLogger.warn("No usage data in response, cannot track costs");
524
+ return this.createEmptyRecord(agentId, model);
525
+ }
526
+ const provider = model.split("/")[0] || "unknown";
527
+ const cost = this.calculateCost(
528
+ provider,
529
+ response.usage.promptTokens,
530
+ response.usage.completionTokens
531
+ );
532
+ const record = {
533
+ timestamp: Date.now(),
534
+ agentId,
535
+ model,
536
+ provider,
537
+ tokens: {
538
+ prompt: response.usage.promptTokens,
539
+ completion: response.usage.completionTokens,
540
+ total: response.usage.totalTokens
541
+ },
542
+ cost,
543
+ userId
544
+ };
545
+ this.records.push(record);
546
+ this.dailyTotal += cost;
547
+ this.monthlyTotal += cost;
548
+ this.checkLimits();
549
+ return record;
550
+ }
551
+ /**
552
+ * Calculate cost based on token usage
553
+ */
554
+ calculateCost(provider, inputTokens, outputTokens) {
555
+ const pricing = this.config.pricing[provider];
556
+ if (!pricing) {
557
+ agentLogger.warn(`No pricing configured for provider: ${provider}`);
558
+ return 0;
559
+ }
560
+ const inputCost = inputTokens / 1e6 * pricing.input;
561
+ const outputCost = outputTokens / 1e6 * pricing.output;
562
+ return inputCost + outputCost;
563
+ }
564
+ /**
565
+ * Get usage summary for a period
566
+ */
567
+ getSummary(startTime, endTime) {
568
+ const start = startTime || 0;
569
+ const end = endTime || Date.now();
570
+ const relevantRecords = this.records.filter(
571
+ (r) => r.timestamp >= start && r.timestamp <= end
572
+ );
573
+ const summary = {
574
+ requests: relevantRecords.length,
575
+ tokens: {
576
+ prompt: 0,
577
+ completion: 0,
578
+ total: 0
579
+ },
580
+ cost: 0,
581
+ byProvider: {},
582
+ period: { start, end }
583
+ };
584
+ for (const record of relevantRecords) {
585
+ summary.tokens.prompt += record.tokens.prompt;
586
+ summary.tokens.completion += record.tokens.completion;
587
+ summary.tokens.total += record.tokens.total;
588
+ summary.cost += record.cost;
589
+ if (!summary.byProvider[record.provider]) {
590
+ summary.byProvider[record.provider] = {
591
+ requests: 0,
592
+ tokens: 0,
593
+ cost: 0
594
+ };
595
+ }
596
+ const providerStats = summary.byProvider[record.provider];
597
+ providerStats.requests++;
598
+ providerStats.tokens += record.tokens.total;
599
+ providerStats.cost += record.cost;
600
+ }
601
+ return summary;
602
+ }
603
+ /**
604
+ * Get daily summary
605
+ */
606
+ getDailySummary() {
607
+ const now = Date.now();
608
+ const dayStart = now - 24 * 60 * 60 * 1e3;
609
+ return this.getSummary(dayStart, now);
610
+ }
611
+ /**
612
+ * Get monthly summary
613
+ */
614
+ getMonthlySummary() {
615
+ const now = Date.now();
616
+ const monthStart = now - 30 * 24 * 60 * 60 * 1e3;
617
+ return this.getSummary(monthStart, now);
618
+ }
619
+ /**
620
+ * Check if limits are exceeded
621
+ */
622
+ checkLimits() {
623
+ if (this.config.limits?.daily && this.dailyTotal > this.config.limits.daily) {
624
+ if (this.config.onLimitExceeded) {
625
+ this.config.onLimitExceeded(this.getDailySummary());
626
+ }
627
+ }
628
+ if (this.config.limits?.monthly && this.monthlyTotal > this.config.limits.monthly) {
629
+ if (this.config.onLimitExceeded) {
630
+ this.config.onLimitExceeded(this.getMonthlySummary());
631
+ }
632
+ }
633
+ }
634
+ /**
635
+ * Reset periodic totals
636
+ */
637
+ startPeriodicReset() {
638
+ setInterval(() => {
639
+ const now = Date.now();
640
+ if (now - this.lastDayReset >= 24 * 60 * 60 * 1e3) {
641
+ this.dailyTotal = 0;
642
+ this.lastDayReset = now;
643
+ }
644
+ if (now - this.lastMonthReset >= 30 * 24 * 60 * 60 * 1e3) {
645
+ this.monthlyTotal = 0;
646
+ this.lastMonthReset = now;
647
+ }
648
+ }, 6e4);
649
+ }
650
+ /**
651
+ * Create empty record
652
+ */
653
+ createEmptyRecord(agentId, model) {
654
+ return {
655
+ timestamp: Date.now(),
656
+ agentId,
657
+ model,
658
+ provider: model.split("/")[0] || "unknown",
659
+ tokens: { prompt: 0, completion: 0, total: 0 },
660
+ cost: 0
661
+ };
662
+ }
663
+ /**
664
+ * Get all records
665
+ */
666
+ getAllRecords() {
667
+ return [...this.records];
668
+ }
669
+ /**
670
+ * Clear all records
671
+ */
672
+ clear() {
673
+ this.records = [];
674
+ this.dailyTotal = 0;
675
+ this.monthlyTotal = 0;
676
+ }
677
+ };
678
+ function createCostTracker(config) {
679
+ const tracker = new CostTracker(config);
680
+ return {
681
+ /**
682
+ * Track agent response
683
+ */
684
+ track(agentId, model, response, userId) {
685
+ return tracker.track(agentId, model, response, userId);
686
+ },
687
+ /**
688
+ * Get usage summary
689
+ */
690
+ getSummary(startTime, endTime) {
691
+ return tracker.getSummary(startTime, endTime);
692
+ },
693
+ /**
694
+ * Get daily summary
695
+ */
696
+ getDailySummary() {
697
+ return tracker.getDailySummary();
698
+ },
699
+ /**
700
+ * Get monthly summary
701
+ */
702
+ getMonthlySummary() {
703
+ return tracker.getMonthlySummary();
704
+ },
705
+ /**
706
+ * Get all records
707
+ */
708
+ getAllRecords() {
709
+ return tracker.getAllRecords();
710
+ },
711
+ /**
712
+ * Clear all data
713
+ */
714
+ clear() {
715
+ tracker.clear();
716
+ }
717
+ };
718
+ }
719
+ function costTrackingMiddleware(config) {
720
+ const tracker = createCostTracker(config);
721
+ return async (context, next) => {
722
+ const result = await next();
723
+ tracker.track(
724
+ context.agentId,
725
+ context.model || "unknown",
726
+ result,
727
+ context.data?.userId
728
+ );
729
+ return result;
730
+ };
731
+ }
732
+
733
+ // src/ai/production/security/validator.ts
734
+ var COMMON_BLOCKED_PATTERNS = {
735
+ /** Prompt injection attempts */
736
+ promptInjection: [
737
+ /ignore\s+previous\s+instructions/i,
738
+ /ignore\s+all\s+previous\s+prompts/i,
739
+ /you\s+are\s+now\s+a/i,
740
+ /pretend\s+you\s+are/i,
741
+ /system:\s*/i,
742
+ /<\|im_start\|>/i,
743
+ /<\|im_end\|>/i
744
+ ],
745
+ /** Potential data exfiltration */
746
+ dataExfiltration: [
747
+ /password/i,
748
+ /api[_\s-]?key/i,
749
+ /secret/i,
750
+ /token/i,
751
+ /credit\s+card/i
752
+ ],
753
+ /** SQL injection patterns */
754
+ sqlInjection: [
755
+ /(\bUNION\b|\bSELECT\b).*\bFROM\b/i,
756
+ /;\s*(DROP|DELETE|UPDATE|INSERT)/i
757
+ ],
758
+ /** XSS patterns */
759
+ xss: [
760
+ /<script[^>]*>.*?<\/script>/gi,
761
+ /javascript:/i,
762
+ /on\w+\s*=/i
763
+ // Event handlers
764
+ ]
765
+ };
766
+ var PII_PATTERNS = {
767
+ email: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi,
768
+ phone: /\b(\+\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g,
769
+ ssn: /\b\d{3}-\d{2}-\d{4}\b/g,
770
+ creditCard: /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g
771
+ };
772
+ var InputValidator = class {
773
+ constructor(config) {
774
+ this.config = config || {};
775
+ }
776
+ /**
777
+ * Validate input
778
+ */
779
+ async validate(input) {
780
+ const violations = [];
781
+ if (this.config?.maxLength && input.length > this.config.maxLength) {
782
+ violations.push({
783
+ type: "input",
784
+ reason: `Input exceeds maximum length of ${this.config.maxLength}`,
785
+ content: input.substring(0, 100) + "..."
786
+ });
787
+ }
788
+ if (this.config?.blockedPatterns) {
789
+ for (const pattern of this.config.blockedPatterns) {
790
+ if (pattern.test(input)) {
791
+ violations.push({
792
+ type: "input",
793
+ reason: "Input matches blocked pattern",
794
+ content: input,
795
+ pattern
796
+ });
797
+ }
798
+ }
799
+ }
800
+ if (this.config?.validate) {
801
+ const customValid = await this.config.validate(input);
802
+ if (!customValid) {
803
+ violations.push({
804
+ type: "input",
805
+ reason: "Custom validation failed",
806
+ content: input
807
+ });
808
+ }
809
+ }
810
+ let sanitized = input;
811
+ if (this.config?.sanitize) {
812
+ sanitized = this.sanitizeInput(input);
813
+ }
814
+ return {
815
+ valid: violations.length === 0,
816
+ sanitized: this.config?.sanitize ? sanitized : void 0,
817
+ violations
818
+ };
819
+ }
820
+ /**
821
+ * Sanitize input (remove potentially harmful content)
822
+ */
823
+ sanitizeInput(input) {
824
+ let sanitized = input;
825
+ sanitized = sanitized.replace(/<script[^>]*>.*?<\/script>/gi, "");
826
+ sanitized = sanitized.replace(/on\w+\s*=\s*["'][^"']*["']/gi, "");
827
+ sanitized = sanitized.replace(/javascript:/gi, "");
828
+ return sanitized;
829
+ }
830
+ };
831
+ var OutputFilter = class {
832
+ constructor(config) {
833
+ this.config = config || {};
834
+ }
835
+ /**
836
+ * Filter output
837
+ */
838
+ async filter(output) {
839
+ const violations = [];
840
+ let filtered = output;
841
+ if (this.config?.blockedPatterns) {
842
+ for (const pattern of this.config.blockedPatterns) {
843
+ if (pattern.test(filtered)) {
844
+ violations.push({
845
+ type: "output",
846
+ reason: "Output contains blocked pattern",
847
+ content: filtered,
848
+ pattern
849
+ });
850
+ filtered = filtered.replace(pattern, "[REDACTED]");
851
+ }
852
+ }
853
+ }
854
+ if (this.config?.filterPII) {
855
+ filtered = this.filterPII(filtered);
856
+ }
857
+ if (this.config?.filter) {
858
+ filtered = await this.config.filter(filtered);
859
+ }
860
+ return { filtered, violations };
861
+ }
862
+ /**
863
+ * Filter PII from output
864
+ */
865
+ filterPII(output) {
866
+ let filtered = output;
867
+ filtered = filtered.replace(PII_PATTERNS.email, "[EMAIL]");
868
+ filtered = filtered.replace(PII_PATTERNS.phone, "[PHONE]");
869
+ filtered = filtered.replace(PII_PATTERNS.ssn, "[SSN]");
870
+ filtered = filtered.replace(PII_PATTERNS.creditCard, "[CREDIT_CARD]");
871
+ return filtered;
872
+ }
873
+ };
874
+ function securityMiddleware(config) {
875
+ const inputValidator = new InputValidator(config.input);
876
+ const outputFilter = new OutputFilter(config.output);
877
+ return async (context, next) => {
878
+ const inputString = typeof context.input === "string" ? context.input : JSON.stringify(context.input);
879
+ const inputValidation = await inputValidator.validate(inputString);
880
+ if (!inputValidation.valid) {
881
+ inputValidation.violations.forEach((v) => {
882
+ if (config.onViolation) {
883
+ config.onViolation(v);
884
+ }
885
+ });
886
+ const firstViolation = inputValidation.violations[0];
887
+ throw toError(createError({
888
+ type: "agent",
889
+ message: `Input validation failed: ${firstViolation?.reason || "Unknown reason"}`
890
+ }));
891
+ }
892
+ if (inputValidation.sanitized) {
893
+ context.input = inputValidation.sanitized;
894
+ }
895
+ const result = await next();
896
+ const outputFiltering = await outputFilter.filter(result.text);
897
+ if (outputFiltering.violations.length > 0) {
898
+ outputFiltering.violations.forEach((v) => {
899
+ if (config.onViolation) {
900
+ config.onViolation(v);
901
+ }
902
+ });
903
+ }
904
+ return {
905
+ ...result,
906
+ text: outputFiltering.filtered
907
+ };
908
+ };
909
+ }
910
+ export {
911
+ COMMON_BLOCKED_PATTERNS,
912
+ InputValidator,
913
+ OutputFilter,
914
+ cacheMiddleware,
915
+ costTrackingMiddleware,
916
+ createCache,
917
+ createCostTracker,
918
+ createRateLimiter,
919
+ rateLimitMiddleware,
920
+ securityMiddleware
921
+ };
922
+ //# sourceMappingURL=production.js.map