chore: recovery checkpoint - v3.0 API successfully recovered

CRITICAL CHECKPOINT - DO NOT PUSH TO GITHUB

Recovery Status:
- Successfully recovered brainy.ts from compiled JavaScript
- All core v3.0 API methods functional (add, get, update, delete, relate, find, etc.)
- Neural subsystem intact (562KB embedded patterns, NLP working)
- Augmentation pipeline operational (20+ augmentations)
- HNSW clustering system complete
- Triple Intelligence compiled (needs constructor fix)
- Test suite validates functionality

Changes preserved:
- 898 files with changes from last 3 days
- 144,475 insertions
- All augmentation improvements
- All test coverage enhancements
- Complete v3.0 feature set

This is a LOCAL checkpoint only - contains recovered work after corruption incident.
Created backup in .backups/brainy-full-20250910-151314.tar.gz

Branch: recovery-checkpoint-20250910-151433
Date: Wed Sep 10 03:18:04 PM PDT 2025
This commit is contained in:
David Snelling 2025-09-10 15:18:04 -07:00
parent f65455fb22
commit 8ff382ca3b
895 changed files with 143654 additions and 28268 deletions

View file

@ -0,0 +1,321 @@
/**
* Rate Limiting Augmentation
* Provides configurable rate limiting for Brainy operations
*/
import { BaseAugmentation } from './brainyAugmentation.js';
/**
* Rate Limit Augmentation
*/
export class RateLimitAugmentation extends BaseAugmentation {
constructor(config = {}) {
super(config);
this.name = 'rateLimiter';
this.timing = 'before';
this.metadata = 'none';
this.operations = ['search', 'find', 'add', 'update', 'delete', 'get'];
this.priority = 10; // High priority, runs early
// Augmentation metadata
this.category = 'core'; // Use 'core' as security isn't a valid category
this.description = 'Provides rate limiting for Brainy operations';
this.limiters = new Map();
// Merge with defaults
this.config = {
enabled: config.enabled ?? true,
limits: {
searches: config.limits?.searches ?? 1000,
writes: config.limits?.writes ?? 100,
reads: config.limits?.reads ?? 5000,
deletes: config.limits?.deletes ?? 50
},
windowMs: config.windowMs ?? 60000, // 1 minute default
skipSuccessfulRequests: config.skipSuccessfulRequests ?? false,
skipFailedRequests: config.skipFailedRequests ?? true,
keyGenerator: config.keyGenerator || this.defaultKeyGenerator
};
this.windowMs = this.config.windowMs;
// Initialize operation limiters
this.initializeLimiters();
}
getManifest() {
return {
id: 'rate-limiter',
name: 'Rate Limiter',
version: '1.0.0',
description: 'Configurable rate limiting for API operations',
longDescription: 'Provides per-operation rate limiting with configurable windows and limits. Helps prevent abuse and ensures fair resource usage.',
category: 'core',
configSchema: {
type: 'object',
properties: {
enabled: {
type: 'boolean',
default: true,
description: 'Enable or disable rate limiting'
},
limits: {
type: 'object',
properties: {
searches: {
type: 'number',
default: 1000,
description: 'Search operations per minute'
},
writes: {
type: 'number',
default: 100,
description: 'Write operations per minute'
},
reads: {
type: 'number',
default: 5000,
description: 'Read operations per minute'
},
deletes: {
type: 'number',
default: 50,
description: 'Delete operations per minute'
}
}
},
windowMs: {
type: 'number',
default: 60000,
description: 'Time window in milliseconds'
}
}
},
configDefaults: {
enabled: true,
limits: {
searches: 1000,
writes: 100,
reads: 5000,
deletes: 50
},
windowMs: 60000
},
minBrainyVersion: '3.0.0',
keywords: ['rate-limit', 'security', 'throttle'],
documentation: 'https://docs.brainy.dev/augmentations/rate-limit',
status: 'stable',
performance: {
memoryUsage: 'low',
cpuUsage: 'low',
networkUsage: 'none'
},
features: ['per-operation-limits', 'configurable-windows', 'key-based-limiting'],
enhancedOperations: ['search', 'add', 'update', 'delete', 'get'],
metrics: [
{
name: 'rate_limit_exceeded',
type: 'counter',
description: 'Number of rate limit violations'
},
{
name: 'rate_limit_requests',
type: 'counter',
description: 'Total requests checked'
}
]
};
}
/**
* Initialize rate limiters for each operation type
*/
initializeLimiters() {
const operations = ['searches', 'writes', 'reads', 'deletes'];
for (const op of operations) {
this.limiters.set(op, new Map());
}
}
/**
* Default key generator (could be IP, user ID, etc.)
*/
defaultKeyGenerator(_context) {
// In a real implementation, this would extract IP or user ID
return 'default';
}
/**
* Check if request should be rate limited
*/
checkRateLimit(operation, key) {
const limiter = this.limiters.get(operation);
if (!limiter)
return false;
const limit = this.config.limits[operation];
if (!limit)
return false;
const now = Date.now();
let entry = limiter.get(key);
// Initialize or reset entry
if (!entry || now >= entry.resetTime) {
entry = {
count: 0,
resetTime: now + this.windowMs
};
limiter.set(key, entry);
}
// Check if limit exceeded
if (entry.count >= limit) {
return true; // Rate limited
}
// Increment counter
entry.count++;
return false;
}
/**
* Get remaining requests for an operation
*/
getRemainingRequests(operation, key) {
const limiter = this.limiters.get(operation);
if (!limiter)
return -1;
const limit = this.config.limits[operation];
if (!limit)
return -1;
const entry = limiter.get(key);
if (!entry)
return limit;
const now = Date.now();
if (now >= entry.resetTime)
return limit;
return Math.max(0, limit - entry.count);
}
/**
* Get time until reset
*/
getResetTime(operation, key) {
const limiter = this.limiters.get(operation);
if (!limiter)
return 0;
const entry = limiter.get(key);
if (!entry)
return 0;
const now = Date.now();
return Math.max(0, entry.resetTime - now);
}
async onInitialize() {
if (!this.config.enabled) {
this.log('Rate limiter disabled by configuration');
return;
}
this.log(`Rate limiter initialized (window: ${this.windowMs}ms)`);
// Start cleanup timer
setInterval(() => {
this.cleanup();
}, this.windowMs);
}
async onShutdown() {
this.clear();
this.log('Rate limiter shut down');
}
/**
* Execute augmentation - apply rate limiting
*/
async execute(operation, params, next) {
// If rate limiting is disabled, just pass through
if (!this.config.enabled) {
return next();
}
// Map operations to rate limit categories
let rateLimitOperation;
switch (operation) {
case 'search':
case 'find':
case 'similar':
rateLimitOperation = 'searches';
break;
case 'add':
case 'update':
rateLimitOperation = 'writes';
break;
case 'delete':
rateLimitOperation = 'deletes';
break;
case 'get':
rateLimitOperation = 'reads';
break;
default:
return next(); // Don't rate limit unknown operations
}
const key = this.config.keyGenerator(params);
if (this.checkRateLimit(rateLimitOperation, key)) {
const error = new Error(`Rate limit exceeded for ${operation}`);
error.statusCode = 429;
error.retryAfter = this.getResetTime(rateLimitOperation, key);
error.rateLimit = {
limit: this.config.limits[rateLimitOperation],
remaining: 0,
reset: Date.now() + this.getResetTime(rateLimitOperation, key)
};
throw error;
}
try {
const result = await next();
// Add rate limit info to result if possible
if (result && typeof result === 'object' && !Array.isArray(result)) {
result._rateLimit = {
limit: this.config.limits[rateLimitOperation],
remaining: this.getRemainingRequests(rateLimitOperation, key),
reset: Date.now() + this.getResetTime(rateLimitOperation, key)
};
}
return result;
}
catch (error) {
// Optionally don't count failed requests
if (this.config.skipFailedRequests) {
const limiter = this.limiters.get(rateLimitOperation);
const entry = limiter.get(key);
if (entry && entry.count > 0)
entry.count--;
}
throw error;
}
}
/**
* Get rate limit statistics
*/
getStats() {
const stats = { operations: {} };
for (const [operation, limiter] of this.limiters) {
let totalRequests = 0;
for (const entry of limiter.values()) {
totalRequests += entry.count;
}
stats.operations[operation] = {
activeKeys: limiter.size,
totalRequests
};
}
return stats;
}
/**
* Clear all rate limit entries
*/
clear() {
for (const limiter of this.limiters.values()) {
limiter.clear();
}
}
/**
* Clear expired entries (cleanup)
*/
cleanup() {
const now = Date.now();
for (const limiter of this.limiters.values()) {
for (const [key, entry] of limiter) {
if (now >= entry.resetTime) {
limiter.delete(key);
}
}
}
}
}
/**
* Create rate limit augmentation
*/
export function createRateLimitAugmentation(config) {
return new RateLimitAugmentation(config);
}
//# sourceMappingURL=rateLimitAugmentation.js.map