/** * Serverless Safety Tests * * RED PHASE: These tests document module-level mutable state issues in the codebase * that can cause problems in serverless environments like Cloudflare Workers. * * ## Serverless State Risks * * In serverless environments (especially Cloudflare Workers): * 1. **State leakage**: Module-level `let` variables persist across requests within the same isolate * 2. **Cross-request contamination**: Data from one request can leak to another * 3. **Memory leaks**: Unbounded growth of Maps/Sets/Arrays without cleanup * 4. **Stale singletons**: Cached objects may outlive their intended scope * 5. **Counter drift**: Incrementing counters can overflow or become predictable * * ## Files with Module-Level Mutable State * * Identified via: `grep -rE "^(let|var) " packages/* /src/ --include="*.ts" | grep -v test` * * ### Critical (Cross-Request State) * - packages/documentdb/src/bson/objectid.ts: counter, counterInitialized, processUnique * - packages/mongo.do/src/auth.ts: tokenCache * - packages/postgres.do/src/streaming.ts: cursorCounter * - packages/postgres/src/routing/websocket-pool.ts: connectionIdCounter * - packages/postgres/src/worker/auth.ts: tokenCache, authFailureRateLimiter * - packages/postgres/src/pglite/warm-loader.ts: _defaultLoader * * ### Moderate (Singleton Pools) * - packages/documentdb/src/worker/index.ts: proxyPool * - packages/postgres/src/worker/entry.ts: proxyPool * * ### Low (Environment-Specific) * - packages/postgres.do/src/cdc/react-hooks.ts: React (null-safe) * - packages/postgres/src/worker/memory-pressure.ts: cachedPerformanceMemory * - packages/postgres.do/src/cli/commands/dev.ts: migrationChangeTimeout * * @module serverless-safety * @see Issue: postgres-3zu0 */ export {}; /** * # State Management Patterns for Serverless Compatibility * * This codebase implements several patterns to ensure safe operation * in serverless environments like Cloudflare Workers. * * ## Pattern 1: Bounded Caches with LRU Eviction * * Location: packages/shared/src/cache.ts * * Implementation: * - BoundedCache class with configurable maxSize * - LRU eviction using Map's insertion order * - TTL-based expiration with automatic cleanup * - dispose() method to stop timers * * Usage: * ```typescript * const cache = new BoundedCache({ * maxSize: 1000, * defaultTTL: 60000, * cleanupInterval: 60000, * }) * ``` * * ## Pattern 2: Factory Functions for Singletons * * Location: packages/postgres/src/pglite/warm-loader.ts * * Implementation: * - createWarmPGliteLoader() factory creates new instance * - State is instance-level, not module-level * - Module provides lazy-init default (getDefaultLoader()) * * Why: * - Caller controls singleton scope (per-DO, per-test, etc.) * - Easy testing with fresh instances * - Multiple configurations in same isolate * * ## Pattern 3: Request-Scoped Counters (Documented) * * Some counters (cursorCounter, connectionIdCounter) remain * module-level for performance. These are documented as: * * - LOW RISK: Overflow unlikely (would take billions of requests) * - INTENTIONAL: Performance optimization * - MONITORED: Counter values don't affect security * * ## Pattern 4: Clear/Reset Methods for Testing * * All singletons should have: * - reset() or clear() to restore initial state * - dispose() to release resources * - Exported test utilities (clearRateLimitState, clearTokenCache) * * ## Pattern 5: WeakMap for DO-Scoped Singletons * * Location: packages/postgres/src/pglite/init.ts * * Implementation: * - const instanceCache = new WeakMap() * - DO state object used as key * - Instances garbage collected when DO is recycled * * ## Anti-Patterns to Avoid * * 1. ❌ Module-level Map without size limit * 2. ❌ Module-level let without reset capability * 3. ❌ Timers without cleanup (setInterval without clearInterval) * 4. ❌ Growing state without bounds * 5. ❌ Sensitive data in module-level cache without TTL * * ## Summary of Current Module-Level State * * ### Intentional Singletons (Documented as Safe) * - _defaultLoader (warm-loader.ts) - Lazy singleton, has reset() * - tokenCache (auth.ts) - BoundedCache with limits * - instanceCache (init.ts) - WeakMap, auto-cleanup * * ### Counters (Low Risk) * - cursorCounter (streaming.ts) - Random component prevents collision * - connectionIdCounter (websocket-pool.ts) - Per-connection, no overflow risk * - counter (objectid.ts) - Random start, wraps at 16M * * ### Rate Limiter (Properly Bounded) * - authFailureRateLimiter (auth.ts) - Map with proper bounds: * - Max 10,000 entries (RATE_LIMIT_MAX_ENTRIES) * - Lazy cleanup every 5 minutes (RATE_LIMIT_CLEANUP_INTERVAL_MS) * - LRU-style eviction when at capacity */ /** * Summary of Issues by Severity * * ## RESOLVED (GREEN) * 1. ✅ Token cache - Uses BoundedCache with limits and TTL * 2. ✅ Warm loader - Factory pattern with reset capability * 3. ✅ Plugin manager - Instance-based, no module state * 4. ✅ DO instance cache - WeakMap for auto-cleanup * * ## DOCUMENTED AS INTENTIONAL (LOW RISK) * 5. ⚠️ ObjectId counter - Random start, 16M overflow unlikely * 6. ⚠️ Cursor counter - Includes timestamp+random for uniqueness * 7. ⚠️ Connection ID counter - Per-connection, no security impact * 8. ⚠️ processUnique - Shared by design (MongoDB compatibility) * * ## RESOLVED (IMPLEMENTED) * 9. ✅ Rate limiter Map - Has size limit (10K entries) and cleanup * Location: packages/postgres/src/worker/auth.ts * - RATE_LIMIT_MAX_ENTRIES = 10000 * - cleanupExpiredRateLimitEntries() - periodic cleanup * - evictOldestEntries() - LRU-style eviction at capacity * - clearRateLimitState() - test cleanup function * * ## SAFE PATTERNS * 10. ✅ React feature detection - Set once, never mutated */ //# sourceMappingURL=serverless-safety.test.d.ts.map