veryfront 0.0.4 → 0.0.6

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,934 @@
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.cleanupInterval = null;
245
+ this.ttl = ttl;
246
+ this.startCleanup();
247
+ }
248
+ set(key, response) {
249
+ const now = Date.now();
250
+ this.cache.set(key, {
251
+ response,
252
+ cachedAt: now,
253
+ expiresAt: now + this.ttl,
254
+ accessCount: 0,
255
+ lastAccessedAt: now
256
+ });
257
+ }
258
+ get(key) {
259
+ const entry = this.cache.get(key);
260
+ if (!entry)
261
+ return null;
262
+ if (entry.expiresAt && Date.now() >= entry.expiresAt) {
263
+ this.cache.delete(key);
264
+ return null;
265
+ }
266
+ entry.accessCount++;
267
+ entry.lastAccessedAt = Date.now();
268
+ return entry.response;
269
+ }
270
+ has(key) {
271
+ const entry = this.cache.get(key);
272
+ if (!entry)
273
+ return false;
274
+ if (entry.expiresAt && Date.now() >= entry.expiresAt) {
275
+ this.cache.delete(key);
276
+ return false;
277
+ }
278
+ return true;
279
+ }
280
+ delete(key) {
281
+ this.cache.delete(key);
282
+ }
283
+ clear() {
284
+ this.cache.clear();
285
+ }
286
+ size() {
287
+ return this.cache.size;
288
+ }
289
+ destroy() {
290
+ if (this.cleanupInterval) {
291
+ clearInterval(this.cleanupInterval);
292
+ this.cleanupInterval = null;
293
+ }
294
+ this.cache.clear();
295
+ }
296
+ startCleanup() {
297
+ this.cleanupInterval = setInterval(() => {
298
+ const now = Date.now();
299
+ for (const [key, entry] of this.cache.entries()) {
300
+ if (entry.expiresAt && now >= entry.expiresAt) {
301
+ this.cache.delete(key);
302
+ }
303
+ }
304
+ }, 6e4);
305
+ }
306
+ };
307
+ function createCache(config) {
308
+ let cache;
309
+ switch (config.strategy) {
310
+ case "memory":
311
+ cache = new MemoryCache();
312
+ break;
313
+ case "lru":
314
+ cache = new LRUCache(config.maxSize || 100);
315
+ break;
316
+ case "ttl":
317
+ cache = new TTLCache(config.ttl || 3e5);
318
+ break;
319
+ default:
320
+ cache = new MemoryCache();
321
+ }
322
+ const keyGenerator = config.keyGenerator || ((input) => `cache_${hashString(input)}`);
323
+ return {
324
+ /**
325
+ * Get cached response
326
+ */
327
+ get(input, context) {
328
+ const key = keyGenerator(input, context);
329
+ return cache.get(key);
330
+ },
331
+ /**
332
+ * Set cached response
333
+ */
334
+ set(input, response, context) {
335
+ const key = keyGenerator(input, context);
336
+ cache.set(key, response);
337
+ },
338
+ /**
339
+ * Check if cached
340
+ */
341
+ has(input, context) {
342
+ const key = keyGenerator(input, context);
343
+ return cache.has(key);
344
+ },
345
+ /**
346
+ * Delete cached entry
347
+ */
348
+ delete(input, context) {
349
+ const key = keyGenerator(input, context);
350
+ cache.delete(key);
351
+ },
352
+ /**
353
+ * Clear all cache
354
+ */
355
+ clear() {
356
+ cache.clear();
357
+ },
358
+ /**
359
+ * Get cache size
360
+ */
361
+ size() {
362
+ return cache.size();
363
+ }
364
+ };
365
+ }
366
+ function hashString(str) {
367
+ let hash = 0;
368
+ for (let i = 0; i < str.length; i++) {
369
+ const char = str.charCodeAt(i);
370
+ hash = (hash << 5) - hash + char;
371
+ hash = hash & hash;
372
+ }
373
+ return Math.abs(hash).toString(36);
374
+ }
375
+ function cacheMiddleware(config) {
376
+ const cache = createCache(config);
377
+ return async (context, next) => {
378
+ const inputString = typeof context.input === "string" ? context.input : JSON.stringify(context.input);
379
+ const cached = cache.get(inputString, context);
380
+ if (cached) {
381
+ return {
382
+ ...cached,
383
+ metadata: {
384
+ ...cached.metadata,
385
+ fromCache: true,
386
+ cachedAt: Date.now()
387
+ }
388
+ };
389
+ }
390
+ const result = await next();
391
+ cache.set(inputString, result, context);
392
+ return result;
393
+ };
394
+ }
395
+
396
+ // src/core/utils/runtime-guards.ts
397
+ function hasDenoRuntime(global) {
398
+ return typeof global === "object" && global !== null && "Deno" in global && typeof global.Deno?.env?.get === "function";
399
+ }
400
+ function hasNodeProcess(global) {
401
+ return typeof global === "object" && global !== null && "process" in global && typeof global.process?.env === "object";
402
+ }
403
+
404
+ // src/core/utils/logger/env.ts
405
+ function getEnvironmentVariable(name) {
406
+ try {
407
+ if (typeof Deno !== "undefined" && hasDenoRuntime(globalThis)) {
408
+ const value = globalThis.Deno?.env.get(name);
409
+ return value === "" ? void 0 : value;
410
+ }
411
+ if (hasNodeProcess(globalThis)) {
412
+ const value = globalThis.process?.env[name];
413
+ return value === "" ? void 0 : value;
414
+ }
415
+ } catch {
416
+ return void 0;
417
+ }
418
+ return void 0;
419
+ }
420
+
421
+ // src/core/utils/logger/logger.ts
422
+ var cachedLogLevel;
423
+ function resolveLogLevel(force = false) {
424
+ if (force || cachedLogLevel === void 0) {
425
+ cachedLogLevel = getDefaultLevel();
426
+ }
427
+ return cachedLogLevel;
428
+ }
429
+ var ConsoleLogger = class {
430
+ constructor(prefix, level = resolveLogLevel()) {
431
+ this.prefix = prefix;
432
+ this.level = level;
433
+ }
434
+ setLevel(level) {
435
+ this.level = level;
436
+ }
437
+ getLevel() {
438
+ return this.level;
439
+ }
440
+ debug(message, ...args) {
441
+ if (this.level <= 0 /* DEBUG */) {
442
+ console.debug(`[${this.prefix}] DEBUG: ${message}`, ...args);
443
+ }
444
+ }
445
+ info(message, ...args) {
446
+ if (this.level <= 1 /* INFO */) {
447
+ console.log(`[${this.prefix}] ${message}`, ...args);
448
+ }
449
+ }
450
+ warn(message, ...args) {
451
+ if (this.level <= 2 /* WARN */) {
452
+ console.warn(`[${this.prefix}] WARN: ${message}`, ...args);
453
+ }
454
+ }
455
+ error(message, ...args) {
456
+ if (this.level <= 3 /* ERROR */) {
457
+ console.error(`[${this.prefix}] ERROR: ${message}`, ...args);
458
+ }
459
+ }
460
+ async time(label, fn) {
461
+ const start = performance.now();
462
+ try {
463
+ const result = await fn();
464
+ const end = performance.now();
465
+ this.debug(`${label} completed in ${(end - start).toFixed(2)}ms`);
466
+ return result;
467
+ } catch (error) {
468
+ const end = performance.now();
469
+ this.error(`${label} failed after ${(end - start).toFixed(2)}ms`, error);
470
+ throw error;
471
+ }
472
+ }
473
+ };
474
+ function parseLogLevel(levelString) {
475
+ if (!levelString)
476
+ return void 0;
477
+ const upper = levelString.toUpperCase();
478
+ switch (upper) {
479
+ case "DEBUG":
480
+ return 0 /* DEBUG */;
481
+ case "WARN":
482
+ return 2 /* WARN */;
483
+ case "ERROR":
484
+ return 3 /* ERROR */;
485
+ case "INFO":
486
+ return 1 /* INFO */;
487
+ default:
488
+ return void 0;
489
+ }
490
+ }
491
+ var getDefaultLevel = () => {
492
+ const envLevel = getEnvironmentVariable("LOG_LEVEL");
493
+ const parsedLevel = parseLogLevel(envLevel);
494
+ if (parsedLevel !== void 0)
495
+ return parsedLevel;
496
+ const debugFlag = getEnvironmentVariable("VERYFRONT_DEBUG");
497
+ if (debugFlag === "1" || debugFlag === "true")
498
+ return 0 /* DEBUG */;
499
+ return 1 /* INFO */;
500
+ };
501
+ var trackedLoggers = /* @__PURE__ */ new Set();
502
+ function createLogger(prefix) {
503
+ const logger2 = new ConsoleLogger(prefix);
504
+ trackedLoggers.add(logger2);
505
+ return logger2;
506
+ }
507
+ var cliLogger = createLogger("CLI");
508
+ var serverLogger = createLogger("SERVER");
509
+ var rendererLogger = createLogger("RENDERER");
510
+ var bundlerLogger = createLogger("BUNDLER");
511
+ var agentLogger = createLogger("AGENT");
512
+ var logger = createLogger("VERYFRONT");
513
+
514
+ // src/ai/production/cost-tracking/tracker.ts
515
+ var CostTracker = class {
516
+ constructor(config) {
517
+ this.records = [];
518
+ this.dailyTotal = 0;
519
+ this.monthlyTotal = 0;
520
+ this.lastDayReset = Date.now();
521
+ this.lastMonthReset = Date.now();
522
+ this.resetInterval = null;
523
+ this.config = config;
524
+ this.startPeriodicReset();
525
+ }
526
+ /**
527
+ * Track an agent response
528
+ */
529
+ track(agentId, model, response, userId) {
530
+ if (!response.usage) {
531
+ agentLogger.warn("No usage data in response, cannot track costs");
532
+ return this.createEmptyRecord(agentId, model);
533
+ }
534
+ const provider = model.split("/")[0] || "unknown";
535
+ const cost = this.calculateCost(
536
+ provider,
537
+ response.usage.promptTokens,
538
+ response.usage.completionTokens
539
+ );
540
+ const record = {
541
+ timestamp: Date.now(),
542
+ agentId,
543
+ model,
544
+ provider,
545
+ tokens: {
546
+ prompt: response.usage.promptTokens,
547
+ completion: response.usage.completionTokens,
548
+ total: response.usage.totalTokens
549
+ },
550
+ cost,
551
+ userId
552
+ };
553
+ this.records.push(record);
554
+ this.dailyTotal += cost;
555
+ this.monthlyTotal += cost;
556
+ this.checkLimits();
557
+ return record;
558
+ }
559
+ /**
560
+ * Calculate cost based on token usage
561
+ */
562
+ calculateCost(provider, inputTokens, outputTokens) {
563
+ const pricing = this.config.pricing[provider];
564
+ if (!pricing) {
565
+ agentLogger.warn(`No pricing configured for provider: ${provider}`);
566
+ return 0;
567
+ }
568
+ const inputCost = inputTokens / 1e6 * pricing.input;
569
+ const outputCost = outputTokens / 1e6 * pricing.output;
570
+ return inputCost + outputCost;
571
+ }
572
+ /**
573
+ * Get usage summary for a period
574
+ */
575
+ getSummary(startTime, endTime) {
576
+ const start = startTime || 0;
577
+ const end = endTime || Date.now();
578
+ const relevantRecords = this.records.filter(
579
+ (r) => r.timestamp >= start && r.timestamp <= end
580
+ );
581
+ const summary = {
582
+ requests: relevantRecords.length,
583
+ tokens: {
584
+ prompt: 0,
585
+ completion: 0,
586
+ total: 0
587
+ },
588
+ cost: 0,
589
+ byProvider: {},
590
+ period: { start, end }
591
+ };
592
+ for (const record of relevantRecords) {
593
+ summary.tokens.prompt += record.tokens.prompt;
594
+ summary.tokens.completion += record.tokens.completion;
595
+ summary.tokens.total += record.tokens.total;
596
+ summary.cost += record.cost;
597
+ if (!summary.byProvider[record.provider]) {
598
+ summary.byProvider[record.provider] = {
599
+ requests: 0,
600
+ tokens: 0,
601
+ cost: 0
602
+ };
603
+ }
604
+ const providerStats = summary.byProvider[record.provider];
605
+ providerStats.requests++;
606
+ providerStats.tokens += record.tokens.total;
607
+ providerStats.cost += record.cost;
608
+ }
609
+ return summary;
610
+ }
611
+ /**
612
+ * Get daily summary
613
+ */
614
+ getDailySummary() {
615
+ const now = Date.now();
616
+ const dayStart = now - 24 * 60 * 60 * 1e3;
617
+ return this.getSummary(dayStart, now);
618
+ }
619
+ /**
620
+ * Get monthly summary
621
+ */
622
+ getMonthlySummary() {
623
+ const now = Date.now();
624
+ const monthStart = now - 30 * 24 * 60 * 60 * 1e3;
625
+ return this.getSummary(monthStart, now);
626
+ }
627
+ /**
628
+ * Check if limits are exceeded
629
+ */
630
+ checkLimits() {
631
+ if (this.config.limits?.daily && this.dailyTotal > this.config.limits.daily) {
632
+ if (this.config.onLimitExceeded) {
633
+ this.config.onLimitExceeded(this.getDailySummary());
634
+ }
635
+ }
636
+ if (this.config.limits?.monthly && this.monthlyTotal > this.config.limits.monthly) {
637
+ if (this.config.onLimitExceeded) {
638
+ this.config.onLimitExceeded(this.getMonthlySummary());
639
+ }
640
+ }
641
+ }
642
+ startPeriodicReset() {
643
+ this.resetInterval = setInterval(() => {
644
+ const now = Date.now();
645
+ if (now - this.lastDayReset >= 24 * 60 * 60 * 1e3) {
646
+ this.dailyTotal = 0;
647
+ this.lastDayReset = now;
648
+ }
649
+ if (now - this.lastMonthReset >= 30 * 24 * 60 * 60 * 1e3) {
650
+ this.monthlyTotal = 0;
651
+ this.lastMonthReset = now;
652
+ }
653
+ }, 6e4);
654
+ }
655
+ destroy() {
656
+ if (this.resetInterval) {
657
+ clearInterval(this.resetInterval);
658
+ this.resetInterval = null;
659
+ }
660
+ this.records = [];
661
+ }
662
+ /**
663
+ * Create empty record
664
+ */
665
+ createEmptyRecord(agentId, model) {
666
+ return {
667
+ timestamp: Date.now(),
668
+ agentId,
669
+ model,
670
+ provider: model.split("/")[0] || "unknown",
671
+ tokens: { prompt: 0, completion: 0, total: 0 },
672
+ cost: 0
673
+ };
674
+ }
675
+ /**
676
+ * Get all records
677
+ */
678
+ getAllRecords() {
679
+ return [...this.records];
680
+ }
681
+ /**
682
+ * Clear all records
683
+ */
684
+ clear() {
685
+ this.records = [];
686
+ this.dailyTotal = 0;
687
+ this.monthlyTotal = 0;
688
+ }
689
+ };
690
+ function createCostTracker(config) {
691
+ const tracker = new CostTracker(config);
692
+ return {
693
+ /**
694
+ * Track agent response
695
+ */
696
+ track(agentId, model, response, userId) {
697
+ return tracker.track(agentId, model, response, userId);
698
+ },
699
+ /**
700
+ * Get usage summary
701
+ */
702
+ getSummary(startTime, endTime) {
703
+ return tracker.getSummary(startTime, endTime);
704
+ },
705
+ /**
706
+ * Get daily summary
707
+ */
708
+ getDailySummary() {
709
+ return tracker.getDailySummary();
710
+ },
711
+ /**
712
+ * Get monthly summary
713
+ */
714
+ getMonthlySummary() {
715
+ return tracker.getMonthlySummary();
716
+ },
717
+ /**
718
+ * Get all records
719
+ */
720
+ getAllRecords() {
721
+ return tracker.getAllRecords();
722
+ },
723
+ /**
724
+ * Clear all data
725
+ */
726
+ clear() {
727
+ tracker.clear();
728
+ }
729
+ };
730
+ }
731
+ function costTrackingMiddleware(config) {
732
+ const tracker = createCostTracker(config);
733
+ return async (context, next) => {
734
+ const result = await next();
735
+ tracker.track(
736
+ context.agentId,
737
+ context.model || "unknown",
738
+ result,
739
+ context.data?.userId
740
+ );
741
+ return result;
742
+ };
743
+ }
744
+
745
+ // src/ai/production/security/validator.ts
746
+ var COMMON_BLOCKED_PATTERNS = {
747
+ /** Prompt injection attempts */
748
+ promptInjection: [
749
+ /ignore\s+previous\s+instructions/i,
750
+ /ignore\s+all\s+previous\s+prompts/i,
751
+ /you\s+are\s+now\s+a/i,
752
+ /pretend\s+you\s+are/i,
753
+ /system:\s*/i,
754
+ /<\|im_start\|>/i,
755
+ /<\|im_end\|>/i
756
+ ],
757
+ /** Potential data exfiltration */
758
+ dataExfiltration: [
759
+ /password/i,
760
+ /api[_\s-]?key/i,
761
+ /secret/i,
762
+ /token/i,
763
+ /credit\s+card/i
764
+ ],
765
+ /** SQL injection patterns */
766
+ sqlInjection: [
767
+ /(\bUNION\b|\bSELECT\b).*\bFROM\b/i,
768
+ /;\s*(DROP|DELETE|UPDATE|INSERT)/i
769
+ ],
770
+ /** XSS patterns */
771
+ xss: [
772
+ /<script[^>]*>.*?<\/script>/gi,
773
+ /javascript:/i,
774
+ /on\w+\s*=/i
775
+ // Event handlers
776
+ ]
777
+ };
778
+ var PII_PATTERNS = {
779
+ email: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi,
780
+ phone: /\b(\+\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g,
781
+ ssn: /\b\d{3}-\d{2}-\d{4}\b/g,
782
+ creditCard: /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g
783
+ };
784
+ var InputValidator = class {
785
+ constructor(config) {
786
+ this.config = config || {};
787
+ }
788
+ /**
789
+ * Validate input
790
+ */
791
+ async validate(input) {
792
+ const violations = [];
793
+ if (this.config?.maxLength && input.length > this.config.maxLength) {
794
+ violations.push({
795
+ type: "input",
796
+ reason: `Input exceeds maximum length of ${this.config.maxLength}`,
797
+ content: input.substring(0, 100) + "..."
798
+ });
799
+ }
800
+ if (this.config?.blockedPatterns) {
801
+ for (const pattern of this.config.blockedPatterns) {
802
+ if (pattern.test(input)) {
803
+ violations.push({
804
+ type: "input",
805
+ reason: "Input matches blocked pattern",
806
+ content: input,
807
+ pattern
808
+ });
809
+ }
810
+ }
811
+ }
812
+ if (this.config?.validate) {
813
+ const customValid = await this.config.validate(input);
814
+ if (!customValid) {
815
+ violations.push({
816
+ type: "input",
817
+ reason: "Custom validation failed",
818
+ content: input
819
+ });
820
+ }
821
+ }
822
+ let sanitized = input;
823
+ if (this.config?.sanitize) {
824
+ sanitized = this.sanitizeInput(input);
825
+ }
826
+ return {
827
+ valid: violations.length === 0,
828
+ sanitized: this.config?.sanitize ? sanitized : void 0,
829
+ violations
830
+ };
831
+ }
832
+ /**
833
+ * Sanitize input (remove potentially harmful content)
834
+ */
835
+ sanitizeInput(input) {
836
+ let sanitized = input;
837
+ sanitized = sanitized.replace(/<script[^>]*>.*?<\/script>/gi, "");
838
+ sanitized = sanitized.replace(/on\w+\s*=\s*["'][^"']*["']/gi, "");
839
+ sanitized = sanitized.replace(/javascript:/gi, "");
840
+ return sanitized;
841
+ }
842
+ };
843
+ var OutputFilter = class {
844
+ constructor(config) {
845
+ this.config = config || {};
846
+ }
847
+ /**
848
+ * Filter output
849
+ */
850
+ async filter(output) {
851
+ const violations = [];
852
+ let filtered = output;
853
+ if (this.config?.blockedPatterns) {
854
+ for (const pattern of this.config.blockedPatterns) {
855
+ if (pattern.test(filtered)) {
856
+ violations.push({
857
+ type: "output",
858
+ reason: "Output contains blocked pattern",
859
+ content: filtered,
860
+ pattern
861
+ });
862
+ filtered = filtered.replace(pattern, "[REDACTED]");
863
+ }
864
+ }
865
+ }
866
+ if (this.config?.filterPII) {
867
+ filtered = this.filterPII(filtered);
868
+ }
869
+ if (this.config?.filter) {
870
+ filtered = await this.config.filter(filtered);
871
+ }
872
+ return { filtered, violations };
873
+ }
874
+ /**
875
+ * Filter PII from output
876
+ */
877
+ filterPII(output) {
878
+ let filtered = output;
879
+ filtered = filtered.replace(PII_PATTERNS.email, "[EMAIL]");
880
+ filtered = filtered.replace(PII_PATTERNS.phone, "[PHONE]");
881
+ filtered = filtered.replace(PII_PATTERNS.ssn, "[SSN]");
882
+ filtered = filtered.replace(PII_PATTERNS.creditCard, "[CREDIT_CARD]");
883
+ return filtered;
884
+ }
885
+ };
886
+ function securityMiddleware(config) {
887
+ const inputValidator = new InputValidator(config.input);
888
+ const outputFilter = new OutputFilter(config.output);
889
+ return async (context, next) => {
890
+ const inputString = typeof context.input === "string" ? context.input : JSON.stringify(context.input);
891
+ const inputValidation = await inputValidator.validate(inputString);
892
+ if (!inputValidation.valid) {
893
+ inputValidation.violations.forEach((v) => {
894
+ if (config.onViolation) {
895
+ config.onViolation(v);
896
+ }
897
+ });
898
+ const firstViolation = inputValidation.violations[0];
899
+ throw toError(createError({
900
+ type: "agent",
901
+ message: `Input validation failed: ${firstViolation?.reason || "Unknown reason"}`
902
+ }));
903
+ }
904
+ if (inputValidation.sanitized) {
905
+ context.input = inputValidation.sanitized;
906
+ }
907
+ const result = await next();
908
+ const outputFiltering = await outputFilter.filter(result.text);
909
+ if (outputFiltering.violations.length > 0) {
910
+ outputFiltering.violations.forEach((v) => {
911
+ if (config.onViolation) {
912
+ config.onViolation(v);
913
+ }
914
+ });
915
+ }
916
+ return {
917
+ ...result,
918
+ text: outputFiltering.filtered
919
+ };
920
+ };
921
+ }
922
+ export {
923
+ COMMON_BLOCKED_PATTERNS,
924
+ InputValidator,
925
+ OutputFilter,
926
+ cacheMiddleware,
927
+ costTrackingMiddleware,
928
+ createCache,
929
+ createCostTracker,
930
+ createRateLimiter,
931
+ rateLimitMiddleware,
932
+ securityMiddleware
933
+ };
934
+ //# sourceMappingURL=production.js.map