@digilogiclabs/platform-core 1.4.0 → 1.5.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/interfaces/IAI.ts","../src/interfaces/IRAG.ts","../src/testing.ts","../src/adapters/memory/MemoryDatabase.ts","../src/adapters/memory/MemoryCache.ts","../src/adapters/memory/MemoryStorage.ts","../src/adapters/memory/MemoryEmail.ts","../src/interfaces/IQueue.ts","../src/context/CorrelationContext.ts","../src/adapters/memory/MemoryQueue.ts","../src/adapters/console/ConsoleEmail.ts","../src/interfaces/ISecrets.ts","../src/config.ts","../src/interfaces/ITracing.ts","../src/interfaces/ILogger.ts","../src/interfaces/IMetrics.ts","../src/factory.ts","../src/adapters/memory/MemoryCrypto.ts"],"sourcesContent":["/**\n * IAI - Core AI abstraction interface for platform-core\n *\n * Provides a vendor-agnostic interface for AI operations including:\n * - Text generation (chat, completion)\n * - Embeddings generation\n * - Model routing and fallback\n * - Streaming support\n * - Token usage tracking\n */\n\n// ═══════════════════════════════════════════════════════════════\n// CORE TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport type AIProvider =\n | \"openai\"\n | \"anthropic\"\n | \"google\"\n | \"azure\"\n | \"bedrock\"\n | \"custom\";\n\nexport type AIModelType =\n | \"chat\"\n | \"completion\"\n | \"embedding\"\n | \"image\"\n | \"audio\"\n | \"video\";\n\nexport type AIRole = \"system\" | \"user\" | \"assistant\" | \"function\" | \"tool\";\n\nexport interface AIMessage {\n role: AIRole;\n content: string;\n name?: string;\n toolCallId?: string;\n toolCalls?: AIToolCall[];\n}\n\nexport interface AIToolCall {\n id: string;\n type: \"function\";\n function: {\n name: string;\n arguments: string;\n };\n}\n\nexport interface AITool {\n type: \"function\";\n function: {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n };\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MODEL CONFIGURATION\n// ═══════════════════════════════════════════════════════════════\n\nexport interface AIModelConfig {\n /** Model identifier (e.g., 'gpt-4', 'claude-3-opus') */\n modelId: string;\n /** Provider for this model */\n provider: AIProvider;\n /** Model capabilities */\n capabilities: AIModelType[];\n /** Maximum context window in tokens */\n maxContextTokens: number;\n /** Maximum output tokens */\n maxOutputTokens: number;\n /** Cost per 1K input tokens in USD */\n inputCostPer1K: number;\n /** Cost per 1K output tokens in USD */\n outputCostPer1K: number;\n /** Supports streaming */\n supportsStreaming: boolean;\n /** Supports function/tool calling */\n supportsTools: boolean;\n /** Supports vision (image input) */\n supportsVision: boolean;\n /** Rate limits per minute */\n rateLimits?: {\n requestsPerMinute: number;\n tokensPerMinute: number;\n };\n /** Custom endpoint for self-hosted models */\n endpoint?: string;\n /** Additional provider-specific config */\n providerConfig?: Record<string, unknown>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// REQUEST/RESPONSE TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport interface AIChatRequest {\n messages: AIMessage[];\n model?: string;\n temperature?: number;\n maxTokens?: number;\n topP?: number;\n frequencyPenalty?: number;\n presencePenalty?: number;\n stop?: string | string[];\n tools?: AITool[];\n toolChoice?:\n | \"auto\"\n | \"none\"\n | \"required\"\n | { type: \"function\"; function: { name: string } };\n stream?: boolean;\n user?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface AICompletionRequest {\n prompt: string;\n model?: string;\n temperature?: number;\n maxTokens?: number;\n topP?: number;\n frequencyPenalty?: number;\n presencePenalty?: number;\n stop?: string | string[];\n stream?: boolean;\n user?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface AIEmbeddingRequest {\n input: string | string[];\n model?: string;\n dimensions?: number;\n user?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface AIChatResponse {\n id: string;\n model: string;\n provider: AIProvider;\n choices: AIChatChoice[];\n usage: AIUsageInfo;\n created: Date;\n finishReason: AIFinishReason;\n}\n\nexport interface AIChatChoice {\n index: number;\n message: AIMessage;\n finishReason: AIFinishReason;\n}\n\nexport type AIFinishReason =\n | \"stop\"\n | \"length\"\n | \"tool_calls\"\n | \"content_filter\"\n | \"error\";\n\nexport interface AICompletionResponse {\n id: string;\n model: string;\n provider: AIProvider;\n text: string;\n usage: AIUsageInfo;\n created: Date;\n finishReason: AIFinishReason;\n}\n\nexport interface AIEmbeddingResponse {\n id: string;\n model: string;\n provider: AIProvider;\n embeddings: number[][];\n usage: AIUsageInfo;\n created: Date;\n}\n\nexport interface AIUsageInfo {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n estimatedCostUsd: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// STREAMING TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport interface AIStreamChunk {\n id: string;\n model: string;\n provider: AIProvider;\n delta: {\n content?: string;\n toolCalls?: AIToolCall[];\n role?: AIRole;\n };\n finishReason?: AIFinishReason;\n usage?: AIUsageInfo;\n}\n\nexport type AIStreamCallback = (chunk: AIStreamChunk) => void | Promise<void>;\n\n// ═══════════════════════════════════════════════════════════════\n// ROUTING CONFIGURATION\n// ═══════════════════════════════════════════════════════════════\n\nexport type RoutingStrategy =\n | \"priority\"\n | \"round-robin\"\n | \"least-latency\"\n | \"cost-optimized\"\n | \"random\";\n\nexport interface AIRouterConfig {\n /** Primary model to use */\n primaryModel: string;\n /** Fallback models in order of preference */\n fallbackModels?: string[];\n /** Routing strategy for load balancing */\n strategy?: RoutingStrategy;\n /** Maximum retries before failing */\n maxRetries?: number;\n /** Timeout in milliseconds */\n timeoutMs?: number;\n /** Enable automatic fallback on errors */\n autoFallback?: boolean;\n /** Cost budget per request in USD (for cost-optimized routing) */\n costBudget?: number;\n /** Custom routing function */\n customRouter?: (request: AIChatRequest | AICompletionRequest) => string;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// ERROR TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport type AIErrorCode =\n | \"invalid_request\"\n | \"authentication_error\"\n | \"rate_limit_exceeded\"\n | \"quota_exceeded\"\n | \"model_not_found\"\n | \"context_length_exceeded\"\n | \"content_filter\"\n | \"server_error\"\n | \"timeout\"\n | \"network_error\"\n | \"provider_unavailable\"\n | \"unknown\";\n\nexport interface AIError extends Error {\n code: AIErrorCode;\n provider?: AIProvider;\n model?: string;\n statusCode?: number;\n retryable: boolean;\n retryAfterMs?: number;\n}\n\nexport const AIErrorMessages: Record<AIErrorCode, string> = {\n invalid_request: \"The request was invalid or malformed\",\n authentication_error: \"Authentication failed - check your API key\",\n rate_limit_exceeded: \"Rate limit exceeded - try again later\",\n quota_exceeded: \"Usage quota exceeded for this billing period\",\n model_not_found: \"The specified model was not found\",\n context_length_exceeded: \"Input exceeds the model context length\",\n content_filter: \"Content was filtered due to policy violations\",\n server_error: \"The AI provider encountered an internal error\",\n timeout: \"The request timed out\",\n network_error: \"Network error connecting to AI provider\",\n provider_unavailable: \"The AI provider is currently unavailable\",\n unknown: \"An unknown error occurred\",\n};\n\nexport function createAIError(\n code: AIErrorCode,\n message?: string,\n options?: {\n provider?: AIProvider;\n model?: string;\n statusCode?: number;\n retryable?: boolean;\n retryAfterMs?: number;\n cause?: Error;\n },\n): AIError {\n const error = new Error(message || AIErrorMessages[code]) as AIError;\n error.name = \"AIError\";\n error.code = code;\n error.provider = options?.provider;\n error.model = options?.model;\n error.statusCode = options?.statusCode;\n error.retryable =\n options?.retryable ??\n [\n \"rate_limit_exceeded\",\n \"server_error\",\n \"timeout\",\n \"network_error\",\n ].includes(code);\n error.retryAfterMs = options?.retryAfterMs;\n if (options?.cause) {\n error.cause = options.cause;\n }\n return error;\n}\n\nexport function isAIError(error: unknown): error is AIError {\n return (\n error instanceof Error &&\n \"code\" in error &&\n typeof (error as AIError).retryable === \"boolean\"\n );\n}\n\n// ═══════════════════════════════════════════════════════════════\n// AI CONFIGURATION\n// ═══════════════════════════════════════════════════════════════\n\nexport interface AIConfig {\n /** Default model for chat requests */\n defaultChatModel?: string;\n /** Default model for completion requests */\n defaultCompletionModel?: string;\n /** Default model for embedding requests */\n defaultEmbeddingModel?: string;\n /** Router configuration */\n router?: AIRouterConfig;\n /** Available model configurations */\n models?: AIModelConfig[];\n /** API keys for providers */\n apiKeys?: Partial<Record<AIProvider, string>>;\n /** Default timeout in milliseconds */\n defaultTimeoutMs?: number;\n /** Enable request/response logging */\n enableLogging?: boolean;\n /** Cache embeddings */\n cacheEmbeddings?: boolean;\n /** Embedding cache TTL in seconds */\n embeddingCacheTtlSeconds?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MAIN INTERFACE\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * IAI - Core AI interface\n *\n * @example\n * ```typescript\n * const ai = platform.ai;\n *\n * // Chat completion\n * const response = await ai.chat({\n * messages: [\n * { role: 'system', content: 'You are a helpful assistant.' },\n * { role: 'user', content: 'Hello!' }\n * ]\n * });\n *\n * // Streaming chat\n * for await (const chunk of ai.chatStream({\n * messages: [{ role: 'user', content: 'Tell me a story' }]\n * })) {\n * process.stdout.write(chunk.delta.content || '');\n * }\n *\n * // Embeddings\n * const embeddings = await ai.embed({\n * input: ['Hello world', 'Goodbye world']\n * });\n * ```\n */\nexport interface IAI {\n // ─────────────────────────────────────────────────────────────\n // Chat Operations\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Send a chat completion request\n */\n chat(request: AIChatRequest): Promise<AIChatResponse>;\n\n /**\n * Send a streaming chat completion request\n */\n chatStream(request: AIChatRequest): AsyncIterable<AIStreamChunk>;\n\n /**\n * Send a chat completion request with callback-based streaming\n */\n chatWithCallback(\n request: AIChatRequest,\n callback: AIStreamCallback,\n ): Promise<AIChatResponse>;\n\n // ─────────────────────────────────────────────────────────────\n // Completion Operations\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Send a text completion request\n */\n complete(request: AICompletionRequest): Promise<AICompletionResponse>;\n\n /**\n * Send a streaming completion request\n */\n completeStream(request: AICompletionRequest): AsyncIterable<AIStreamChunk>;\n\n // ─────────────────────────────────────────────────────────────\n // Embedding Operations\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Generate embeddings for text\n */\n embed(request: AIEmbeddingRequest): Promise<AIEmbeddingResponse>;\n\n /**\n * Calculate similarity between two texts\n */\n similarity(text1: string, text2: string, model?: string): Promise<number>;\n\n // ─────────────────────────────────────────────────────────────\n // Model Management\n // ─────────────────────────────────────────────────────────────\n\n /**\n * List available models\n */\n listModels(): Promise<AIModelConfig[]>;\n\n /**\n * Get model configuration\n */\n getModel(modelId: string): Promise<AIModelConfig | null>;\n\n /**\n * Check if a model supports a capability\n */\n supportsCapability(\n modelId: string,\n capability: AIModelType,\n ): Promise<boolean>;\n\n /**\n * Estimate tokens for text\n */\n estimateTokens(text: string, model?: string): Promise<number>;\n\n /**\n * Estimate cost for a request\n */\n estimateCost(\n request: AIChatRequest | AICompletionRequest | AIEmbeddingRequest,\n ): Promise<number>;\n\n // ─────────────────────────────────────────────────────────────\n // Health & Status\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Check if AI service is healthy\n */\n healthCheck(): Promise<{\n healthy: boolean;\n providers: Record<\n AIProvider,\n { available: boolean; latencyMs?: number; error?: string }\n >;\n }>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MEMORY IMPLEMENTATION\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * MemoryAI - In-memory implementation for testing\n */\nexport class MemoryAI implements IAI {\n private models: AIModelConfig[] = [];\n private responses: Map<string, AIChatResponse | AICompletionResponse> =\n new Map();\n private embeddings: Map<string, number[]> = new Map();\n private requestLog: Array<{\n type: string;\n request: unknown;\n timestamp: Date;\n }> = [];\n\n constructor(private config: AIConfig = {}) {\n // Initialize with default models\n this.models = config.models || [\n {\n modelId: \"gpt-4\",\n provider: \"openai\",\n capabilities: [\"chat\", \"completion\"],\n maxContextTokens: 128000,\n maxOutputTokens: 4096,\n inputCostPer1K: 0.03,\n outputCostPer1K: 0.06,\n supportsStreaming: true,\n supportsTools: true,\n supportsVision: true,\n },\n {\n modelId: \"claude-3-opus\",\n provider: \"anthropic\",\n capabilities: [\"chat\"],\n maxContextTokens: 200000,\n maxOutputTokens: 4096,\n inputCostPer1K: 0.015,\n outputCostPer1K: 0.075,\n supportsStreaming: true,\n supportsTools: true,\n supportsVision: true,\n },\n {\n modelId: \"text-embedding-3-small\",\n provider: \"openai\",\n capabilities: [\"embedding\"],\n maxContextTokens: 8191,\n maxOutputTokens: 0,\n inputCostPer1K: 0.00002,\n outputCostPer1K: 0,\n supportsStreaming: false,\n supportsTools: false,\n supportsVision: false,\n },\n ];\n }\n\n // ─────────────────────────────────────────────────────────────\n // Test Helpers\n // ─────────────────────────────────────────────────────────────\n\n setResponse(\n key: string,\n response: AIChatResponse | AICompletionResponse,\n ): void {\n this.responses.set(key, response);\n }\n\n setEmbedding(text: string, embedding: number[]): void {\n this.embeddings.set(text, embedding);\n }\n\n getRequestLog(): Array<{ type: string; request: unknown; timestamp: Date }> {\n return [...this.requestLog];\n }\n\n clearRequestLog(): void {\n this.requestLog = [];\n }\n\n // ─────────────────────────────────────────────────────────────\n // Chat Operations\n // ─────────────────────────────────────────────────────────────\n\n async chat(request: AIChatRequest): Promise<AIChatResponse> {\n this.requestLog.push({ type: \"chat\", request, timestamp: new Date() });\n\n const model = request.model || this.config.defaultChatModel || \"gpt-4\";\n const lastMessage = request.messages[request.messages.length - 1];\n const key = `${model}:${lastMessage?.content}`;\n\n if (this.responses.has(key)) {\n return this.responses.get(key) as AIChatResponse;\n }\n\n // Generate mock response\n const response: AIChatResponse = {\n id: `chatcmpl-${Date.now()}`,\n model,\n provider: \"openai\",\n choices: [\n {\n index: 0,\n message: {\n role: \"assistant\",\n content: `Mock response to: ${lastMessage?.content || \"empty\"}`,\n },\n finishReason: \"stop\",\n },\n ],\n usage: {\n promptTokens: this.estimateTokensSync(\n request.messages.map((m) => m.content).join(\" \"),\n ),\n completionTokens: 20,\n totalTokens: 0,\n estimatedCostUsd: 0,\n },\n created: new Date(),\n finishReason: \"stop\",\n };\n\n response.usage.totalTokens =\n response.usage.promptTokens + response.usage.completionTokens;\n response.usage.estimatedCostUsd = this.calculateCost(model, response.usage);\n\n return response;\n }\n\n async *chatStream(request: AIChatRequest): AsyncIterable<AIStreamChunk> {\n this.requestLog.push({\n type: \"chatStream\",\n request,\n timestamp: new Date(),\n });\n\n const model = request.model || this.config.defaultChatModel || \"gpt-4\";\n const lastMessage = request.messages[request.messages.length - 1];\n const responseText = `Mock streaming response to: ${lastMessage?.content || \"empty\"}`;\n const words = responseText.split(\" \");\n\n for (let i = 0; i < words.length; i++) {\n yield {\n id: `chatcmpl-${Date.now()}`,\n model,\n provider: \"openai\",\n delta: {\n content: (i > 0 ? \" \" : \"\") + words[i],\n role: i === 0 ? \"assistant\" : undefined,\n },\n finishReason: i === words.length - 1 ? \"stop\" : undefined,\n };\n }\n }\n\n async chatWithCallback(\n request: AIChatRequest,\n callback: AIStreamCallback,\n ): Promise<AIChatResponse> {\n let fullContent = \"\";\n\n for await (const chunk of this.chatStream(request)) {\n await callback(chunk);\n if (chunk.delta.content) {\n fullContent += chunk.delta.content;\n }\n }\n\n const model = request.model || this.config.defaultChatModel || \"gpt-4\";\n\n return {\n id: `chatcmpl-${Date.now()}`,\n model,\n provider: \"openai\",\n choices: [\n {\n index: 0,\n message: { role: \"assistant\", content: fullContent },\n finishReason: \"stop\",\n },\n ],\n usage: {\n promptTokens: this.estimateTokensSync(\n request.messages.map((m) => m.content).join(\" \"),\n ),\n completionTokens: this.estimateTokensSync(fullContent),\n totalTokens: 0,\n estimatedCostUsd: 0,\n },\n created: new Date(),\n finishReason: \"stop\",\n };\n }\n\n // ─────────────────────────────────────────────────────────────\n // Completion Operations\n // ─────────────────────────────────────────────────────────────\n\n async complete(request: AICompletionRequest): Promise<AICompletionResponse> {\n this.requestLog.push({ type: \"complete\", request, timestamp: new Date() });\n\n const model =\n request.model || this.config.defaultCompletionModel || \"gpt-4\";\n const key = `completion:${model}:${request.prompt}`;\n\n if (this.responses.has(key)) {\n return this.responses.get(key) as AICompletionResponse;\n }\n\n const response: AICompletionResponse = {\n id: `cmpl-${Date.now()}`,\n model,\n provider: \"openai\",\n text: `Mock completion of: ${request.prompt.substring(0, 50)}...`,\n usage: {\n promptTokens: this.estimateTokensSync(request.prompt),\n completionTokens: 20,\n totalTokens: 0,\n estimatedCostUsd: 0,\n },\n created: new Date(),\n finishReason: \"stop\",\n };\n\n response.usage.totalTokens =\n response.usage.promptTokens + response.usage.completionTokens;\n response.usage.estimatedCostUsd = this.calculateCost(model, response.usage);\n\n return response;\n }\n\n async *completeStream(\n request: AICompletionRequest,\n ): AsyncIterable<AIStreamChunk> {\n this.requestLog.push({\n type: \"completeStream\",\n request,\n timestamp: new Date(),\n });\n\n const model =\n request.model || this.config.defaultCompletionModel || \"gpt-4\";\n const responseText = `Mock streaming completion of: ${request.prompt.substring(0, 30)}...`;\n const words = responseText.split(\" \");\n\n for (let i = 0; i < words.length; i++) {\n yield {\n id: `cmpl-${Date.now()}`,\n model,\n provider: \"openai\",\n delta: {\n content: (i > 0 ? \" \" : \"\") + words[i],\n },\n finishReason: i === words.length - 1 ? \"stop\" : undefined,\n };\n }\n }\n\n // ─────────────────────────────────────────────────────────────\n // Embedding Operations\n // ─────────────────────────────────────────────────────────────\n\n async embed(request: AIEmbeddingRequest): Promise<AIEmbeddingResponse> {\n this.requestLog.push({ type: \"embed\", request, timestamp: new Date() });\n\n const model =\n request.model ||\n this.config.defaultEmbeddingModel ||\n \"text-embedding-3-small\";\n const inputs = Array.isArray(request.input)\n ? request.input\n : [request.input];\n const dimensions = request.dimensions || 1536;\n\n const embeddings = inputs.map((text) => {\n if (this.embeddings.has(text)) {\n return this.embeddings.get(text)!;\n }\n // Generate deterministic mock embedding based on text hash\n return this.generateMockEmbedding(text, dimensions);\n });\n\n return {\n id: `emb-${Date.now()}`,\n model,\n provider: \"openai\",\n embeddings,\n usage: {\n promptTokens: inputs.reduce(\n (sum, t) => sum + this.estimateTokensSync(t),\n 0,\n ),\n completionTokens: 0,\n totalTokens: 0,\n estimatedCostUsd: 0,\n },\n created: new Date(),\n };\n }\n\n async similarity(\n text1: string,\n text2: string,\n model?: string,\n ): Promise<number> {\n const response = await this.embed({ input: [text1, text2], model });\n const [emb1, emb2] = response.embeddings;\n return this.cosineSimilarity(emb1!, emb2!);\n }\n\n // ─────────────────────────────────────────────────────────────\n // Model Management\n // ─────────────────────────────────────────────────────────────\n\n async listModels(): Promise<AIModelConfig[]> {\n return [...this.models];\n }\n\n async getModel(modelId: string): Promise<AIModelConfig | null> {\n return this.models.find((m) => m.modelId === modelId) || null;\n }\n\n async supportsCapability(\n modelId: string,\n capability: AIModelType,\n ): Promise<boolean> {\n const model = await this.getModel(modelId);\n return model?.capabilities.includes(capability) ?? false;\n }\n\n async estimateTokens(text: string, _model?: string): Promise<number> {\n return this.estimateTokensSync(text);\n }\n\n async estimateCost(\n request: AIChatRequest | AICompletionRequest | AIEmbeddingRequest,\n ): Promise<number> {\n let model: string;\n let inputTokens: number;\n\n if (\"messages\" in request) {\n model = request.model || this.config.defaultChatModel || \"gpt-4\";\n inputTokens = this.estimateTokensSync(\n request.messages.map((m) => m.content).join(\" \"),\n );\n } else if (\"prompt\" in request) {\n model = request.model || this.config.defaultCompletionModel || \"gpt-4\";\n inputTokens = this.estimateTokensSync(request.prompt);\n } else {\n model =\n request.model ||\n this.config.defaultEmbeddingModel ||\n \"text-embedding-3-small\";\n const inputs = Array.isArray(request.input)\n ? request.input\n : [request.input];\n inputTokens = inputs.reduce(\n (sum, t) => sum + this.estimateTokensSync(t),\n 0,\n );\n }\n\n const modelConfig = await this.getModel(model);\n if (!modelConfig) return 0;\n\n const estimatedOutputTokens =\n \"messages\" in request || \"prompt\" in request ? 100 : 0;\n return (\n (inputTokens / 1000) * modelConfig.inputCostPer1K +\n (estimatedOutputTokens / 1000) * modelConfig.outputCostPer1K\n );\n }\n\n // ─────────────────────────────────────────────────────────────\n // Health & Status\n // ─────────────────────────────────────────────────────────────\n\n async healthCheck(): Promise<{\n healthy: boolean;\n providers: Record<\n AIProvider,\n { available: boolean; latencyMs?: number; error?: string }\n >;\n }> {\n return {\n healthy: true,\n providers: {\n openai: { available: true, latencyMs: 50 },\n anthropic: { available: true, latencyMs: 60 },\n google: { available: true, latencyMs: 55 },\n azure: { available: false, error: \"Not configured\" },\n bedrock: { available: false, error: \"Not configured\" },\n custom: { available: false, error: \"Not configured\" },\n },\n };\n }\n\n // ─────────────────────────────────────────────────────────────\n // Private Helpers\n // ─────────────────────────────────────────────────────────────\n\n private estimateTokensSync(text: string): number {\n // Rough approximation: ~4 characters per token\n return Math.ceil(text.length / 4);\n }\n\n private calculateCost(modelId: string, usage: AIUsageInfo): number {\n const model = this.models.find((m) => m.modelId === modelId);\n if (!model) return 0;\n\n return (\n (usage.promptTokens / 1000) * model.inputCostPer1K +\n (usage.completionTokens / 1000) * model.outputCostPer1K\n );\n }\n\n private generateMockEmbedding(text: string, dimensions: number): number[] {\n // Generate deterministic embedding based on text hash\n const embedding: number[] = [];\n let hash = 0;\n for (let i = 0; i < text.length; i++) {\n hash = (hash << 5) - hash + text.charCodeAt(i);\n hash = hash & hash;\n }\n\n for (let i = 0; i < dimensions; i++) {\n // Generate pseudo-random values based on hash and index\n const seed = hash + i * 31;\n embedding.push(Math.sin(seed) * 0.5);\n }\n\n // Normalize to unit vector\n const magnitude = Math.sqrt(embedding.reduce((sum, v) => sum + v * v, 0));\n return embedding.map((v) => v / magnitude);\n }\n\n private cosineSimilarity(a: number[], b: number[]): number {\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i]! * b[i]!;\n normA += a[i]! * a[i]!;\n normB += b[i]! * b[i]!;\n }\n\n return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));\n }\n}\n","/**\n * IRAG - Retrieval Augmented Generation interface\n *\n * Provides infrastructure for building RAG pipelines:\n * - Document ingestion and chunking\n * - Vector storage and retrieval\n * - Semantic search\n * - Hybrid search (vector + keyword)\n * - Reranking\n * - Context assembly\n */\n\n// ═══════════════════════════════════════════════════════════════\n// DOCUMENT TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport type DocumentStatus = \"pending\" | \"processing\" | \"indexed\" | \"failed\";\n\nexport interface RAGDocument {\n id: string;\n /** Source identifier (e.g., file path, URL, database ID) */\n source: string;\n /** Document type (pdf, markdown, html, text, etc.) */\n type: string;\n /** Original content */\n content: string;\n /** Document title */\n title?: string;\n /** Document metadata */\n metadata: Record<string, unknown>;\n /** Tenant ID for multi-tenant isolation */\n tenantId?: string;\n /** Collection/namespace */\n collection: string;\n /** Document status */\n status: DocumentStatus;\n /** Error message if failed */\n error?: string;\n /** Chunk count */\n chunkCount?: number;\n /** Token count */\n tokenCount?: number;\n /** Created timestamp */\n createdAt: Date;\n /** Updated timestamp */\n updatedAt: Date;\n}\n\nexport interface RAGChunk {\n id: string;\n documentId: string;\n /** Chunk index within document */\n index: number;\n /** Chunk content */\n content: string;\n /** Embedding vector */\n embedding?: number[];\n /** Chunk metadata */\n metadata: Record<string, unknown>;\n /** Start character position in original document */\n startOffset?: number;\n /** End character position */\n endOffset?: number;\n /** Token count */\n tokenCount: number;\n /** Collection/namespace */\n collection: string;\n /** Tenant ID */\n tenantId?: string;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// CHUNKING CONFIGURATION\n// ═══════════════════════════════════════════════════════════════\n\nexport type ChunkingStrategy =\n | \"fixed\"\n | \"sentence\"\n | \"paragraph\"\n | \"semantic\"\n | \"recursive\";\n\nexport interface ChunkingConfig {\n /** Chunking strategy */\n strategy: ChunkingStrategy;\n /** Target chunk size in tokens */\n chunkSize: number;\n /** Overlap between chunks in tokens */\n chunkOverlap: number;\n /** Minimum chunk size */\n minChunkSize?: number;\n /** Maximum chunk size */\n maxChunkSize?: number;\n /** Separators for recursive chunking */\n separators?: string[];\n /** Keep metadata in chunks */\n includeMetadata?: boolean;\n /** Add document title to each chunk */\n includeTitle?: boolean;\n}\n\nexport const ChunkingPresets: Record<string, ChunkingConfig> = {\n default: {\n strategy: \"recursive\",\n chunkSize: 512,\n chunkOverlap: 50,\n minChunkSize: 100,\n separators: [\"\\n\\n\", \"\\n\", \". \", \" \"],\n },\n small: {\n strategy: \"sentence\",\n chunkSize: 256,\n chunkOverlap: 25,\n minChunkSize: 50,\n },\n large: {\n strategy: \"paragraph\",\n chunkSize: 1024,\n chunkOverlap: 100,\n minChunkSize: 200,\n },\n code: {\n strategy: \"recursive\",\n chunkSize: 1000,\n chunkOverlap: 100,\n separators: [\"\\n\\nclass \", \"\\n\\nfunction \", \"\\n\\ndef \", \"\\n\\n\", \"\\n\"],\n },\n};\n\n// ═══════════════════════════════════════════════════════════════\n// SEARCH TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport type SearchMode = \"vector\" | \"keyword\" | \"hybrid\";\n\nexport interface RAGSearchQuery {\n /** Search query text */\n query: string;\n /** Collection to search */\n collection: string;\n /** Tenant ID for filtering */\n tenantId?: string;\n /** Search mode */\n mode?: SearchMode;\n /** Maximum results to return */\n limit?: number;\n /** Minimum similarity score (0-1) */\n minScore?: number;\n /** Metadata filters */\n filters?: RAGFilter[];\n /** Include embeddings in results */\n includeEmbeddings?: boolean;\n /** Include original document content */\n includeDocumentContent?: boolean;\n /** Rerank results using cross-encoder */\n rerank?: boolean;\n /** Number of candidates for reranking */\n rerankCandidates?: number;\n}\n\nexport interface RAGFilter {\n field: string;\n operator:\n | \"eq\"\n | \"ne\"\n | \"gt\"\n | \"gte\"\n | \"lt\"\n | \"lte\"\n | \"in\"\n | \"nin\"\n | \"contains\";\n value: unknown;\n}\n\nexport interface RAGSearchResult {\n chunk: RAGChunk;\n score: number;\n document?: RAGDocument;\n highlights?: string[];\n}\n\nexport interface RAGSearchResponse {\n results: RAGSearchResult[];\n query: string;\n totalMatches: number;\n searchTimeMs: number;\n mode: SearchMode;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// CONTEXT ASSEMBLY\n// ═══════════════════════════════════════════════════════════════\n\nexport interface ContextAssemblyConfig {\n /** Maximum tokens for assembled context */\n maxTokens: number;\n /** Template for formatting each chunk */\n chunkTemplate?: string;\n /** Template for the full context */\n contextTemplate?: string;\n /** Include source citations */\n includeCitations?: boolean;\n /** Deduplicate similar chunks */\n deduplicate?: boolean;\n /** Deduplication similarity threshold */\n dedupeThreshold?: number;\n /** Sort order for chunks */\n sortBy?: \"score\" | \"document\" | \"position\";\n}\n\nexport interface AssembledContext {\n /** Final assembled context string */\n context: string;\n /** Chunks included in context */\n chunks: RAGChunk[];\n /** Total tokens used */\n tokenCount: number;\n /** Source documents referenced */\n sources: Array<{\n documentId: string;\n title?: string;\n source: string;\n }>;\n /** Chunks excluded due to limits */\n truncated: boolean;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// INGESTION TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport interface IngestionOptions {\n /** Collection to add documents to */\n collection: string;\n /** Tenant ID */\n tenantId?: string;\n /** Chunking configuration */\n chunking?: Partial<ChunkingConfig>;\n /** Document metadata to attach */\n metadata?: Record<string, unknown>;\n /** Generate embeddings immediately */\n generateEmbeddings?: boolean;\n /** Batch size for processing */\n batchSize?: number;\n /** Skip existing documents */\n skipExisting?: boolean;\n}\n\nexport interface IngestionResult {\n documentId: string;\n status: DocumentStatus;\n chunkCount: number;\n tokenCount: number;\n error?: string;\n processingTimeMs: number;\n}\n\nexport interface BulkIngestionResult {\n total: number;\n successful: number;\n failed: number;\n results: IngestionResult[];\n totalProcessingTimeMs: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// COLLECTION MANAGEMENT\n// ═══════════════════════════════════════════════════════════════\n\nexport interface RAGCollection {\n name: string;\n description?: string;\n /** Embedding model used */\n embeddingModel: string;\n /** Embedding dimensions */\n dimensions: number;\n /** Distance metric for similarity */\n distanceMetric: \"cosine\" | \"euclidean\" | \"dotproduct\";\n /** Chunking config for this collection */\n chunkingConfig: ChunkingConfig;\n /** Document count */\n documentCount: number;\n /** Chunk count */\n chunkCount: number;\n /** Total token count */\n totalTokens: number;\n /** Created timestamp */\n createdAt: Date;\n /** Updated timestamp */\n updatedAt: Date;\n}\n\nexport interface CreateCollectionOptions {\n name: string;\n description?: string;\n embeddingModel?: string;\n dimensions?: number;\n distanceMetric?: \"cosine\" | \"euclidean\" | \"dotproduct\";\n chunkingConfig?: Partial<ChunkingConfig>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// PIPELINE TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport interface RAGPipelineStep {\n name: string;\n type: \"transform\" | \"filter\" | \"enrich\" | \"embed\" | \"store\";\n config: Record<string, unknown>;\n enabled: boolean;\n}\n\nexport interface RAGPipeline {\n id: string;\n name: string;\n description?: string;\n collection: string;\n steps: RAGPipelineStep[];\n createdAt: Date;\n updatedAt: Date;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// CONFIGURATION\n// ═══════════════════════════════════════════════════════════════\n\nexport interface RAGConfig {\n /** Default embedding model */\n defaultEmbeddingModel?: string;\n /** Default chunking config */\n defaultChunkingConfig?: Partial<ChunkingConfig>;\n /** Default search mode */\n defaultSearchMode?: SearchMode;\n /** Default result limit */\n defaultLimit?: number;\n /** Enable caching */\n enableCache?: boolean;\n /** Cache TTL in seconds */\n cacheTtlSeconds?: number;\n /** Maximum documents per collection */\n maxDocumentsPerCollection?: number;\n /** Maximum chunks per document */\n maxChunksPerDocument?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MAIN INTERFACE\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * IRAG - RAG pipeline interface\n *\n * @example\n * ```typescript\n * const rag = platform.rag;\n *\n * // Create a collection\n * await rag.createCollection({\n * name: 'knowledge-base',\n * embeddingModel: 'text-embedding-3-small',\n * });\n *\n * // Ingest documents\n * await rag.ingest('knowledge-base', [\n * { source: 'doc1.pdf', content: '...', type: 'pdf' },\n * { source: 'doc2.md', content: '...', type: 'markdown' },\n * ]);\n *\n * // Search\n * const results = await rag.search({\n * query: 'How do I configure authentication?',\n * collection: 'knowledge-base',\n * limit: 5,\n * });\n *\n * // Assemble context for LLM\n * const context = await rag.assembleContext(results, {\n * maxTokens: 4000,\n * includeCitations: true,\n * });\n *\n * // Use with AI\n * const response = await ai.chat({\n * messages: [\n * { role: 'system', content: `Use this context: ${context.context}` },\n * { role: 'user', content: 'How do I configure authentication?' }\n * ]\n * });\n * ```\n */\nexport interface IRAG {\n // ─────────────────────────────────────────────────────────────\n // Collection Management\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Create a new collection\n */\n createCollection(options: CreateCollectionOptions): Promise<RAGCollection>;\n\n /**\n * Get a collection by name\n */\n getCollection(name: string): Promise<RAGCollection | null>;\n\n /**\n * List all collections\n */\n listCollections(tenantId?: string): Promise<RAGCollection[]>;\n\n /**\n * Delete a collection and all its documents\n */\n deleteCollection(name: string): Promise<void>;\n\n /**\n * Get collection statistics\n */\n getCollectionStats(name: string): Promise<{\n documentCount: number;\n chunkCount: number;\n totalTokens: number;\n averageChunkSize: number;\n storageBytes: number;\n }>;\n\n // ─────────────────────────────────────────────────────────────\n // Document Management\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Ingest documents into a collection\n */\n ingest(\n collection: string,\n documents: Array<\n Omit<\n RAGDocument,\n | \"id\"\n | \"status\"\n | \"chunkCount\"\n | \"tokenCount\"\n | \"createdAt\"\n | \"updatedAt\"\n >\n >,\n options?: Partial<IngestionOptions>,\n ): Promise<BulkIngestionResult>;\n\n /**\n * Ingest a single document\n */\n ingestOne(\n collection: string,\n document: Omit<\n RAGDocument,\n | \"id\"\n | \"status\"\n | \"chunkCount\"\n | \"tokenCount\"\n | \"createdAt\"\n | \"updatedAt\"\n | \"collection\"\n >,\n options?: Partial<IngestionOptions>,\n ): Promise<IngestionResult>;\n\n /**\n * Get a document by ID\n */\n getDocument(documentId: string): Promise<RAGDocument | null>;\n\n /**\n * List documents in a collection\n */\n listDocuments(\n collection: string,\n options?: {\n tenantId?: string;\n status?: DocumentStatus;\n limit?: number;\n offset?: number;\n },\n ): Promise<{ documents: RAGDocument[]; total: number }>;\n\n /**\n * Delete a document and its chunks\n */\n deleteDocument(documentId: string): Promise<void>;\n\n /**\n * Reprocess a document (re-chunk and re-embed)\n */\n reprocessDocument(\n documentId: string,\n options?: Partial<IngestionOptions>,\n ): Promise<IngestionResult>;\n\n // ─────────────────────────────────────────────────────────────\n // Chunk Management\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Get chunks for a document\n */\n getChunks(documentId: string): Promise<RAGChunk[]>;\n\n /**\n * Get a specific chunk by ID\n */\n getChunk(chunkId: string): Promise<RAGChunk | null>;\n\n /**\n * Update chunk metadata\n */\n updateChunkMetadata(\n chunkId: string,\n metadata: Record<string, unknown>,\n ): Promise<RAGChunk>;\n\n // ─────────────────────────────────────────────────────────────\n // Search & Retrieval\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Search for relevant chunks\n */\n search(query: RAGSearchQuery): Promise<RAGSearchResponse>;\n\n /**\n * Get similar chunks to a given chunk\n */\n findSimilar(\n chunkId: string,\n options?: {\n limit?: number;\n minScore?: number;\n collection?: string;\n },\n ): Promise<RAGSearchResult[]>;\n\n /**\n * Multi-query search (query expansion)\n */\n multiSearch(queries: RAGSearchQuery[]): Promise<RAGSearchResponse[]>;\n\n // ─────────────────────────────────────────────────────────────\n // Context Assembly\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Assemble context from search results\n */\n assembleContext(\n results: RAGSearchResponse | RAGSearchResult[],\n config?: Partial<ContextAssemblyConfig>,\n ): Promise<AssembledContext>;\n\n /**\n * Query and assemble in one step\n */\n queryWithContext(\n query: RAGSearchQuery,\n contextConfig?: Partial<ContextAssemblyConfig>,\n ): Promise<{\n searchResponse: RAGSearchResponse;\n context: AssembledContext;\n }>;\n\n // ─────────────────────────────────────────────────────────────\n // Embedding Management\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Generate embeddings for text\n */\n embed(texts: string | string[], model?: string): Promise<number[][]>;\n\n /**\n * Update embeddings for a collection\n */\n reembed(\n collection: string,\n model?: string,\n batchSize?: number,\n ): Promise<{\n updated: number;\n errors: number;\n }>;\n\n // ─────────────────────────────────────────────────────────────\n // Pipeline Management\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Create a processing pipeline\n */\n createPipeline(\n pipeline: Omit<RAGPipeline, \"id\" | \"createdAt\" | \"updatedAt\">,\n ): Promise<RAGPipeline>;\n\n /**\n * Get a pipeline\n */\n getPipeline(pipelineId: string): Promise<RAGPipeline | null>;\n\n /**\n * Run a pipeline on documents\n */\n runPipeline(\n pipelineId: string,\n documentIds: string[],\n ): Promise<BulkIngestionResult>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MEMORY IMPLEMENTATION\n// ═══════════════════════════════════════════════════════════════\n\nimport { randomBytes } from \"crypto\";\n\n/**\n * MemoryRAG - In-memory implementation for testing\n */\nexport class MemoryRAG implements IRAG {\n private collections: Map<string, RAGCollection> = new Map();\n private documents: Map<string, RAGDocument> = new Map();\n private chunks: Map<string, RAGChunk> = new Map();\n private pipelines: Map<string, RAGPipeline> = new Map();\n private embeddings: Map<string, number[]> = new Map();\n\n constructor(private config: RAGConfig = {}) {}\n\n // ─────────────────────────────────────────────────────────────\n // Collection Management\n // ─────────────────────────────────────────────────────────────\n\n async createCollection(\n options: CreateCollectionOptions,\n ): Promise<RAGCollection> {\n const now = new Date();\n const collection: RAGCollection = {\n name: options.name,\n description: options.description,\n embeddingModel:\n options.embeddingModel ||\n this.config.defaultEmbeddingModel ||\n \"text-embedding-3-small\",\n dimensions: options.dimensions || 1536,\n distanceMetric: options.distanceMetric || \"cosine\",\n chunkingConfig: {\n ...ChunkingPresets.default,\n ...this.config.defaultChunkingConfig,\n ...options.chunkingConfig,\n } as ChunkingConfig,\n documentCount: 0,\n chunkCount: 0,\n totalTokens: 0,\n createdAt: now,\n updatedAt: now,\n };\n\n this.collections.set(options.name, collection);\n return collection;\n }\n\n async getCollection(name: string): Promise<RAGCollection | null> {\n return this.collections.get(name) || null;\n }\n\n async listCollections(tenantId?: string): Promise<RAGCollection[]> {\n const collections = Array.from(this.collections.values());\n // In memory implementation, we don't filter by tenant at collection level\n return collections;\n }\n\n async deleteCollection(name: string): Promise<void> {\n // Delete all documents and chunks in collection\n for (const [id, doc] of this.documents) {\n if (doc.collection === name) {\n // Delete chunks\n for (const [chunkId, chunk] of this.chunks) {\n if (chunk.documentId === id) {\n this.chunks.delete(chunkId);\n }\n }\n this.documents.delete(id);\n }\n }\n this.collections.delete(name);\n }\n\n async getCollectionStats(name: string): Promise<{\n documentCount: number;\n chunkCount: number;\n totalTokens: number;\n averageChunkSize: number;\n storageBytes: number;\n }> {\n const collection = await this.getCollection(name);\n if (!collection) {\n throw new Error(`Collection not found: ${name}`);\n }\n\n const docs = Array.from(this.documents.values()).filter(\n (d) => d.collection === name,\n );\n const docChunks = Array.from(this.chunks.values()).filter(\n (c) => c.collection === name,\n );\n const totalTokens = docChunks.reduce((sum, c) => sum + c.tokenCount, 0);\n\n return {\n documentCount: docs.length,\n chunkCount: docChunks.length,\n totalTokens,\n averageChunkSize:\n docChunks.length > 0 ? totalTokens / docChunks.length : 0,\n storageBytes: docChunks.reduce((sum, c) => sum + c.content.length, 0),\n };\n }\n\n // ─────────────────────────────────────────────────────────────\n // Document Management\n // ─────────────────────────────────────────────────────────────\n\n async ingest(\n collection: string,\n documents: Array<\n Omit<\n RAGDocument,\n | \"id\"\n | \"status\"\n | \"chunkCount\"\n | \"tokenCount\"\n | \"createdAt\"\n | \"updatedAt\"\n >\n >,\n options?: Partial<IngestionOptions>,\n ): Promise<BulkIngestionResult> {\n const startTime = Date.now();\n const results: IngestionResult[] = [];\n\n for (const doc of documents) {\n const result = await this.ingestOne(\n collection,\n doc as Omit<\n RAGDocument,\n | \"id\"\n | \"status\"\n | \"chunkCount\"\n | \"tokenCount\"\n | \"createdAt\"\n | \"updatedAt\"\n | \"collection\"\n >,\n options,\n );\n results.push(result);\n }\n\n return {\n total: documents.length,\n successful: results.filter((r) => r.status === \"indexed\").length,\n failed: results.filter((r) => r.status === \"failed\").length,\n results,\n totalProcessingTimeMs: Date.now() - startTime,\n };\n }\n\n async ingestOne(\n collection: string,\n document: Omit<\n RAGDocument,\n | \"id\"\n | \"status\"\n | \"chunkCount\"\n | \"tokenCount\"\n | \"createdAt\"\n | \"updatedAt\"\n | \"collection\"\n >,\n options?: Partial<IngestionOptions>,\n ): Promise<IngestionResult> {\n const startTime = Date.now();\n const docId = `doc_${Date.now()}_${randomBytes(4).toString(\"hex\")}`;\n const now = new Date();\n\n try {\n // Get collection config\n const col = await this.getCollection(collection);\n if (!col) {\n throw new Error(`Collection not found: ${collection}`);\n }\n\n // Create document\n const doc: RAGDocument = {\n ...document,\n id: docId,\n collection,\n status: \"processing\",\n tenantId: options?.tenantId || document.tenantId,\n metadata: { ...document.metadata, ...options?.metadata },\n createdAt: now,\n updatedAt: now,\n };\n this.documents.set(docId, doc);\n\n // Chunk the document\n const chunkingConfig = { ...col.chunkingConfig, ...options?.chunking };\n const docChunks = this.chunkDocument(doc, chunkingConfig);\n\n // Generate embeddings if requested\n if (options?.generateEmbeddings !== false) {\n for (const chunk of docChunks) {\n chunk.embedding = await this.generateMockEmbedding(\n chunk.content,\n col.dimensions,\n );\n this.embeddings.set(chunk.id, chunk.embedding);\n }\n }\n\n // Store chunks\n for (const chunk of docChunks) {\n this.chunks.set(chunk.id, chunk);\n }\n\n // Update document\n doc.status = \"indexed\";\n doc.chunkCount = docChunks.length;\n doc.tokenCount = docChunks.reduce((sum, c) => sum + c.tokenCount, 0);\n this.documents.set(docId, doc);\n\n // Update collection stats\n col.documentCount++;\n col.chunkCount += docChunks.length;\n col.totalTokens += doc.tokenCount;\n col.updatedAt = new Date();\n\n return {\n documentId: docId,\n status: \"indexed\",\n chunkCount: doc.chunkCount,\n tokenCount: doc.tokenCount,\n processingTimeMs: Date.now() - startTime,\n };\n } catch (error) {\n const doc = this.documents.get(docId);\n if (doc) {\n doc.status = \"failed\";\n doc.error = error instanceof Error ? error.message : \"Unknown error\";\n }\n\n return {\n documentId: docId,\n status: \"failed\",\n chunkCount: 0,\n tokenCount: 0,\n error: error instanceof Error ? error.message : \"Unknown error\",\n processingTimeMs: Date.now() - startTime,\n };\n }\n }\n\n async getDocument(documentId: string): Promise<RAGDocument | null> {\n return this.documents.get(documentId) || null;\n }\n\n async listDocuments(\n collection: string,\n options?: {\n tenantId?: string;\n status?: DocumentStatus;\n limit?: number;\n offset?: number;\n },\n ): Promise<{ documents: RAGDocument[]; total: number }> {\n let docs = Array.from(this.documents.values()).filter(\n (d) => d.collection === collection,\n );\n\n if (options?.tenantId) {\n docs = docs.filter((d) => d.tenantId === options.tenantId);\n }\n\n if (options?.status) {\n docs = docs.filter((d) => d.status === options.status);\n }\n\n const total = docs.length;\n const offset = options?.offset || 0;\n const limit = options?.limit || 50;\n\n return {\n documents: docs.slice(offset, offset + limit),\n total,\n };\n }\n\n async deleteDocument(documentId: string): Promise<void> {\n const doc = await this.getDocument(documentId);\n if (doc) {\n // Delete chunks\n for (const [chunkId, chunk] of this.chunks) {\n if (chunk.documentId === documentId) {\n this.chunks.delete(chunkId);\n this.embeddings.delete(chunkId);\n }\n }\n\n // Update collection\n const collection = await this.getCollection(doc.collection);\n if (collection) {\n collection.documentCount--;\n collection.chunkCount -= doc.chunkCount || 0;\n collection.totalTokens -= doc.tokenCount || 0;\n }\n\n this.documents.delete(documentId);\n }\n }\n\n async reprocessDocument(\n documentId: string,\n options?: Partial<IngestionOptions>,\n ): Promise<IngestionResult> {\n const doc = await this.getDocument(documentId);\n if (!doc) {\n throw new Error(`Document not found: ${documentId}`);\n }\n\n // Delete existing chunks\n for (const [chunkId, chunk] of this.chunks) {\n if (chunk.documentId === documentId) {\n this.chunks.delete(chunkId);\n this.embeddings.delete(chunkId);\n }\n }\n\n // Re-ingest\n return this.ingestOne(\n doc.collection,\n {\n source: doc.source,\n type: doc.type,\n content: doc.content,\n title: doc.title,\n metadata: doc.metadata,\n tenantId: doc.tenantId,\n },\n options,\n );\n }\n\n // ─────────────────────────────────────────────────────────────\n // Chunk Management\n // ─────────────────────────────────────────────────────────────\n\n async getChunks(documentId: string): Promise<RAGChunk[]> {\n return Array.from(this.chunks.values())\n .filter((c) => c.documentId === documentId)\n .sort((a, b) => a.index - b.index);\n }\n\n async getChunk(chunkId: string): Promise<RAGChunk | null> {\n return this.chunks.get(chunkId) || null;\n }\n\n async updateChunkMetadata(\n chunkId: string,\n metadata: Record<string, unknown>,\n ): Promise<RAGChunk> {\n const chunk = await this.getChunk(chunkId);\n if (!chunk) {\n throw new Error(`Chunk not found: ${chunkId}`);\n }\n\n chunk.metadata = { ...chunk.metadata, ...metadata };\n this.chunks.set(chunkId, chunk);\n return chunk;\n }\n\n // ─────────────────────────────────────────────────────────────\n // Search & Retrieval\n // ─────────────────────────────────────────────────────────────\n\n async search(query: RAGSearchQuery): Promise<RAGSearchResponse> {\n const startTime = Date.now();\n const mode = query.mode || this.config.defaultSearchMode || \"vector\";\n const limit = query.limit || this.config.defaultLimit || 10;\n\n // Get query embedding\n const queryEmbedding = await this.generateMockEmbedding(query.query, 1536);\n\n // Get chunks from collection\n let chunks = Array.from(this.chunks.values()).filter(\n (c) => c.collection === query.collection,\n );\n\n // Filter by tenant\n if (query.tenantId) {\n chunks = chunks.filter((c) => c.tenantId === query.tenantId);\n }\n\n // Apply metadata filters\n if (query.filters) {\n chunks = chunks.filter((c) =>\n this.matchesFilters(c.metadata, query.filters!),\n );\n }\n\n // Score chunks\n let results: RAGSearchResult[] = chunks.map((chunk) => {\n const embedding = this.embeddings.get(chunk.id) || [];\n const vectorScore =\n embedding.length > 0\n ? this.cosineSimilarity(queryEmbedding, embedding)\n : 0;\n const keywordScore = this.keywordScore(query.query, chunk.content);\n\n let score: number;\n switch (mode) {\n case \"vector\":\n score = vectorScore;\n break;\n case \"keyword\":\n score = keywordScore;\n break;\n case \"hybrid\":\n score = 0.7 * vectorScore + 0.3 * keywordScore;\n break;\n default:\n score = vectorScore;\n }\n\n return { chunk, score };\n });\n\n // Filter by min score\n if (query.minScore) {\n results = results.filter((r) => r.score >= query.minScore!);\n }\n\n // Sort by score\n results.sort((a, b) => b.score - a.score);\n\n // Rerank if requested\n if (query.rerank) {\n const candidates = results.slice(0, query.rerankCandidates || limit * 3);\n // Mock reranking - in production, use a cross-encoder\n results = candidates.sort((a, b) => {\n const aRelevance = this.keywordScore(query.query, a.chunk.content);\n const bRelevance = this.keywordScore(query.query, b.chunk.content);\n return b.score + bRelevance - (a.score + aRelevance);\n });\n }\n\n // Limit results\n results = results.slice(0, limit);\n\n // Add documents if requested\n if (query.includeDocumentContent) {\n for (const result of results) {\n result.document =\n (await this.getDocument(result.chunk.documentId)) || undefined;\n }\n }\n\n // Add highlights\n for (const result of results) {\n result.highlights = this.generateHighlights(\n query.query,\n result.chunk.content,\n );\n }\n\n return {\n results,\n query: query.query,\n totalMatches: results.length,\n searchTimeMs: Date.now() - startTime,\n mode,\n };\n }\n\n async findSimilar(\n chunkId: string,\n options?: {\n limit?: number;\n minScore?: number;\n collection?: string;\n },\n ): Promise<RAGSearchResult[]> {\n const chunk = await this.getChunk(chunkId);\n if (!chunk) {\n throw new Error(`Chunk not found: ${chunkId}`);\n }\n\n const embedding = this.embeddings.get(chunkId);\n if (!embedding) {\n return [];\n }\n\n const collection = options?.collection || chunk.collection;\n let chunks = Array.from(this.chunks.values()).filter(\n (c) => c.collection === collection && c.id !== chunkId,\n );\n\n const results: RAGSearchResult[] = chunks.map((c) => {\n const otherEmbedding = this.embeddings.get(c.id) || [];\n const score =\n otherEmbedding.length > 0\n ? this.cosineSimilarity(embedding, otherEmbedding)\n : 0;\n return { chunk: c, score };\n });\n\n let filteredResults = results;\n if (options?.minScore) {\n filteredResults = results.filter((r) => r.score >= options.minScore!);\n }\n\n filteredResults.sort((a, b) => b.score - a.score);\n\n return filteredResults.slice(0, options?.limit || 10);\n }\n\n async multiSearch(queries: RAGSearchQuery[]): Promise<RAGSearchResponse[]> {\n return Promise.all(queries.map((q) => this.search(q)));\n }\n\n // ─────────────────────────────────────────────────────────────\n // Context Assembly\n // ─────────────────────────────────────────────────────────────\n\n async assembleContext(\n results: RAGSearchResponse | RAGSearchResult[],\n config?: Partial<ContextAssemblyConfig>,\n ): Promise<AssembledContext> {\n const resultArray = \"results\" in results ? results.results : results;\n const maxTokens = config?.maxTokens || 4000;\n const chunkTemplate = config?.chunkTemplate || \"{{content}}\";\n const contextTemplate = config?.contextTemplate || \"{{chunks}}\";\n\n let chunks: RAGChunk[] = [];\n let totalTokens = 0;\n const sources: AssembledContext[\"sources\"] = [];\n const seenDocs = new Set<string>();\n\n // Deduplicate if requested\n let processedResults = resultArray;\n if (config?.deduplicate) {\n const threshold = config.dedupeThreshold || 0.9;\n processedResults = this.deduplicateResults(resultArray, threshold);\n }\n\n // Sort if requested\n if (config?.sortBy) {\n processedResults = [...processedResults].sort((a, b) => {\n switch (config.sortBy) {\n case \"score\":\n return b.score - a.score;\n case \"document\":\n return a.chunk.documentId.localeCompare(b.chunk.documentId);\n case \"position\":\n return a.chunk.index - b.chunk.index;\n default:\n return 0;\n }\n });\n }\n\n // Assemble chunks until max tokens\n let truncated = false;\n for (const result of processedResults) {\n if (totalTokens + result.chunk.tokenCount > maxTokens) {\n truncated = true;\n break;\n }\n\n chunks.push(result.chunk);\n totalTokens += result.chunk.tokenCount;\n\n // Track sources\n if (!seenDocs.has(result.chunk.documentId)) {\n seenDocs.add(result.chunk.documentId);\n const doc = await this.getDocument(result.chunk.documentId);\n sources.push({\n documentId: result.chunk.documentId,\n title: doc?.title,\n source: doc?.source || \"\",\n });\n }\n }\n\n // Format chunks\n const formattedChunks = chunks.map((chunk, i) => {\n let formatted = chunkTemplate\n .replace(\"{{content}}\", chunk.content)\n .replace(\"{{index}}\", String(i + 1))\n .replace(\"{{documentId}}\", chunk.documentId);\n\n if (config?.includeCitations) {\n formatted = `[${i + 1}] ${formatted}`;\n }\n\n return formatted;\n });\n\n // Build final context\n let context = contextTemplate.replace(\n \"{{chunks}}\",\n formattedChunks.join(\"\\n\\n\"),\n );\n\n if (config?.includeCitations && sources.length > 0) {\n const citations = sources\n .map((s, i) => `[${i + 1}] ${s.title || s.source}`)\n .join(\"\\n\");\n context += `\\n\\nSources:\\n${citations}`;\n }\n\n return {\n context,\n chunks,\n tokenCount: totalTokens,\n sources,\n truncated,\n };\n }\n\n async queryWithContext(\n query: RAGSearchQuery,\n contextConfig?: Partial<ContextAssemblyConfig>,\n ): Promise<{\n searchResponse: RAGSearchResponse;\n context: AssembledContext;\n }> {\n const searchResponse = await this.search(query);\n const context = await this.assembleContext(searchResponse, contextConfig);\n return { searchResponse, context };\n }\n\n // ─────────────────────────────────────────────────────────────\n // Embedding Management\n // ─────────────────────────────────────────────────────────────\n\n async embed(texts: string | string[], model?: string): Promise<number[][]> {\n const textArray = Array.isArray(texts) ? texts : [texts];\n return Promise.all(\n textArray.map((text) => this.generateMockEmbedding(text, 1536)),\n );\n }\n\n async reembed(\n collection: string,\n model?: string,\n batchSize?: number,\n ): Promise<{\n updated: number;\n errors: number;\n }> {\n const col = await this.getCollection(collection);\n if (!col) {\n throw new Error(`Collection not found: ${collection}`);\n }\n\n let updated = 0;\n let errors = 0;\n\n const chunks = Array.from(this.chunks.values()).filter(\n (c) => c.collection === collection,\n );\n\n for (const chunk of chunks) {\n try {\n const embedding = await this.generateMockEmbedding(\n chunk.content,\n col.dimensions,\n );\n chunk.embedding = embedding;\n this.embeddings.set(chunk.id, embedding);\n updated++;\n } catch {\n errors++;\n }\n }\n\n return { updated, errors };\n }\n\n // ─────────────────────────────────────────────────────────────\n // Pipeline Management\n // ─────────────────────────────────────────────────────────────\n\n async createPipeline(\n pipeline: Omit<RAGPipeline, \"id\" | \"createdAt\" | \"updatedAt\">,\n ): Promise<RAGPipeline> {\n const id = `pipeline_${Date.now()}`;\n const now = new Date();\n\n const newPipeline: RAGPipeline = {\n ...pipeline,\n id,\n createdAt: now,\n updatedAt: now,\n };\n\n this.pipelines.set(id, newPipeline);\n return newPipeline;\n }\n\n async getPipeline(pipelineId: string): Promise<RAGPipeline | null> {\n return this.pipelines.get(pipelineId) || null;\n }\n\n async runPipeline(\n pipelineId: string,\n documentIds: string[],\n ): Promise<BulkIngestionResult> {\n const pipeline = await this.getPipeline(pipelineId);\n if (!pipeline) {\n throw new Error(`Pipeline not found: ${pipelineId}`);\n }\n\n // For memory implementation, just reprocess documents\n const results: IngestionResult[] = [];\n for (const docId of documentIds) {\n const result = await this.reprocessDocument(docId);\n results.push(result);\n }\n\n return {\n total: documentIds.length,\n successful: results.filter((r) => r.status === \"indexed\").length,\n failed: results.filter((r) => r.status === \"failed\").length,\n results,\n totalProcessingTimeMs: results.reduce(\n (sum, r) => sum + r.processingTimeMs,\n 0,\n ),\n };\n }\n\n // ─────────────────────────────────────────────────────────────\n // Private Helpers\n // ─────────────────────────────────────────────────────────────\n\n private chunkDocument(doc: RAGDocument, config: ChunkingConfig): RAGChunk[] {\n const chunks: RAGChunk[] = [];\n const content = doc.content;\n const chunkSize = config.chunkSize;\n const overlap = config.chunkOverlap;\n\n // Simple fixed-size chunking for memory implementation\n let startOffset = 0;\n let index = 0;\n\n while (startOffset < content.length) {\n const endOffset = Math.min(startOffset + chunkSize * 4, content.length); // Approximate 4 chars per token\n const chunkContent = content.slice(startOffset, endOffset);\n\n chunks.push({\n id: `chunk_${doc.id}_${index}`,\n documentId: doc.id,\n index,\n content: chunkContent,\n metadata: config.includeMetadata ? doc.metadata : {},\n startOffset,\n endOffset,\n tokenCount: Math.ceil(chunkContent.length / 4),\n collection: doc.collection,\n tenantId: doc.tenantId,\n });\n\n startOffset = endOffset - overlap * 4;\n index++;\n }\n\n return chunks;\n }\n\n private async generateMockEmbedding(\n text: string,\n dimensions: number,\n ): Promise<number[]> {\n // Generate deterministic embedding based on text hash\n const embedding: number[] = [];\n let hash = 0;\n for (let i = 0; i < text.length; i++) {\n hash = (hash << 5) - hash + text.charCodeAt(i);\n hash = hash & hash;\n }\n\n for (let i = 0; i < dimensions; i++) {\n const seed = hash + i * 31;\n embedding.push(Math.sin(seed) * 0.5);\n }\n\n // Normalize\n const magnitude = Math.sqrt(embedding.reduce((sum, v) => sum + v * v, 0));\n return embedding.map((v) => v / magnitude);\n }\n\n private cosineSimilarity(a: number[], b: number[]): number {\n if (a.length !== b.length) return 0;\n\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i]! * b[i]!;\n normA += a[i]! * a[i]!;\n normB += b[i]! * b[i]!;\n }\n\n const denominator = Math.sqrt(normA) * Math.sqrt(normB);\n return denominator > 0 ? dotProduct / denominator : 0;\n }\n\n private keywordScore(query: string, content: string): number {\n const queryWords = query.toLowerCase().split(/\\s+/);\n const contentLower = content.toLowerCase();\n let matches = 0;\n\n for (const word of queryWords) {\n if (contentLower.includes(word)) {\n matches++;\n }\n }\n\n return queryWords.length > 0 ? matches / queryWords.length : 0;\n }\n\n private matchesFilters(\n metadata: Record<string, unknown>,\n filters: RAGFilter[],\n ): boolean {\n for (const filter of filters) {\n const value = metadata[filter.field];\n\n switch (filter.operator) {\n case \"eq\":\n if (value !== filter.value) return false;\n break;\n case \"ne\":\n if (value === filter.value) return false;\n break;\n case \"gt\":\n if (\n typeof value !== \"number\" ||\n typeof filter.value !== \"number\" ||\n value <= filter.value\n )\n return false;\n break;\n case \"gte\":\n if (\n typeof value !== \"number\" ||\n typeof filter.value !== \"number\" ||\n value < filter.value\n )\n return false;\n break;\n case \"lt\":\n if (\n typeof value !== \"number\" ||\n typeof filter.value !== \"number\" ||\n value >= filter.value\n )\n return false;\n break;\n case \"lte\":\n if (\n typeof value !== \"number\" ||\n typeof filter.value !== \"number\" ||\n value > filter.value\n )\n return false;\n break;\n case \"in\":\n if (!Array.isArray(filter.value) || !filter.value.includes(value))\n return false;\n break;\n case \"nin\":\n if (!Array.isArray(filter.value) || filter.value.includes(value))\n return false;\n break;\n case \"contains\":\n if (\n typeof value !== \"string\" ||\n typeof filter.value !== \"string\" ||\n !value.includes(filter.value)\n )\n return false;\n break;\n }\n }\n\n return true;\n }\n\n private generateHighlights(query: string, content: string): string[] {\n const words = query.toLowerCase().split(/\\s+/);\n const highlights: string[] = [];\n\n for (const word of words) {\n const index = content.toLowerCase().indexOf(word);\n if (index !== -1) {\n const start = Math.max(0, index - 30);\n const end = Math.min(content.length, index + word.length + 30);\n highlights.push(`...${content.slice(start, end)}...`);\n }\n }\n\n return highlights.slice(0, 3);\n }\n\n private deduplicateResults(\n results: RAGSearchResult[],\n threshold: number,\n ): RAGSearchResult[] {\n const deduplicated: RAGSearchResult[] = [];\n\n for (const result of results) {\n const isDuplicate = deduplicated.some((r) => {\n const embedding1 = this.embeddings.get(result.chunk.id);\n const embedding2 = this.embeddings.get(r.chunk.id);\n if (!embedding1 || !embedding2) return false;\n return this.cosineSimilarity(embedding1, embedding2) > threshold;\n });\n\n if (!isDuplicate) {\n deduplicated.push(result);\n }\n }\n\n return deduplicated;\n }\n}\n","/**\n * Testing Utilities for Platform Core\n *\n * This module provides utilities for testing applications that use platform-core.\n * Import from '@digilogiclabs/platform-core/testing' in your test files.\n */\n\n// ═══════════════════════════════════════════════════════════════\n// MEMORY ADAPTERS (Always safe for testing)\n// ═══════════════════════════════════════════════════════════════\n\nexport { MemoryDatabase } from \"./adapters/memory/MemoryDatabase\";\nexport { MemoryCache } from \"./adapters/memory/MemoryCache\";\nexport { MemoryStorage } from \"./adapters/memory/MemoryStorage\";\nexport { MemoryEmail } from \"./adapters/memory/MemoryEmail\";\nexport { MemoryQueue } from \"./adapters/memory/MemoryQueue\";\nexport { ConsoleEmail } from \"./adapters/console/ConsoleEmail\";\n\n// ═══════════════════════════════════════════════════════════════\n// SECRETS (Testing implementations)\n// ═══════════════════════════════════════════════════════════════\n\nexport { MemorySecrets, EnvSecrets } from \"./interfaces/ISecrets\";\n\n// ═══════════════════════════════════════════════════════════════\n// FACTORY (Creates in-memory platform)\n// ═══════════════════════════════════════════════════════════════\n\nexport { createPlatform } from \"./factory\";\n\n// ═══════════════════════════════════════════════════════════════\n// LOGGER & METRICS (Testing implementations)\n// ═══════════════════════════════════════════════════════════════\n\nexport { ConsoleLogger, NoopLogger } from \"./interfaces/ILogger\";\nexport { MemoryMetrics, NoopMetrics } from \"./interfaces/IMetrics\";\n\n// ═══════════════════════════════════════════════════════════════\n// INTERFACES (For type checking)\n// ═══════════════════════════════════════════════════════════════\n\nexport type {\n IDatabase,\n IQueryBuilder,\n QueryResult,\n ICache,\n IStorage,\n IEmail,\n IQueue,\n IPlatform,\n ILogger,\n IMetrics,\n ISecrets,\n Job,\n JobOptions,\n EmailMessage,\n StorageFile,\n} from \"./interfaces\";\n\n// ═══════════════════════════════════════════════════════════════\n// TEST HELPERS\n// ═══════════════════════════════════════════════════════════════\n\nimport type { IDatabase, IPlatform } from \"./interfaces\";\nimport { createPlatform } from \"./factory\";\nimport { MemoryDatabase } from \"./adapters/memory/MemoryDatabase\";\nimport { MemoryCache } from \"./adapters/memory/MemoryCache\";\nimport { MemoryStorage } from \"./adapters/memory/MemoryStorage\";\nimport { MemoryEmail } from \"./adapters/memory/MemoryEmail\";\nimport { MemoryQueue } from \"./adapters/memory/MemoryQueue\";\n\n/**\n * Create a fresh test platform with all memory adapters.\n * Each call creates a new isolated platform instance.\n */\nexport function createTestPlatform(): IPlatform {\n return createPlatform();\n}\n\n/**\n * Test platform with access to underlying adapters for assertions.\n * Allows direct inspection of emails sent, queue jobs, etc.\n */\nexport interface TestPlatformWithInternals extends IPlatform {\n /** Access underlying memory database */\n memoryDb: MemoryDatabase;\n /** Access underlying memory cache */\n memoryCache: MemoryCache;\n /** Access underlying memory storage */\n memoryStorage: MemoryStorage;\n /** Access underlying memory email (check sent emails) */\n memoryEmail: MemoryEmail;\n /** Access underlying memory queue (check queued jobs) */\n memoryQueue: MemoryQueue;\n}\n\n/**\n * Create a test platform with direct access to underlying adapters.\n * Useful for asserting on emails sent, jobs queued, etc.\n *\n * @example\n * ```typescript\n * const { platform, memoryEmail, memoryQueue } = createTestPlatformWithInternals();\n *\n * // Run your code that sends emails\n * await myService.sendWelcomeEmail(user);\n *\n * // Assert email was sent\n * const sentEmails = memoryEmail.getSentEmails();\n * expect(sentEmails).toHaveLength(1);\n * expect(sentEmails[0].to).toBe(user.email);\n * ```\n */\nexport function createTestPlatformWithInternals(): TestPlatformWithInternals {\n const memoryDb = new MemoryDatabase();\n const memoryCache = new MemoryCache();\n const memoryStorage = new MemoryStorage();\n const memoryEmail = new MemoryEmail();\n const memoryQueue = new MemoryQueue();\n\n const platform: IPlatform = {\n db: memoryDb,\n cache: memoryCache,\n storage: memoryStorage,\n email: memoryEmail,\n queue: memoryQueue,\n\n async healthCheck() {\n const [dbHealth, cacheHealth, storageHealth, emailHealth, queueHealth] =\n await Promise.all([\n memoryDb.healthCheck(),\n memoryCache.healthCheck(),\n memoryStorage.healthCheck(),\n memoryEmail.healthCheck(),\n memoryQueue.healthCheck(),\n ]);\n\n return {\n healthy:\n dbHealth &&\n cacheHealth &&\n storageHealth &&\n emailHealth &&\n queueHealth,\n services: {\n database: dbHealth,\n cache: cacheHealth,\n storage: storageHealth,\n email: emailHealth,\n queue: queueHealth,\n },\n timestamp: Date.now(),\n };\n },\n\n async close() {\n await Promise.all([\n memoryDb.close(),\n memoryCache.close(),\n memoryQueue.close(),\n ]);\n },\n };\n\n return {\n ...platform,\n memoryDb,\n memoryCache,\n memoryStorage,\n memoryEmail,\n memoryQueue,\n };\n}\n\n/**\n * Seed test data into a memory database.\n *\n * @example\n * ```typescript\n * const platform = createTestPlatform();\n * await seedTestData(platform.db, 'users', [\n * { id: '1', name: 'Alice', email: 'alice@test.com' },\n * { id: '2', name: 'Bob', email: 'bob@test.com' },\n * ]);\n * ```\n */\nexport async function seedTestData<T extends Record<string, unknown>>(\n db: IDatabase,\n table: string,\n data: T[],\n): Promise<void> {\n for (const row of data) {\n await db.from(table).insert(row).execute();\n }\n}\n\n/**\n * Clear all data from a test platform.\n * Useful in beforeEach/afterEach hooks.\n */\nexport async function clearTestPlatform(\n platform: TestPlatformWithInternals,\n): Promise<void> {\n platform.memoryDb.clear();\n platform.memoryCache.clear();\n platform.memoryStorage.clear();\n platform.memoryEmail.clear();\n platform.memoryQueue.clear();\n}\n\n/**\n * Wait for all pending queue jobs to complete.\n * Useful when testing async workflows.\n *\n * @param platform - Test platform with memory queue\n * @param timeoutMs - Maximum time to wait (default: 5000ms)\n */\nexport async function waitForQueueDrain(\n platform: TestPlatformWithInternals,\n timeoutMs: number = 5000,\n): Promise<void> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n const pendingJobs = platform.memoryQueue.getPendingJobs?.() ?? [];\n if (pendingJobs.length === 0) {\n return;\n }\n await new Promise((resolve) => setTimeout(resolve, 50));\n }\n\n throw new Error(`Queue did not drain within ${timeoutMs}ms`);\n}\n\n/**\n * Assert that an email was sent with specific properties.\n */\nexport function assertEmailSent(\n memoryEmail: MemoryEmail,\n expected: {\n to?: string;\n subject?: string | RegExp;\n bodyContains?: string;\n },\n): void {\n const emails = memoryEmail.getSentEmails();\n\n const matchesTo = (\n emailTo: string | string[] | undefined,\n expectedTo: string,\n ): boolean => {\n if (!emailTo) return false;\n if (Array.isArray(emailTo)) {\n return emailTo.some(\n (addr) =>\n addr === expectedTo ||\n (typeof addr === \"object\" &&\n (addr as { email?: string }).email === expectedTo),\n );\n }\n return (\n emailTo === expectedTo ||\n (typeof emailTo === \"object\" &&\n (emailTo as { email?: string }).email === expectedTo)\n );\n };\n\n const found = emails.find((email) => {\n if (\n expected.to &&\n !matchesTo(email.to as unknown as string | string[], expected.to)\n )\n return false;\n if (expected.subject) {\n if (\n typeof expected.subject === \"string\" &&\n email.subject !== expected.subject\n )\n return false;\n if (\n expected.subject instanceof RegExp &&\n !expected.subject.test(email.subject)\n )\n return false;\n }\n if (expected.bodyContains) {\n const body = email.html || email.text || \"\";\n if (!body.includes(expected.bodyContains)) return false;\n }\n return true;\n });\n\n if (!found) {\n const emailSummary = emails\n .map((e) => ` - To: ${JSON.stringify(e.to)}, Subject: ${e.subject}`)\n .join(\"\\n\");\n throw new Error(\n `Expected email not found.\\nExpected: ${JSON.stringify(expected)}\\nSent emails:\\n${emailSummary || \" (none)\"}`,\n );\n }\n}\n\n/**\n * Create a mock function that tracks calls.\n * Simple alternative to jest.fn() for test frameworks without built-in mocking.\n */\nexport function createMockFn<TArgs extends unknown[], TReturn>(\n implementation?: (...args: TArgs) => TReturn,\n): {\n (...args: TArgs): TReturn;\n calls: TArgs[];\n callCount: number;\n lastCall: TArgs | undefined;\n reset: () => void;\n} {\n const calls: TArgs[] = [];\n\n const fn = function (...args: TArgs): TReturn {\n calls.push(args);\n return implementation?.(...args) as TReturn;\n };\n\n Object.defineProperty(fn, \"calls\", {\n get: () => calls,\n });\n\n Object.defineProperty(fn, \"callCount\", {\n get: () => calls.length,\n });\n\n Object.defineProperty(fn, \"lastCall\", {\n get: () => calls[calls.length - 1],\n });\n\n fn.reset = () => {\n calls.length = 0;\n };\n\n return fn as typeof fn & {\n calls: TArgs[];\n callCount: number;\n lastCall: TArgs | undefined;\n reset: () => void;\n };\n}\n","/**\n * Memory Database Adapter\n * In-memory implementation for testing\n */\n\nimport {\n IDatabase,\n IQueryBuilder,\n QueryResult,\n} from \"../../interfaces/IDatabase\";\n\nexport class MemoryDatabase implements IDatabase {\n private tables: Map<string, unknown[]> = new Map();\n\n from<T = unknown>(table: string): IQueryBuilder<T> {\n if (!this.tables.has(table)) {\n this.tables.set(table, []);\n }\n return new MemoryQueryBuilder<T>(this.tables, table);\n }\n\n async raw<T = unknown>(\n sql: string,\n params?: unknown[],\n ): Promise<QueryResult<T>> {\n // Basic implementation - just return empty for now\n console.warn(\"MemoryDatabase.raw() is a stub implementation\");\n return { data: [] };\n }\n\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\n // Memory adapter doesn't need real transactions\n return fn(this);\n }\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n async close(): Promise<void> {\n this.tables.clear();\n }\n\n /**\n * Clear all data (for testing)\n */\n clear(): void {\n this.tables.clear();\n }\n\n /**\n * Get table data (for testing)\n */\n getTable<T = unknown>(tableName: string): T[] {\n return (this.tables.get(tableName) as T[]) ?? [];\n }\n}\n\nclass MemoryQueryBuilder<T = unknown> implements IQueryBuilder<T> {\n private tables: Map<string, unknown[]>;\n private tableName: string;\n private _select: string[] = [\"*\"];\n private _where: Array<{ column: string; operator: string; value: unknown }> =\n [];\n private _orderBy: { column: string; direction: \"asc\" | \"desc\" } | null = null;\n private _limit: number | null = null;\n private _offset: number = 0;\n private _insertData: Partial<T>[] | null = null;\n private _updateData: Partial<T> | null = null;\n private _deleteFlag: boolean = false;\n\n constructor(tables: Map<string, unknown[]>, tableName: string) {\n this.tables = tables;\n this.tableName = tableName;\n }\n\n select(columns?: string | string[]): IQueryBuilder<T> {\n if (columns) {\n this._select = Array.isArray(columns) ? columns : [columns];\n }\n return this;\n }\n\n insert(data: Partial<T> | Partial<T>[]): IQueryBuilder<T> {\n this._insertData = Array.isArray(data) ? data : [data];\n return this;\n }\n\n update(data: Partial<T>): IQueryBuilder<T> {\n this._updateData = data;\n return this;\n }\n\n delete(): IQueryBuilder<T> {\n this._deleteFlag = true;\n return this;\n }\n\n where(column: string, operator: string, value: unknown): IQueryBuilder<T> {\n this._where.push({ column, operator, value });\n return this;\n }\n\n whereIn(column: string, values: unknown[]): IQueryBuilder<T> {\n this._where.push({ column, operator: \"in\", value: values });\n return this;\n }\n\n orderBy(column: string, direction: \"asc\" | \"desc\" = \"asc\"): IQueryBuilder<T> {\n this._orderBy = { column, direction };\n return this;\n }\n\n limit(count: number): IQueryBuilder<T> {\n this._limit = count;\n return this;\n }\n\n offset(count: number): IQueryBuilder<T> {\n this._offset = count;\n return this;\n }\n\n async single(): Promise<{ data: T | null; error?: Error }> {\n const result = await this.execute();\n return { data: result.data[0] || null };\n }\n\n async execute(): Promise<QueryResult<T>> {\n const table = (this.tables.get(this.tableName) as T[]) || [];\n\n // Handle insert\n if (this._insertData) {\n const newItems = this._insertData.map((item, i) => ({\n id: `mem_${Date.now()}_${i}`,\n ...item,\n created_at: new Date().toISOString(),\n }));\n this.tables.set(this.tableName, [...table, ...newItems]);\n return { data: newItems as T[] };\n }\n\n // Handle delete\n if (this._deleteFlag) {\n const filtered = table.filter((item) => !this.matchesWhere(item));\n const deleted = table.filter((item) => this.matchesWhere(item));\n this.tables.set(this.tableName, filtered);\n return { data: deleted, count: deleted.length };\n }\n\n // Handle update\n if (this._updateData) {\n const updated: T[] = [];\n const newTable = table.map((item) => {\n if (this.matchesWhere(item)) {\n const updatedItem = {\n ...item,\n ...this._updateData,\n updated_at: new Date().toISOString(),\n };\n updated.push(updatedItem as T);\n return updatedItem;\n }\n return item;\n });\n this.tables.set(this.tableName, newTable);\n return { data: updated, count: updated.length };\n }\n\n // Handle select\n let result = table.filter((item) => this.matchesWhere(item));\n\n // Sort\n if (this._orderBy) {\n const { column, direction } = this._orderBy;\n result.sort((a, b) => {\n const aVal = (a as Record<string, unknown>)[column] as\n | string\n | number\n | null;\n const bVal = (b as Record<string, unknown>)[column] as\n | string\n | number\n | null;\n if (aVal === null || aVal === undefined)\n return direction === \"asc\" ? 1 : -1;\n if (bVal === null || bVal === undefined)\n return direction === \"asc\" ? -1 : 1;\n const cmp = aVal < bVal ? -1 : aVal > bVal ? 1 : 0;\n return direction === \"asc\" ? cmp : -cmp;\n });\n }\n\n // Pagination\n if (this._offset > 0 || this._limit !== null) {\n const start = this._offset;\n const end = this._limit !== null ? start + this._limit : undefined;\n result = result.slice(start, end);\n }\n\n return { data: result, count: result.length };\n }\n\n private matchesWhere(item: T): boolean {\n if (this._where.length === 0) return true;\n\n return this._where.every(({ column, operator, value }) => {\n const itemValue = (item as Record<string, unknown>)[column];\n\n switch (operator) {\n case \"=\":\n case \"==\":\n return itemValue === value;\n case \"!=\":\n case \"<>\":\n return itemValue !== value;\n case \">\":\n return (itemValue as number) > (value as number);\n case \">=\":\n return (itemValue as number) >= (value as number);\n case \"<\":\n return (itemValue as number) < (value as number);\n case \"<=\":\n return (itemValue as number) <= (value as number);\n case \"in\":\n return Array.isArray(value) && value.includes(itemValue);\n case \"like\":\n return String(itemValue).includes(String(value).replace(/%/g, \"\"));\n default:\n return itemValue === value;\n }\n });\n }\n}\n","/**\n * Memory Cache Adapter\n * In-memory implementation for testing\n */\n\nimport { ICache } from \"../../interfaces/ICache\";\n\ninterface CacheEntry<T> {\n value: T;\n expiresAt: number | null;\n}\n\nexport class MemoryCache implements ICache {\n private store: Map<string, CacheEntry<unknown>> = new Map();\n private subscriptions: Map<string, Set<(message: string) => void>> =\n new Map();\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const entry = this.store.get(key);\n if (!entry) return null;\n\n if (entry.expiresAt && Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return null;\n }\n\n return entry.value as T;\n }\n\n async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n const expiresAt = ttl ? Date.now() + ttl * 1000 : null;\n this.store.set(key, { value, expiresAt });\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n async exists(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== null;\n }\n\n async deletePattern(pattern: string): Promise<number> {\n const regex = new RegExp(\"^\" + pattern.replace(/\\*/g, \".*\") + \"$\");\n let count = 0;\n\n for (const key of this.store.keys()) {\n if (regex.test(key)) {\n this.store.delete(key);\n count++;\n }\n }\n\n return count;\n }\n\n async mget<T = unknown>(keys: string[]): Promise<(T | null)[]> {\n return Promise.all(keys.map((key) => this.get<T>(key)));\n }\n\n async mset<T = unknown>(\n entries: Array<{ key: string; value: T; ttl?: number }>,\n ): Promise<void> {\n await Promise.all(\n entries.map(({ key, value, ttl }) => this.set(key, value, ttl)),\n );\n }\n\n async incr(key: string, by: number = 1): Promise<number> {\n const current = (await this.get<number>(key)) || 0;\n const newValue = current + by;\n await this.set(key, newValue);\n return newValue;\n }\n\n async publish(channel: string, message: string): Promise<void> {\n const subscribers = this.subscriptions.get(channel);\n if (subscribers) {\n subscribers.forEach((callback) => callback(message));\n }\n }\n\n async subscribe(\n channel: string,\n callback: (message: string) => void,\n ): Promise<() => void> {\n if (!this.subscriptions.has(channel)) {\n this.subscriptions.set(channel, new Set());\n }\n\n this.subscriptions.get(channel)!.add(callback);\n\n return () => {\n this.subscriptions.get(channel)?.delete(callback);\n };\n }\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n async close(): Promise<void> {\n this.store.clear();\n this.subscriptions.clear();\n }\n\n /**\n * Clear all cached data (for testing)\n */\n clear(): void {\n this.store.clear();\n this.subscriptions.clear();\n }\n\n /**\n * Get number of cached items (for testing)\n */\n get size(): number {\n return this.store.size;\n }\n}\n","// Memory Storage - stub implementation\nimport {\n IStorage,\n StorageFile,\n UploadOptions,\n} from \"../../interfaces/IStorage\";\n\nexport class MemoryStorage implements IStorage {\n private files = new Map<string, { data: Buffer; contentType?: string }>();\n\n async upload(\n key: string,\n data: Buffer | Blob | ReadableStream,\n options?: UploadOptions,\n ) {\n this.files.set(key, {\n data: Buffer.from(\"mock\"),\n contentType: options?.contentType,\n });\n return { url: \"memory://\" + key };\n }\n async download(key: string) {\n return this.files.get(key)?.data || Buffer.from(\"\");\n }\n async getSignedUrl(key: string) {\n return \"memory://\" + key;\n }\n async delete(key: string) {\n this.files.delete(key);\n }\n async deleteMany(keys: string[]) {\n keys.forEach((k) => this.files.delete(k));\n }\n async list(prefix?: string): Promise<StorageFile[]> {\n return [];\n }\n async exists(key: string) {\n return this.files.has(key);\n }\n async getMetadata(key: string) {\n return null;\n }\n async healthCheck() {\n return true;\n }\n\n /**\n * Clear all files (for testing)\n */\n clear(): void {\n this.files.clear();\n }\n\n /**\n * Get number of stored files (for testing)\n */\n get size(): number {\n return this.files.size;\n }\n}\n","// Memory Email - stub implementation\nimport { IEmail, EmailMessage, EmailResult } from \"../../interfaces/IEmail\";\n\nexport class MemoryEmail implements IEmail {\n private sentEmails: EmailMessage[] = [];\n\n async send(message: EmailMessage): Promise<EmailResult> {\n this.sentEmails.push(message);\n return { id: \"mem_\" + this.sentEmails.length, success: true };\n }\n\n async sendBatch(messages: EmailMessage[]): Promise<EmailResult[]> {\n return Promise.all(messages.map((m) => this.send(m)));\n }\n\n async healthCheck() {\n return true;\n }\n\n // Test helpers\n getSentEmails(): EmailMessage[] {\n return this.sentEmails;\n }\n\n /**\n * Clear sent emails (for testing)\n */\n clear(): void {\n this.sentEmails = [];\n }\n\n /**\n * Get number of sent emails (for testing)\n */\n get size(): number {\n return this.sentEmails.length;\n }\n}\n","/**\n * Queue abstraction interface\n * Provides a vendor-agnostic way to work with job queues\n *\n * Design Principles:\n * - Self-hostable: Works with Redis (BullMQ) or in-memory for testing\n * - No cloud lock-in: All adapters use open-source technologies\n * - Backward compatible: All new fields/methods are optional\n * - Zero external costs: Only requires self-hosted Redis for production\n */\n\n// ═══════════════════════════════════════════════════════════════\n// BACKOFF & REPEAT OPTIONS\n// ═══════════════════════════════════════════════════════════════\n\nexport interface BackoffOptions {\n type: \"fixed\" | \"exponential\";\n delay: number;\n /** Maximum delay for exponential backoff (ms) */\n maxDelay?: number;\n}\n\nexport interface RepeatOptions {\n /** Repeat every N milliseconds */\n every?: number;\n /** Cron expression (e.g., \"0 * * * *\" for hourly) */\n cron?: string;\n /** Timezone for cron (e.g., \"America/New_York\") */\n tz?: string;\n /** Maximum number of times to repeat */\n limit?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// JOB OPTIONS (backward compatible - all new fields optional)\n// ═══════════════════════════════════════════════════════════════\n\nexport interface JobOptions {\n /** Delay before job is processed (ms) */\n delay?: number;\n /** Number of retry attempts */\n attempts?: number;\n /** Backoff strategy */\n backoff?: BackoffOptions;\n /** Job priority (higher = more priority) */\n priority?: number;\n /** Remove job after completion */\n removeOnComplete?: boolean | number;\n /** Remove job after failure */\n removeOnFail?: boolean | number;\n /** Job timeout in milliseconds (new) */\n timeout?: number;\n /** Custom job ID (new) */\n jobId?: string;\n /** Repeat/cron options (new) */\n repeat?: RepeatOptions;\n /** Correlation ID for tracing (new) */\n correlationId?: string;\n /** Custom metadata (new) */\n metadata?: Record<string, unknown>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// JOB TYPES (backward compatible - all new fields optional)\n// ═══════════════════════════════════════════════════════════════\n\nexport type JobState =\n | \"waiting\"\n | \"active\"\n | \"completed\"\n | \"failed\"\n | \"delayed\";\n\nexport interface Job<T = unknown> {\n id: string;\n name: string;\n data: T;\n attemptsMade: number;\n progress: number;\n timestamp: number;\n /** Job state (new, optional) */\n state?: JobState;\n /** Processing start time (new, optional) */\n processedOn?: number;\n /** Completion time (new, optional) */\n finishedOn?: number;\n /** Failure reason (new, optional) */\n failedReason?: string;\n /** Correlation ID (new, optional) */\n correlationId?: string;\n /** Custom metadata (new, optional) */\n metadata?: Record<string, unknown>;\n}\n\nexport interface JobResult<T = unknown> {\n jobId: string;\n result?: T;\n error?: Error;\n /** Duration in ms (new, optional) */\n duration?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// JOB CONTEXT (new - for enhanced handlers)\n// ═══════════════════════════════════════════════════════════════\n\nexport interface JobContext<T = unknown> {\n job: Job<T>;\n /** Update job progress (0-100) */\n updateProgress(progress: number): Promise<void>;\n /** Log message for this job */\n log(message: string): void;\n /** Check if job timed out */\n isTimedOut(): boolean;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// QUEUE STATISTICS\n// ═══════════════════════════════════════════════════════════════\n\nexport interface QueueStats {\n waiting: number;\n active: number;\n completed: number;\n failed: number;\n delayed: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// JOB EVENTS (new)\n// ═══════════════════════════════════════════════════════════════\n\nexport type JobEventType =\n | \"completed\"\n | \"failed\"\n | \"progress\"\n | \"active\"\n | \"stalled\";\n\nexport interface JobEvent<T = unknown> {\n type: JobEventType;\n job: Job<T>;\n result?: unknown;\n error?: Error;\n progress?: number;\n timestamp: number;\n}\n\nexport type JobEventHandler<T = unknown> = (\n event: JobEvent<T>,\n) => void | Promise<void>;\n\n// ═══════════════════════════════════════════════════════════════\n// QUEUE INTERFACE (backward compatible - new methods optional)\n// ═══════════════════════════════════════════════════════════════\n\nexport interface IQueue<T = unknown> {\n // ─────────────────────────────────────────────────────────────\n // Core Methods (existing - unchanged)\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Add a job to the queue\n */\n add(name: string, data: T, options?: JobOptions): Promise<Job<T>>;\n\n /**\n * Add multiple jobs\n */\n addBulk(\n jobs: Array<{ name: string; data: T; options?: JobOptions }>,\n ): Promise<Job<T>[]>;\n\n /**\n * Process jobs (backward compatible signature)\n * New signature with options is also supported\n */\n process(\n handler: (job: Job<T>) => Promise<unknown>,\n options?: { concurrency?: number },\n ): void;\n\n /**\n * Get a job by ID\n */\n getJob(id: string): Promise<Job<T> | null>;\n\n /**\n * Remove a job\n */\n removeJob(id: string): Promise<void>;\n\n /**\n * Pause the queue\n */\n pause(): Promise<void>;\n\n /**\n * Resume the queue\n */\n resume(): Promise<void>;\n\n /**\n * Get queue statistics\n */\n getStats(): Promise<QueueStats>;\n\n /**\n * Check queue connectivity\n */\n healthCheck(): Promise<boolean>;\n\n /**\n * Close queue connection\n */\n close(): Promise<void>;\n\n // ─────────────────────────────────────────────────────────────\n // New Methods (optional - adapters may throw \"not implemented\")\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Add a recurring job (cron/interval)\n * @throws {Error} If adapter doesn't support recurring jobs\n */\n addRecurring?(\n name: string,\n data: T,\n repeat: RepeatOptions,\n options?: Omit<JobOptions, \"repeat\">,\n ): Promise<Job<T>>;\n\n /**\n * Get jobs by state\n */\n getJobs?(\n state: JobState | JobState[],\n start?: number,\n end?: number,\n ): Promise<Job<T>[]>;\n\n /**\n * Get failed jobs (dead letter queue)\n */\n getFailedJobs?(start?: number, end?: number): Promise<Job<T>[]>;\n\n /**\n * Retry a failed job\n */\n retryJob?(id: string): Promise<void>;\n\n /**\n * Replay all failed jobs\n */\n replayAllFailed?(): Promise<number>;\n\n /**\n * Update job progress\n */\n updateProgress?(id: string, progress: number): Promise<void>;\n\n /**\n * Clean old jobs\n */\n clean?(grace: number, limit: number, state: JobState): Promise<string[]>;\n\n /**\n * Remove all jobs\n */\n obliterate?(options?: { force?: boolean }): Promise<void>;\n\n /**\n * Subscribe to job events\n */\n on?(event: JobEventType, handler: JobEventHandler<T>): void;\n\n /**\n * Unsubscribe from job events\n */\n off?(event: JobEventType, handler: JobEventHandler<T>): void;\n\n /**\n * Get queue name\n */\n getName?(): string;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// HELPER FUNCTIONS\n// ═══════════════════════════════════════════════════════════════\n\nimport { randomBytes } from \"crypto\";\n\n/**\n * Calculate exponential backoff delay\n */\nexport function calculateBackoff(\n attempt: number,\n options: BackoffOptions,\n): number {\n if (options.type === \"fixed\") {\n return options.delay;\n }\n const delay = options.delay * Math.pow(2, attempt - 1);\n const maxDelay = options.maxDelay ?? options.delay * 32;\n return Math.min(delay, maxDelay);\n}\n\n/**\n * Generate a unique job ID\n */\nexport function generateJobId(): string {\n const timestamp = Date.now().toString(36);\n const random = randomBytes(4).toString(\"hex\");\n return `job_${timestamp}_${random}`;\n}\n","/**\n * Correlation Context using AsyncLocalStorage\n *\n * Provides automatic propagation of trace/correlation IDs and request context\n * across async operations without explicit passing.\n *\n * Design Principles:\n * - Zero external dependencies (uses Node.js built-in AsyncLocalStorage)\n * - Self-hosted compatible\n * - Integrates with logging, metrics, and tracing\n */\n\nimport { AsyncLocalStorage } from \"async_hooks\";\nimport { randomBytes } from \"crypto\";\n\n// ═══════════════════════════════════════════════════════════════\n// CONTEXT TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport interface CorrelationData {\n /** Unique trace ID for distributed tracing */\n traceId?: string;\n /** Span ID for current operation */\n spanId?: string;\n /** Request ID for HTTP requests */\n requestId?: string;\n /** Correlation ID for job/event processing */\n correlationId?: string;\n /** User ID if authenticated */\n userId?: string;\n /** Tenant ID for multi-tenant applications */\n tenantId?: string;\n /** Session ID */\n sessionId?: string;\n /** Custom metadata */\n metadata?: Record<string, unknown>;\n /** Operation name (for logging) */\n operation?: string;\n /** Start time of the context */\n startTime?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// CORRELATION CONTEXT CLASS\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Singleton correlation context using AsyncLocalStorage\n */\nclass CorrelationContextManager {\n private storage = new AsyncLocalStorage<CorrelationData>();\n private idGenerator: () => string;\n\n constructor() {\n // Default ID generator (can be overridden)\n this.idGenerator = () => {\n const timestamp = Date.now().toString(36);\n const random = randomBytes(4).toString(\"hex\");\n return `${timestamp}-${random}`;\n };\n }\n\n /**\n * Set custom ID generator\n */\n setIdGenerator(generator: () => string): void {\n this.idGenerator = generator;\n }\n\n /**\n * Generate a new ID\n */\n generateId(): string {\n return this.idGenerator();\n }\n\n /**\n * Run a function with correlation context\n */\n run<T>(data: CorrelationData, fn: () => T): T {\n return this.storage.run(\n {\n ...data,\n startTime: data.startTime ?? Date.now(),\n },\n fn,\n );\n }\n\n /**\n * Run an async function with correlation context\n */\n async runAsync<T>(data: CorrelationData, fn: () => Promise<T>): Promise<T> {\n return this.storage.run(\n {\n ...data,\n startTime: data.startTime ?? Date.now(),\n },\n fn,\n );\n }\n\n /**\n * Get current correlation data\n */\n get(): CorrelationData | undefined {\n return this.storage.getStore();\n }\n\n /**\n * Get current correlation data or empty object\n */\n getOrEmpty(): CorrelationData {\n return this.storage.getStore() ?? {};\n }\n\n /**\n * Get trace ID from current context\n */\n getTraceId(): string | undefined {\n return this.get()?.traceId;\n }\n\n /**\n * Get correlation ID from current context\n */\n getCorrelationId(): string | undefined {\n return this.get()?.correlationId ?? this.get()?.traceId;\n }\n\n /**\n * Get request ID from current context\n */\n getRequestId(): string | undefined {\n return this.get()?.requestId;\n }\n\n /**\n * Get user ID from current context\n */\n getUserId(): string | undefined {\n return this.get()?.userId;\n }\n\n /**\n * Get tenant ID from current context\n */\n getTenantId(): string | undefined {\n return this.get()?.tenantId;\n }\n\n /**\n * Check if we're in a correlation context\n */\n isInContext(): boolean {\n return this.storage.getStore() !== undefined;\n }\n\n /**\n * Update current context (merge data)\n * Note: This doesn't actually update the store, but returns merged data\n * for use in nested contexts\n */\n extend(data: Partial<CorrelationData>): CorrelationData {\n const current = this.get() ?? {};\n return {\n ...current,\n ...data,\n metadata: {\n ...current.metadata,\n ...data.metadata,\n },\n };\n }\n\n /**\n * Run a nested context with extended data\n */\n runNested<T>(data: Partial<CorrelationData>, fn: () => T): T {\n return this.run(this.extend(data), fn);\n }\n\n /**\n * Run a nested async context with extended data\n */\n async runNestedAsync<T>(\n data: Partial<CorrelationData>,\n fn: () => Promise<T>,\n ): Promise<T> {\n return this.runAsync(this.extend(data), fn);\n }\n\n /**\n * Get context as log metadata (for structured logging)\n */\n getLogMeta(): Record<string, unknown> {\n const ctx = this.get();\n if (!ctx) return {};\n\n const meta: Record<string, unknown> = {};\n\n if (ctx.traceId) meta.traceId = ctx.traceId;\n if (ctx.spanId) meta.spanId = ctx.spanId;\n if (ctx.requestId) meta.requestId = ctx.requestId;\n if (ctx.correlationId) meta.correlationId = ctx.correlationId;\n if (ctx.userId) meta.userId = ctx.userId;\n if (ctx.tenantId) meta.tenantId = ctx.tenantId;\n if (ctx.sessionId) meta.sessionId = ctx.sessionId;\n if (ctx.operation) meta.operation = ctx.operation;\n\n return meta;\n }\n\n /**\n * Get context as HTTP headers (for propagation)\n */\n getHeaders(): Record<string, string> {\n const ctx = this.get();\n if (!ctx) return {};\n\n const headers: Record<string, string> = {};\n\n if (ctx.traceId) {\n // W3C Trace Context format\n const spanId = ctx.spanId ?? this.generateId().substring(0, 16);\n headers[\"traceparent\"] = `00-${ctx.traceId}-${spanId}-01`;\n }\n\n if (ctx.requestId) {\n headers[\"x-request-id\"] = ctx.requestId;\n }\n\n if (ctx.correlationId) {\n headers[\"x-correlation-id\"] = ctx.correlationId;\n }\n\n return headers;\n }\n\n /**\n * Parse context from HTTP headers\n */\n parseHeaders(\n headers: Record<string, string | string[] | undefined>,\n ): CorrelationData {\n const data: CorrelationData = {};\n\n // Parse W3C Trace Context\n const traceparent = headers[\"traceparent\"];\n if (traceparent && typeof traceparent === \"string\") {\n const parts = traceparent.split(\"-\");\n if (parts.length >= 3 && parts[0] === \"00\") {\n data.traceId = parts[1];\n data.spanId = parts[2];\n }\n }\n\n // Parse request ID\n const requestId = headers[\"x-request-id\"];\n if (requestId) {\n data.requestId = Array.isArray(requestId) ? requestId[0] : requestId;\n }\n\n // Parse correlation ID\n const correlationId = headers[\"x-correlation-id\"];\n if (correlationId) {\n data.correlationId = Array.isArray(correlationId)\n ? correlationId[0]\n : correlationId;\n }\n\n return data;\n }\n\n /**\n * Get elapsed time since context start (ms)\n */\n getElapsed(): number {\n const ctx = this.get();\n if (!ctx?.startTime) return 0;\n return Date.now() - ctx.startTime;\n }\n\n /**\n * Create a child span context\n */\n createChildSpan(operation: string): CorrelationData {\n const current = this.get() ?? {};\n return {\n ...current,\n spanId: this.generateId().substring(0, 16),\n operation,\n startTime: Date.now(),\n };\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// SINGLETON INSTANCE & EXPORTS\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Global correlation context instance\n */\nexport const correlationContext = new CorrelationContextManager();\n\n// Convenience exports\nexport const runWithContext = correlationContext.run.bind(correlationContext);\nexport const runWithContextAsync =\n correlationContext.runAsync.bind(correlationContext);\nexport const getContext = correlationContext.get.bind(correlationContext);\nexport const getTraceId =\n correlationContext.getTraceId.bind(correlationContext);\nexport const getCorrelationId =\n correlationContext.getCorrelationId.bind(correlationContext);\nexport const getRequestId =\n correlationContext.getRequestId.bind(correlationContext);\nexport const getUserId = correlationContext.getUserId.bind(correlationContext);\nexport const getTenantId =\n correlationContext.getTenantId.bind(correlationContext);\nexport const getLogMeta =\n correlationContext.getLogMeta.bind(correlationContext);\nexport const isInContext =\n correlationContext.isInContext.bind(correlationContext);\n\n// ═══════════════════════════════════════════════════════════════\n// MIDDLEWARE HELPERS\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Create correlation context from incoming HTTP request\n */\nexport function createRequestContext(\n headers: Record<string, string | string[] | undefined>,\n options?: {\n generateTraceId?: boolean;\n generateRequestId?: boolean;\n operation?: string;\n userId?: string;\n tenantId?: string;\n },\n): CorrelationData {\n const parsed = correlationContext.parseHeaders(headers);\n\n return {\n ...parsed,\n traceId:\n parsed.traceId ??\n (options?.generateTraceId ? correlationContext.generateId() : undefined),\n requestId:\n parsed.requestId ??\n (options?.generateRequestId\n ? correlationContext.generateId()\n : undefined),\n operation: options?.operation,\n userId: options?.userId,\n tenantId: options?.tenantId,\n startTime: Date.now(),\n };\n}\n\n/**\n * Create correlation context for queue job processing\n */\nexport function createJobContext(job: {\n id: string;\n name: string;\n correlationId?: string;\n metadata?: Record<string, unknown>;\n}): CorrelationData {\n return {\n correlationId: job.correlationId ?? job.id,\n traceId: correlationContext.generateId(),\n operation: `job:${job.name}`,\n metadata: job.metadata,\n startTime: Date.now(),\n };\n}\n\n/**\n * Decorator to wrap a function with correlation context\n */\nexport function withCorrelation<TArgs extends unknown[], TReturn>(\n fn: (...args: TArgs) => TReturn,\n getContext: (...args: TArgs) => CorrelationData,\n): (...args: TArgs) => TReturn {\n return (...args: TArgs) => {\n const ctx = getContext(...args);\n return correlationContext.run(ctx, () => fn(...args));\n };\n}\n\n/**\n * Decorator to wrap an async function with correlation context\n */\nexport function withCorrelationAsync<TArgs extends unknown[], TReturn>(\n fn: (...args: TArgs) => Promise<TReturn>,\n getContext: (...args: TArgs) => CorrelationData,\n): (...args: TArgs) => Promise<TReturn> {\n return async (...args: TArgs) => {\n const ctx = getContext(...args);\n return correlationContext.runAsync(ctx, () => fn(...args));\n };\n}\n","/**\n * Enhanced Memory Queue Implementation\n *\n * Full-featured in-memory queue for testing with:\n * - Retry/backoff support\n * - Job state management\n * - Event emitters\n * - Dead letter queue (failed jobs)\n * - Recurring job support\n *\n * Design: Self-contained, no external dependencies, full IQueue compliance\n */\nimport {\n IQueue,\n Job,\n JobOptions,\n JobState,\n QueueStats,\n RepeatOptions,\n JobEventType,\n JobEventHandler,\n JobEvent,\n calculateBackoff,\n generateJobId,\n} from \"../../interfaces/IQueue\";\nimport { createJobContext, runWithContext } from \"../../context\";\n\ninterface InternalJob<T> extends Job<T> {\n options?: JobOptions;\n repeatKey?: string;\n}\n\nexport class MemoryQueue<T = unknown> implements IQueue<T> {\n private jobs: Map<string, InternalJob<T>> = new Map();\n private handlers: Array<(job: Job<T>) => Promise<unknown>> = [];\n private eventHandlers: Map<JobEventType, Set<JobEventHandler<T>>> = new Map();\n private paused = false;\n private processingConcurrency = 1;\n private activeCount = 0;\n private repeatIntervals: Map<string, NodeJS.Timeout> = new Map();\n private queueName: string;\n private processingQueue: string[] = [];\n private isProcessing = false;\n\n constructor(name: string = \"default\") {\n this.queueName = name;\n }\n\n // ═══════════════════════════════════════════════════════════════\n // CORE METHODS (IQueue interface)\n // ═══════════════════════════════════════════════════════════════\n\n async add(name: string, data: T, options?: JobOptions): Promise<Job<T>> {\n const jobId = options?.jobId || generateJobId();\n const now = Date.now();\n\n const job: InternalJob<T> = {\n id: jobId,\n name,\n data,\n attemptsMade: 0,\n progress: 0,\n timestamp: now,\n state: options?.delay ? \"delayed\" : \"waiting\",\n correlationId: options?.correlationId,\n metadata: options?.metadata,\n options,\n };\n\n this.jobs.set(jobId, job);\n\n // Handle delayed jobs\n if (options?.delay && options.delay > 0) {\n setTimeout(() => {\n const j = this.jobs.get(jobId);\n if (j && j.state === \"delayed\") {\n j.state = \"waiting\";\n this.processNext();\n }\n }, options.delay);\n } else {\n this.processNext();\n }\n\n return this.toPublicJob(job);\n }\n\n async addBulk(\n jobs: Array<{ name: string; data: T; options?: JobOptions }>,\n ): Promise<Job<T>[]> {\n return Promise.all(jobs.map((j) => this.add(j.name, j.data, j.options)));\n }\n\n process(\n handler: (job: Job<T>) => Promise<unknown>,\n options?: { concurrency?: number },\n ): void {\n this.handlers.push(handler);\n if (options?.concurrency) {\n this.processingConcurrency = options.concurrency;\n }\n this.processNext();\n }\n\n async getJob(id: string): Promise<Job<T> | null> {\n const job = this.jobs.get(id);\n return job ? this.toPublicJob(job) : null;\n }\n\n async removeJob(id: string): Promise<void> {\n this.jobs.delete(id);\n }\n\n async pause(): Promise<void> {\n this.paused = true;\n }\n\n async resume(): Promise<void> {\n this.paused = false;\n this.processNext();\n }\n\n async getStats(): Promise<QueueStats> {\n const stats: QueueStats = {\n waiting: 0,\n active: 0,\n completed: 0,\n failed: 0,\n delayed: 0,\n };\n\n for (const job of this.jobs.values()) {\n switch (job.state) {\n case \"waiting\":\n stats.waiting++;\n break;\n case \"active\":\n stats.active++;\n break;\n case \"completed\":\n stats.completed++;\n break;\n case \"failed\":\n stats.failed++;\n break;\n case \"delayed\":\n stats.delayed++;\n break;\n }\n }\n\n return stats;\n }\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n async close(): Promise<void> {\n // Clear all intervals for recurring jobs\n for (const interval of this.repeatIntervals.values()) {\n clearInterval(interval);\n }\n this.repeatIntervals.clear();\n this.jobs.clear();\n this.handlers = [];\n this.eventHandlers.clear();\n this.paused = true;\n }\n\n // ═══════════════════════════════════════════════════════════════\n // OPTIONAL METHODS (new in enhanced interface)\n // ═══════════════════════════════════════════════════════════════\n\n async addRecurring(\n name: string,\n data: T,\n repeat: RepeatOptions,\n options?: Omit<JobOptions, \"repeat\">,\n ): Promise<Job<T>> {\n const repeatKey = `repeat:${name}:${Date.now()}`;\n\n // Create initial job\n const job = await this.add(name, data, { ...options, jobId: repeatKey });\n const internalJob = this.jobs.get(repeatKey);\n if (internalJob) {\n internalJob.repeatKey = repeatKey;\n }\n\n // Set up recurring execution\n if (repeat.every) {\n let execCount = 0;\n const interval = setInterval(async () => {\n if (repeat.limit && execCount >= repeat.limit) {\n clearInterval(interval);\n this.repeatIntervals.delete(repeatKey);\n return;\n }\n execCount++;\n await this.add(name, data, options);\n }, repeat.every);\n\n this.repeatIntervals.set(repeatKey, interval);\n }\n\n // Note: Cron support would require a cron parser library\n // For memory adapter, we support interval-based repeat only\n if (repeat.cron) {\n console.warn(\n \"MemoryQueue: Cron expressions not supported, use 'every' for intervals\",\n );\n }\n\n return job;\n }\n\n async getJobs(\n state: JobState | JobState[],\n start: number = 0,\n end: number = -1,\n ): Promise<Job<T>[]> {\n const states = Array.isArray(state) ? state : [state];\n const filtered = Array.from(this.jobs.values())\n .filter((j) => states.includes(j.state || \"waiting\"))\n .sort((a, b) => a.timestamp - b.timestamp);\n\n const endIndex = end === -1 ? filtered.length : end + 1;\n return filtered.slice(start, endIndex).map((j) => this.toPublicJob(j));\n }\n\n async getFailedJobs(start: number = 0, end: number = -1): Promise<Job<T>[]> {\n return this.getJobs(\"failed\", start, end);\n }\n\n async retryJob(id: string): Promise<void> {\n const job = this.jobs.get(id);\n if (!job || job.state !== \"failed\") {\n return;\n }\n\n job.state = \"waiting\";\n job.attemptsMade = 0;\n job.failedReason = undefined;\n this.processNext();\n }\n\n async replayAllFailed(): Promise<number> {\n const failedJobs = Array.from(this.jobs.values()).filter(\n (j) => j.state === \"failed\",\n );\n\n for (const job of failedJobs) {\n job.state = \"waiting\";\n job.attemptsMade = 0;\n job.failedReason = undefined;\n }\n\n this.processNext();\n return failedJobs.length;\n }\n\n async updateProgress(id: string, progress: number): Promise<void> {\n const job = this.jobs.get(id);\n if (job) {\n job.progress = Math.min(100, Math.max(0, progress));\n this.emitEvent(\"progress\", job, { progress });\n }\n }\n\n async clean(\n grace: number,\n limit: number,\n state: JobState,\n ): Promise<string[]> {\n const now = Date.now();\n const removed: string[] = [];\n\n for (const [id, job] of this.jobs.entries()) {\n if (removed.length >= limit) break;\n\n if (job.state === state) {\n const finishedTime = job.finishedOn || job.timestamp;\n if (now - finishedTime > grace) {\n this.jobs.delete(id);\n removed.push(id);\n }\n }\n }\n\n return removed;\n }\n\n async obliterate(options?: { force?: boolean }): Promise<void> {\n // Clear all intervals\n for (const interval of this.repeatIntervals.values()) {\n clearInterval(interval);\n }\n this.repeatIntervals.clear();\n this.jobs.clear();\n }\n\n on(event: JobEventType, handler: JobEventHandler<T>): void {\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, new Set());\n }\n this.eventHandlers.get(event)!.add(handler);\n }\n\n off(event: JobEventType, handler: JobEventHandler<T>): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n\n getName(): string {\n return this.queueName;\n }\n\n // ═══════════════════════════════════════════════════════════════\n // TESTING UTILITIES (not part of IQueue interface)\n // ═══════════════════════════════════════════════════════════════\n\n /**\n * Clear all jobs (for testing)\n */\n clear(): void {\n for (const interval of this.repeatIntervals.values()) {\n clearInterval(interval);\n }\n this.repeatIntervals.clear();\n this.jobs.clear();\n this.handlers = [];\n this.paused = false;\n this.activeCount = 0;\n }\n\n /**\n * Get all jobs regardless of state (for testing)\n */\n getAllJobs(): Job<T>[] {\n return Array.from(this.jobs.values()).map((j) => this.toPublicJob(j));\n }\n\n /**\n * Get pending (waiting) jobs (for testing)\n */\n getPendingJobs(): Job<T>[] {\n return Array.from(this.jobs.values())\n .filter((j) => j.state === \"waiting\")\n .map((j) => this.toPublicJob(j));\n }\n\n /**\n * Get number of jobs (for testing)\n */\n get size(): number {\n return this.jobs.size;\n }\n\n /**\n * Wait for all jobs to complete (for testing)\n */\n async drain(timeout: number = 5000): Promise<void> {\n const start = Date.now();\n while (this.activeCount > 0 || this.hasWaitingJobs()) {\n if (Date.now() - start > timeout) {\n throw new Error(\"Queue drain timeout\");\n }\n await new Promise((resolve) => setTimeout(resolve, 10));\n }\n }\n\n // ═══════════════════════════════════════════════════════════════\n // PRIVATE METHODS\n // ═══════════════════════════════════════════════════════════════\n\n private hasWaitingJobs(): boolean {\n for (const job of this.jobs.values()) {\n if (job.state === \"waiting\") return true;\n }\n return false;\n }\n\n private async processNext(): Promise<void> {\n if (this.paused || this.handlers.length === 0 || this.isProcessing) {\n return;\n }\n\n if (this.activeCount >= this.processingConcurrency) {\n return;\n }\n\n // Find next waiting job\n let nextJob: InternalJob<T> | undefined;\n for (const job of this.jobs.values()) {\n if (job.state === \"waiting\") {\n nextJob = job;\n break;\n }\n }\n\n if (!nextJob) {\n return;\n }\n\n this.activeCount++;\n nextJob.state = \"active\";\n nextJob.processedOn = Date.now();\n\n this.emitEvent(\"active\", nextJob);\n\n try {\n // Execute all handlers\n for (const handler of this.handlers) {\n await this.executeWithTimeout(handler, nextJob);\n }\n\n // Success\n nextJob.state = \"completed\";\n nextJob.finishedOn = Date.now();\n nextJob.progress = 100;\n\n this.emitEvent(\"completed\", nextJob);\n\n // Handle removeOnComplete\n if (nextJob.options?.removeOnComplete === true) {\n this.jobs.delete(nextJob.id);\n }\n } catch (error) {\n await this.handleJobFailure(nextJob, error as Error);\n } finally {\n this.activeCount--;\n // Process next job\n setImmediate(() => this.processNext());\n }\n }\n\n private async executeWithTimeout(\n handler: (job: Job<T>) => Promise<unknown>,\n job: InternalJob<T>,\n ): Promise<void> {\n const timeout = job.options?.timeout;\n const publicJob = this.toPublicJob(job);\n\n // Create correlation context for this job\n const jobContext = createJobContext({\n id: job.id,\n name: job.name,\n correlationId: job.correlationId,\n metadata: job.metadata,\n });\n\n // Execute handler within correlation context\n const executeHandler = () =>\n runWithContext(jobContext, () => handler(publicJob));\n\n if (!timeout) {\n await executeHandler();\n return;\n }\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error(\"Job timeout\")), timeout);\n });\n\n await Promise.race([executeHandler(), timeoutPromise]);\n }\n\n private async handleJobFailure(\n job: InternalJob<T>,\n error: Error,\n ): Promise<void> {\n job.attemptsMade++;\n const maxAttempts = job.options?.attempts || 1;\n\n if (job.attemptsMade < maxAttempts) {\n // Retry with backoff\n job.state = \"delayed\";\n const backoffDelay = job.options?.backoff\n ? calculateBackoff(job.attemptsMade, job.options.backoff)\n : 1000;\n\n setTimeout(() => {\n const j = this.jobs.get(job.id);\n if (j && j.state === \"delayed\") {\n j.state = \"waiting\";\n this.processNext();\n }\n }, backoffDelay);\n } else {\n // Move to failed (dead letter queue)\n job.state = \"failed\";\n job.finishedOn = Date.now();\n job.failedReason = error.message;\n\n this.emitEvent(\"failed\", job, { error });\n\n // Handle removeOnFail\n if (job.options?.removeOnFail === true) {\n this.jobs.delete(job.id);\n }\n }\n }\n\n private emitEvent(\n type: JobEventType,\n job: InternalJob<T>,\n extra?: { error?: Error; progress?: number; result?: unknown },\n ): void {\n const handlers = this.eventHandlers.get(type);\n if (!handlers) return;\n\n const event: JobEvent<T> = {\n type,\n job: this.toPublicJob(job),\n timestamp: Date.now(),\n ...extra,\n };\n\n for (const handler of handlers) {\n try {\n handler(event);\n } catch {\n // Ignore handler errors\n }\n }\n }\n\n private toPublicJob(job: InternalJob<T>): Job<T> {\n return {\n id: job.id,\n name: job.name,\n data: job.data,\n attemptsMade: job.attemptsMade,\n progress: job.progress,\n timestamp: job.timestamp,\n state: job.state,\n processedOn: job.processedOn,\n finishedOn: job.finishedOn,\n failedReason: job.failedReason,\n correlationId: job.correlationId,\n metadata: job.metadata,\n };\n }\n}\n","/**\n * Console Email Adapter\n * Development implementation that logs emails to console instead of sending\n */\n\nimport {\n IEmail,\n EmailMessage,\n EmailResult,\n EmailAddress,\n} from \"../../interfaces/IEmail\";\nimport { randomBytes } from \"crypto\";\n\nexport class ConsoleEmail implements IEmail {\n private sentEmails: EmailMessage[] = [];\n\n async send(message: EmailMessage): Promise<EmailResult> {\n const id = `console_${Date.now()}_${randomBytes(4).toString(\"hex\")}`;\n\n console.log(\"\\n\" + \"=\".repeat(60));\n console.log(\"📧 EMAIL SENT (Console Adapter)\");\n console.log(\"=\".repeat(60));\n console.log(`ID: ${id}`);\n console.log(`To: ${this.formatAddresses(message.to)}`);\n console.log(\n `From: ${message.from ? this.formatAddress(message.from) : \"(default)\"}`,\n );\n console.log(`Subject: ${message.subject}`);\n\n if (message.replyTo) {\n console.log(`Reply-To: ${this.formatAddress(message.replyTo)}`);\n }\n\n if (message.tags && message.tags.length > 0) {\n console.log(`Tags: ${message.tags.join(\", \")}`);\n }\n\n if (message.attachments && message.attachments.length > 0) {\n console.log(\n `Attachments: ${message.attachments.map((a) => a.filename).join(\", \")}`,\n );\n }\n\n console.log(\"-\".repeat(60));\n\n if (message.text) {\n console.log(\"TEXT BODY:\");\n console.log(\n message.text.slice(0, 500) +\n (message.text.length > 500 ? \"\\n...(truncated)\" : \"\"),\n );\n }\n\n if (message.html) {\n console.log(\n \"HTML BODY: [HTML content - \" + message.html.length + \" chars]\",\n );\n }\n\n console.log(\"=\".repeat(60) + \"\\n\");\n\n this.sentEmails.push(message);\n\n return {\n id,\n success: true,\n };\n }\n\n async sendBatch(messages: EmailMessage[]): Promise<EmailResult[]> {\n const results: EmailResult[] = [];\n\n for (const message of messages) {\n results.push(await this.send(message));\n }\n\n return results;\n }\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n /**\n * Get all sent emails (for testing)\n */\n getSentEmails(): EmailMessage[] {\n return [...this.sentEmails];\n }\n\n /**\n * Clear sent emails (for testing)\n */\n clearSentEmails(): void {\n this.sentEmails = [];\n }\n\n private formatAddress(address: EmailAddress): string {\n if (address.name) {\n return `${address.name} <${address.email}>`;\n }\n return address.email;\n }\n\n private formatAddresses(addresses: EmailAddress | EmailAddress[]): string {\n const list = Array.isArray(addresses) ? addresses : [addresses];\n return list.map((addr) => this.formatAddress(addr)).join(\", \");\n }\n}\n","/**\n * Secrets Management Interface\n *\n * Provides a vendor-agnostic abstraction for secrets management.\n * Supports various backends: Environment variables, HashiCorp Vault,\n * AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, etc.\n */\n\n/**\n * Secret metadata\n */\nexport interface SecretMetadata {\n /** Secret version or ETag */\n version?: string;\n\n /** Creation timestamp */\n createdAt?: Date;\n\n /** Last updated timestamp */\n updatedAt?: Date;\n\n /** Expiration timestamp */\n expiresAt?: Date;\n\n /** Custom tags/labels */\n tags?: Record<string, string>;\n}\n\n/**\n * Secret with metadata\n */\nexport interface Secret<T = string> {\n /** Secret key/name */\n key: string;\n\n /** Secret value */\n value: T;\n\n /** Secret metadata */\n metadata?: SecretMetadata;\n}\n\n/**\n * Options for getting secrets\n */\nexport interface GetSecretOptions {\n /** Specific version to retrieve */\n version?: string;\n\n /** Include metadata in response */\n includeMetadata?: boolean;\n\n /** Cache TTL in seconds (0 = no cache) */\n cacheTtl?: number;\n}\n\n/**\n * Options for setting secrets\n */\nexport interface SetSecretOptions {\n /** Expiration timestamp */\n expiresAt?: Date;\n\n /** Custom tags/labels */\n tags?: Record<string, string>;\n\n /** Description */\n description?: string;\n}\n\n/**\n * Options for rotating secrets\n */\nexport interface RotateSecretOptions {\n /** Custom rotation function */\n rotationFn?: () => Promise<string>;\n\n /** Rotation period in days */\n rotationPeriodDays?: number;\n\n /** Keep previous version count */\n keepPreviousVersions?: number;\n}\n\n/**\n * Result of a rotation operation\n */\nexport interface RotationResult {\n /** New secret value */\n newValue: string;\n\n /** Previous secret value (for rollback) */\n previousValue?: string;\n\n /** New version identifier */\n newVersion: string;\n\n /** Previous version identifier */\n previousVersion?: string;\n}\n\n/**\n * Secrets Management Interface\n */\nexport interface ISecrets {\n /**\n * Get a secret value by key\n */\n get(key: string, options?: GetSecretOptions): Promise<string | null>;\n\n /**\n * Get a secret with metadata\n */\n getWithMetadata(\n key: string,\n options?: GetSecretOptions,\n ): Promise<Secret | null>;\n\n /**\n * Get multiple secrets at once\n */\n mget(keys: string[]): Promise<Map<string, string | null>>;\n\n /**\n * Set a secret value\n */\n set(key: string, value: string, options?: SetSecretOptions): Promise<void>;\n\n /**\n * Delete a secret\n */\n delete(key: string): Promise<void>;\n\n /**\n * Check if a secret exists\n */\n exists(key: string): Promise<boolean>;\n\n /**\n * List all secret keys (optionally filtered by prefix)\n */\n list(prefix?: string): Promise<string[]>;\n\n /**\n * Rotate a secret (generate new value)\n */\n rotate(key: string, options?: RotateSecretOptions): Promise<RotationResult>;\n\n /**\n * Get all versions of a secret\n */\n getVersions(key: string): Promise<SecretMetadata[]>;\n\n /**\n * Health check\n */\n healthCheck(): Promise<boolean>;\n}\n\n/**\n * Environment Variables Secrets Adapter\n * Simple implementation using process.env - suitable for development\n * and containerized deployments with injected secrets\n */\nexport class EnvSecrets implements ISecrets {\n private prefix: string;\n private cache: Map<string, { value: string; expiresAt: number }> = new Map();\n\n constructor(options: { prefix?: string } = {}) {\n this.prefix = options.prefix ?? \"\";\n }\n\n private getEnvKey(key: string): string {\n const normalizedKey = key.toUpperCase().replace(/[.-]/g, \"_\");\n return this.prefix ? `${this.prefix}_${normalizedKey}` : normalizedKey;\n }\n\n async get(key: string, options?: GetSecretOptions): Promise<string | null> {\n // Check cache first\n if (options?.cacheTtl) {\n const cached = this.cache.get(key);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.value;\n }\n }\n\n const envKey = this.getEnvKey(key);\n const value = process.env[envKey] ?? null;\n\n // Cache if requested\n if (value && options?.cacheTtl) {\n this.cache.set(key, {\n value,\n expiresAt: Date.now() + options.cacheTtl * 1000,\n });\n }\n\n return value;\n }\n\n async getWithMetadata(\n key: string,\n options?: GetSecretOptions,\n ): Promise<Secret | null> {\n const value = await this.get(key, options);\n if (value === null) {\n return null;\n }\n\n return {\n key,\n value,\n metadata: {\n // Environment variables don't have native metadata\n createdAt: undefined,\n updatedAt: undefined,\n },\n };\n }\n\n async mget(keys: string[]): Promise<Map<string, string | null>> {\n const result = new Map<string, string | null>();\n for (const key of keys) {\n result.set(key, await this.get(key));\n }\n return result;\n }\n\n async set(\n key: string,\n value: string,\n _options?: SetSecretOptions,\n ): Promise<void> {\n const envKey = this.getEnvKey(key);\n process.env[envKey] = value;\n\n // Update cache\n this.cache.delete(key);\n }\n\n async delete(key: string): Promise<void> {\n const envKey = this.getEnvKey(key);\n delete process.env[envKey];\n this.cache.delete(key);\n }\n\n async exists(key: string): Promise<boolean> {\n const envKey = this.getEnvKey(key);\n return process.env[envKey] !== undefined;\n }\n\n async list(prefix?: string): Promise<string[]> {\n const keys: string[] = [];\n const envPrefix = this.prefix ? `${this.prefix}_` : \"\";\n const searchPrefix = prefix\n ? `${envPrefix}${prefix.toUpperCase().replace(/[.-]/g, \"_\")}`\n : envPrefix;\n\n for (const key of Object.keys(process.env)) {\n if (key.startsWith(searchPrefix || \"\")) {\n // Convert back to normalized key format\n const normalizedKey = key\n .slice(envPrefix.length)\n .toLowerCase()\n .replace(/_/g, \"-\");\n keys.push(normalizedKey);\n }\n }\n\n return keys;\n }\n\n async rotate(\n key: string,\n options?: RotateSecretOptions,\n ): Promise<RotationResult> {\n const previousValue = await this.get(key);\n\n // Generate new value\n const newValue = options?.rotationFn\n ? await options.rotationFn()\n : this.generateSecureValue();\n\n await this.set(key, newValue);\n\n return {\n newValue,\n previousValue: previousValue ?? undefined,\n newVersion: \"current\",\n previousVersion: previousValue ? \"previous\" : undefined,\n };\n }\n\n async getVersions(_key: string): Promise<SecretMetadata[]> {\n // Environment variables don't support versioning\n return [];\n }\n\n async healthCheck(): Promise<boolean> {\n // Environment is always available\n return true;\n }\n\n private generateSecureValue(length: number = 32): string {\n const chars =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*\";\n let result = \"\";\n const randomValues = new Uint32Array(length);\n crypto.getRandomValues(randomValues);\n for (let i = 0; i < length; i++) {\n result += chars[randomValues[i]! % chars.length];\n }\n return result;\n }\n\n /**\n * Clear the internal cache\n */\n clearCache(): void {\n this.cache.clear();\n }\n}\n\nimport { randomBytes } from \"crypto\";\n\n/**\n * Memory-based Secrets Adapter\n * For testing purposes only - stores secrets in memory\n */\nexport class MemorySecrets implements ISecrets {\n private secrets: Map<string, Secret> = new Map();\n private versions: Map<string, SecretMetadata[]> = new Map();\n\n async get(key: string, _options?: GetSecretOptions): Promise<string | null> {\n const secret = this.secrets.get(key);\n if (!secret) {\n return null;\n }\n\n // Check expiration\n if (secret.metadata?.expiresAt && secret.metadata.expiresAt < new Date()) {\n await this.delete(key);\n return null;\n }\n\n return secret.value;\n }\n\n async getWithMetadata(\n key: string,\n options?: GetSecretOptions,\n ): Promise<Secret | null> {\n const value = await this.get(key, options);\n if (value === null) {\n return null;\n }\n\n return this.secrets.get(key) ?? null;\n }\n\n async mget(keys: string[]): Promise<Map<string, string | null>> {\n const result = new Map<string, string | null>();\n for (const key of keys) {\n result.set(key, await this.get(key));\n }\n return result;\n }\n\n async set(\n key: string,\n value: string,\n options?: SetSecretOptions,\n ): Promise<void> {\n const now = new Date();\n const version = `v${Date.now()}`;\n\n // Store version history\n const currentSecret = this.secrets.get(key);\n if (currentSecret?.metadata) {\n const history = this.versions.get(key) ?? [];\n history.push(currentSecret.metadata);\n this.versions.set(key, history);\n }\n\n this.secrets.set(key, {\n key,\n value,\n metadata: {\n version,\n createdAt: currentSecret?.metadata?.createdAt ?? now,\n updatedAt: now,\n expiresAt: options?.expiresAt,\n tags: options?.tags,\n },\n });\n }\n\n async delete(key: string): Promise<void> {\n this.secrets.delete(key);\n this.versions.delete(key);\n }\n\n async exists(key: string): Promise<boolean> {\n return this.secrets.has(key);\n }\n\n async list(prefix?: string): Promise<string[]> {\n const keys: string[] = [];\n for (const key of this.secrets.keys()) {\n if (!prefix || key.startsWith(prefix)) {\n keys.push(key);\n }\n }\n return keys;\n }\n\n async rotate(\n key: string,\n options?: RotateSecretOptions,\n ): Promise<RotationResult> {\n const currentSecret = this.secrets.get(key);\n const previousValue = currentSecret?.value;\n const previousVersion = currentSecret?.metadata?.version;\n\n // Generate new value\n const newValue = options?.rotationFn\n ? await options.rotationFn()\n : this.generateSecureValue();\n\n await this.set(key, newValue);\n const newVersion = this.secrets.get(key)?.metadata?.version ?? \"unknown\";\n\n return {\n newValue,\n previousValue,\n newVersion,\n previousVersion,\n };\n }\n\n async getVersions(key: string): Promise<SecretMetadata[]> {\n const current = this.secrets.get(key)?.metadata;\n const history = this.versions.get(key) ?? [];\n\n if (current) {\n return [...history, current];\n }\n\n return history;\n }\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n private generateSecureValue(length: number = 32): string {\n return randomBytes(length).toString(\"base64url\").slice(0, length);\n }\n\n /**\n * Clear all secrets (for testing)\n */\n clear(): void {\n this.secrets.clear();\n this.versions.clear();\n }\n\n /**\n * Get count of secrets (for testing)\n */\n get size(): number {\n return this.secrets.size;\n }\n}\n","/**\n * Platform Configuration\n * Comprehensive Zod schema for all platform options with validation\n */\n\nimport { z } from \"zod\";\n\n// ═══════════════════════════════════════════════════════════════\n// PROVIDER SCHEMAS\n// ═══════════════════════════════════════════════════════════════\n\nexport const DatabaseProviderSchema = z.enum([\n \"memory\",\n \"postgres\",\n \"supabase\",\n]);\nexport const CacheProviderSchema = z.enum([\"memory\", \"redis\", \"upstash\"]);\nexport const StorageProviderSchema = z.enum([\n \"memory\",\n \"s3\",\n \"minio\",\n \"r2\",\n \"supabase\",\n]);\nexport const EmailProviderSchema = z.enum([\n \"memory\",\n \"console\",\n \"smtp\",\n \"resend\",\n]);\nexport const QueueProviderSchema = z.enum([\"memory\", \"bullmq\"]);\nexport const TracingProviderSchema = z.enum([\"noop\", \"memory\", \"otlp\"]);\nexport const LogLevelSchema = z.enum([\"debug\", \"info\", \"warn\", \"error\"]);\nexport const AIProviderSchema = z.enum([\n \"memory\",\n \"openai\",\n \"anthropic\",\n \"google\",\n]);\nexport const RAGProviderSchema = z.enum([\"memory\", \"pinecone\", \"weaviate\"]);\n\n// ═══════════════════════════════════════════════════════════════\n// SERVICE CONFIGURATION SCHEMAS\n// ═══════════════════════════════════════════════════════════════\n\nexport const DatabaseConfigSchema = z\n .object({\n provider: DatabaseProviderSchema.default(\"memory\"),\n url: z.string().optional().describe(\"PostgreSQL connection URL\"),\n connectionString: z\n .string()\n .optional()\n .describe(\"PostgreSQL connection string (alias for url)\"),\n supabaseUrl: z.string().url().optional().describe(\"Supabase project URL\"),\n supabaseAnonKey: z.string().optional().describe(\"Supabase anonymous key\"),\n supabaseServiceRoleKey: z\n .string()\n .optional()\n .describe(\"Supabase service role key\"),\n poolSize: z\n .number()\n .int()\n .min(1)\n .max(100)\n .default(10)\n .describe(\"Connection pool size\"),\n connectionTimeout: z\n .number()\n .int()\n .min(1000)\n .max(60000)\n .default(5000)\n .describe(\"Connection timeout in ms\"),\n ssl: z\n .union([\n z.boolean(),\n z.object({ rejectUnauthorized: z.boolean().optional() }),\n ])\n .optional()\n .describe(\"SSL configuration\"),\n })\n .refine(\n (data) => {\n if (data.provider === \"supabase\") {\n return data.supabaseUrl && data.supabaseAnonKey;\n }\n if (data.provider === \"postgres\") {\n return data.url || data.connectionString;\n }\n return true;\n },\n {\n message:\n \"Supabase requires supabaseUrl and supabaseAnonKey; PostgreSQL requires url or connectionString\",\n },\n );\n\nexport const CacheConfigSchema = z\n .object({\n provider: CacheProviderSchema.default(\"memory\"),\n url: z.string().url().optional().describe(\"Redis connection URL\"),\n upstashUrl: z.string().url().optional().describe(\"Upstash REST URL\"),\n upstashToken: z.string().optional().describe(\"Upstash REST token\"),\n defaultTTL: z\n .number()\n .int()\n .min(0)\n .default(3600)\n .describe(\"Default TTL in seconds\"),\n keyPrefix: z.string().default(\"\").describe(\"Prefix for all cache keys\"),\n maxRetries: z\n .number()\n .int()\n .min(0)\n .max(10)\n .default(3)\n .describe(\"Max retries for cache operations\"),\n })\n .refine(\n (data) => {\n if (data.provider === \"upstash\") {\n return data.upstashUrl && data.upstashToken;\n }\n if (data.provider === \"redis\") {\n return data.url;\n }\n return true;\n },\n {\n message:\n \"Upstash requires upstashUrl and upstashToken; Redis requires url\",\n },\n );\n\nexport const StorageConfigSchema = z\n .object({\n provider: StorageProviderSchema.default(\"memory\"),\n endpoint: z\n .string()\n .url()\n .optional()\n .describe(\"S3-compatible endpoint URL\"),\n region: z.string().default(\"us-east-1\").describe(\"AWS region\"),\n accessKey: z.string().optional().describe(\"AWS access key ID\"),\n secretKey: z.string().optional().describe(\"AWS secret access key\"),\n bucket: z.string().optional().describe(\"S3 bucket name\"),\n publicUrl: z\n .string()\n .url()\n .optional()\n .describe(\"Public URL for accessing files\"),\n forcePathStyle: z\n .boolean()\n .default(false)\n .describe(\"Use path-style URLs (required for MinIO)\"),\n signedUrlExpiry: z\n .number()\n .int()\n .min(60)\n .max(604800)\n .default(3600)\n .describe(\"Signed URL expiry in seconds\"),\n })\n .refine(\n (data) => {\n if ([\"s3\", \"minio\", \"r2\"].includes(data.provider)) {\n return data.accessKey && data.secretKey && data.bucket;\n }\n return true;\n },\n {\n message: \"S3/MinIO/R2 requires accessKey, secretKey, and bucket\",\n },\n );\n\nexport const EmailConfigSchema = z\n .object({\n provider: EmailProviderSchema.default(\"memory\"),\n host: z.string().optional().describe(\"SMTP host\"),\n port: z.number().int().min(1).max(65535).optional().describe(\"SMTP port\"),\n secure: z.boolean().default(false).describe(\"Use TLS for SMTP\"),\n username: z.string().optional().describe(\"SMTP username\"),\n password: z.string().optional().describe(\"SMTP password\"),\n apiKey: z.string().optional().describe(\"Resend API key\"),\n from: z\n .string()\n .email()\n .or(z.string().regex(/^.+\\s<.+@.+>$/))\n .optional()\n .describe(\"Default from address\"),\n replyTo: z.string().email().optional().describe(\"Default reply-to address\"),\n rateLimitPerSecond: z\n .number()\n .int()\n .min(1)\n .max(100)\n .default(10)\n .describe(\"Max emails per second\"),\n })\n .refine(\n (data) => {\n if (data.provider === \"smtp\") {\n return data.host && data.port;\n }\n if (data.provider === \"resend\") {\n return data.apiKey;\n }\n return true;\n },\n {\n message: \"SMTP requires host and port; Resend requires apiKey\",\n },\n );\n\nexport const QueueConfigSchema = z\n .object({\n provider: QueueProviderSchema.default(\"memory\"),\n redisUrl: z\n .string()\n .url()\n .optional()\n .describe(\"Redis connection URL for BullMQ\"),\n queueName: z\n .string()\n .default(\"platform-jobs\")\n .describe(\"Default queue name\"),\n concurrency: z\n .number()\n .int()\n .min(1)\n .max(100)\n .default(5)\n .describe(\"Worker concurrency\"),\n maxRetries: z\n .number()\n .int()\n .min(0)\n .max(10)\n .default(3)\n .describe(\"Max job retries\"),\n retryDelay: z\n .number()\n .int()\n .min(0)\n .default(1000)\n .describe(\"Retry delay in ms\"),\n removeOnComplete: z\n .boolean()\n .default(true)\n .describe(\"Remove completed jobs\"),\n removeOnFail: z.boolean().default(false).describe(\"Remove failed jobs\"),\n })\n .refine(\n (data) => {\n if (data.provider === \"bullmq\") {\n return data.redisUrl;\n }\n return true;\n },\n {\n message: \"BullMQ requires redisUrl\",\n },\n );\n\nexport const AIConfigSchema = z\n .object({\n enabled: z.boolean().default(false).describe(\"Enable AI capabilities\"),\n provider: AIProviderSchema.default(\"memory\"),\n apiKey: z.string().optional().describe(\"API key for the AI provider\"),\n model: z.string().optional().describe(\"Default model to use\"),\n maxTokens: z\n .number()\n .int()\n .min(1)\n .max(200000)\n .default(4096)\n .describe(\"Default max tokens\"),\n temperature: z\n .number()\n .min(0)\n .max(2)\n .default(0.7)\n .describe(\"Default temperature\"),\n timeout: z\n .number()\n .int()\n .min(1000)\n .max(300000)\n .default(60000)\n .describe(\"Request timeout in ms\"),\n baseUrl: z.string().url().optional().describe(\"Custom base URL for API\"),\n })\n .refine(\n (data) => {\n if (data.enabled && data.provider !== \"memory\") {\n return data.apiKey;\n }\n return true;\n },\n {\n message: \"Production AI providers require an API key\",\n },\n );\n\nexport const RAGConfigSchema = z\n .object({\n enabled: z.boolean().default(false).describe(\"Enable RAG capabilities\"),\n provider: RAGProviderSchema.default(\"memory\"),\n apiKey: z.string().optional().describe(\"API key for the RAG provider\"),\n environment: z.string().optional().describe(\"Pinecone environment\"),\n indexName: z\n .string()\n .optional()\n .describe(\"Pinecone index name or Weaviate class\"),\n namespace: z.string().optional().describe(\"Default namespace\"),\n host: z.string().url().optional().describe(\"Weaviate host URL\"),\n embeddingProvider: AIProviderSchema.default(\"memory\").describe(\n \"Provider for generating embeddings\",\n ),\n embeddingApiKey: z\n .string()\n .optional()\n .describe(\"API key for embedding provider\"),\n embeddingModel: z\n .string()\n .optional()\n .describe(\"Model for generating embeddings\"),\n })\n .refine(\n (data) => {\n if (data.enabled && data.provider === \"pinecone\") {\n return data.apiKey && data.indexName;\n }\n if (data.enabled && data.provider === \"weaviate\") {\n return data.host;\n }\n return true;\n },\n {\n message: \"Pinecone requires apiKey and indexName; Weaviate requires host\",\n },\n );\n\n// ═══════════════════════════════════════════════════════════════\n// CRYPTO CONFIGURATION SCHEMA\n// ═══════════════════════════════════════════════════════════════\n\nexport const CryptoConfigSchema = z.object({\n enabled: z\n .boolean()\n .default(false)\n .describe(\"Enable field-level encryption\"),\n masterKey: z\n .string()\n .optional()\n .describe(\"256-bit master key as hex (64 chars). Required when enabled.\"),\n hmacKey: z\n .string()\n .optional()\n .describe(\"HMAC key for deterministic hashing (derived from master key if not provided)\"),\n}).refine(\n (data) => {\n if (data.enabled) {\n return data.masterKey && data.masterKey.length >= 64;\n }\n return true;\n },\n {\n message:\n \"Crypto requires a 256-bit master key (64 hex characters) when enabled\",\n },\n);\n\n// ═══════════════════════════════════════════════════════════════\n// SECURITY CONFIGURATION SCHEMA\n// ═══════════════════════════════════════════════════════════════\n\nexport const SecurityConfigSchema = z.object({\n enforceTls: z\n .boolean()\n .default(true)\n .describe(\"Enforce TLS for production connections\"),\n tlsWarnOnly: z\n .boolean()\n .default(false)\n .describe(\"Warn instead of throwing when TLS is missing in production\"),\n});\n\n// ═══════════════════════════════════════════════════════════════\n// RESILIENCE CONFIGURATION SCHEMAS\n// ═══════════════════════════════════════════════════════════════\n\nexport const RetryConfigSchema = z.object({\n enabled: z\n .boolean()\n .default(true)\n .describe(\"Enable retry for failed operations\"),\n maxAttempts: z\n .number()\n .int()\n .min(1)\n .max(10)\n .default(3)\n .describe(\"Maximum retry attempts\"),\n baseDelay: z\n .number()\n .int()\n .min(0)\n .max(10000)\n .default(100)\n .describe(\"Base delay in ms\"),\n maxDelay: z\n .number()\n .int()\n .min(0)\n .max(60000)\n .default(5000)\n .describe(\"Maximum delay in ms\"),\n backoffMultiplier: z\n .number()\n .min(1)\n .max(5)\n .default(2)\n .describe(\"Exponential backoff multiplier\"),\n jitter: z.boolean().default(true).describe(\"Add jitter to retry delays\"),\n});\n\nexport const CircuitBreakerConfigSchema = z.object({\n enabled: z.boolean().default(true).describe(\"Enable circuit breaker\"),\n failureThreshold: z\n .number()\n .int()\n .min(1)\n .max(100)\n .default(5)\n .describe(\"Failures before opening circuit\"),\n resetTimeout: z\n .number()\n .int()\n .min(1000)\n .max(300000)\n .default(30000)\n .describe(\"Reset timeout in ms\"),\n halfOpenRequests: z\n .number()\n .int()\n .min(1)\n .max(10)\n .default(3)\n .describe(\"Requests allowed in half-open state\"),\n monitorInterval: z\n .number()\n .int()\n .min(1000)\n .max(60000)\n .default(10000)\n .describe(\"Health monitor interval in ms\"),\n});\n\nexport const TimeoutConfigSchema = z.object({\n enabled: z.boolean().default(true).describe(\"Enable operation timeouts\"),\n default: z\n .number()\n .int()\n .min(100)\n .max(300000)\n .default(30000)\n .describe(\"Default timeout in ms\"),\n database: z\n .number()\n .int()\n .min(100)\n .max(300000)\n .default(10000)\n .describe(\"Database operation timeout\"),\n cache: z\n .number()\n .int()\n .min(100)\n .max(60000)\n .default(5000)\n .describe(\"Cache operation timeout\"),\n storage: z\n .number()\n .int()\n .min(100)\n .max(600000)\n .default(60000)\n .describe(\"Storage operation timeout\"),\n email: z\n .number()\n .int()\n .min(100)\n .max(120000)\n .default(30000)\n .describe(\"Email operation timeout\"),\n queue: z\n .number()\n .int()\n .min(100)\n .max(60000)\n .default(10000)\n .describe(\"Queue operation timeout\"),\n});\n\nexport const BulkheadConfigSchema = z.object({\n enabled: z.boolean().default(false).describe(\"Enable bulkhead isolation\"),\n maxConcurrent: z\n .number()\n .int()\n .min(1)\n .max(1000)\n .default(10)\n .describe(\"Maximum concurrent operations\"),\n maxQueued: z\n .number()\n .int()\n .min(0)\n .max(10000)\n .default(100)\n .describe(\"Maximum queued operations\"),\n timeout: z\n .number()\n .int()\n .min(0)\n .max(300000)\n .default(30000)\n .describe(\"Queue timeout in ms\"),\n});\n\nexport const ResilienceConfigSchema = z.object({\n retry: RetryConfigSchema.default({}),\n circuitBreaker: CircuitBreakerConfigSchema.default({}),\n timeout: TimeoutConfigSchema.default({}),\n bulkhead: BulkheadConfigSchema.default({}),\n});\n\n// ═══════════════════════════════════════════════════════════════\n// OBSERVABILITY CONFIGURATION SCHEMAS\n// ═══════════════════════════════════════════════════════════════\n\nexport const LoggingConfigSchema = z.object({\n level: LogLevelSchema.default(\"info\").describe(\"Minimum log level\"),\n format: z\n .enum([\"json\", \"pretty\"])\n .default(\"json\")\n .describe(\"Log output format\"),\n includeTimestamp: z\n .boolean()\n .default(true)\n .describe(\"Include timestamp in logs\"),\n includeCorrelationId: z\n .boolean()\n .default(true)\n .describe(\"Include correlation ID in logs\"),\n redactKeys: z\n .array(z.string())\n .default([\"password\", \"token\", \"secret\", \"apiKey\", \"authorization\"])\n .describe(\"Keys to redact from logs\"),\n});\n\nexport const MetricsConfigSchema = z.object({\n enabled: z.boolean().default(false).describe(\"Enable metrics collection\"),\n prefix: z.string().default(\"platform\").describe(\"Metric name prefix\"),\n defaultTags: z\n .record(z.string())\n .default({})\n .describe(\"Default tags for all metrics\"),\n flushInterval: z\n .number()\n .int()\n .min(1000)\n .max(60000)\n .default(10000)\n .describe(\"Flush interval in ms\"),\n histogramBuckets: z\n .array(z.number())\n .default([5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000])\n .describe(\"Histogram bucket boundaries in ms\"),\n});\n\nexport const TracingConfigSchema = z.object({\n enabled: z.boolean().default(false).describe(\"Enable distributed tracing\"),\n provider: TracingProviderSchema.default(\"noop\").describe(\"Tracing provider\"),\n serviceName: z.string().optional().describe(\"Service name for traces\"),\n serviceVersion: z.string().optional().describe(\"Service version\"),\n environment: z\n .string()\n .optional()\n .describe(\"Environment (dev, staging, production)\"),\n sampleRate: z\n .number()\n .min(0)\n .max(1)\n .default(1)\n .describe(\"Trace sampling rate\"),\n propagateContext: z\n .boolean()\n .default(true)\n .describe(\"Propagate trace context to downstream services\"),\n endpoint: z.string().url().optional().describe(\"OTLP exporter endpoint\"),\n exporterType: z\n .enum([\"otlp-http\", \"otlp-grpc\", \"console\"])\n .default(\"otlp-http\")\n .describe(\"Exporter type\"),\n});\n\nexport const ObservabilityConfigSchema = z.object({\n logging: LoggingConfigSchema.default({}),\n metrics: MetricsConfigSchema.default({}),\n tracing: TracingConfigSchema.default({}),\n});\n\n// ═══════════════════════════════════════════════════════════════\n// MIDDLEWARE CONFIGURATION SCHEMA\n// ═══════════════════════════════════════════════════════════════\n\nexport const MiddlewareConfigSchema = z.object({\n enabled: z.boolean().default(true).describe(\"Enable middleware chain\"),\n logging: z.boolean().default(true).describe(\"Enable logging middleware\"),\n metrics: z.boolean().default(false).describe(\"Enable metrics middleware\"),\n slowQuery: z\n .object({\n enabled: z.boolean().default(true),\n thresholdMs: z.number().int().min(1).default(1000),\n })\n .default({}),\n cache: z\n .object({\n enabled: z.boolean().default(false),\n defaultTTL: z.number().int().min(0).default(300),\n })\n .default({}),\n});\n\n// ═══════════════════════════════════════════════════════════════\n// MAIN PLATFORM CONFIGURATION SCHEMA\n// ═══════════════════════════════════════════════════════════════\n\nexport const PlatformConfigSchema = z.object({\n // Service configurations\n database: DatabaseConfigSchema.default({ provider: \"memory\" }),\n cache: CacheConfigSchema.default({ provider: \"memory\" }),\n storage: StorageConfigSchema.default({ provider: \"memory\" }),\n email: EmailConfigSchema.default({ provider: \"memory\" }),\n queue: QueueConfigSchema.default({ provider: \"memory\" }),\n\n // AI configurations\n ai: AIConfigSchema.default({ enabled: false }),\n rag: RAGConfigSchema.default({ enabled: false }),\n\n // Crypto configuration\n crypto: CryptoConfigSchema.default({ enabled: false }),\n\n // Security configuration\n security: SecurityConfigSchema.default({}),\n\n // Resilience configuration\n resilience: ResilienceConfigSchema.default({}),\n\n // Observability configuration\n observability: ObservabilityConfigSchema.default({}),\n\n // Middleware configuration\n middleware: MiddlewareConfigSchema.default({}),\n});\n\nexport type PlatformConfig = z.infer<typeof PlatformConfigSchema>;\nexport type DatabaseConfig = z.infer<typeof DatabaseConfigSchema>;\nexport type CacheConfig = z.infer<typeof CacheConfigSchema>;\nexport type StorageConfig = z.infer<typeof StorageConfigSchema>;\nexport type EmailConfig = z.infer<typeof EmailConfigSchema>;\nexport type QueueConfig = z.infer<typeof QueueConfigSchema>;\nexport type AIConfig = z.infer<typeof AIConfigSchema>;\nexport type RAGConfig = z.infer<typeof RAGConfigSchema>;\nexport type ResilienceConfig = z.infer<typeof ResilienceConfigSchema>;\nexport type ObservabilityConfig = z.infer<typeof ObservabilityConfigSchema>;\nexport type TracingConfig = z.infer<typeof TracingConfigSchema>;\nexport type MiddlewareConfig = z.infer<typeof MiddlewareConfigSchema>;\nexport type CryptoConfig = z.infer<typeof CryptoConfigSchema>;\nexport type SecurityConfig = z.infer<typeof SecurityConfigSchema>;\n\n// ═══════════════════════════════════════════════════════════════\n// CONFIGURATION LOADING\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Load configuration from environment variables\n */\nexport function loadConfig(): PlatformConfig {\n return PlatformConfigSchema.parse({\n database: {\n provider:\n process.env.PLATFORM_DB_PROVIDER ||\n process.env.DATABASE_PROVIDER ||\n \"memory\",\n url: process.env.DATABASE_URL,\n supabaseUrl: process.env.SUPABASE_URL,\n supabaseAnonKey: process.env.SUPABASE_ANON_KEY,\n supabaseServiceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY,\n poolSize: process.env.DATABASE_POOL_SIZE\n ? parseInt(process.env.DATABASE_POOL_SIZE)\n : undefined,\n connectionTimeout: process.env.DATABASE_TIMEOUT\n ? parseInt(process.env.DATABASE_TIMEOUT)\n : undefined,\n },\n cache: {\n provider:\n process.env.PLATFORM_CACHE_PROVIDER ||\n process.env.CACHE_PROVIDER ||\n \"memory\",\n url: process.env.REDIS_URL,\n upstashUrl: process.env.UPSTASH_REDIS_REST_URL,\n upstashToken: process.env.UPSTASH_REDIS_REST_TOKEN,\n defaultTTL: process.env.CACHE_DEFAULT_TTL\n ? parseInt(process.env.CACHE_DEFAULT_TTL)\n : undefined,\n keyPrefix: process.env.CACHE_KEY_PREFIX,\n },\n storage: {\n provider:\n process.env.PLATFORM_STORAGE_PROVIDER ||\n process.env.STORAGE_PROVIDER ||\n \"memory\",\n endpoint: process.env.S3_ENDPOINT,\n region: process.env.S3_REGION || process.env.AWS_REGION || \"us-east-1\",\n accessKey: process.env.S3_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY_ID,\n secretKey:\n process.env.S3_SECRET_ACCESS_KEY || process.env.AWS_SECRET_ACCESS_KEY,\n bucket: process.env.S3_BUCKET,\n publicUrl: process.env.S3_PUBLIC_URL,\n forcePathStyle: process.env.S3_FORCE_PATH_STYLE === \"true\",\n signedUrlExpiry: process.env.S3_SIGNED_URL_EXPIRY\n ? parseInt(process.env.S3_SIGNED_URL_EXPIRY)\n : undefined,\n },\n email: {\n provider:\n process.env.PLATFORM_EMAIL_PROVIDER ||\n process.env.EMAIL_PROVIDER ||\n \"memory\",\n host: process.env.SMTP_HOST,\n port: process.env.SMTP_PORT ? parseInt(process.env.SMTP_PORT) : undefined,\n secure: process.env.SMTP_SECURE === \"true\",\n username: process.env.SMTP_USERNAME,\n password: process.env.SMTP_PASSWORD,\n apiKey: process.env.RESEND_API_KEY,\n from: process.env.EMAIL_FROM,\n replyTo: process.env.EMAIL_REPLY_TO,\n },\n queue: {\n provider:\n process.env.PLATFORM_QUEUE_PROVIDER ||\n process.env.QUEUE_PROVIDER ||\n \"memory\",\n redisUrl: process.env.REDIS_URL,\n queueName: process.env.QUEUE_NAME,\n concurrency: process.env.QUEUE_CONCURRENCY\n ? parseInt(process.env.QUEUE_CONCURRENCY)\n : undefined,\n maxRetries: process.env.QUEUE_MAX_RETRIES\n ? parseInt(process.env.QUEUE_MAX_RETRIES)\n : undefined,\n },\n ai: {\n enabled: process.env.AI_ENABLED === \"true\",\n provider:\n (process.env.AI_PROVIDER as\n | \"memory\"\n | \"openai\"\n | \"anthropic\"\n | \"google\") || \"memory\",\n apiKey:\n process.env.OPENAI_API_KEY ||\n process.env.ANTHROPIC_API_KEY ||\n process.env.GOOGLE_AI_API_KEY,\n model: process.env.AI_MODEL,\n maxTokens: process.env.AI_MAX_TOKENS\n ? parseInt(process.env.AI_MAX_TOKENS)\n : undefined,\n temperature: process.env.AI_TEMPERATURE\n ? parseFloat(process.env.AI_TEMPERATURE)\n : undefined,\n timeout: process.env.AI_TIMEOUT\n ? parseInt(process.env.AI_TIMEOUT)\n : undefined,\n baseUrl: process.env.AI_BASE_URL,\n },\n rag: {\n enabled: process.env.RAG_ENABLED === \"true\",\n provider:\n (process.env.RAG_PROVIDER as \"memory\" | \"pinecone\" | \"weaviate\") ||\n \"memory\",\n apiKey: process.env.PINECONE_API_KEY,\n environment: process.env.PINECONE_ENVIRONMENT,\n indexName: process.env.PINECONE_INDEX || process.env.RAG_INDEX_NAME,\n namespace: process.env.RAG_NAMESPACE,\n host: process.env.WEAVIATE_HOST,\n embeddingProvider:\n (process.env.EMBEDDING_PROVIDER as\n | \"memory\"\n | \"openai\"\n | \"anthropic\"\n | \"google\") || \"memory\",\n embeddingApiKey:\n process.env.EMBEDDING_API_KEY || process.env.OPENAI_API_KEY,\n embeddingModel: process.env.EMBEDDING_MODEL,\n },\n crypto: {\n enabled: process.env.CRYPTO_ENABLED === \"true\",\n masterKey: process.env.CRYPTO_MASTER_KEY,\n hmacKey: process.env.CRYPTO_HMAC_KEY,\n },\n security: {\n enforceTls: process.env.SECURITY_ENFORCE_TLS !== \"false\",\n tlsWarnOnly: process.env.SECURITY_TLS_WARN_ONLY === \"true\",\n },\n resilience: {\n retry: {\n enabled: process.env.RESILIENCE_RETRY_ENABLED !== \"false\",\n maxAttempts: process.env.RESILIENCE_RETRY_MAX_ATTEMPTS\n ? parseInt(process.env.RESILIENCE_RETRY_MAX_ATTEMPTS)\n : undefined,\n baseDelay: process.env.RESILIENCE_RETRY_BASE_DELAY\n ? parseInt(process.env.RESILIENCE_RETRY_BASE_DELAY)\n : undefined,\n maxDelay: process.env.RESILIENCE_RETRY_MAX_DELAY\n ? parseInt(process.env.RESILIENCE_RETRY_MAX_DELAY)\n : undefined,\n },\n circuitBreaker: {\n enabled: process.env.RESILIENCE_CIRCUIT_BREAKER_ENABLED !== \"false\",\n failureThreshold: process.env.RESILIENCE_CIRCUIT_BREAKER_THRESHOLD\n ? parseInt(process.env.RESILIENCE_CIRCUIT_BREAKER_THRESHOLD)\n : undefined,\n resetTimeout: process.env.RESILIENCE_CIRCUIT_BREAKER_RESET_TIMEOUT\n ? parseInt(process.env.RESILIENCE_CIRCUIT_BREAKER_RESET_TIMEOUT)\n : undefined,\n },\n timeout: {\n enabled: process.env.RESILIENCE_TIMEOUT_ENABLED !== \"false\",\n default: process.env.RESILIENCE_TIMEOUT_DEFAULT\n ? parseInt(process.env.RESILIENCE_TIMEOUT_DEFAULT)\n : undefined,\n },\n },\n observability: {\n logging: {\n level:\n (process.env.LOG_LEVEL as \"debug\" | \"info\" | \"warn\" | \"error\") ||\n \"info\",\n format: (process.env.LOG_FORMAT as \"json\" | \"pretty\") || \"json\",\n },\n metrics: {\n enabled: process.env.METRICS_ENABLED === \"true\",\n prefix: process.env.METRICS_PREFIX,\n },\n tracing: {\n enabled: process.env.TRACING_ENABLED === \"true\",\n provider:\n (process.env.TRACING_PROVIDER as \"noop\" | \"memory\" | \"otlp\") ||\n \"noop\",\n serviceName: process.env.SERVICE_NAME || process.env.OTEL_SERVICE_NAME,\n serviceVersion: process.env.SERVICE_VERSION,\n environment: process.env.NODE_ENV,\n sampleRate: process.env.TRACING_SAMPLE_RATE\n ? parseFloat(process.env.TRACING_SAMPLE_RATE)\n : undefined,\n endpoint:\n process.env.OTEL_EXPORTER_OTLP_ENDPOINT ||\n process.env.TRACING_ENDPOINT,\n exporterType:\n (process.env.OTEL_EXPORTER_TYPE as\n | \"otlp-http\"\n | \"otlp-grpc\"\n | \"console\") || \"otlp-http\",\n },\n },\n middleware: {\n enabled: process.env.MIDDLEWARE_ENABLED !== \"false\",\n logging: process.env.MIDDLEWARE_LOGGING !== \"false\",\n metrics: process.env.MIDDLEWARE_METRICS === \"true\",\n slowQuery: {\n enabled: process.env.MIDDLEWARE_SLOW_QUERY !== \"false\",\n thresholdMs: process.env.MIDDLEWARE_SLOW_QUERY_THRESHOLD\n ? parseInt(process.env.MIDDLEWARE_SLOW_QUERY_THRESHOLD)\n : undefined,\n },\n },\n });\n}\n\n/**\n * Validate configuration object\n * @throws ZodError if validation fails\n */\nexport function validateConfig(config: unknown): PlatformConfig {\n return PlatformConfigSchema.parse(config);\n}\n\n/**\n * Safely validate configuration, returning errors instead of throwing\n */\nexport function safeValidateConfig(config: unknown): {\n success: boolean;\n data?: PlatformConfig;\n errors?: z.ZodError;\n} {\n const result = PlatformConfigSchema.safeParse(config);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return { success: false, errors: result.error };\n}\n\n/**\n * Get configuration with defaults applied\n */\nexport function getDefaultConfig(): PlatformConfig {\n return PlatformConfigSchema.parse({});\n}\n","/**\n * Distributed Tracing Interface\n *\n * Provides vendor-agnostic distributed tracing for observability.\n * Supports OpenTelemetry, Jaeger, Zipkin, and custom implementations.\n */\n\n// ═══════════════════════════════════════════════════════════════\n// TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport type SpanKind =\n | \"internal\"\n | \"server\"\n | \"client\"\n | \"producer\"\n | \"consumer\";\n\nexport type SpanStatusCode = \"unset\" | \"ok\" | \"error\";\n\nexport interface SpanStatus {\n code: SpanStatusCode;\n message?: string;\n}\n\nexport interface SpanContext {\n traceId: string;\n spanId: string;\n traceFlags: number;\n traceState?: string;\n}\n\nexport interface SpanOptions {\n /** Type of span */\n kind?: SpanKind;\n\n /** Initial attributes */\n attributes?: Record<string, string | number | boolean>;\n\n /** Parent span (for manual context propagation) */\n parent?: ISpan;\n\n /** Links to other spans */\n links?: SpanContext[];\n\n /** Start time (defaults to now) */\n startTime?: number;\n}\n\nexport interface SpanEvent {\n name: string;\n timestamp: number;\n attributes?: Record<string, string | number | boolean>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// SPAN INTERFACE\n// ═══════════════════════════════════════════════════════════════\n\nexport interface ISpan {\n /** Span name */\n readonly name: string;\n\n /** Span context (trace ID, span ID) */\n readonly context: SpanContext;\n\n /** Whether the span is recording */\n readonly isRecording: boolean;\n\n /**\n * Set a single attribute\n */\n setAttribute(key: string, value: string | number | boolean): this;\n\n /**\n * Set multiple attributes\n */\n setAttributes(attributes: Record<string, string | number | boolean>): this;\n\n /**\n * Add an event to the span\n */\n addEvent(\n name: string,\n attributes?: Record<string, string | number | boolean>,\n ): this;\n\n /**\n * Set the span status\n */\n setStatus(status: SpanStatus): this;\n\n /**\n * Record an exception\n */\n recordException(\n exception: Error,\n attributes?: Record<string, string | number | boolean>,\n ): this;\n\n /**\n * Update the span name\n */\n updateName(name: string): this;\n\n /**\n * End the span (required to export)\n */\n end(endTime?: number): void;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// TRACING INTERFACE\n// ═══════════════════════════════════════════════════════════════\n\nexport interface ITracing {\n /**\n * Create and start a new span\n */\n startSpan(name: string, options?: SpanOptions): ISpan;\n\n /**\n * Get the currently active span\n */\n getCurrentSpan(): ISpan | undefined;\n\n /**\n * Execute a function within a span context\n */\n withSpan<T>(name: string, fn: (span: ISpan) => T, options?: SpanOptions): T;\n\n /**\n * Execute an async function within a span context\n */\n withSpanAsync<T>(\n name: string,\n fn: (span: ISpan) => Promise<T>,\n options?: SpanOptions,\n ): Promise<T>;\n\n /**\n * Instrument a function with automatic span creation\n */\n instrument<TArgs extends unknown[], TReturn>(\n name: string,\n fn: (...args: TArgs) => TReturn,\n options?: SpanOptions,\n ): (...args: TArgs) => TReturn;\n\n /**\n * Instrument an async function with automatic span creation\n */\n instrumentAsync<TArgs extends unknown[], TReturn>(\n name: string,\n fn: (...args: TArgs) => Promise<TReturn>,\n options?: SpanOptions,\n ): (...args: TArgs) => Promise<TReturn>;\n\n /**\n * Extract trace context from headers (for incoming requests)\n */\n extractContext(\n headers: Record<string, string | string[] | undefined>,\n ): SpanContext | undefined;\n\n /**\n * Inject trace context into headers (for outgoing requests)\n */\n injectContext(headers: Record<string, string>): void;\n\n /**\n * Check if tracing is enabled and healthy\n */\n healthCheck(): Promise<boolean>;\n\n /**\n * Flush pending spans to the exporter\n */\n flush(): Promise<void>;\n\n /**\n * Shutdown the tracer\n */\n close(): Promise<void>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// TRACING CONFIGURATION\n// ═══════════════════════════════════════════════════════════════\n\nexport interface TracingConfig {\n /** Enable tracing */\n enabled: boolean;\n\n /** Service name for traces */\n serviceName: string;\n\n /** Service version */\n serviceVersion?: string;\n\n /** Environment (dev, staging, production) */\n environment?: string;\n\n /** Sampling rate (0.0 to 1.0) */\n sampleRate?: number;\n\n /** Exporter type */\n exporter?: \"console\" | \"otlp\" | \"jaeger\" | \"zipkin\" | \"none\";\n\n /** Exporter endpoint */\n endpoint?: string;\n\n /** Additional resource attributes */\n resourceAttributes?: Record<string, string>;\n\n /** Propagation format */\n propagation?: \"w3c\" | \"b3\" | \"jaeger\";\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MEMORY TRACING (For Testing)\n// ═══════════════════════════════════════════════════════════════\n\nclass MemorySpan implements ISpan {\n readonly name: string;\n readonly context: SpanContext;\n readonly isRecording: boolean = true;\n\n private _attributes: Record<string, string | number | boolean> = {};\n private _events: SpanEvent[] = [];\n private _status: SpanStatus = { code: \"unset\" };\n private _endTime?: number;\n private _startTime: number;\n\n constructor(name: string, traceId: string, parentSpanId?: string) {\n this.name = name;\n this._startTime = Date.now();\n this.context = {\n traceId,\n spanId: this.generateSpanId(),\n traceFlags: 1,\n };\n }\n\n private generateSpanId(): string {\n return randomBytes(8).toString(\"hex\");\n }\n\n setAttribute(key: string, value: string | number | boolean): this {\n this._attributes[key] = value;\n return this;\n }\n\n setAttributes(attributes: Record<string, string | number | boolean>): this {\n Object.assign(this._attributes, attributes);\n return this;\n }\n\n addEvent(\n name: string,\n attributes?: Record<string, string | number | boolean>,\n ): this {\n this._events.push({ name, timestamp: Date.now(), attributes });\n return this;\n }\n\n setStatus(status: SpanStatus): this {\n this._status = status;\n return this;\n }\n\n recordException(\n exception: Error,\n attributes?: Record<string, string | number | boolean>,\n ): this {\n this.addEvent(\"exception\", {\n \"exception.type\": exception.name,\n \"exception.message\": exception.message,\n \"exception.stacktrace\": exception.stack || \"\",\n ...attributes,\n });\n this.setStatus({ code: \"error\", message: exception.message });\n return this;\n }\n\n updateName(name: string): this {\n (this as { name: string }).name = name;\n return this;\n }\n\n end(endTime?: number): void {\n this._endTime = endTime ?? Date.now();\n }\n\n // Testing helpers\n getAttributes(): Record<string, string | number | boolean> {\n return { ...this._attributes };\n }\n\n getEvents(): SpanEvent[] {\n return [...this._events];\n }\n\n getStatus(): SpanStatus {\n return { ...this._status };\n }\n\n getDuration(): number | undefined {\n return this._endTime ? this._endTime - this._startTime : undefined;\n }\n\n isEnded(): boolean {\n return this._endTime !== undefined;\n }\n}\n\nimport { randomBytes } from \"crypto\";\n\nexport class MemoryTracing implements ITracing {\n private spans: MemorySpan[] = [];\n private currentSpan: MemorySpan | undefined;\n private traceId: string;\n\n constructor() {\n this.traceId = this.generateTraceId();\n }\n\n private generateTraceId(): string {\n return randomBytes(16).toString(\"hex\");\n }\n\n startSpan(name: string, options?: SpanOptions): ISpan {\n const span = new MemorySpan(\n name,\n this.traceId,\n this.currentSpan?.context.spanId,\n );\n\n if (options?.attributes) {\n span.setAttributes(options.attributes);\n }\n\n this.spans.push(span);\n this.currentSpan = span;\n\n return span;\n }\n\n getCurrentSpan(): ISpan | undefined {\n return this.currentSpan;\n }\n\n withSpan<T>(name: string, fn: (span: ISpan) => T, options?: SpanOptions): T {\n const span = this.startSpan(name, options);\n try {\n const result = fn(span);\n span.setStatus({ code: \"ok\" });\n return result;\n } catch (error) {\n span.recordException(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n } finally {\n span.end();\n }\n }\n\n async withSpanAsync<T>(\n name: string,\n fn: (span: ISpan) => Promise<T>,\n options?: SpanOptions,\n ): Promise<T> {\n const span = this.startSpan(name, options);\n try {\n const result = await fn(span);\n span.setStatus({ code: \"ok\" });\n return result;\n } catch (error) {\n span.recordException(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n } finally {\n span.end();\n }\n }\n\n instrument<TArgs extends unknown[], TReturn>(\n name: string,\n fn: (...args: TArgs) => TReturn,\n options?: SpanOptions,\n ): (...args: TArgs) => TReturn {\n return (...args: TArgs) => this.withSpan(name, () => fn(...args), options);\n }\n\n instrumentAsync<TArgs extends unknown[], TReturn>(\n name: string,\n fn: (...args: TArgs) => Promise<TReturn>,\n options?: SpanOptions,\n ): (...args: TArgs) => Promise<TReturn> {\n return (...args: TArgs) =>\n this.withSpanAsync(name, () => fn(...args), options);\n }\n\n extractContext(\n headers: Record<string, string | string[] | undefined>,\n ): SpanContext | undefined {\n const traceparent = headers[\"traceparent\"];\n if (!traceparent || typeof traceparent !== \"string\") return undefined;\n\n // Parse W3C Trace Context format: version-traceId-spanId-flags\n const parts = traceparent.split(\"-\");\n if (parts.length !== 4) return undefined;\n\n return {\n traceId: parts[1]!,\n spanId: parts[2]!,\n traceFlags: parseInt(parts[3]!, 16),\n };\n }\n\n injectContext(headers: Record<string, string>): void {\n if (this.currentSpan) {\n const ctx = this.currentSpan.context;\n headers[\"traceparent\"] =\n `00-${ctx.traceId}-${ctx.spanId}-${ctx.traceFlags.toString(16).padStart(2, \"0\")}`;\n }\n }\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n async flush(): Promise<void> {\n // No-op for memory implementation\n }\n\n async close(): Promise<void> {\n this.spans = [];\n this.currentSpan = undefined;\n }\n\n // Testing helpers\n getSpans(): MemorySpan[] {\n return [...this.spans];\n }\n\n getCompletedSpans(): MemorySpan[] {\n return this.spans.filter((s) => s.isEnded());\n }\n\n clear(): void {\n this.spans = [];\n this.currentSpan = undefined;\n this.traceId = this.generateTraceId();\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// NOOP TRACING (Disabled)\n// ═══════════════════════════════════════════════════════════════\n\nclass NoopSpan implements ISpan {\n readonly name: string = \"\";\n readonly context: SpanContext = { traceId: \"\", spanId: \"\", traceFlags: 0 };\n readonly isRecording: boolean = false;\n\n setAttribute(): this {\n return this;\n }\n setAttributes(): this {\n return this;\n }\n addEvent(): this {\n return this;\n }\n setStatus(): this {\n return this;\n }\n recordException(): this {\n return this;\n }\n updateName(): this {\n return this;\n }\n end(): void {}\n}\n\nexport class NoopTracing implements ITracing {\n private noopSpan = new NoopSpan();\n\n startSpan(): ISpan {\n return this.noopSpan;\n }\n\n getCurrentSpan(): ISpan | undefined {\n return undefined;\n }\n\n withSpan<T>(_name: string, fn: (span: ISpan) => T): T {\n return fn(this.noopSpan);\n }\n\n async withSpanAsync<T>(\n _name: string,\n fn: (span: ISpan) => Promise<T>,\n ): Promise<T> {\n return fn(this.noopSpan);\n }\n\n instrument<TArgs extends unknown[], TReturn>(\n _name: string,\n fn: (...args: TArgs) => TReturn,\n ): (...args: TArgs) => TReturn {\n return fn;\n }\n\n instrumentAsync<TArgs extends unknown[], TReturn>(\n _name: string,\n fn: (...args: TArgs) => Promise<TReturn>,\n ): (...args: TArgs) => Promise<TReturn> {\n return fn;\n }\n\n extractContext(): SpanContext | undefined {\n return undefined;\n }\n\n injectContext(): void {}\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n async flush(): Promise<void> {}\n\n async close(): Promise<void> {}\n}\n","/**\n * Logger Interface\n * Standardizes logging across the platform\n */\n\n/**\n * Log levels in order of severity\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\n/**\n * Metadata that can be attached to log entries\n */\nexport interface LogMeta {\n /** Error object if logging an error */\n error?: Error;\n /** Duration in milliseconds (for timing operations) */\n duration?: number;\n /** Request ID for tracing */\n requestId?: string;\n /** User ID if applicable */\n userId?: string;\n /** Any additional key-value pairs */\n [key: string]: unknown;\n}\n\n/**\n * A structured log entry\n */\nexport interface LogEntry {\n /** Log level */\n level: LogLevel;\n /** Log message */\n message: string;\n /** When the log was created */\n timestamp: Date;\n /** Optional metadata */\n meta?: LogMeta;\n /** Logger context (e.g., service name) */\n context?: Record<string, unknown>;\n}\n\n/**\n * Logger interface for structured logging\n */\nexport interface ILogger {\n /**\n * Log a debug message (for development/troubleshooting)\n */\n debug(message: string, meta?: LogMeta): void;\n\n /**\n * Log an informational message\n */\n info(message: string, meta?: LogMeta): void;\n\n /**\n * Log a warning message\n */\n warn(message: string, meta?: LogMeta): void;\n\n /**\n * Log an error message\n */\n error(message: string, meta?: LogMeta): void;\n\n /**\n * Create a child logger with additional context\n * @param context Additional context to include in all logs from this child\n */\n child(context: Record<string, unknown>): ILogger;\n}\n\n/**\n * Configuration options for loggers\n */\nexport interface LoggerConfig {\n /** Minimum level to log */\n level?: LogLevel;\n /** Whether to pretty print (for development) */\n pretty?: boolean;\n /** Service name to include in logs */\n service?: string;\n /** Environment name */\n environment?: string;\n}\n\n/**\n * Console logger implementation (for development)\n */\nexport class ConsoleLogger implements ILogger {\n private context: Record<string, unknown>;\n private level: LogLevel;\n\n private static levelPriority: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n };\n\n constructor(config: LoggerConfig = {}) {\n this.context = {\n service: config.service,\n environment: config.environment,\n };\n this.level = config.level || \"info\";\n }\n\n private shouldLog(level: LogLevel): boolean {\n return (\n ConsoleLogger.levelPriority[level] >=\n ConsoleLogger.levelPriority[this.level]\n );\n }\n\n private log(level: LogLevel, message: string, meta?: LogMeta): void {\n if (!this.shouldLog(level)) return;\n\n const entry: LogEntry = {\n level,\n message,\n timestamp: new Date(),\n meta,\n context: this.context,\n };\n\n const prefix = `[${entry.timestamp.toISOString()}] [${level.toUpperCase()}]`;\n const contextStr =\n Object.keys(this.context).length > 0\n ? ` [${Object.entries(this.context)\n .map(([k, v]) => `${k}=${v}`)\n .join(\" \")}]`\n : \"\";\n\n switch (level) {\n case \"debug\":\n console.debug(`${prefix}${contextStr} ${message}`, meta || \"\");\n break;\n case \"info\":\n console.info(`${prefix}${contextStr} ${message}`, meta || \"\");\n break;\n case \"warn\":\n console.warn(`${prefix}${contextStr} ${message}`, meta || \"\");\n break;\n case \"error\":\n console.error(`${prefix}${contextStr} ${message}`, meta || \"\");\n if (meta?.error) {\n console.error(meta.error);\n }\n break;\n }\n }\n\n debug(message: string, meta?: LogMeta): void {\n this.log(\"debug\", message, meta);\n }\n\n info(message: string, meta?: LogMeta): void {\n this.log(\"info\", message, meta);\n }\n\n warn(message: string, meta?: LogMeta): void {\n this.log(\"warn\", message, meta);\n }\n\n error(message: string, meta?: LogMeta): void {\n this.log(\"error\", message, meta);\n }\n\n child(context: Record<string, unknown>): ILogger {\n const childLogger = new ConsoleLogger({ level: this.level });\n childLogger.context = { ...this.context, ...context };\n return childLogger;\n }\n}\n\n/**\n * No-op logger for testing or when logging is disabled\n */\nexport class NoopLogger implements ILogger {\n debug(): void {}\n info(): void {}\n warn(): void {}\n error(): void {}\n child(): ILogger {\n return this;\n }\n}\n","/**\n * Metrics Interface\n *\n * Provides observability through counters, gauges, histograms, and timers.\n */\n\n/**\n * Tags for metrics (key-value pairs for dimensions)\n */\nexport type MetricTags = Record<string, string | number | boolean>;\n\n/**\n * Metrics interface for observability\n */\nexport interface IMetrics {\n /**\n * Increment a counter by a value (default 1)\n *\n * @example\n * metrics.increment('api.requests', 1, { method: 'GET', path: '/users' })\n */\n increment(name: string, value?: number, tags?: MetricTags): void;\n\n /**\n * Decrement a counter by a value (default 1)\n *\n * @example\n * metrics.decrement('active.connections', 1, { server: 'api-1' })\n */\n decrement(name: string, value?: number, tags?: MetricTags): void;\n\n /**\n * Set a gauge to a specific value\n *\n * @example\n * metrics.gauge('queue.size', 42, { queue: 'emails' })\n */\n gauge(name: string, value: number, tags?: MetricTags): void;\n\n /**\n * Record a value in a histogram (for distributions)\n *\n * @example\n * metrics.histogram('response.size', 1024, { endpoint: '/api/users' })\n */\n histogram(name: string, value: number, tags?: MetricTags): void;\n\n /**\n * Record a timing value in milliseconds\n *\n * @example\n * metrics.timing('db.query.duration', 42, { table: 'users' })\n */\n timing(name: string, value: number, tags?: MetricTags): void;\n\n /**\n * Start a timer and return a function to stop it\n *\n * @example\n * const stop = metrics.startTimer('api.request.duration', { method: 'GET' })\n * // ... do work ...\n * stop() // Records the duration\n */\n startTimer(name: string, tags?: MetricTags): () => void;\n\n /**\n * Record a distribution value (similar to histogram but for Datadog)\n *\n * @example\n * metrics.distribution('payment.amount', 99.99, { currency: 'USD' })\n */\n distribution?(name: string, value: number, tags?: MetricTags): void;\n\n /**\n * Record a set value (count unique elements)\n *\n * @example\n * metrics.set('unique.users', 'user-123')\n */\n set?(name: string, value: string | number, tags?: MetricTags): void;\n\n /**\n * Flush all pending metrics to the backend\n */\n flush(): Promise<void>;\n\n /**\n * Close the metrics client\n */\n close(): Promise<void>;\n}\n\n/**\n * Memory-based metrics implementation for testing\n */\nexport class MemoryMetrics implements IMetrics {\n private counters: Map<string, { value: number; tags: MetricTags }[]> =\n new Map();\n private gauges: Map<\n string,\n { value: number; tags: MetricTags; timestamp: number }\n > = new Map();\n private histograms: Map<string, { values: number[]; tags: MetricTags }[]> =\n new Map();\n private timings: Map<string, { values: number[]; tags: MetricTags }[]> =\n new Map();\n private sets: Map<string, Set<string | number>> = new Map();\n\n increment(name: string, value = 1, tags: MetricTags = {}): void {\n const key = this.createKey(name, tags);\n const existing = this.counters.get(key);\n\n if (existing && existing[0]) {\n existing[0].value += value;\n } else {\n this.counters.set(key, [{ value, tags }]);\n }\n }\n\n decrement(name: string, value = 1, tags: MetricTags = {}): void {\n this.increment(name, -value, tags);\n }\n\n gauge(name: string, value: number, tags: MetricTags = {}): void {\n const key = this.createKey(name, tags);\n this.gauges.set(key, { value, tags, timestamp: Date.now() });\n }\n\n histogram(name: string, value: number, tags: MetricTags = {}): void {\n const key = this.createKey(name, tags);\n const existing = this.histograms.get(key);\n\n if (existing && existing[0]) {\n existing[0].values.push(value);\n } else {\n this.histograms.set(key, [{ values: [value], tags }]);\n }\n }\n\n timing(name: string, value: number, tags: MetricTags = {}): void {\n const key = this.createKey(name, tags);\n const existing = this.timings.get(key);\n\n if (existing && existing[0]) {\n existing[0].values.push(value);\n } else {\n this.timings.set(key, [{ values: [value], tags }]);\n }\n }\n\n startTimer(name: string, tags: MetricTags = {}): () => void {\n const start = Date.now();\n return () => {\n const duration = Date.now() - start;\n this.timing(name, duration, tags);\n };\n }\n\n distribution(name: string, value: number, tags: MetricTags = {}): void {\n this.histogram(name, value, tags);\n }\n\n set(name: string, value: string | number, tags: MetricTags = {}): void {\n const key = this.createKey(name, tags);\n let existing = this.sets.get(key);\n\n if (!existing) {\n existing = new Set();\n this.sets.set(key, existing);\n }\n\n existing.add(value);\n }\n\n async flush(): Promise<void> {\n // No-op for memory implementation\n }\n\n async close(): Promise<void> {\n // No-op for memory implementation\n }\n\n // ═══════════════════════════════════════════════════════════════\n // Test helpers\n // ═══════════════════════════════════════════════════════════════\n\n /**\n * Get counter value\n */\n getCounter(name: string, tags: MetricTags = {}): number {\n const key = this.createKey(name, tags);\n const data = this.counters.get(key);\n return data?.[0]?.value ?? 0;\n }\n\n /**\n * Get gauge value\n */\n getGauge(name: string, tags: MetricTags = {}): number | undefined {\n const key = this.createKey(name, tags);\n return this.gauges.get(key)?.value;\n }\n\n /**\n * Get histogram values\n */\n getHistogram(name: string, tags: MetricTags = {}): number[] {\n const key = this.createKey(name, tags);\n return this.histograms.get(key)?.[0]?.values ?? [];\n }\n\n /**\n * Get timing values\n */\n getTiming(name: string, tags: MetricTags = {}): number[] {\n const key = this.createKey(name, tags);\n return this.timings.get(key)?.[0]?.values ?? [];\n }\n\n /**\n * Get set size\n */\n getSetSize(name: string, tags: MetricTags = {}): number {\n const key = this.createKey(name, tags);\n return this.sets.get(key)?.size ?? 0;\n }\n\n /**\n * Get all metrics as a summary\n */\n getSummary(): MetricsSummary {\n const summary: MetricsSummary = {\n counters: {},\n gauges: {},\n histograms: {},\n timings: {},\n sets: {},\n };\n\n for (const [key, data] of this.counters) {\n const first = data[0];\n if (first) {\n summary.counters[key] = first.value;\n }\n }\n\n for (const [key, data] of this.gauges) {\n summary.gauges[key] = data.value;\n }\n\n for (const [key, data] of this.histograms) {\n const first = data[0];\n if (first) {\n const values = first.values;\n summary.histograms[key] = {\n count: values.length,\n sum: values.reduce((a, b) => a + b, 0),\n min: Math.min(...values),\n max: Math.max(...values),\n avg:\n values.length > 0\n ? values.reduce((a, b) => a + b, 0) / values.length\n : 0,\n };\n }\n }\n\n for (const [key, data] of this.timings) {\n const first = data[0];\n if (first) {\n const values = first.values;\n summary.timings[key] = {\n count: values.length,\n sum: values.reduce((a, b) => a + b, 0),\n min: Math.min(...values),\n max: Math.max(...values),\n avg:\n values.length > 0\n ? values.reduce((a, b) => a + b, 0) / values.length\n : 0,\n p50: this.percentile(values, 50),\n p95: this.percentile(values, 95),\n p99: this.percentile(values, 99),\n };\n }\n }\n\n for (const [key, data] of this.sets) {\n summary.sets[key] = data.size;\n }\n\n return summary;\n }\n\n /**\n * Reset all metrics\n */\n reset(): void {\n this.counters.clear();\n this.gauges.clear();\n this.histograms.clear();\n this.timings.clear();\n this.sets.clear();\n }\n\n private createKey(name: string, tags: MetricTags): string {\n const tagStr = Object.entries(tags)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}:${v}`)\n .join(\",\");\n return tagStr ? `${name}|${tagStr}` : name;\n }\n\n private percentile(values: number[], p: number): number {\n if (values.length === 0) return 0;\n\n const sorted = [...values].sort((a, b) => a - b);\n const index = Math.ceil((p / 100) * sorted.length) - 1;\n const safeIndex = Math.max(0, index);\n return sorted[safeIndex] ?? 0;\n }\n}\n\n/**\n * No-op metrics implementation\n */\nexport class NoopMetrics implements IMetrics {\n increment(): void {}\n decrement(): void {}\n gauge(): void {}\n histogram(): void {}\n timing(): void {}\n startTimer(): () => void {\n return () => {};\n }\n distribution(): void {}\n set(): void {}\n async flush(): Promise<void> {}\n async close(): Promise<void> {}\n}\n\n/**\n * Summary of all metrics\n */\nexport interface MetricsSummary {\n counters: Record<string, number>;\n gauges: Record<string, number>;\n histograms: Record<string, HistogramStats>;\n timings: Record<string, TimingStats>;\n sets: Record<string, number>;\n}\n\n/**\n * Histogram statistics\n */\nexport interface HistogramStats {\n count: number;\n sum: number;\n min: number;\n max: number;\n avg: number;\n}\n\n/**\n * Timing statistics\n */\nexport interface TimingStats extends HistogramStats {\n p50: number;\n p95: number;\n p99: number;\n}\n\n/**\n * Create a scoped metrics instance with a prefix\n */\nexport function createScopedMetrics(\n metrics: IMetrics,\n prefix: string,\n defaultTags: MetricTags = {},\n): IMetrics {\n const prefixedName = (name: string) => `${prefix}.${name}`;\n const mergedTags = (tags?: MetricTags) => ({ ...defaultTags, ...tags });\n\n return {\n increment(name, value, tags) {\n metrics.increment(prefixedName(name), value, mergedTags(tags));\n },\n decrement(name, value, tags) {\n metrics.decrement(prefixedName(name), value, mergedTags(tags));\n },\n gauge(name, value, tags) {\n metrics.gauge(prefixedName(name), value, mergedTags(tags));\n },\n histogram(name, value, tags) {\n metrics.histogram(prefixedName(name), value, mergedTags(tags));\n },\n timing(name, value, tags) {\n metrics.timing(prefixedName(name), value, mergedTags(tags));\n },\n startTimer(name, tags) {\n return metrics.startTimer(prefixedName(name), mergedTags(tags));\n },\n distribution(name, value, tags) {\n metrics.distribution?.(prefixedName(name), value, mergedTags(tags));\n },\n set(name, value, tags) {\n metrics.set?.(prefixedName(name), value, mergedTags(tags));\n },\n flush: () => metrics.flush(),\n close: () => metrics.close(),\n };\n}\n","/**\n * Platform Factory\n * Create a platform instance with configured adapters\n */\n\nimport {\n IPlatform,\n PlatformHealthStatus,\n IDatabase,\n ICache,\n IStorage,\n IEmail,\n IQueue,\n ILogger,\n IMetrics,\n ITracing,\n} from \"./interfaces\";\nimport type { IAI, IRAG, ICrypto } from \"./interfaces\";\nimport { PlatformConfig, loadConfig } from \"./config\";\n\n// Memory adapters (always available)\nimport { MemoryDatabase } from \"./adapters/memory/MemoryDatabase\";\nimport { MemoryCache } from \"./adapters/memory/MemoryCache\";\nimport { MemoryStorage } from \"./adapters/memory/MemoryStorage\";\nimport { MemoryEmail } from \"./adapters/memory/MemoryEmail\";\nimport { MemoryQueue } from \"./adapters/memory/MemoryQueue\";\n\n// Console adapters\nimport { ConsoleEmail } from \"./adapters/console/ConsoleEmail\";\n\n// Tracing adapters (always available)\nimport { MemoryTracing, NoopTracing } from \"./interfaces/ITracing\";\n\n// Logger and Metrics (always available)\nimport { ConsoleLogger, NoopLogger } from \"./interfaces/ILogger\";\nimport { MemoryMetrics, NoopMetrics } from \"./interfaces/IMetrics\";\n\n// AI/RAG Memory adapters (always available)\nimport { MemoryAI } from \"./interfaces/IAI\";\nimport { MemoryRAG } from \"./interfaces/IRAG\";\n\n// Crypto adapters\nimport { MemoryCrypto } from \"./adapters/memory/MemoryCrypto\";\n\n/**\n * Create a database adapter based on configuration\n */\nasync function createDatabaseAdapter(\n config: PlatformConfig,\n): Promise<IDatabase> {\n switch (config.database.provider) {\n case \"postgres\": {\n const connectionString =\n config.database.connectionString ||\n config.database.url ||\n process.env.DATABASE_URL;\n if (!connectionString) {\n throw new Error(\n \"PostgreSQL requires DATABASE_URL, url, or connectionString configuration\",\n );\n }\n const { PostgresDatabase } =\n await import(\"./adapters/postgres/PostgresDatabase\");\n return PostgresDatabase.create({\n connectionString,\n max: config.database.poolSize,\n ssl: config.database.ssl,\n connectionTimeoutMillis: config.database.connectionTimeout,\n });\n }\n case \"supabase\": {\n if (!config.database.supabaseUrl || !config.database.supabaseAnonKey) {\n throw new Error(\n \"Supabase requires SUPABASE_URL and SUPABASE_ANON_KEY environment variables\",\n );\n }\n const { createClient } = await import(\"@supabase/supabase-js\");\n const { SupabaseDatabase } =\n await import(\"./adapters/supabase/SupabaseDatabase\");\n const client = createClient(\n config.database.supabaseUrl,\n config.database.supabaseServiceRoleKey ||\n config.database.supabaseAnonKey,\n );\n return new SupabaseDatabase(client);\n }\n case \"memory\":\n default:\n return new MemoryDatabase();\n }\n}\n\n/**\n * Create a cache adapter based on configuration\n */\nasync function createCacheAdapter(config: PlatformConfig): Promise<ICache> {\n switch (config.cache.provider) {\n case \"redis\": {\n const url = config.cache.url || process.env.REDIS_URL;\n if (!url) {\n throw new Error(\"Redis requires REDIS_URL or cache.url configuration\");\n }\n const { RedisCache } = await import(\"./adapters/redis/RedisCache\");\n return RedisCache.create({\n url,\n keyPrefix: config.cache.keyPrefix,\n });\n }\n case \"upstash\": {\n if (!config.cache.upstashUrl || !config.cache.upstashToken) {\n throw new Error(\n \"Upstash requires UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN environment variables\",\n );\n }\n const { Redis } = await import(\"@upstash/redis\");\n const { UpstashCache } = await import(\"./adapters/upstash/UpstashCache\");\n const client = new Redis({\n url: config.cache.upstashUrl,\n token: config.cache.upstashToken,\n });\n return new UpstashCache(client);\n }\n case \"memory\":\n default:\n return new MemoryCache();\n }\n}\n\n/**\n * Create a storage adapter based on configuration\n */\nasync function createStorageAdapter(config: PlatformConfig): Promise<IStorage> {\n switch (config.storage.provider) {\n case \"supabase\": {\n const url = config.database.supabaseUrl || process.env.SUPABASE_URL;\n const apiKey =\n config.database.supabaseServiceRoleKey ||\n config.database.supabaseAnonKey ||\n process.env.SUPABASE_ANON_KEY;\n const bucket =\n config.storage.bucket ||\n process.env.SUPABASE_STORAGE_BUCKET ||\n \"uploads\";\n\n if (!url || !apiKey) {\n throw new Error(\n \"Supabase storage requires SUPABASE_URL and SUPABASE_ANON_KEY\",\n );\n }\n\n const { SupabaseStorage } =\n await import(\"./adapters/supabase-storage/SupabaseStorage\");\n return SupabaseStorage.create({\n url,\n apiKey,\n bucket,\n publicBucket: config.storage.publicUrl !== undefined,\n signedUrlExpiry: config.storage.signedUrlExpiry,\n });\n }\n case \"s3\":\n case \"minio\":\n case \"r2\": {\n if (\n !config.storage.accessKey ||\n !config.storage.secretKey ||\n !config.storage.bucket\n ) {\n throw new Error(\n \"S3 requires S3_ACCESS_KEY, S3_SECRET_KEY, and S3_BUCKET environment variables\",\n );\n }\n const { S3Client } = await import(\"@aws-sdk/client-s3\");\n const { getSignedUrl } = await import(\"@aws-sdk/s3-request-presigner\");\n const { S3Storage } = await import(\"./adapters/s3/S3Storage\");\n\n const client = new S3Client({\n endpoint: config.storage.endpoint,\n region: config.storage.region || \"us-east-1\",\n credentials: {\n accessKeyId: config.storage.accessKey,\n secretAccessKey: config.storage.secretKey,\n },\n forcePathStyle:\n config.storage.forcePathStyle || config.storage.provider === \"minio\",\n });\n\n return new S3Storage(\n client,\n config.storage.bucket,\n getSignedUrl,\n config.storage.publicUrl,\n );\n }\n case \"memory\":\n default:\n return new MemoryStorage();\n }\n}\n\n/**\n * Create an email adapter based on configuration\n */\nasync function createEmailAdapter(config: PlatformConfig): Promise<IEmail> {\n switch (config.email.provider) {\n case \"smtp\": {\n if (!config.email.host || !config.email.port) {\n throw new Error(\n \"SMTP requires host and port configuration (SMTP_HOST, SMTP_PORT)\",\n );\n }\n const { SmtpEmail } = await import(\"./adapters/smtp/SmtpEmail\");\n return SmtpEmail.create({\n host: config.email.host,\n port: config.email.port,\n secure: config.email.secure,\n username: config.email.username,\n password: config.email.password,\n from: config.email.from,\n });\n }\n case \"resend\": {\n if (!config.email.apiKey) {\n throw new Error(\"Resend requires RESEND_API_KEY environment variable\");\n }\n const { Resend } = await import(\"resend\");\n const { ResendEmail } = await import(\"./adapters/resend/ResendEmail\");\n const client = new Resend(config.email.apiKey);\n return new ResendEmail(client, config.email.from);\n }\n case \"console\":\n return new ConsoleEmail();\n case \"memory\":\n default:\n return new MemoryEmail();\n }\n}\n\n/**\n * Create a queue adapter based on configuration\n */\nasync function createQueueAdapter(config: PlatformConfig): Promise<IQueue> {\n switch (config.queue.provider) {\n case \"bullmq\": {\n if (!config.queue.redisUrl && !config.cache.url) {\n throw new Error(\"BullMQ requires REDIS_URL environment variable\");\n }\n const { BullMQQueue } = await import(\"./adapters/bullmq/BullMQQueue\");\n return new BullMQQueue({\n redisUrl: config.queue.redisUrl || config.cache.url,\n queueName: \"platform-jobs\",\n });\n }\n case \"memory\":\n default:\n return new MemoryQueue();\n }\n}\n\n/**\n * Create a tracing adapter based on configuration\n */\nasync function createTracingAdapter(config: PlatformConfig): Promise<ITracing> {\n const tracingConfig = config.observability.tracing;\n\n // If tracing is disabled, return noop\n if (!tracingConfig.enabled) {\n return new NoopTracing();\n }\n\n switch (tracingConfig.provider) {\n case \"otlp\": {\n // OpenTelemetry adapter - dynamically imported\n const { OpenTelemetryTracing } =\n await import(\"./adapters/opentelemetry/OpenTelemetryTracing\");\n return OpenTelemetryTracing.create({\n serviceName: tracingConfig.serviceName || \"unknown-service\",\n serviceVersion: tracingConfig.serviceVersion,\n environment: tracingConfig.environment,\n endpoint: tracingConfig.endpoint,\n exporterType: tracingConfig.exporterType,\n sampleRate: tracingConfig.sampleRate,\n });\n }\n case \"memory\":\n return new MemoryTracing();\n case \"noop\":\n default:\n return new NoopTracing();\n }\n}\n\n/**\n * Create a logger based on configuration\n */\nfunction createLogger(config: PlatformConfig): ILogger {\n if (!config.observability.logging) {\n return new NoopLogger();\n }\n\n return new ConsoleLogger({\n level: config.observability.logging.level,\n service: config.observability.tracing.serviceName,\n environment: config.observability.tracing.environment,\n });\n}\n\n/**\n * Create a metrics collector based on configuration\n */\nfunction createMetrics(config: PlatformConfig): IMetrics {\n if (!config.observability.metrics.enabled) {\n return new NoopMetrics();\n }\n\n // MemoryMetrics is a simple in-memory implementation\n // Production metrics would use a dedicated backend (Prometheus, StatsD, etc.)\n return new MemoryMetrics();\n}\n\n/**\n * Create an AI adapter based on configuration\n */\nasync function createAIAdapter(config: PlatformConfig): Promise<IAI | null> {\n if (!config.ai.enabled) {\n return null;\n }\n\n switch (config.ai.provider) {\n case \"openai\": {\n if (!config.ai.apiKey) {\n throw new Error(\"OpenAI requires OPENAI_API_KEY environment variable\");\n }\n const { OpenAIAdapter } = await import(\"./adapters/openai/OpenAIAdapter\");\n return new OpenAIAdapter({\n apiKey: config.ai.apiKey,\n defaultChatModel: config.ai.model || \"gpt-4o\",\n defaultTimeoutMs: config.ai.timeout,\n baseURL: config.ai.baseUrl,\n });\n }\n case \"anthropic\": {\n if (!config.ai.apiKey) {\n throw new Error(\n \"Anthropic requires ANTHROPIC_API_KEY environment variable\",\n );\n }\n const { AnthropicAdapter } =\n await import(\"./adapters/anthropic/AnthropicAdapter\");\n return new AnthropicAdapter({\n apiKey: config.ai.apiKey,\n defaultChatModel: config.ai.model || \"claude-sonnet-4-20250514\",\n defaultTimeoutMs: config.ai.timeout,\n baseURL: config.ai.baseUrl,\n });\n }\n case \"google\": {\n if (!config.ai.apiKey) {\n throw new Error(\n \"Google AI requires GOOGLE_AI_API_KEY environment variable\",\n );\n }\n const { GoogleAIAdapter } =\n await import(\"./adapters/google/GoogleAIAdapter\");\n return new GoogleAIAdapter({\n apiKey: config.ai.apiKey,\n defaultChatModel: config.ai.model || \"gemini-1.5-pro\",\n defaultTimeoutMs: config.ai.timeout,\n });\n }\n case \"memory\":\n default:\n return new MemoryAI();\n }\n}\n\n/**\n * Create a RAG adapter based on configuration\n */\nasync function createRAGAdapter(\n config: PlatformConfig,\n ai?: IAI | null,\n): Promise<IRAG | null> {\n if (!config.rag.enabled) {\n return null;\n }\n\n switch (config.rag.provider) {\n case \"pinecone\": {\n if (!config.rag.apiKey || !config.rag.indexName) {\n throw new Error(\n \"Pinecone requires PINECONE_API_KEY and PINECONE_INDEX environment variables\",\n );\n }\n if (!ai) {\n throw new Error(\n \"Pinecone RAG requires an AI adapter for embeddings. Enable AI with AI_ENABLED=true\",\n );\n }\n const { createPineconeRAG } =\n await import(\"./adapters/pinecone/PineconeRAG\");\n return createPineconeRAG({\n apiKey: config.rag.apiKey,\n indexName: config.rag.indexName,\n defaultNamespace: config.rag.namespace,\n ai,\n });\n }\n case \"weaviate\": {\n if (!config.rag.host) {\n throw new Error(\"Weaviate requires WEAVIATE_HOST environment variable\");\n }\n const { createWeaviateRAG } =\n await import(\"./adapters/weaviate/WeaviateRAG\");\n return createWeaviateRAG({\n host: config.rag.host,\n apiKey: config.rag.apiKey,\n ai: ai || undefined,\n });\n }\n case \"memory\":\n default:\n return new MemoryRAG();\n }\n}\n\n/**\n * Create a crypto adapter based on configuration\n */\nasync function createCryptoAdapter(\n config: PlatformConfig,\n): Promise<ICrypto | null> {\n if (!config.crypto.enabled) {\n return null;\n }\n\n if (config.crypto.masterKey && config.crypto.masterKey.length >= 64) {\n const { NodeCrypto } = await import(\"./adapters/node-crypto/NodeCrypto\");\n return new NodeCrypto({\n masterKey: config.crypto.masterKey,\n hmacKey: config.crypto.hmacKey,\n });\n }\n\n // Fallback to memory adapter (testing/development)\n return new MemoryCrypto();\n}\n\n/**\n * Validate TLS configuration for production environments\n */\nfunction validateTlsSecurity(config: PlatformConfig): void {\n const isProduction = process.env.NODE_ENV === \"production\";\n if (!isProduction || !config.security.enforceTls) {\n return;\n }\n\n const warnings: string[] = [];\n\n // Check PostgreSQL SSL\n if (config.database.provider === \"postgres\") {\n const connStr = config.database.connectionString || config.database.url || \"\";\n const hasSSL = config.database.ssl || connStr.includes(\"sslmode=require\") || connStr.includes(\"sslmode=verify\");\n if (!hasSSL) {\n warnings.push(\n \"PostgreSQL: TLS/SSL not configured. Set database.ssl=true or add sslmode=require to connection string.\",\n );\n }\n }\n\n // Check Redis TLS\n if (config.cache.provider === \"redis\") {\n const url = config.cache.url || \"\";\n if (url && !url.startsWith(\"rediss://\")) {\n warnings.push(\n \"Redis: Connection URL uses redis:// instead of rediss:// (TLS). Consider enabling TLS.\",\n );\n }\n }\n\n // Check SMTP TLS\n if (config.email.provider === \"smtp\") {\n if (!config.email.secure) {\n warnings.push(\n \"SMTP: secure=false in production. Set email.secure=true for TLS.\",\n );\n }\n }\n\n if (warnings.length > 0) {\n const message = `[Security] TLS warnings in production:\\n - ${warnings.join(\"\\n - \")}`;\n if (config.security.tlsWarnOnly) {\n console.warn(message);\n } else {\n throw new Error(message);\n }\n }\n}\n\n/**\n * Create a platform instance (async version)\n */\nexport async function createPlatformAsync(\n config?: Partial<PlatformConfig>,\n): Promise<IPlatform> {\n const finalConfig = config ? deepMerge(loadConfig(), config) : loadConfig();\n\n // Validate TLS configuration for production\n validateTlsSecurity(finalConfig);\n\n const [db, cache, storage, email, queue, tracing, crypto] =\n await Promise.all([\n createDatabaseAdapter(finalConfig),\n createCacheAdapter(finalConfig),\n createStorageAdapter(finalConfig),\n createEmailAdapter(finalConfig),\n createQueueAdapter(finalConfig),\n createTracingAdapter(finalConfig),\n createCryptoAdapter(finalConfig),\n ]);\n\n const logger = createLogger(finalConfig);\n const metrics = createMetrics(finalConfig);\n\n // Create AI adapter first (RAG may depend on it for embeddings)\n const ai = await createAIAdapter(finalConfig);\n const rag = await createRAGAdapter(finalConfig, ai);\n\n return createPlatformFromAdapters(\n db,\n cache,\n storage,\n email,\n queue,\n logger,\n metrics,\n tracing,\n ai,\n rag,\n crypto,\n );\n}\n\n/**\n * Create a platform instance (sync version - uses memory adapters only)\n * For production adapters, use createPlatformAsync\n */\nexport function createPlatform(config?: Partial<PlatformConfig>): IPlatform {\n const finalConfig = config ? deepMerge(loadConfig(), config) : loadConfig();\n\n // Check if any production adapters are requested\n const hasProductionAdapters =\n finalConfig.database.provider !== \"memory\" ||\n finalConfig.cache.provider !== \"memory\" ||\n finalConfig.storage.provider !== \"memory\" ||\n (finalConfig.email.provider !== \"memory\" &&\n finalConfig.email.provider !== \"console\") ||\n finalConfig.observability.tracing.provider === \"otlp\" ||\n (finalConfig.ai.enabled && finalConfig.ai.provider !== \"memory\") ||\n (finalConfig.rag.enabled && finalConfig.rag.provider !== \"memory\");\n\n if (hasProductionAdapters) {\n console.warn(\n \"createPlatform() is synchronous and cannot initialize production adapters. \" +\n \"Use createPlatformAsync() for production adapters, or use memory/console adapters.\",\n );\n }\n\n // Create sync-compatible adapters\n const db = new MemoryDatabase();\n const cache = new MemoryCache();\n const storage = new MemoryStorage();\n const email =\n finalConfig.email.provider === \"console\"\n ? new ConsoleEmail()\n : new MemoryEmail();\n const queue = new MemoryQueue();\n const logger = createLogger(finalConfig);\n const metrics = createMetrics(finalConfig);\n const tracing =\n finalConfig.observability.tracing.provider === \"memory\"\n ? new MemoryTracing()\n : new NoopTracing();\n\n // Create memory AI/RAG if enabled\n const ai = finalConfig.ai.enabled ? new MemoryAI() : null;\n const rag = finalConfig.rag.enabled ? new MemoryRAG() : null;\n const crypto = finalConfig.crypto.enabled ? new MemoryCrypto() : null;\n\n return createPlatformFromAdapters(\n db,\n cache,\n storage,\n email,\n queue,\n logger,\n metrics,\n tracing,\n ai,\n rag,\n crypto,\n );\n}\n\n/**\n * Create platform object from adapters\n */\nfunction createPlatformFromAdapters(\n db: IDatabase,\n cache: ICache,\n storage: IStorage,\n email: IEmail,\n queue: IQueue,\n logger: ILogger,\n metrics: IMetrics,\n tracing: ITracing,\n ai?: IAI | null,\n rag?: IRAG | null,\n crypto?: ICrypto | null,\n): IPlatform {\n const platform: IPlatform = {\n db,\n cache,\n storage,\n email,\n queue,\n logger,\n metrics,\n tracing,\n\n async healthCheck(): Promise<PlatformHealthStatus> {\n const [\n dbHealth,\n cacheHealth,\n storageHealth,\n emailHealth,\n queueHealth,\n tracingHealth,\n ] = await Promise.all([\n db.healthCheck(),\n cache.healthCheck(),\n storage.healthCheck(),\n email.healthCheck(),\n queue.healthCheck(),\n tracing.healthCheck(),\n ]);\n\n return {\n healthy:\n dbHealth &&\n cacheHealth &&\n storageHealth &&\n emailHealth &&\n queueHealth &&\n tracingHealth,\n services: {\n database: dbHealth,\n cache: cacheHealth,\n storage: storageHealth,\n email: emailHealth,\n queue: queueHealth,\n tracing: tracingHealth,\n },\n timestamp: Date.now(),\n };\n },\n\n async close(): Promise<void> {\n await Promise.all([\n db.close(),\n cache.close(),\n queue.close(),\n tracing.close(),\n ]);\n },\n };\n\n // Add optional AI adapter\n if (ai) {\n (platform as IPlatform & { ai: IAI }).ai = ai;\n }\n\n // Add optional RAG adapter\n if (rag) {\n (platform as IPlatform & { rag: IRAG }).rag = rag;\n }\n\n // Add optional Crypto adapter\n if (crypto) {\n (platform as IPlatform & { crypto: ICrypto }).crypto = crypto;\n }\n\n return platform;\n}\n\n/**\n * Deep merge two objects\n */\nfunction deepMerge<T extends Record<string, unknown>>(\n target: T,\n source: Partial<T>,\n): T {\n const result = { ...target };\n\n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (\n sourceValue !== undefined &&\n typeof sourceValue === \"object\" &&\n sourceValue !== null &&\n !Array.isArray(sourceValue) &&\n typeof targetValue === \"object\" &&\n targetValue !== null &&\n !Array.isArray(targetValue)\n ) {\n result[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>,\n ) as T[Extract<keyof T, string>];\n } else if (sourceValue !== undefined) {\n result[key] = sourceValue as T[Extract<keyof T, string>];\n }\n }\n }\n\n return result;\n}\n","/**\r\n * MemoryCrypto - In-memory ICrypto adapter for testing\r\n * Uses Node.js built-in crypto module with keys stored in memory.\r\n */\r\n\r\nimport { randomBytes, createCipheriv, createDecipheriv, createHmac } from \"crypto\";\r\nimport type {\r\n ICrypto,\r\n EncryptedField,\r\n DeterministicEncryptedField,\r\n CryptoKeyMetadata,\r\n CryptoKeyStatus,\r\n EncryptOptions,\r\n KeyRotationResult,\r\n} from \"../../interfaces/ICrypto\";\r\n\r\ninterface StoredKey {\r\n id: string;\r\n key: Buffer;\r\n status: CryptoKeyStatus;\r\n createdAt: Date;\r\n}\r\n\r\nexport class MemoryCrypto implements ICrypto {\r\n private keys: Map<string, StoredKey> = new Map();\r\n private activeKeyId: string;\r\n private hmacKey: Buffer;\r\n\r\n constructor(options?: { masterKey?: string; hmacKey?: string }) {\r\n // Derive or generate keys\r\n const masterKeyBuf = options?.masterKey\r\n ? Buffer.from(options.masterKey, \"hex\")\r\n : randomBytes(32);\r\n this.hmacKey = options?.hmacKey\r\n ? Buffer.from(options.hmacKey, \"hex\")\r\n : randomBytes(32);\r\n\r\n // Create initial DEK\r\n const keyId = this.generateKeyId();\r\n this.keys.set(keyId, {\r\n id: keyId,\r\n key: masterKeyBuf,\r\n status: \"active\",\r\n createdAt: new Date(),\r\n });\r\n this.activeKeyId = keyId;\r\n }\r\n\r\n async encrypt(\r\n plaintext: string,\r\n options?: EncryptOptions,\r\n ): Promise<EncryptedField> {\r\n const keyId = options?.keyId || this.activeKeyId;\r\n const stored = this.keys.get(keyId);\r\n if (!stored) {\r\n throw new Error(`Key not found: ${keyId}`);\r\n }\r\n if (stored.status === \"retired\") {\r\n throw new Error(`Key is retired: ${keyId}`);\r\n }\r\n if (stored.status === \"decrypt-only\" && !options?.keyId) {\r\n throw new Error(`Key is decrypt-only: ${keyId}`);\r\n }\r\n\r\n const iv = randomBytes(12); // 96-bit IV for GCM\r\n const cipher = createCipheriv(\"aes-256-gcm\", stored.key, iv);\r\n\r\n if (options?.aad) {\r\n cipher.setAAD(Buffer.from(options.aad, \"utf8\"));\r\n }\r\n\r\n const encrypted = Buffer.concat([\r\n cipher.update(plaintext, \"utf8\"),\r\n cipher.final(),\r\n ]);\r\n const tag = cipher.getAuthTag();\r\n\r\n return {\r\n ciphertext: encrypted.toString(\"base64\"),\r\n iv: iv.toString(\"base64\"),\r\n tag: tag.toString(\"base64\"),\r\n keyId,\r\n algorithm: \"aes-256-gcm\",\r\n version: 1,\r\n };\r\n }\r\n\r\n async decrypt(\r\n field: EncryptedField,\r\n options?: EncryptOptions,\r\n ): Promise<string> {\r\n const stored = this.keys.get(field.keyId);\r\n if (!stored) {\r\n throw new Error(`Key not found: ${field.keyId}`);\r\n }\r\n if (stored.status === \"retired\") {\r\n throw new Error(`Key is retired and cannot decrypt: ${field.keyId}`);\r\n }\r\n\r\n const decipher = createDecipheriv(\r\n \"aes-256-gcm\",\r\n stored.key,\r\n Buffer.from(field.iv, \"base64\"),\r\n );\r\n decipher.setAuthTag(Buffer.from(field.tag, \"base64\"));\r\n\r\n if (options?.aad) {\r\n decipher.setAAD(Buffer.from(options.aad, \"utf8\"));\r\n }\r\n\r\n const decrypted = Buffer.concat([\r\n decipher.update(Buffer.from(field.ciphertext, \"base64\")),\r\n decipher.final(),\r\n ]);\r\n\r\n return decrypted.toString(\"utf8\");\r\n }\r\n\r\n async encryptDeterministic(\r\n plaintext: string,\r\n options?: EncryptOptions,\r\n ): Promise<DeterministicEncryptedField> {\r\n const hash = await this.computeHash(plaintext);\r\n const encrypted = await this.encrypt(plaintext, options);\r\n return { hash, encrypted };\r\n }\r\n\r\n async computeHash(plaintext: string): Promise<string> {\r\n return createHmac(\"sha256\", this.hmacKey)\r\n .update(plaintext, \"utf8\")\r\n .digest(\"hex\");\r\n }\r\n\r\n async encryptBatch(\r\n fields: Record<string, string>,\r\n options?: EncryptOptions,\r\n ): Promise<Record<string, EncryptedField>> {\r\n const result: Record<string, EncryptedField> = {};\r\n for (const [key, value] of Object.entries(fields)) {\r\n result[key] = await this.encrypt(value, options);\r\n }\r\n return result;\r\n }\r\n\r\n async decryptBatch(\r\n fields: Record<string, EncryptedField>,\r\n options?: EncryptOptions,\r\n ): Promise<Record<string, string>> {\r\n const result: Record<string, string> = {};\r\n for (const [key, value] of Object.entries(fields)) {\r\n result[key] = await this.decrypt(value, options);\r\n }\r\n return result;\r\n }\r\n\r\n async rotateKey(): Promise<KeyRotationResult> {\r\n const previousKeyId = this.activeKeyId;\r\n\r\n // Mark current key as decrypt-only\r\n const currentKey = this.keys.get(previousKeyId);\r\n if (currentKey) {\r\n currentKey.status = \"decrypt-only\";\r\n }\r\n\r\n // Generate new active key\r\n const newKeyId = this.generateKeyId();\r\n this.keys.set(newKeyId, {\r\n id: newKeyId,\r\n key: randomBytes(32),\r\n status: \"active\",\r\n createdAt: new Date(),\r\n });\r\n this.activeKeyId = newKeyId;\r\n\r\n return { newKeyId, previousKeyId };\r\n }\r\n\r\n async reEncrypt(\r\n field: EncryptedField,\r\n options?: EncryptOptions,\r\n ): Promise<EncryptedField> {\r\n const plaintext = await this.decrypt(field);\r\n return this.encrypt(plaintext, options);\r\n }\r\n\r\n async listKeys(): Promise<CryptoKeyMetadata[]> {\r\n return Array.from(this.keys.values()).map((k) => ({\r\n keyId: k.id,\r\n createdAt: k.createdAt,\r\n status: k.status,\r\n }));\r\n }\r\n\r\n async getActiveKeyId(): Promise<string> {\r\n return this.activeKeyId;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n const testPlain = \"health-check-test\";\r\n const encrypted = await this.encrypt(testPlain);\r\n const decrypted = await this.decrypt(encrypted);\r\n return decrypted === testPlain;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n private generateKeyId(): string {\r\n return `key_${randomBytes(8).toString(\"hex\")}`;\r\n }\r\n}\r\n"],"mappings":"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","names":["import_crypto","import_crypto","import_crypto","import_crypto","import_crypto","import_crypto","crypto"]}
1
+ {"version":3,"sources":["../src/interfaces/IAI.ts","../src/interfaces/IRAG.ts","../src/testing.ts","../src/adapters/memory/MemoryDatabase.ts","../src/adapters/memory/MemoryCache.ts","../src/adapters/memory/MemoryStorage.ts","../src/adapters/memory/MemoryEmail.ts","../src/interfaces/IQueue.ts","../src/context/CorrelationContext.ts","../src/adapters/memory/MemoryQueue.ts","../src/adapters/console/ConsoleEmail.ts","../src/interfaces/ISecrets.ts","../src/config.ts","../src/interfaces/ITracing.ts","../src/interfaces/ILogger.ts","../src/interfaces/IMetrics.ts","../src/factory.ts","../src/adapters/memory/MemoryCrypto.ts"],"sourcesContent":["/**\n * IAI - Core AI abstraction interface for platform-core\n *\n * Provides a vendor-agnostic interface for AI operations including:\n * - Text generation (chat, completion)\n * - Embeddings generation\n * - Model routing and fallback\n * - Streaming support\n * - Token usage tracking\n */\n\n// ═══════════════════════════════════════════════════════════════\n// CORE TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport type AIProvider =\n | \"openai\"\n | \"anthropic\"\n | \"google\"\n | \"azure\"\n | \"bedrock\"\n | \"custom\";\n\nexport type AIModelType =\n | \"chat\"\n | \"completion\"\n | \"embedding\"\n | \"image\"\n | \"audio\"\n | \"video\";\n\nexport type AIRole = \"system\" | \"user\" | \"assistant\" | \"function\" | \"tool\";\n\nexport interface AIMessage {\n role: AIRole;\n content: string;\n name?: string;\n toolCallId?: string;\n toolCalls?: AIToolCall[];\n}\n\nexport interface AIToolCall {\n id: string;\n type: \"function\";\n function: {\n name: string;\n arguments: string;\n };\n}\n\nexport interface AITool {\n type: \"function\";\n function: {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n };\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MODEL CONFIGURATION\n// ═══════════════════════════════════════════════════════════════\n\nexport interface AIModelConfig {\n /** Model identifier (e.g., 'gpt-4', 'claude-3-opus') */\n modelId: string;\n /** Provider for this model */\n provider: AIProvider;\n /** Model capabilities */\n capabilities: AIModelType[];\n /** Maximum context window in tokens */\n maxContextTokens: number;\n /** Maximum output tokens */\n maxOutputTokens: number;\n /** Cost per 1K input tokens in USD */\n inputCostPer1K: number;\n /** Cost per 1K output tokens in USD */\n outputCostPer1K: number;\n /** Supports streaming */\n supportsStreaming: boolean;\n /** Supports function/tool calling */\n supportsTools: boolean;\n /** Supports vision (image input) */\n supportsVision: boolean;\n /** Rate limits per minute */\n rateLimits?: {\n requestsPerMinute: number;\n tokensPerMinute: number;\n };\n /** Custom endpoint for self-hosted models */\n endpoint?: string;\n /** Additional provider-specific config */\n providerConfig?: Record<string, unknown>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// REQUEST/RESPONSE TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport interface AIChatRequest {\n messages: AIMessage[];\n model?: string;\n temperature?: number;\n maxTokens?: number;\n topP?: number;\n frequencyPenalty?: number;\n presencePenalty?: number;\n stop?: string | string[];\n tools?: AITool[];\n toolChoice?:\n | \"auto\"\n | \"none\"\n | \"required\"\n | { type: \"function\"; function: { name: string } };\n stream?: boolean;\n user?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface AICompletionRequest {\n prompt: string;\n model?: string;\n temperature?: number;\n maxTokens?: number;\n topP?: number;\n frequencyPenalty?: number;\n presencePenalty?: number;\n stop?: string | string[];\n stream?: boolean;\n user?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface AIEmbeddingRequest {\n input: string | string[];\n model?: string;\n dimensions?: number;\n user?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface AIChatResponse {\n id: string;\n model: string;\n provider: AIProvider;\n choices: AIChatChoice[];\n usage: AIUsageInfo;\n created: Date;\n finishReason: AIFinishReason;\n}\n\nexport interface AIChatChoice {\n index: number;\n message: AIMessage;\n finishReason: AIFinishReason;\n}\n\nexport type AIFinishReason =\n | \"stop\"\n | \"length\"\n | \"tool_calls\"\n | \"content_filter\"\n | \"error\";\n\nexport interface AICompletionResponse {\n id: string;\n model: string;\n provider: AIProvider;\n text: string;\n usage: AIUsageInfo;\n created: Date;\n finishReason: AIFinishReason;\n}\n\nexport interface AIEmbeddingResponse {\n id: string;\n model: string;\n provider: AIProvider;\n embeddings: number[][];\n usage: AIUsageInfo;\n created: Date;\n}\n\nexport interface AIUsageInfo {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n estimatedCostUsd: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// STREAMING TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport interface AIStreamChunk {\n id: string;\n model: string;\n provider: AIProvider;\n delta: {\n content?: string;\n toolCalls?: AIToolCall[];\n role?: AIRole;\n };\n finishReason?: AIFinishReason;\n usage?: AIUsageInfo;\n}\n\nexport type AIStreamCallback = (chunk: AIStreamChunk) => void | Promise<void>;\n\n// ═══════════════════════════════════════════════════════════════\n// ROUTING CONFIGURATION\n// ═══════════════════════════════════════════════════════════════\n\nexport type RoutingStrategy =\n | \"priority\"\n | \"round-robin\"\n | \"least-latency\"\n | \"cost-optimized\"\n | \"random\";\n\nexport interface AIRouterConfig {\n /** Primary model to use */\n primaryModel: string;\n /** Fallback models in order of preference */\n fallbackModels?: string[];\n /** Routing strategy for load balancing */\n strategy?: RoutingStrategy;\n /** Maximum retries before failing */\n maxRetries?: number;\n /** Timeout in milliseconds */\n timeoutMs?: number;\n /** Enable automatic fallback on errors */\n autoFallback?: boolean;\n /** Cost budget per request in USD (for cost-optimized routing) */\n costBudget?: number;\n /** Custom routing function */\n customRouter?: (request: AIChatRequest | AICompletionRequest) => string;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// ERROR TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport type AIErrorCode =\n | \"invalid_request\"\n | \"authentication_error\"\n | \"rate_limit_exceeded\"\n | \"quota_exceeded\"\n | \"model_not_found\"\n | \"context_length_exceeded\"\n | \"content_filter\"\n | \"server_error\"\n | \"timeout\"\n | \"network_error\"\n | \"provider_unavailable\"\n | \"unknown\";\n\nexport interface AIError extends Error {\n code: AIErrorCode;\n provider?: AIProvider;\n model?: string;\n statusCode?: number;\n retryable: boolean;\n retryAfterMs?: number;\n}\n\nexport const AIErrorMessages: Record<AIErrorCode, string> = {\n invalid_request: \"The request was invalid or malformed\",\n authentication_error: \"Authentication failed - check your API key\",\n rate_limit_exceeded: \"Rate limit exceeded - try again later\",\n quota_exceeded: \"Usage quota exceeded for this billing period\",\n model_not_found: \"The specified model was not found\",\n context_length_exceeded: \"Input exceeds the model context length\",\n content_filter: \"Content was filtered due to policy violations\",\n server_error: \"The AI provider encountered an internal error\",\n timeout: \"The request timed out\",\n network_error: \"Network error connecting to AI provider\",\n provider_unavailable: \"The AI provider is currently unavailable\",\n unknown: \"An unknown error occurred\",\n};\n\nexport function createAIError(\n code: AIErrorCode,\n message?: string,\n options?: {\n provider?: AIProvider;\n model?: string;\n statusCode?: number;\n retryable?: boolean;\n retryAfterMs?: number;\n cause?: Error;\n },\n): AIError {\n const error = new Error(message || AIErrorMessages[code]) as AIError;\n error.name = \"AIError\";\n error.code = code;\n error.provider = options?.provider;\n error.model = options?.model;\n error.statusCode = options?.statusCode;\n error.retryable =\n options?.retryable ??\n [\n \"rate_limit_exceeded\",\n \"server_error\",\n \"timeout\",\n \"network_error\",\n ].includes(code);\n error.retryAfterMs = options?.retryAfterMs;\n if (options?.cause) {\n error.cause = options.cause;\n }\n return error;\n}\n\nexport function isAIError(error: unknown): error is AIError {\n return (\n error instanceof Error &&\n \"code\" in error &&\n typeof (error as AIError).retryable === \"boolean\"\n );\n}\n\n// ═══════════════════════════════════════════════════════════════\n// AI CONFIGURATION\n// ═══════════════════════════════════════════════════════════════\n\nexport interface AIConfig {\n /** Default model for chat requests */\n defaultChatModel?: string;\n /** Default model for completion requests */\n defaultCompletionModel?: string;\n /** Default model for embedding requests */\n defaultEmbeddingModel?: string;\n /** Router configuration */\n router?: AIRouterConfig;\n /** Available model configurations */\n models?: AIModelConfig[];\n /** API keys for providers */\n apiKeys?: Partial<Record<AIProvider, string>>;\n /** Default timeout in milliseconds */\n defaultTimeoutMs?: number;\n /** Enable request/response logging */\n enableLogging?: boolean;\n /** Cache embeddings */\n cacheEmbeddings?: boolean;\n /** Embedding cache TTL in seconds */\n embeddingCacheTtlSeconds?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MAIN INTERFACE\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * IAI - Core AI interface\n *\n * @example\n * ```typescript\n * const ai = platform.ai;\n *\n * // Chat completion\n * const response = await ai.chat({\n * messages: [\n * { role: 'system', content: 'You are a helpful assistant.' },\n * { role: 'user', content: 'Hello!' }\n * ]\n * });\n *\n * // Streaming chat\n * for await (const chunk of ai.chatStream({\n * messages: [{ role: 'user', content: 'Tell me a story' }]\n * })) {\n * process.stdout.write(chunk.delta.content || '');\n * }\n *\n * // Embeddings\n * const embeddings = await ai.embed({\n * input: ['Hello world', 'Goodbye world']\n * });\n * ```\n */\nexport interface IAI {\n // ─────────────────────────────────────────────────────────────\n // Chat Operations\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Send a chat completion request\n */\n chat(request: AIChatRequest): Promise<AIChatResponse>;\n\n /**\n * Send a streaming chat completion request\n */\n chatStream(request: AIChatRequest): AsyncIterable<AIStreamChunk>;\n\n /**\n * Send a chat completion request with callback-based streaming\n */\n chatWithCallback(\n request: AIChatRequest,\n callback: AIStreamCallback,\n ): Promise<AIChatResponse>;\n\n // ─────────────────────────────────────────────────────────────\n // Completion Operations\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Send a text completion request\n */\n complete(request: AICompletionRequest): Promise<AICompletionResponse>;\n\n /**\n * Send a streaming completion request\n */\n completeStream(request: AICompletionRequest): AsyncIterable<AIStreamChunk>;\n\n // ─────────────────────────────────────────────────────────────\n // Embedding Operations\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Generate embeddings for text\n */\n embed(request: AIEmbeddingRequest): Promise<AIEmbeddingResponse>;\n\n /**\n * Calculate similarity between two texts\n */\n similarity(text1: string, text2: string, model?: string): Promise<number>;\n\n // ─────────────────────────────────────────────────────────────\n // Model Management\n // ─────────────────────────────────────────────────────────────\n\n /**\n * List available models\n */\n listModels(): Promise<AIModelConfig[]>;\n\n /**\n * Get model configuration\n */\n getModel(modelId: string): Promise<AIModelConfig | null>;\n\n /**\n * Check if a model supports a capability\n */\n supportsCapability(\n modelId: string,\n capability: AIModelType,\n ): Promise<boolean>;\n\n /**\n * Estimate tokens for text\n */\n estimateTokens(text: string, model?: string): Promise<number>;\n\n /**\n * Estimate cost for a request\n */\n estimateCost(\n request: AIChatRequest | AICompletionRequest | AIEmbeddingRequest,\n ): Promise<number>;\n\n // ─────────────────────────────────────────────────────────────\n // Health & Status\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Check if AI service is healthy\n */\n healthCheck(): Promise<{\n healthy: boolean;\n providers: Record<\n AIProvider,\n { available: boolean; latencyMs?: number; error?: string }\n >;\n }>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MEMORY IMPLEMENTATION\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * MemoryAI - In-memory implementation for testing\n */\nexport class MemoryAI implements IAI {\n private models: AIModelConfig[] = [];\n private responses: Map<string, AIChatResponse | AICompletionResponse> =\n new Map();\n private embeddings: Map<string, number[]> = new Map();\n private requestLog: Array<{\n type: string;\n request: unknown;\n timestamp: Date;\n }> = [];\n\n constructor(private config: AIConfig = {}) {\n // Initialize with default models\n this.models = config.models || [\n {\n modelId: \"gpt-4\",\n provider: \"openai\",\n capabilities: [\"chat\", \"completion\"],\n maxContextTokens: 128000,\n maxOutputTokens: 4096,\n inputCostPer1K: 0.03,\n outputCostPer1K: 0.06,\n supportsStreaming: true,\n supportsTools: true,\n supportsVision: true,\n },\n {\n modelId: \"claude-3-opus\",\n provider: \"anthropic\",\n capabilities: [\"chat\"],\n maxContextTokens: 200000,\n maxOutputTokens: 4096,\n inputCostPer1K: 0.015,\n outputCostPer1K: 0.075,\n supportsStreaming: true,\n supportsTools: true,\n supportsVision: true,\n },\n {\n modelId: \"text-embedding-3-small\",\n provider: \"openai\",\n capabilities: [\"embedding\"],\n maxContextTokens: 8191,\n maxOutputTokens: 0,\n inputCostPer1K: 0.00002,\n outputCostPer1K: 0,\n supportsStreaming: false,\n supportsTools: false,\n supportsVision: false,\n },\n ];\n }\n\n // ─────────────────────────────────────────────────────────────\n // Test Helpers\n // ─────────────────────────────────────────────────────────────\n\n setResponse(\n key: string,\n response: AIChatResponse | AICompletionResponse,\n ): void {\n this.responses.set(key, response);\n }\n\n setEmbedding(text: string, embedding: number[]): void {\n this.embeddings.set(text, embedding);\n }\n\n getRequestLog(): Array<{ type: string; request: unknown; timestamp: Date }> {\n return [...this.requestLog];\n }\n\n clearRequestLog(): void {\n this.requestLog = [];\n }\n\n // ─────────────────────────────────────────────────────────────\n // Chat Operations\n // ─────────────────────────────────────────────────────────────\n\n async chat(request: AIChatRequest): Promise<AIChatResponse> {\n this.requestLog.push({ type: \"chat\", request, timestamp: new Date() });\n\n const model = request.model || this.config.defaultChatModel || \"gpt-4\";\n const lastMessage = request.messages[request.messages.length - 1];\n const key = `${model}:${lastMessage?.content}`;\n\n if (this.responses.has(key)) {\n return this.responses.get(key) as AIChatResponse;\n }\n\n // Generate mock response\n const response: AIChatResponse = {\n id: `chatcmpl-${Date.now()}`,\n model,\n provider: \"openai\",\n choices: [\n {\n index: 0,\n message: {\n role: \"assistant\",\n content: `Mock response to: ${lastMessage?.content || \"empty\"}`,\n },\n finishReason: \"stop\",\n },\n ],\n usage: {\n promptTokens: this.estimateTokensSync(\n request.messages.map((m) => m.content).join(\" \"),\n ),\n completionTokens: 20,\n totalTokens: 0,\n estimatedCostUsd: 0,\n },\n created: new Date(),\n finishReason: \"stop\",\n };\n\n response.usage.totalTokens =\n response.usage.promptTokens + response.usage.completionTokens;\n response.usage.estimatedCostUsd = this.calculateCost(model, response.usage);\n\n return response;\n }\n\n async *chatStream(request: AIChatRequest): AsyncIterable<AIStreamChunk> {\n this.requestLog.push({\n type: \"chatStream\",\n request,\n timestamp: new Date(),\n });\n\n const model = request.model || this.config.defaultChatModel || \"gpt-4\";\n const lastMessage = request.messages[request.messages.length - 1];\n const responseText = `Mock streaming response to: ${lastMessage?.content || \"empty\"}`;\n const words = responseText.split(\" \");\n\n for (let i = 0; i < words.length; i++) {\n yield {\n id: `chatcmpl-${Date.now()}`,\n model,\n provider: \"openai\",\n delta: {\n content: (i > 0 ? \" \" : \"\") + words[i],\n role: i === 0 ? \"assistant\" : undefined,\n },\n finishReason: i === words.length - 1 ? \"stop\" : undefined,\n };\n }\n }\n\n async chatWithCallback(\n request: AIChatRequest,\n callback: AIStreamCallback,\n ): Promise<AIChatResponse> {\n let fullContent = \"\";\n\n for await (const chunk of this.chatStream(request)) {\n await callback(chunk);\n if (chunk.delta.content) {\n fullContent += chunk.delta.content;\n }\n }\n\n const model = request.model || this.config.defaultChatModel || \"gpt-4\";\n\n return {\n id: `chatcmpl-${Date.now()}`,\n model,\n provider: \"openai\",\n choices: [\n {\n index: 0,\n message: { role: \"assistant\", content: fullContent },\n finishReason: \"stop\",\n },\n ],\n usage: {\n promptTokens: this.estimateTokensSync(\n request.messages.map((m) => m.content).join(\" \"),\n ),\n completionTokens: this.estimateTokensSync(fullContent),\n totalTokens: 0,\n estimatedCostUsd: 0,\n },\n created: new Date(),\n finishReason: \"stop\",\n };\n }\n\n // ─────────────────────────────────────────────────────────────\n // Completion Operations\n // ─────────────────────────────────────────────────────────────\n\n async complete(request: AICompletionRequest): Promise<AICompletionResponse> {\n this.requestLog.push({ type: \"complete\", request, timestamp: new Date() });\n\n const model =\n request.model || this.config.defaultCompletionModel || \"gpt-4\";\n const key = `completion:${model}:${request.prompt}`;\n\n if (this.responses.has(key)) {\n return this.responses.get(key) as AICompletionResponse;\n }\n\n const response: AICompletionResponse = {\n id: `cmpl-${Date.now()}`,\n model,\n provider: \"openai\",\n text: `Mock completion of: ${request.prompt.substring(0, 50)}...`,\n usage: {\n promptTokens: this.estimateTokensSync(request.prompt),\n completionTokens: 20,\n totalTokens: 0,\n estimatedCostUsd: 0,\n },\n created: new Date(),\n finishReason: \"stop\",\n };\n\n response.usage.totalTokens =\n response.usage.promptTokens + response.usage.completionTokens;\n response.usage.estimatedCostUsd = this.calculateCost(model, response.usage);\n\n return response;\n }\n\n async *completeStream(\n request: AICompletionRequest,\n ): AsyncIterable<AIStreamChunk> {\n this.requestLog.push({\n type: \"completeStream\",\n request,\n timestamp: new Date(),\n });\n\n const model =\n request.model || this.config.defaultCompletionModel || \"gpt-4\";\n const responseText = `Mock streaming completion of: ${request.prompt.substring(0, 30)}...`;\n const words = responseText.split(\" \");\n\n for (let i = 0; i < words.length; i++) {\n yield {\n id: `cmpl-${Date.now()}`,\n model,\n provider: \"openai\",\n delta: {\n content: (i > 0 ? \" \" : \"\") + words[i],\n },\n finishReason: i === words.length - 1 ? \"stop\" : undefined,\n };\n }\n }\n\n // ─────────────────────────────────────────────────────────────\n // Embedding Operations\n // ─────────────────────────────────────────────────────────────\n\n async embed(request: AIEmbeddingRequest): Promise<AIEmbeddingResponse> {\n this.requestLog.push({ type: \"embed\", request, timestamp: new Date() });\n\n const model =\n request.model ||\n this.config.defaultEmbeddingModel ||\n \"text-embedding-3-small\";\n const inputs = Array.isArray(request.input)\n ? request.input\n : [request.input];\n const dimensions = request.dimensions || 1536;\n\n const embeddings = inputs.map((text) => {\n if (this.embeddings.has(text)) {\n return this.embeddings.get(text)!;\n }\n // Generate deterministic mock embedding based on text hash\n return this.generateMockEmbedding(text, dimensions);\n });\n\n return {\n id: `emb-${Date.now()}`,\n model,\n provider: \"openai\",\n embeddings,\n usage: {\n promptTokens: inputs.reduce(\n (sum, t) => sum + this.estimateTokensSync(t),\n 0,\n ),\n completionTokens: 0,\n totalTokens: 0,\n estimatedCostUsd: 0,\n },\n created: new Date(),\n };\n }\n\n async similarity(\n text1: string,\n text2: string,\n model?: string,\n ): Promise<number> {\n const response = await this.embed({ input: [text1, text2], model });\n const [emb1, emb2] = response.embeddings;\n return this.cosineSimilarity(emb1!, emb2!);\n }\n\n // ─────────────────────────────────────────────────────────────\n // Model Management\n // ─────────────────────────────────────────────────────────────\n\n async listModels(): Promise<AIModelConfig[]> {\n return [...this.models];\n }\n\n async getModel(modelId: string): Promise<AIModelConfig | null> {\n return this.models.find((m) => m.modelId === modelId) || null;\n }\n\n async supportsCapability(\n modelId: string,\n capability: AIModelType,\n ): Promise<boolean> {\n const model = await this.getModel(modelId);\n return model?.capabilities.includes(capability) ?? false;\n }\n\n async estimateTokens(text: string, _model?: string): Promise<number> {\n return this.estimateTokensSync(text);\n }\n\n async estimateCost(\n request: AIChatRequest | AICompletionRequest | AIEmbeddingRequest,\n ): Promise<number> {\n let model: string;\n let inputTokens: number;\n\n if (\"messages\" in request) {\n model = request.model || this.config.defaultChatModel || \"gpt-4\";\n inputTokens = this.estimateTokensSync(\n request.messages.map((m) => m.content).join(\" \"),\n );\n } else if (\"prompt\" in request) {\n model = request.model || this.config.defaultCompletionModel || \"gpt-4\";\n inputTokens = this.estimateTokensSync(request.prompt);\n } else {\n model =\n request.model ||\n this.config.defaultEmbeddingModel ||\n \"text-embedding-3-small\";\n const inputs = Array.isArray(request.input)\n ? request.input\n : [request.input];\n inputTokens = inputs.reduce(\n (sum, t) => sum + this.estimateTokensSync(t),\n 0,\n );\n }\n\n const modelConfig = await this.getModel(model);\n if (!modelConfig) return 0;\n\n const estimatedOutputTokens =\n \"messages\" in request || \"prompt\" in request ? 100 : 0;\n return (\n (inputTokens / 1000) * modelConfig.inputCostPer1K +\n (estimatedOutputTokens / 1000) * modelConfig.outputCostPer1K\n );\n }\n\n // ─────────────────────────────────────────────────────────────\n // Health & Status\n // ─────────────────────────────────────────────────────────────\n\n async healthCheck(): Promise<{\n healthy: boolean;\n providers: Record<\n AIProvider,\n { available: boolean; latencyMs?: number; error?: string }\n >;\n }> {\n return {\n healthy: true,\n providers: {\n openai: { available: true, latencyMs: 50 },\n anthropic: { available: true, latencyMs: 60 },\n google: { available: true, latencyMs: 55 },\n azure: { available: false, error: \"Not configured\" },\n bedrock: { available: false, error: \"Not configured\" },\n custom: { available: false, error: \"Not configured\" },\n },\n };\n }\n\n // ─────────────────────────────────────────────────────────────\n // Private Helpers\n // ─────────────────────────────────────────────────────────────\n\n private estimateTokensSync(text: string): number {\n // Rough approximation: ~4 characters per token\n return Math.ceil(text.length / 4);\n }\n\n private calculateCost(modelId: string, usage: AIUsageInfo): number {\n const model = this.models.find((m) => m.modelId === modelId);\n if (!model) return 0;\n\n return (\n (usage.promptTokens / 1000) * model.inputCostPer1K +\n (usage.completionTokens / 1000) * model.outputCostPer1K\n );\n }\n\n private generateMockEmbedding(text: string, dimensions: number): number[] {\n // Generate deterministic embedding based on text hash\n const embedding: number[] = [];\n let hash = 0;\n for (let i = 0; i < text.length; i++) {\n hash = (hash << 5) - hash + text.charCodeAt(i);\n hash = hash & hash;\n }\n\n for (let i = 0; i < dimensions; i++) {\n // Generate pseudo-random values based on hash and index\n const seed = hash + i * 31;\n embedding.push(Math.sin(seed) * 0.5);\n }\n\n // Normalize to unit vector\n const magnitude = Math.sqrt(embedding.reduce((sum, v) => sum + v * v, 0));\n return embedding.map((v) => v / magnitude);\n }\n\n private cosineSimilarity(a: number[], b: number[]): number {\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i]! * b[i]!;\n normA += a[i]! * a[i]!;\n normB += b[i]! * b[i]!;\n }\n\n return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));\n }\n}\n","/**\n * IRAG - Retrieval Augmented Generation interface\n *\n * Provides infrastructure for building RAG pipelines:\n * - Document ingestion and chunking\n * - Vector storage and retrieval\n * - Semantic search\n * - Hybrid search (vector + keyword)\n * - Reranking\n * - Context assembly\n */\n\n// ═══════════════════════════════════════════════════════════════\n// DOCUMENT TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport type DocumentStatus = \"pending\" | \"processing\" | \"indexed\" | \"failed\";\n\nexport interface RAGDocument {\n id: string;\n /** Source identifier (e.g., file path, URL, database ID) */\n source: string;\n /** Document type (pdf, markdown, html, text, etc.) */\n type: string;\n /** Original content */\n content: string;\n /** Document title */\n title?: string;\n /** Document metadata */\n metadata: Record<string, unknown>;\n /** Tenant ID for multi-tenant isolation */\n tenantId?: string;\n /** Collection/namespace */\n collection: string;\n /** Document status */\n status: DocumentStatus;\n /** Error message if failed */\n error?: string;\n /** Chunk count */\n chunkCount?: number;\n /** Token count */\n tokenCount?: number;\n /** Created timestamp */\n createdAt: Date;\n /** Updated timestamp */\n updatedAt: Date;\n}\n\nexport interface RAGChunk {\n id: string;\n documentId: string;\n /** Chunk index within document */\n index: number;\n /** Chunk content */\n content: string;\n /** Embedding vector */\n embedding?: number[];\n /** Chunk metadata */\n metadata: Record<string, unknown>;\n /** Start character position in original document */\n startOffset?: number;\n /** End character position */\n endOffset?: number;\n /** Token count */\n tokenCount: number;\n /** Collection/namespace */\n collection: string;\n /** Tenant ID */\n tenantId?: string;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// CHUNKING CONFIGURATION\n// ═══════════════════════════════════════════════════════════════\n\nexport type ChunkingStrategy =\n | \"fixed\"\n | \"sentence\"\n | \"paragraph\"\n | \"semantic\"\n | \"recursive\";\n\nexport interface ChunkingConfig {\n /** Chunking strategy */\n strategy: ChunkingStrategy;\n /** Target chunk size in tokens */\n chunkSize: number;\n /** Overlap between chunks in tokens */\n chunkOverlap: number;\n /** Minimum chunk size */\n minChunkSize?: number;\n /** Maximum chunk size */\n maxChunkSize?: number;\n /** Separators for recursive chunking */\n separators?: string[];\n /** Keep metadata in chunks */\n includeMetadata?: boolean;\n /** Add document title to each chunk */\n includeTitle?: boolean;\n}\n\nexport const ChunkingPresets: Record<string, ChunkingConfig> = {\n default: {\n strategy: \"recursive\",\n chunkSize: 512,\n chunkOverlap: 50,\n minChunkSize: 100,\n separators: [\"\\n\\n\", \"\\n\", \". \", \" \"],\n },\n small: {\n strategy: \"sentence\",\n chunkSize: 256,\n chunkOverlap: 25,\n minChunkSize: 50,\n },\n large: {\n strategy: \"paragraph\",\n chunkSize: 1024,\n chunkOverlap: 100,\n minChunkSize: 200,\n },\n code: {\n strategy: \"recursive\",\n chunkSize: 1000,\n chunkOverlap: 100,\n separators: [\"\\n\\nclass \", \"\\n\\nfunction \", \"\\n\\ndef \", \"\\n\\n\", \"\\n\"],\n },\n};\n\n// ═══════════════════════════════════════════════════════════════\n// SEARCH TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport type SearchMode = \"vector\" | \"keyword\" | \"hybrid\";\n\nexport interface RAGSearchQuery {\n /** Search query text */\n query: string;\n /** Collection to search */\n collection: string;\n /** Tenant ID for filtering */\n tenantId?: string;\n /** Search mode */\n mode?: SearchMode;\n /** Maximum results to return */\n limit?: number;\n /** Minimum similarity score (0-1) */\n minScore?: number;\n /** Metadata filters */\n filters?: RAGFilter[];\n /** Include embeddings in results */\n includeEmbeddings?: boolean;\n /** Include original document content */\n includeDocumentContent?: boolean;\n /** Rerank results using cross-encoder */\n rerank?: boolean;\n /** Number of candidates for reranking */\n rerankCandidates?: number;\n}\n\nexport interface RAGFilter {\n field: string;\n operator:\n | \"eq\"\n | \"ne\"\n | \"gt\"\n | \"gte\"\n | \"lt\"\n | \"lte\"\n | \"in\"\n | \"nin\"\n | \"contains\";\n value: unknown;\n}\n\nexport interface RAGSearchResult {\n chunk: RAGChunk;\n score: number;\n document?: RAGDocument;\n highlights?: string[];\n}\n\nexport interface RAGSearchResponse {\n results: RAGSearchResult[];\n query: string;\n totalMatches: number;\n searchTimeMs: number;\n mode: SearchMode;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// CONTEXT ASSEMBLY\n// ═══════════════════════════════════════════════════════════════\n\nexport interface ContextAssemblyConfig {\n /** Maximum tokens for assembled context */\n maxTokens: number;\n /** Template for formatting each chunk */\n chunkTemplate?: string;\n /** Template for the full context */\n contextTemplate?: string;\n /** Include source citations */\n includeCitations?: boolean;\n /** Deduplicate similar chunks */\n deduplicate?: boolean;\n /** Deduplication similarity threshold */\n dedupeThreshold?: number;\n /** Sort order for chunks */\n sortBy?: \"score\" | \"document\" | \"position\";\n}\n\nexport interface AssembledContext {\n /** Final assembled context string */\n context: string;\n /** Chunks included in context */\n chunks: RAGChunk[];\n /** Total tokens used */\n tokenCount: number;\n /** Source documents referenced */\n sources: Array<{\n documentId: string;\n title?: string;\n source: string;\n }>;\n /** Chunks excluded due to limits */\n truncated: boolean;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// INGESTION TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport interface IngestionOptions {\n /** Collection to add documents to */\n collection: string;\n /** Tenant ID */\n tenantId?: string;\n /** Chunking configuration */\n chunking?: Partial<ChunkingConfig>;\n /** Document metadata to attach */\n metadata?: Record<string, unknown>;\n /** Generate embeddings immediately */\n generateEmbeddings?: boolean;\n /** Batch size for processing */\n batchSize?: number;\n /** Skip existing documents */\n skipExisting?: boolean;\n}\n\nexport interface IngestionResult {\n documentId: string;\n status: DocumentStatus;\n chunkCount: number;\n tokenCount: number;\n error?: string;\n processingTimeMs: number;\n}\n\nexport interface BulkIngestionResult {\n total: number;\n successful: number;\n failed: number;\n results: IngestionResult[];\n totalProcessingTimeMs: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// COLLECTION MANAGEMENT\n// ═══════════════════════════════════════════════════════════════\n\nexport interface RAGCollection {\n name: string;\n description?: string;\n /** Embedding model used */\n embeddingModel: string;\n /** Embedding dimensions */\n dimensions: number;\n /** Distance metric for similarity */\n distanceMetric: \"cosine\" | \"euclidean\" | \"dotproduct\";\n /** Chunking config for this collection */\n chunkingConfig: ChunkingConfig;\n /** Document count */\n documentCount: number;\n /** Chunk count */\n chunkCount: number;\n /** Total token count */\n totalTokens: number;\n /** Created timestamp */\n createdAt: Date;\n /** Updated timestamp */\n updatedAt: Date;\n}\n\nexport interface CreateCollectionOptions {\n name: string;\n description?: string;\n embeddingModel?: string;\n dimensions?: number;\n distanceMetric?: \"cosine\" | \"euclidean\" | \"dotproduct\";\n chunkingConfig?: Partial<ChunkingConfig>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// PIPELINE TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport interface RAGPipelineStep {\n name: string;\n type: \"transform\" | \"filter\" | \"enrich\" | \"embed\" | \"store\";\n config: Record<string, unknown>;\n enabled: boolean;\n}\n\nexport interface RAGPipeline {\n id: string;\n name: string;\n description?: string;\n collection: string;\n steps: RAGPipelineStep[];\n createdAt: Date;\n updatedAt: Date;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// CONFIGURATION\n// ═══════════════════════════════════════════════════════════════\n\nexport interface RAGConfig {\n /** Default embedding model */\n defaultEmbeddingModel?: string;\n /** Default chunking config */\n defaultChunkingConfig?: Partial<ChunkingConfig>;\n /** Default search mode */\n defaultSearchMode?: SearchMode;\n /** Default result limit */\n defaultLimit?: number;\n /** Enable caching */\n enableCache?: boolean;\n /** Cache TTL in seconds */\n cacheTtlSeconds?: number;\n /** Maximum documents per collection */\n maxDocumentsPerCollection?: number;\n /** Maximum chunks per document */\n maxChunksPerDocument?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MAIN INTERFACE\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * IRAG - RAG pipeline interface\n *\n * @example\n * ```typescript\n * const rag = platform.rag;\n *\n * // Create a collection\n * await rag.createCollection({\n * name: 'knowledge-base',\n * embeddingModel: 'text-embedding-3-small',\n * });\n *\n * // Ingest documents\n * await rag.ingest('knowledge-base', [\n * { source: 'doc1.pdf', content: '...', type: 'pdf' },\n * { source: 'doc2.md', content: '...', type: 'markdown' },\n * ]);\n *\n * // Search\n * const results = await rag.search({\n * query: 'How do I configure authentication?',\n * collection: 'knowledge-base',\n * limit: 5,\n * });\n *\n * // Assemble context for LLM\n * const context = await rag.assembleContext(results, {\n * maxTokens: 4000,\n * includeCitations: true,\n * });\n *\n * // Use with AI\n * const response = await ai.chat({\n * messages: [\n * { role: 'system', content: `Use this context: ${context.context}` },\n * { role: 'user', content: 'How do I configure authentication?' }\n * ]\n * });\n * ```\n */\nexport interface IRAG {\n // ─────────────────────────────────────────────────────────────\n // Collection Management\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Create a new collection\n */\n createCollection(options: CreateCollectionOptions): Promise<RAGCollection>;\n\n /**\n * Get a collection by name\n */\n getCollection(name: string): Promise<RAGCollection | null>;\n\n /**\n * List all collections\n */\n listCollections(tenantId?: string): Promise<RAGCollection[]>;\n\n /**\n * Delete a collection and all its documents\n */\n deleteCollection(name: string): Promise<void>;\n\n /**\n * Get collection statistics\n */\n getCollectionStats(name: string): Promise<{\n documentCount: number;\n chunkCount: number;\n totalTokens: number;\n averageChunkSize: number;\n storageBytes: number;\n }>;\n\n // ─────────────────────────────────────────────────────────────\n // Document Management\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Ingest documents into a collection\n */\n ingest(\n collection: string,\n documents: Array<\n Omit<\n RAGDocument,\n | \"id\"\n | \"status\"\n | \"chunkCount\"\n | \"tokenCount\"\n | \"createdAt\"\n | \"updatedAt\"\n >\n >,\n options?: Partial<IngestionOptions>,\n ): Promise<BulkIngestionResult>;\n\n /**\n * Ingest a single document\n */\n ingestOne(\n collection: string,\n document: Omit<\n RAGDocument,\n | \"id\"\n | \"status\"\n | \"chunkCount\"\n | \"tokenCount\"\n | \"createdAt\"\n | \"updatedAt\"\n | \"collection\"\n >,\n options?: Partial<IngestionOptions>,\n ): Promise<IngestionResult>;\n\n /**\n * Get a document by ID\n */\n getDocument(documentId: string): Promise<RAGDocument | null>;\n\n /**\n * List documents in a collection\n */\n listDocuments(\n collection: string,\n options?: {\n tenantId?: string;\n status?: DocumentStatus;\n limit?: number;\n offset?: number;\n },\n ): Promise<{ documents: RAGDocument[]; total: number }>;\n\n /**\n * Delete a document and its chunks\n */\n deleteDocument(documentId: string): Promise<void>;\n\n /**\n * Reprocess a document (re-chunk and re-embed)\n */\n reprocessDocument(\n documentId: string,\n options?: Partial<IngestionOptions>,\n ): Promise<IngestionResult>;\n\n // ─────────────────────────────────────────────────────────────\n // Chunk Management\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Get chunks for a document\n */\n getChunks(documentId: string): Promise<RAGChunk[]>;\n\n /**\n * Get a specific chunk by ID\n */\n getChunk(chunkId: string): Promise<RAGChunk | null>;\n\n /**\n * Update chunk metadata\n */\n updateChunkMetadata(\n chunkId: string,\n metadata: Record<string, unknown>,\n ): Promise<RAGChunk>;\n\n // ─────────────────────────────────────────────────────────────\n // Search & Retrieval\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Search for relevant chunks\n */\n search(query: RAGSearchQuery): Promise<RAGSearchResponse>;\n\n /**\n * Get similar chunks to a given chunk\n */\n findSimilar(\n chunkId: string,\n options?: {\n limit?: number;\n minScore?: number;\n collection?: string;\n },\n ): Promise<RAGSearchResult[]>;\n\n /**\n * Multi-query search (query expansion)\n */\n multiSearch(queries: RAGSearchQuery[]): Promise<RAGSearchResponse[]>;\n\n // ─────────────────────────────────────────────────────────────\n // Context Assembly\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Assemble context from search results\n */\n assembleContext(\n results: RAGSearchResponse | RAGSearchResult[],\n config?: Partial<ContextAssemblyConfig>,\n ): Promise<AssembledContext>;\n\n /**\n * Query and assemble in one step\n */\n queryWithContext(\n query: RAGSearchQuery,\n contextConfig?: Partial<ContextAssemblyConfig>,\n ): Promise<{\n searchResponse: RAGSearchResponse;\n context: AssembledContext;\n }>;\n\n // ─────────────────────────────────────────────────────────────\n // Embedding Management\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Generate embeddings for text\n */\n embed(texts: string | string[], model?: string): Promise<number[][]>;\n\n /**\n * Update embeddings for a collection\n */\n reembed(\n collection: string,\n model?: string,\n batchSize?: number,\n ): Promise<{\n updated: number;\n errors: number;\n }>;\n\n // ─────────────────────────────────────────────────────────────\n // Pipeline Management\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Create a processing pipeline\n */\n createPipeline(\n pipeline: Omit<RAGPipeline, \"id\" | \"createdAt\" | \"updatedAt\">,\n ): Promise<RAGPipeline>;\n\n /**\n * Get a pipeline\n */\n getPipeline(pipelineId: string): Promise<RAGPipeline | null>;\n\n /**\n * Run a pipeline on documents\n */\n runPipeline(\n pipelineId: string,\n documentIds: string[],\n ): Promise<BulkIngestionResult>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MEMORY IMPLEMENTATION\n// ═══════════════════════════════════════════════════════════════\n\nimport { randomBytes } from \"crypto\";\n\n/**\n * MemoryRAG - In-memory implementation for testing\n */\nexport class MemoryRAG implements IRAG {\n private collections: Map<string, RAGCollection> = new Map();\n private documents: Map<string, RAGDocument> = new Map();\n private chunks: Map<string, RAGChunk> = new Map();\n private pipelines: Map<string, RAGPipeline> = new Map();\n private embeddings: Map<string, number[]> = new Map();\n\n constructor(private config: RAGConfig = {}) {}\n\n // ─────────────────────────────────────────────────────────────\n // Collection Management\n // ─────────────────────────────────────────────────────────────\n\n async createCollection(\n options: CreateCollectionOptions,\n ): Promise<RAGCollection> {\n const now = new Date();\n const collection: RAGCollection = {\n name: options.name,\n description: options.description,\n embeddingModel:\n options.embeddingModel ||\n this.config.defaultEmbeddingModel ||\n \"text-embedding-3-small\",\n dimensions: options.dimensions || 1536,\n distanceMetric: options.distanceMetric || \"cosine\",\n chunkingConfig: {\n ...ChunkingPresets.default,\n ...this.config.defaultChunkingConfig,\n ...options.chunkingConfig,\n } as ChunkingConfig,\n documentCount: 0,\n chunkCount: 0,\n totalTokens: 0,\n createdAt: now,\n updatedAt: now,\n };\n\n this.collections.set(options.name, collection);\n return collection;\n }\n\n async getCollection(name: string): Promise<RAGCollection | null> {\n return this.collections.get(name) || null;\n }\n\n async listCollections(tenantId?: string): Promise<RAGCollection[]> {\n const collections = Array.from(this.collections.values());\n // In memory implementation, we don't filter by tenant at collection level\n return collections;\n }\n\n async deleteCollection(name: string): Promise<void> {\n // Delete all documents and chunks in collection\n for (const [id, doc] of this.documents) {\n if (doc.collection === name) {\n // Delete chunks\n for (const [chunkId, chunk] of this.chunks) {\n if (chunk.documentId === id) {\n this.chunks.delete(chunkId);\n }\n }\n this.documents.delete(id);\n }\n }\n this.collections.delete(name);\n }\n\n async getCollectionStats(name: string): Promise<{\n documentCount: number;\n chunkCount: number;\n totalTokens: number;\n averageChunkSize: number;\n storageBytes: number;\n }> {\n const collection = await this.getCollection(name);\n if (!collection) {\n throw new Error(`Collection not found: ${name}`);\n }\n\n const docs = Array.from(this.documents.values()).filter(\n (d) => d.collection === name,\n );\n const docChunks = Array.from(this.chunks.values()).filter(\n (c) => c.collection === name,\n );\n const totalTokens = docChunks.reduce((sum, c) => sum + c.tokenCount, 0);\n\n return {\n documentCount: docs.length,\n chunkCount: docChunks.length,\n totalTokens,\n averageChunkSize:\n docChunks.length > 0 ? totalTokens / docChunks.length : 0,\n storageBytes: docChunks.reduce((sum, c) => sum + c.content.length, 0),\n };\n }\n\n // ─────────────────────────────────────────────────────────────\n // Document Management\n // ─────────────────────────────────────────────────────────────\n\n async ingest(\n collection: string,\n documents: Array<\n Omit<\n RAGDocument,\n | \"id\"\n | \"status\"\n | \"chunkCount\"\n | \"tokenCount\"\n | \"createdAt\"\n | \"updatedAt\"\n >\n >,\n options?: Partial<IngestionOptions>,\n ): Promise<BulkIngestionResult> {\n const startTime = Date.now();\n const results: IngestionResult[] = [];\n\n for (const doc of documents) {\n const result = await this.ingestOne(\n collection,\n doc as Omit<\n RAGDocument,\n | \"id\"\n | \"status\"\n | \"chunkCount\"\n | \"tokenCount\"\n | \"createdAt\"\n | \"updatedAt\"\n | \"collection\"\n >,\n options,\n );\n results.push(result);\n }\n\n return {\n total: documents.length,\n successful: results.filter((r) => r.status === \"indexed\").length,\n failed: results.filter((r) => r.status === \"failed\").length,\n results,\n totalProcessingTimeMs: Date.now() - startTime,\n };\n }\n\n async ingestOne(\n collection: string,\n document: Omit<\n RAGDocument,\n | \"id\"\n | \"status\"\n | \"chunkCount\"\n | \"tokenCount\"\n | \"createdAt\"\n | \"updatedAt\"\n | \"collection\"\n >,\n options?: Partial<IngestionOptions>,\n ): Promise<IngestionResult> {\n const startTime = Date.now();\n const docId = `doc_${Date.now()}_${randomBytes(4).toString(\"hex\")}`;\n const now = new Date();\n\n try {\n // Get collection config\n const col = await this.getCollection(collection);\n if (!col) {\n throw new Error(`Collection not found: ${collection}`);\n }\n\n // Create document\n const doc: RAGDocument = {\n ...document,\n id: docId,\n collection,\n status: \"processing\",\n tenantId: options?.tenantId || document.tenantId,\n metadata: { ...document.metadata, ...options?.metadata },\n createdAt: now,\n updatedAt: now,\n };\n this.documents.set(docId, doc);\n\n // Chunk the document\n const chunkingConfig = { ...col.chunkingConfig, ...options?.chunking };\n const docChunks = this.chunkDocument(doc, chunkingConfig);\n\n // Generate embeddings if requested\n if (options?.generateEmbeddings !== false) {\n for (const chunk of docChunks) {\n chunk.embedding = await this.generateMockEmbedding(\n chunk.content,\n col.dimensions,\n );\n this.embeddings.set(chunk.id, chunk.embedding);\n }\n }\n\n // Store chunks\n for (const chunk of docChunks) {\n this.chunks.set(chunk.id, chunk);\n }\n\n // Update document\n doc.status = \"indexed\";\n doc.chunkCount = docChunks.length;\n doc.tokenCount = docChunks.reduce((sum, c) => sum + c.tokenCount, 0);\n this.documents.set(docId, doc);\n\n // Update collection stats\n col.documentCount++;\n col.chunkCount += docChunks.length;\n col.totalTokens += doc.tokenCount;\n col.updatedAt = new Date();\n\n return {\n documentId: docId,\n status: \"indexed\",\n chunkCount: doc.chunkCount,\n tokenCount: doc.tokenCount,\n processingTimeMs: Date.now() - startTime,\n };\n } catch (error) {\n const doc = this.documents.get(docId);\n if (doc) {\n doc.status = \"failed\";\n doc.error = error instanceof Error ? error.message : \"Unknown error\";\n }\n\n return {\n documentId: docId,\n status: \"failed\",\n chunkCount: 0,\n tokenCount: 0,\n error: error instanceof Error ? error.message : \"Unknown error\",\n processingTimeMs: Date.now() - startTime,\n };\n }\n }\n\n async getDocument(documentId: string): Promise<RAGDocument | null> {\n return this.documents.get(documentId) || null;\n }\n\n async listDocuments(\n collection: string,\n options?: {\n tenantId?: string;\n status?: DocumentStatus;\n limit?: number;\n offset?: number;\n },\n ): Promise<{ documents: RAGDocument[]; total: number }> {\n let docs = Array.from(this.documents.values()).filter(\n (d) => d.collection === collection,\n );\n\n if (options?.tenantId) {\n docs = docs.filter((d) => d.tenantId === options.tenantId);\n }\n\n if (options?.status) {\n docs = docs.filter((d) => d.status === options.status);\n }\n\n const total = docs.length;\n const offset = options?.offset || 0;\n const limit = options?.limit || 50;\n\n return {\n documents: docs.slice(offset, offset + limit),\n total,\n };\n }\n\n async deleteDocument(documentId: string): Promise<void> {\n const doc = await this.getDocument(documentId);\n if (doc) {\n // Delete chunks\n for (const [chunkId, chunk] of this.chunks) {\n if (chunk.documentId === documentId) {\n this.chunks.delete(chunkId);\n this.embeddings.delete(chunkId);\n }\n }\n\n // Update collection\n const collection = await this.getCollection(doc.collection);\n if (collection) {\n collection.documentCount--;\n collection.chunkCount -= doc.chunkCount || 0;\n collection.totalTokens -= doc.tokenCount || 0;\n }\n\n this.documents.delete(documentId);\n }\n }\n\n async reprocessDocument(\n documentId: string,\n options?: Partial<IngestionOptions>,\n ): Promise<IngestionResult> {\n const doc = await this.getDocument(documentId);\n if (!doc) {\n throw new Error(`Document not found: ${documentId}`);\n }\n\n // Delete existing chunks\n for (const [chunkId, chunk] of this.chunks) {\n if (chunk.documentId === documentId) {\n this.chunks.delete(chunkId);\n this.embeddings.delete(chunkId);\n }\n }\n\n // Re-ingest\n return this.ingestOne(\n doc.collection,\n {\n source: doc.source,\n type: doc.type,\n content: doc.content,\n title: doc.title,\n metadata: doc.metadata,\n tenantId: doc.tenantId,\n },\n options,\n );\n }\n\n // ─────────────────────────────────────────────────────────────\n // Chunk Management\n // ─────────────────────────────────────────────────────────────\n\n async getChunks(documentId: string): Promise<RAGChunk[]> {\n return Array.from(this.chunks.values())\n .filter((c) => c.documentId === documentId)\n .sort((a, b) => a.index - b.index);\n }\n\n async getChunk(chunkId: string): Promise<RAGChunk | null> {\n return this.chunks.get(chunkId) || null;\n }\n\n async updateChunkMetadata(\n chunkId: string,\n metadata: Record<string, unknown>,\n ): Promise<RAGChunk> {\n const chunk = await this.getChunk(chunkId);\n if (!chunk) {\n throw new Error(`Chunk not found: ${chunkId}`);\n }\n\n chunk.metadata = { ...chunk.metadata, ...metadata };\n this.chunks.set(chunkId, chunk);\n return chunk;\n }\n\n // ─────────────────────────────────────────────────────────────\n // Search & Retrieval\n // ─────────────────────────────────────────────────────────────\n\n async search(query: RAGSearchQuery): Promise<RAGSearchResponse> {\n const startTime = Date.now();\n const mode = query.mode || this.config.defaultSearchMode || \"vector\";\n const limit = query.limit || this.config.defaultLimit || 10;\n\n // Get query embedding\n const queryEmbedding = await this.generateMockEmbedding(query.query, 1536);\n\n // Get chunks from collection\n let chunks = Array.from(this.chunks.values()).filter(\n (c) => c.collection === query.collection,\n );\n\n // Filter by tenant\n if (query.tenantId) {\n chunks = chunks.filter((c) => c.tenantId === query.tenantId);\n }\n\n // Apply metadata filters\n if (query.filters) {\n chunks = chunks.filter((c) =>\n this.matchesFilters(c.metadata, query.filters!),\n );\n }\n\n // Score chunks\n let results: RAGSearchResult[] = chunks.map((chunk) => {\n const embedding = this.embeddings.get(chunk.id) || [];\n const vectorScore =\n embedding.length > 0\n ? this.cosineSimilarity(queryEmbedding, embedding)\n : 0;\n const keywordScore = this.keywordScore(query.query, chunk.content);\n\n let score: number;\n switch (mode) {\n case \"vector\":\n score = vectorScore;\n break;\n case \"keyword\":\n score = keywordScore;\n break;\n case \"hybrid\":\n score = 0.7 * vectorScore + 0.3 * keywordScore;\n break;\n default:\n score = vectorScore;\n }\n\n return { chunk, score };\n });\n\n // Filter by min score\n if (query.minScore) {\n results = results.filter((r) => r.score >= query.minScore!);\n }\n\n // Sort by score\n results.sort((a, b) => b.score - a.score);\n\n // Rerank if requested\n if (query.rerank) {\n const candidates = results.slice(0, query.rerankCandidates || limit * 3);\n // Mock reranking - in production, use a cross-encoder\n results = candidates.sort((a, b) => {\n const aRelevance = this.keywordScore(query.query, a.chunk.content);\n const bRelevance = this.keywordScore(query.query, b.chunk.content);\n return b.score + bRelevance - (a.score + aRelevance);\n });\n }\n\n // Limit results\n results = results.slice(0, limit);\n\n // Add documents if requested\n if (query.includeDocumentContent) {\n for (const result of results) {\n result.document =\n (await this.getDocument(result.chunk.documentId)) || undefined;\n }\n }\n\n // Add highlights\n for (const result of results) {\n result.highlights = this.generateHighlights(\n query.query,\n result.chunk.content,\n );\n }\n\n return {\n results,\n query: query.query,\n totalMatches: results.length,\n searchTimeMs: Date.now() - startTime,\n mode,\n };\n }\n\n async findSimilar(\n chunkId: string,\n options?: {\n limit?: number;\n minScore?: number;\n collection?: string;\n },\n ): Promise<RAGSearchResult[]> {\n const chunk = await this.getChunk(chunkId);\n if (!chunk) {\n throw new Error(`Chunk not found: ${chunkId}`);\n }\n\n const embedding = this.embeddings.get(chunkId);\n if (!embedding) {\n return [];\n }\n\n const collection = options?.collection || chunk.collection;\n let chunks = Array.from(this.chunks.values()).filter(\n (c) => c.collection === collection && c.id !== chunkId,\n );\n\n const results: RAGSearchResult[] = chunks.map((c) => {\n const otherEmbedding = this.embeddings.get(c.id) || [];\n const score =\n otherEmbedding.length > 0\n ? this.cosineSimilarity(embedding, otherEmbedding)\n : 0;\n return { chunk: c, score };\n });\n\n let filteredResults = results;\n if (options?.minScore) {\n filteredResults = results.filter((r) => r.score >= options.minScore!);\n }\n\n filteredResults.sort((a, b) => b.score - a.score);\n\n return filteredResults.slice(0, options?.limit || 10);\n }\n\n async multiSearch(queries: RAGSearchQuery[]): Promise<RAGSearchResponse[]> {\n return Promise.all(queries.map((q) => this.search(q)));\n }\n\n // ─────────────────────────────────────────────────────────────\n // Context Assembly\n // ─────────────────────────────────────────────────────────────\n\n async assembleContext(\n results: RAGSearchResponse | RAGSearchResult[],\n config?: Partial<ContextAssemblyConfig>,\n ): Promise<AssembledContext> {\n const resultArray = \"results\" in results ? results.results : results;\n const maxTokens = config?.maxTokens || 4000;\n const chunkTemplate = config?.chunkTemplate || \"{{content}}\";\n const contextTemplate = config?.contextTemplate || \"{{chunks}}\";\n\n let chunks: RAGChunk[] = [];\n let totalTokens = 0;\n const sources: AssembledContext[\"sources\"] = [];\n const seenDocs = new Set<string>();\n\n // Deduplicate if requested\n let processedResults = resultArray;\n if (config?.deduplicate) {\n const threshold = config.dedupeThreshold || 0.9;\n processedResults = this.deduplicateResults(resultArray, threshold);\n }\n\n // Sort if requested\n if (config?.sortBy) {\n processedResults = [...processedResults].sort((a, b) => {\n switch (config.sortBy) {\n case \"score\":\n return b.score - a.score;\n case \"document\":\n return a.chunk.documentId.localeCompare(b.chunk.documentId);\n case \"position\":\n return a.chunk.index - b.chunk.index;\n default:\n return 0;\n }\n });\n }\n\n // Assemble chunks until max tokens\n let truncated = false;\n for (const result of processedResults) {\n if (totalTokens + result.chunk.tokenCount > maxTokens) {\n truncated = true;\n break;\n }\n\n chunks.push(result.chunk);\n totalTokens += result.chunk.tokenCount;\n\n // Track sources\n if (!seenDocs.has(result.chunk.documentId)) {\n seenDocs.add(result.chunk.documentId);\n const doc = await this.getDocument(result.chunk.documentId);\n sources.push({\n documentId: result.chunk.documentId,\n title: doc?.title,\n source: doc?.source || \"\",\n });\n }\n }\n\n // Format chunks\n const formattedChunks = chunks.map((chunk, i) => {\n let formatted = chunkTemplate\n .replace(\"{{content}}\", chunk.content)\n .replace(\"{{index}}\", String(i + 1))\n .replace(\"{{documentId}}\", chunk.documentId);\n\n if (config?.includeCitations) {\n formatted = `[${i + 1}] ${formatted}`;\n }\n\n return formatted;\n });\n\n // Build final context\n let context = contextTemplate.replace(\n \"{{chunks}}\",\n formattedChunks.join(\"\\n\\n\"),\n );\n\n if (config?.includeCitations && sources.length > 0) {\n const citations = sources\n .map((s, i) => `[${i + 1}] ${s.title || s.source}`)\n .join(\"\\n\");\n context += `\\n\\nSources:\\n${citations}`;\n }\n\n return {\n context,\n chunks,\n tokenCount: totalTokens,\n sources,\n truncated,\n };\n }\n\n async queryWithContext(\n query: RAGSearchQuery,\n contextConfig?: Partial<ContextAssemblyConfig>,\n ): Promise<{\n searchResponse: RAGSearchResponse;\n context: AssembledContext;\n }> {\n const searchResponse = await this.search(query);\n const context = await this.assembleContext(searchResponse, contextConfig);\n return { searchResponse, context };\n }\n\n // ─────────────────────────────────────────────────────────────\n // Embedding Management\n // ─────────────────────────────────────────────────────────────\n\n async embed(texts: string | string[], model?: string): Promise<number[][]> {\n const textArray = Array.isArray(texts) ? texts : [texts];\n return Promise.all(\n textArray.map((text) => this.generateMockEmbedding(text, 1536)),\n );\n }\n\n async reembed(\n collection: string,\n model?: string,\n batchSize?: number,\n ): Promise<{\n updated: number;\n errors: number;\n }> {\n const col = await this.getCollection(collection);\n if (!col) {\n throw new Error(`Collection not found: ${collection}`);\n }\n\n let updated = 0;\n let errors = 0;\n\n const chunks = Array.from(this.chunks.values()).filter(\n (c) => c.collection === collection,\n );\n\n for (const chunk of chunks) {\n try {\n const embedding = await this.generateMockEmbedding(\n chunk.content,\n col.dimensions,\n );\n chunk.embedding = embedding;\n this.embeddings.set(chunk.id, embedding);\n updated++;\n } catch {\n errors++;\n }\n }\n\n return { updated, errors };\n }\n\n // ─────────────────────────────────────────────────────────────\n // Pipeline Management\n // ─────────────────────────────────────────────────────────────\n\n async createPipeline(\n pipeline: Omit<RAGPipeline, \"id\" | \"createdAt\" | \"updatedAt\">,\n ): Promise<RAGPipeline> {\n const id = `pipeline_${Date.now()}`;\n const now = new Date();\n\n const newPipeline: RAGPipeline = {\n ...pipeline,\n id,\n createdAt: now,\n updatedAt: now,\n };\n\n this.pipelines.set(id, newPipeline);\n return newPipeline;\n }\n\n async getPipeline(pipelineId: string): Promise<RAGPipeline | null> {\n return this.pipelines.get(pipelineId) || null;\n }\n\n async runPipeline(\n pipelineId: string,\n documentIds: string[],\n ): Promise<BulkIngestionResult> {\n const pipeline = await this.getPipeline(pipelineId);\n if (!pipeline) {\n throw new Error(`Pipeline not found: ${pipelineId}`);\n }\n\n // For memory implementation, just reprocess documents\n const results: IngestionResult[] = [];\n for (const docId of documentIds) {\n const result = await this.reprocessDocument(docId);\n results.push(result);\n }\n\n return {\n total: documentIds.length,\n successful: results.filter((r) => r.status === \"indexed\").length,\n failed: results.filter((r) => r.status === \"failed\").length,\n results,\n totalProcessingTimeMs: results.reduce(\n (sum, r) => sum + r.processingTimeMs,\n 0,\n ),\n };\n }\n\n // ─────────────────────────────────────────────────────────────\n // Private Helpers\n // ─────────────────────────────────────────────────────────────\n\n private chunkDocument(doc: RAGDocument, config: ChunkingConfig): RAGChunk[] {\n const chunks: RAGChunk[] = [];\n const content = doc.content;\n const chunkSize = config.chunkSize;\n const overlap = config.chunkOverlap;\n\n // Simple fixed-size chunking for memory implementation\n let startOffset = 0;\n let index = 0;\n\n while (startOffset < content.length) {\n const endOffset = Math.min(startOffset + chunkSize * 4, content.length); // Approximate 4 chars per token\n const chunkContent = content.slice(startOffset, endOffset);\n\n chunks.push({\n id: `chunk_${doc.id}_${index}`,\n documentId: doc.id,\n index,\n content: chunkContent,\n metadata: config.includeMetadata ? doc.metadata : {},\n startOffset,\n endOffset,\n tokenCount: Math.ceil(chunkContent.length / 4),\n collection: doc.collection,\n tenantId: doc.tenantId,\n });\n\n startOffset = endOffset - overlap * 4;\n index++;\n }\n\n return chunks;\n }\n\n private async generateMockEmbedding(\n text: string,\n dimensions: number,\n ): Promise<number[]> {\n // Generate deterministic embedding based on text hash\n const embedding: number[] = [];\n let hash = 0;\n for (let i = 0; i < text.length; i++) {\n hash = (hash << 5) - hash + text.charCodeAt(i);\n hash = hash & hash;\n }\n\n for (let i = 0; i < dimensions; i++) {\n const seed = hash + i * 31;\n embedding.push(Math.sin(seed) * 0.5);\n }\n\n // Normalize\n const magnitude = Math.sqrt(embedding.reduce((sum, v) => sum + v * v, 0));\n return embedding.map((v) => v / magnitude);\n }\n\n private cosineSimilarity(a: number[], b: number[]): number {\n if (a.length !== b.length) return 0;\n\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i]! * b[i]!;\n normA += a[i]! * a[i]!;\n normB += b[i]! * b[i]!;\n }\n\n const denominator = Math.sqrt(normA) * Math.sqrt(normB);\n return denominator > 0 ? dotProduct / denominator : 0;\n }\n\n private keywordScore(query: string, content: string): number {\n const queryWords = query.toLowerCase().split(/\\s+/);\n const contentLower = content.toLowerCase();\n let matches = 0;\n\n for (const word of queryWords) {\n if (contentLower.includes(word)) {\n matches++;\n }\n }\n\n return queryWords.length > 0 ? matches / queryWords.length : 0;\n }\n\n private matchesFilters(\n metadata: Record<string, unknown>,\n filters: RAGFilter[],\n ): boolean {\n for (const filter of filters) {\n const value = metadata[filter.field];\n\n switch (filter.operator) {\n case \"eq\":\n if (value !== filter.value) return false;\n break;\n case \"ne\":\n if (value === filter.value) return false;\n break;\n case \"gt\":\n if (\n typeof value !== \"number\" ||\n typeof filter.value !== \"number\" ||\n value <= filter.value\n )\n return false;\n break;\n case \"gte\":\n if (\n typeof value !== \"number\" ||\n typeof filter.value !== \"number\" ||\n value < filter.value\n )\n return false;\n break;\n case \"lt\":\n if (\n typeof value !== \"number\" ||\n typeof filter.value !== \"number\" ||\n value >= filter.value\n )\n return false;\n break;\n case \"lte\":\n if (\n typeof value !== \"number\" ||\n typeof filter.value !== \"number\" ||\n value > filter.value\n )\n return false;\n break;\n case \"in\":\n if (!Array.isArray(filter.value) || !filter.value.includes(value))\n return false;\n break;\n case \"nin\":\n if (!Array.isArray(filter.value) || filter.value.includes(value))\n return false;\n break;\n case \"contains\":\n if (\n typeof value !== \"string\" ||\n typeof filter.value !== \"string\" ||\n !value.includes(filter.value)\n )\n return false;\n break;\n }\n }\n\n return true;\n }\n\n private generateHighlights(query: string, content: string): string[] {\n const words = query.toLowerCase().split(/\\s+/);\n const highlights: string[] = [];\n\n for (const word of words) {\n const index = content.toLowerCase().indexOf(word);\n if (index !== -1) {\n const start = Math.max(0, index - 30);\n const end = Math.min(content.length, index + word.length + 30);\n highlights.push(`...${content.slice(start, end)}...`);\n }\n }\n\n return highlights.slice(0, 3);\n }\n\n private deduplicateResults(\n results: RAGSearchResult[],\n threshold: number,\n ): RAGSearchResult[] {\n const deduplicated: RAGSearchResult[] = [];\n\n for (const result of results) {\n const isDuplicate = deduplicated.some((r) => {\n const embedding1 = this.embeddings.get(result.chunk.id);\n const embedding2 = this.embeddings.get(r.chunk.id);\n if (!embedding1 || !embedding2) return false;\n return this.cosineSimilarity(embedding1, embedding2) > threshold;\n });\n\n if (!isDuplicate) {\n deduplicated.push(result);\n }\n }\n\n return deduplicated;\n }\n}\n","/**\n * Testing Utilities for Platform Core\n *\n * This module provides utilities for testing applications that use platform-core.\n * Import from '@digilogiclabs/platform-core/testing' in your test files.\n */\n\n// ═══════════════════════════════════════════════════════════════\n// MEMORY ADAPTERS (Always safe for testing)\n// ═══════════════════════════════════════════════════════════════\n\nexport { MemoryDatabase } from \"./adapters/memory/MemoryDatabase\";\nexport { MemoryCache } from \"./adapters/memory/MemoryCache\";\nexport { MemoryStorage } from \"./adapters/memory/MemoryStorage\";\nexport { MemoryEmail } from \"./adapters/memory/MemoryEmail\";\nexport { MemoryQueue } from \"./adapters/memory/MemoryQueue\";\nexport { ConsoleEmail } from \"./adapters/console/ConsoleEmail\";\n\n// ═══════════════════════════════════════════════════════════════\n// SECRETS (Testing implementations)\n// ═══════════════════════════════════════════════════════════════\n\nexport { MemorySecrets, EnvSecrets } from \"./interfaces/ISecrets\";\n\n// ═══════════════════════════════════════════════════════════════\n// FACTORY (Creates in-memory platform)\n// ═══════════════════════════════════════════════════════════════\n\nexport { createPlatform } from \"./factory\";\n\n// ═══════════════════════════════════════════════════════════════\n// LOGGER & METRICS (Testing implementations)\n// ═══════════════════════════════════════════════════════════════\n\nexport { ConsoleLogger, NoopLogger } from \"./interfaces/ILogger\";\nexport { MemoryMetrics, NoopMetrics } from \"./interfaces/IMetrics\";\n\n// ═══════════════════════════════════════════════════════════════\n// INTERFACES (For type checking)\n// ═══════════════════════════════════════════════════════════════\n\nexport type {\n IDatabase,\n IQueryBuilder,\n QueryResult,\n ICache,\n IStorage,\n IEmail,\n IQueue,\n IPlatform,\n ILogger,\n IMetrics,\n ISecrets,\n Job,\n JobOptions,\n EmailMessage,\n StorageFile,\n} from \"./interfaces\";\n\n// ═══════════════════════════════════════════════════════════════\n// TEST HELPERS\n// ═══════════════════════════════════════════════════════════════\n\nimport type { IDatabase, IPlatform } from \"./interfaces\";\nimport { createPlatform } from \"./factory\";\nimport { MemoryDatabase } from \"./adapters/memory/MemoryDatabase\";\nimport { MemoryCache } from \"./adapters/memory/MemoryCache\";\nimport { MemoryStorage } from \"./adapters/memory/MemoryStorage\";\nimport { MemoryEmail } from \"./adapters/memory/MemoryEmail\";\nimport { MemoryQueue } from \"./adapters/memory/MemoryQueue\";\n\n/**\n * Create a fresh test platform with all memory adapters.\n * Each call creates a new isolated platform instance.\n */\nexport function createTestPlatform(): IPlatform {\n return createPlatform();\n}\n\n/**\n * Test platform with access to underlying adapters for assertions.\n * Allows direct inspection of emails sent, queue jobs, etc.\n */\nexport interface TestPlatformWithInternals extends IPlatform {\n /** Access underlying memory database */\n memoryDb: MemoryDatabase;\n /** Access underlying memory cache */\n memoryCache: MemoryCache;\n /** Access underlying memory storage */\n memoryStorage: MemoryStorage;\n /** Access underlying memory email (check sent emails) */\n memoryEmail: MemoryEmail;\n /** Access underlying memory queue (check queued jobs) */\n memoryQueue: MemoryQueue;\n}\n\n/**\n * Create a test platform with direct access to underlying adapters.\n * Useful for asserting on emails sent, jobs queued, etc.\n *\n * @example\n * ```typescript\n * const { platform, memoryEmail, memoryQueue } = createTestPlatformWithInternals();\n *\n * // Run your code that sends emails\n * await myService.sendWelcomeEmail(user);\n *\n * // Assert email was sent\n * const sentEmails = memoryEmail.getSentEmails();\n * expect(sentEmails).toHaveLength(1);\n * expect(sentEmails[0].to).toBe(user.email);\n * ```\n */\nexport function createTestPlatformWithInternals(): TestPlatformWithInternals {\n const memoryDb = new MemoryDatabase();\n const memoryCache = new MemoryCache();\n const memoryStorage = new MemoryStorage();\n const memoryEmail = new MemoryEmail();\n const memoryQueue = new MemoryQueue();\n\n const platform: IPlatform = {\n db: memoryDb,\n cache: memoryCache,\n storage: memoryStorage,\n email: memoryEmail,\n queue: memoryQueue,\n\n async healthCheck() {\n const [dbHealth, cacheHealth, storageHealth, emailHealth, queueHealth] =\n await Promise.all([\n memoryDb.healthCheck(),\n memoryCache.healthCheck(),\n memoryStorage.healthCheck(),\n memoryEmail.healthCheck(),\n memoryQueue.healthCheck(),\n ]);\n\n return {\n healthy:\n dbHealth &&\n cacheHealth &&\n storageHealth &&\n emailHealth &&\n queueHealth,\n services: {\n database: dbHealth,\n cache: cacheHealth,\n storage: storageHealth,\n email: emailHealth,\n queue: queueHealth,\n },\n timestamp: Date.now(),\n };\n },\n\n async close() {\n await Promise.all([\n memoryDb.close(),\n memoryCache.close(),\n memoryQueue.close(),\n ]);\n },\n };\n\n return {\n ...platform,\n memoryDb,\n memoryCache,\n memoryStorage,\n memoryEmail,\n memoryQueue,\n };\n}\n\n/**\n * Seed test data into a memory database.\n *\n * @example\n * ```typescript\n * const platform = createTestPlatform();\n * await seedTestData(platform.db, 'users', [\n * { id: '1', name: 'Alice', email: 'alice@test.com' },\n * { id: '2', name: 'Bob', email: 'bob@test.com' },\n * ]);\n * ```\n */\nexport async function seedTestData<T extends Record<string, unknown>>(\n db: IDatabase,\n table: string,\n data: T[],\n): Promise<void> {\n for (const row of data) {\n await db.from(table).insert(row).execute();\n }\n}\n\n/**\n * Clear all data from a test platform.\n * Useful in beforeEach/afterEach hooks.\n */\nexport async function clearTestPlatform(\n platform: TestPlatformWithInternals,\n): Promise<void> {\n platform.memoryDb.clear();\n platform.memoryCache.clear();\n platform.memoryStorage.clear();\n platform.memoryEmail.clear();\n platform.memoryQueue.clear();\n}\n\n/**\n * Wait for all pending queue jobs to complete.\n * Useful when testing async workflows.\n *\n * @param platform - Test platform with memory queue\n * @param timeoutMs - Maximum time to wait (default: 5000ms)\n */\nexport async function waitForQueueDrain(\n platform: TestPlatformWithInternals,\n timeoutMs: number = 5000,\n): Promise<void> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n const pendingJobs = platform.memoryQueue.getPendingJobs?.() ?? [];\n if (pendingJobs.length === 0) {\n return;\n }\n await new Promise((resolve) => setTimeout(resolve, 50));\n }\n\n throw new Error(`Queue did not drain within ${timeoutMs}ms`);\n}\n\n/**\n * Assert that an email was sent with specific properties.\n */\nexport function assertEmailSent(\n memoryEmail: MemoryEmail,\n expected: {\n to?: string;\n subject?: string | RegExp;\n bodyContains?: string;\n },\n): void {\n const emails = memoryEmail.getSentEmails();\n\n const matchesTo = (\n emailTo: string | string[] | undefined,\n expectedTo: string,\n ): boolean => {\n if (!emailTo) return false;\n if (Array.isArray(emailTo)) {\n return emailTo.some(\n (addr) =>\n addr === expectedTo ||\n (typeof addr === \"object\" &&\n (addr as { email?: string }).email === expectedTo),\n );\n }\n return (\n emailTo === expectedTo ||\n (typeof emailTo === \"object\" &&\n (emailTo as { email?: string }).email === expectedTo)\n );\n };\n\n const found = emails.find((email) => {\n if (\n expected.to &&\n !matchesTo(email.to as unknown as string | string[], expected.to)\n )\n return false;\n if (expected.subject) {\n if (\n typeof expected.subject === \"string\" &&\n email.subject !== expected.subject\n )\n return false;\n if (\n expected.subject instanceof RegExp &&\n !expected.subject.test(email.subject)\n )\n return false;\n }\n if (expected.bodyContains) {\n const body = email.html || email.text || \"\";\n if (!body.includes(expected.bodyContains)) return false;\n }\n return true;\n });\n\n if (!found) {\n const emailSummary = emails\n .map((e) => ` - To: ${JSON.stringify(e.to)}, Subject: ${e.subject}`)\n .join(\"\\n\");\n throw new Error(\n `Expected email not found.\\nExpected: ${JSON.stringify(expected)}\\nSent emails:\\n${emailSummary || \" (none)\"}`,\n );\n }\n}\n\n/**\n * Create a mock function that tracks calls.\n * Simple alternative to jest.fn() for test frameworks without built-in mocking.\n */\nexport function createMockFn<TArgs extends unknown[], TReturn>(\n implementation?: (...args: TArgs) => TReturn,\n): {\n (...args: TArgs): TReturn;\n calls: TArgs[];\n callCount: number;\n lastCall: TArgs | undefined;\n reset: () => void;\n} {\n const calls: TArgs[] = [];\n\n const fn = function (...args: TArgs): TReturn {\n calls.push(args);\n return implementation?.(...args) as TReturn;\n };\n\n Object.defineProperty(fn, \"calls\", {\n get: () => calls,\n });\n\n Object.defineProperty(fn, \"callCount\", {\n get: () => calls.length,\n });\n\n Object.defineProperty(fn, \"lastCall\", {\n get: () => calls[calls.length - 1],\n });\n\n fn.reset = () => {\n calls.length = 0;\n };\n\n return fn as typeof fn & {\n calls: TArgs[];\n callCount: number;\n lastCall: TArgs | undefined;\n reset: () => void;\n };\n}\n","/**\n * Memory Database Adapter\n * In-memory implementation for testing\n */\n\nimport {\n IDatabase,\n IQueryBuilder,\n QueryResult,\n} from \"../../interfaces/IDatabase\";\n\nexport class MemoryDatabase implements IDatabase {\n private tables: Map<string, unknown[]> = new Map();\n\n from<T = unknown>(table: string): IQueryBuilder<T> {\n if (!this.tables.has(table)) {\n this.tables.set(table, []);\n }\n return new MemoryQueryBuilder<T>(this.tables, table);\n }\n\n async raw<T = unknown>(\n sql: string,\n params?: unknown[],\n ): Promise<QueryResult<T>> {\n // Basic implementation - just return empty for now\n console.warn(\"MemoryDatabase.raw() is a stub implementation\");\n return { data: [] };\n }\n\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\n // Memory adapter doesn't need real transactions\n return fn(this);\n }\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n async close(): Promise<void> {\n this.tables.clear();\n }\n\n /**\n * Clear all data (for testing)\n */\n clear(): void {\n this.tables.clear();\n }\n\n /**\n * Get table data (for testing)\n */\n getTable<T = unknown>(tableName: string): T[] {\n return (this.tables.get(tableName) as T[]) ?? [];\n }\n}\n\nclass MemoryQueryBuilder<T = unknown> implements IQueryBuilder<T> {\n private tables: Map<string, unknown[]>;\n private tableName: string;\n private _select: string[] = [\"*\"];\n private _where: Array<{ column: string; operator: string; value: unknown }> =\n [];\n private _orderBy: { column: string; direction: \"asc\" | \"desc\" } | null = null;\n private _limit: number | null = null;\n private _offset: number = 0;\n private _insertData: Partial<T>[] | null = null;\n private _updateData: Partial<T> | null = null;\n private _deleteFlag: boolean = false;\n\n constructor(tables: Map<string, unknown[]>, tableName: string) {\n this.tables = tables;\n this.tableName = tableName;\n }\n\n select(columns?: string | string[]): IQueryBuilder<T> {\n if (columns) {\n this._select = Array.isArray(columns) ? columns : [columns];\n }\n return this;\n }\n\n insert(data: Partial<T> | Partial<T>[]): IQueryBuilder<T> {\n this._insertData = Array.isArray(data) ? data : [data];\n return this;\n }\n\n update(data: Partial<T>): IQueryBuilder<T> {\n this._updateData = data;\n return this;\n }\n\n delete(): IQueryBuilder<T> {\n this._deleteFlag = true;\n return this;\n }\n\n where(column: string, operator: string, value: unknown): IQueryBuilder<T> {\n this._where.push({ column, operator, value });\n return this;\n }\n\n whereIn(column: string, values: unknown[]): IQueryBuilder<T> {\n this._where.push({ column, operator: \"in\", value: values });\n return this;\n }\n\n orderBy(column: string, direction: \"asc\" | \"desc\" = \"asc\"): IQueryBuilder<T> {\n this._orderBy = { column, direction };\n return this;\n }\n\n limit(count: number): IQueryBuilder<T> {\n this._limit = count;\n return this;\n }\n\n offset(count: number): IQueryBuilder<T> {\n this._offset = count;\n return this;\n }\n\n async single(): Promise<{ data: T | null; error?: Error }> {\n const result = await this.execute();\n return { data: result.data[0] || null };\n }\n\n async execute(): Promise<QueryResult<T>> {\n const table = (this.tables.get(this.tableName) as T[]) || [];\n\n // Handle insert\n if (this._insertData) {\n const newItems = this._insertData.map((item, i) => ({\n id: `mem_${Date.now()}_${i}`,\n ...item,\n created_at: new Date().toISOString(),\n }));\n this.tables.set(this.tableName, [...table, ...newItems]);\n return { data: newItems as T[] };\n }\n\n // Handle delete\n if (this._deleteFlag) {\n const filtered = table.filter((item) => !this.matchesWhere(item));\n const deleted = table.filter((item) => this.matchesWhere(item));\n this.tables.set(this.tableName, filtered);\n return { data: deleted, count: deleted.length };\n }\n\n // Handle update\n if (this._updateData) {\n const updated: T[] = [];\n const newTable = table.map((item) => {\n if (this.matchesWhere(item)) {\n const updatedItem = {\n ...item,\n ...this._updateData,\n updated_at: new Date().toISOString(),\n };\n updated.push(updatedItem as T);\n return updatedItem;\n }\n return item;\n });\n this.tables.set(this.tableName, newTable);\n return { data: updated, count: updated.length };\n }\n\n // Handle select\n let result = table.filter((item) => this.matchesWhere(item));\n\n // Sort\n if (this._orderBy) {\n const { column, direction } = this._orderBy;\n result.sort((a, b) => {\n const aVal = (a as Record<string, unknown>)[column] as\n | string\n | number\n | null;\n const bVal = (b as Record<string, unknown>)[column] as\n | string\n | number\n | null;\n if (aVal === null || aVal === undefined)\n return direction === \"asc\" ? 1 : -1;\n if (bVal === null || bVal === undefined)\n return direction === \"asc\" ? -1 : 1;\n const cmp = aVal < bVal ? -1 : aVal > bVal ? 1 : 0;\n return direction === \"asc\" ? cmp : -cmp;\n });\n }\n\n // Pagination\n if (this._offset > 0 || this._limit !== null) {\n const start = this._offset;\n const end = this._limit !== null ? start + this._limit : undefined;\n result = result.slice(start, end);\n }\n\n return { data: result, count: result.length };\n }\n\n private matchesWhere(item: T): boolean {\n if (this._where.length === 0) return true;\n\n return this._where.every(({ column, operator, value }) => {\n const itemValue = (item as Record<string, unknown>)[column];\n\n switch (operator) {\n case \"=\":\n case \"==\":\n return itemValue === value;\n case \"!=\":\n case \"<>\":\n return itemValue !== value;\n case \">\":\n return (itemValue as number) > (value as number);\n case \">=\":\n return (itemValue as number) >= (value as number);\n case \"<\":\n return (itemValue as number) < (value as number);\n case \"<=\":\n return (itemValue as number) <= (value as number);\n case \"in\":\n return Array.isArray(value) && value.includes(itemValue);\n case \"like\":\n return String(itemValue).includes(String(value).replace(/%/g, \"\"));\n default:\n return itemValue === value;\n }\n });\n }\n}\n","/**\n * Memory Cache Adapter\n * In-memory implementation for testing\n */\n\nimport { ICache } from \"../../interfaces/ICache\";\n\ninterface CacheEntry<T> {\n value: T;\n expiresAt: number | null;\n}\n\nexport class MemoryCache implements ICache {\n private store: Map<string, CacheEntry<unknown>> = new Map();\n private subscriptions: Map<string, Set<(message: string) => void>> =\n new Map();\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const entry = this.store.get(key);\n if (!entry) return null;\n\n if (entry.expiresAt && Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return null;\n }\n\n return entry.value as T;\n }\n\n async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n const expiresAt = ttl ? Date.now() + ttl * 1000 : null;\n this.store.set(key, { value, expiresAt });\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n async exists(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== null;\n }\n\n async deletePattern(pattern: string): Promise<number> {\n const regex = new RegExp(\"^\" + pattern.replace(/\\*/g, \".*\") + \"$\");\n let count = 0;\n\n for (const key of this.store.keys()) {\n if (regex.test(key)) {\n this.store.delete(key);\n count++;\n }\n }\n\n return count;\n }\n\n async mget<T = unknown>(keys: string[]): Promise<(T | null)[]> {\n return Promise.all(keys.map((key) => this.get<T>(key)));\n }\n\n async mset<T = unknown>(\n entries: Array<{ key: string; value: T; ttl?: number }>,\n ): Promise<void> {\n await Promise.all(\n entries.map(({ key, value, ttl }) => this.set(key, value, ttl)),\n );\n }\n\n async incr(key: string, by: number = 1): Promise<number> {\n const current = (await this.get<number>(key)) || 0;\n const newValue = current + by;\n await this.set(key, newValue);\n return newValue;\n }\n\n async publish(channel: string, message: string): Promise<void> {\n const subscribers = this.subscriptions.get(channel);\n if (subscribers) {\n subscribers.forEach((callback) => callback(message));\n }\n }\n\n async subscribe(\n channel: string,\n callback: (message: string) => void,\n ): Promise<() => void> {\n if (!this.subscriptions.has(channel)) {\n this.subscriptions.set(channel, new Set());\n }\n\n this.subscriptions.get(channel)!.add(callback);\n\n return () => {\n this.subscriptions.get(channel)?.delete(callback);\n };\n }\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n async close(): Promise<void> {\n this.store.clear();\n this.subscriptions.clear();\n }\n\n /**\n * Clear all cached data (for testing)\n */\n clear(): void {\n this.store.clear();\n this.subscriptions.clear();\n }\n\n /**\n * Get number of cached items (for testing)\n */\n get size(): number {\n return this.store.size;\n }\n}\n","// Memory Storage - stub implementation\nimport {\n IStorage,\n StorageFile,\n UploadOptions,\n} from \"../../interfaces/IStorage\";\n\nexport class MemoryStorage implements IStorage {\n private files = new Map<string, { data: Buffer; contentType?: string }>();\n\n async upload(\n key: string,\n data: Buffer | Blob | ReadableStream,\n options?: UploadOptions,\n ) {\n this.files.set(key, {\n data: Buffer.from(\"mock\"),\n contentType: options?.contentType,\n });\n return { url: \"memory://\" + key };\n }\n async download(key: string) {\n return this.files.get(key)?.data || Buffer.from(\"\");\n }\n async getSignedUrl(key: string) {\n return \"memory://\" + key;\n }\n async delete(key: string) {\n this.files.delete(key);\n }\n async deleteMany(keys: string[]) {\n keys.forEach((k) => this.files.delete(k));\n }\n async list(prefix?: string): Promise<StorageFile[]> {\n return [];\n }\n async exists(key: string) {\n return this.files.has(key);\n }\n async getMetadata(key: string) {\n return null;\n }\n async healthCheck() {\n return true;\n }\n\n /**\n * Clear all files (for testing)\n */\n clear(): void {\n this.files.clear();\n }\n\n /**\n * Get number of stored files (for testing)\n */\n get size(): number {\n return this.files.size;\n }\n}\n","// Memory Email - stub implementation\nimport { IEmail, EmailMessage, EmailResult } from \"../../interfaces/IEmail\";\n\nexport class MemoryEmail implements IEmail {\n private sentEmails: EmailMessage[] = [];\n\n async send(message: EmailMessage): Promise<EmailResult> {\n this.sentEmails.push(message);\n return { id: \"mem_\" + this.sentEmails.length, success: true };\n }\n\n async sendBatch(messages: EmailMessage[]): Promise<EmailResult[]> {\n return Promise.all(messages.map((m) => this.send(m)));\n }\n\n async healthCheck() {\n return true;\n }\n\n // Test helpers\n getSentEmails(): EmailMessage[] {\n return this.sentEmails;\n }\n\n /**\n * Clear sent emails (for testing)\n */\n clear(): void {\n this.sentEmails = [];\n }\n\n /**\n * Get number of sent emails (for testing)\n */\n get size(): number {\n return this.sentEmails.length;\n }\n}\n","/**\n * Queue abstraction interface\n * Provides a vendor-agnostic way to work with job queues\n *\n * Design Principles:\n * - Self-hostable: Works with Redis (BullMQ) or in-memory for testing\n * - No cloud lock-in: All adapters use open-source technologies\n * - Backward compatible: All new fields/methods are optional\n * - Zero external costs: Only requires self-hosted Redis for production\n */\n\n// ═══════════════════════════════════════════════════════════════\n// BACKOFF & REPEAT OPTIONS\n// ═══════════════════════════════════════════════════════════════\n\nexport interface BackoffOptions {\n type: \"fixed\" | \"exponential\";\n delay: number;\n /** Maximum delay for exponential backoff (ms) */\n maxDelay?: number;\n}\n\nexport interface RepeatOptions {\n /** Repeat every N milliseconds */\n every?: number;\n /** Cron expression (e.g., \"0 * * * *\" for hourly) */\n cron?: string;\n /** Timezone for cron (e.g., \"America/New_York\") */\n tz?: string;\n /** Maximum number of times to repeat */\n limit?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// JOB OPTIONS (backward compatible - all new fields optional)\n// ═══════════════════════════════════════════════════════════════\n\nexport interface JobOptions {\n /** Delay before job is processed (ms) */\n delay?: number;\n /** Number of retry attempts */\n attempts?: number;\n /** Backoff strategy */\n backoff?: BackoffOptions;\n /** Job priority (higher = more priority) */\n priority?: number;\n /** Remove job after completion */\n removeOnComplete?: boolean | number;\n /** Remove job after failure */\n removeOnFail?: boolean | number;\n /** Job timeout in milliseconds (new) */\n timeout?: number;\n /** Custom job ID (new) */\n jobId?: string;\n /** Repeat/cron options (new) */\n repeat?: RepeatOptions;\n /** Correlation ID for tracing (new) */\n correlationId?: string;\n /** Custom metadata (new) */\n metadata?: Record<string, unknown>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// JOB TYPES (backward compatible - all new fields optional)\n// ═══════════════════════════════════════════════════════════════\n\nexport type JobState =\n | \"waiting\"\n | \"active\"\n | \"completed\"\n | \"failed\"\n | \"delayed\";\n\nexport interface Job<T = unknown> {\n id: string;\n name: string;\n data: T;\n attemptsMade: number;\n progress: number;\n timestamp: number;\n /** Job state (new, optional) */\n state?: JobState;\n /** Processing start time (new, optional) */\n processedOn?: number;\n /** Completion time (new, optional) */\n finishedOn?: number;\n /** Failure reason (new, optional) */\n failedReason?: string;\n /** Correlation ID (new, optional) */\n correlationId?: string;\n /** Custom metadata (new, optional) */\n metadata?: Record<string, unknown>;\n}\n\nexport interface JobResult<T = unknown> {\n jobId: string;\n result?: T;\n error?: Error;\n /** Duration in ms (new, optional) */\n duration?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// JOB CONTEXT (new - for enhanced handlers)\n// ═══════════════════════════════════════════════════════════════\n\nexport interface JobContext<T = unknown> {\n job: Job<T>;\n /** Update job progress (0-100) */\n updateProgress(progress: number): Promise<void>;\n /** Log message for this job */\n log(message: string): void;\n /** Check if job timed out */\n isTimedOut(): boolean;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// QUEUE STATISTICS\n// ═══════════════════════════════════════════════════════════════\n\nexport interface QueueStats {\n waiting: number;\n active: number;\n completed: number;\n failed: number;\n delayed: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// JOB EVENTS (new)\n// ═══════════════════════════════════════════════════════════════\n\nexport type JobEventType =\n | \"completed\"\n | \"failed\"\n | \"progress\"\n | \"active\"\n | \"stalled\";\n\nexport interface JobEvent<T = unknown> {\n type: JobEventType;\n job: Job<T>;\n result?: unknown;\n error?: Error;\n progress?: number;\n timestamp: number;\n}\n\nexport type JobEventHandler<T = unknown> = (\n event: JobEvent<T>,\n) => void | Promise<void>;\n\n// ═══════════════════════════════════════════════════════════════\n// QUEUE INTERFACE (backward compatible - new methods optional)\n// ═══════════════════════════════════════════════════════════════\n\nexport interface IQueue<T = unknown> {\n // ─────────────────────────────────────────────────────────────\n // Core Methods (existing - unchanged)\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Add a job to the queue\n */\n add(name: string, data: T, options?: JobOptions): Promise<Job<T>>;\n\n /**\n * Add multiple jobs\n */\n addBulk(\n jobs: Array<{ name: string; data: T; options?: JobOptions }>,\n ): Promise<Job<T>[]>;\n\n /**\n * Process jobs (backward compatible signature)\n * New signature with options is also supported\n */\n process(\n handler: (job: Job<T>) => Promise<unknown>,\n options?: { concurrency?: number },\n ): void;\n\n /**\n * Get a job by ID\n */\n getJob(id: string): Promise<Job<T> | null>;\n\n /**\n * Remove a job\n */\n removeJob(id: string): Promise<void>;\n\n /**\n * Pause the queue\n */\n pause(): Promise<void>;\n\n /**\n * Resume the queue\n */\n resume(): Promise<void>;\n\n /**\n * Get queue statistics\n */\n getStats(): Promise<QueueStats>;\n\n /**\n * Check queue connectivity\n */\n healthCheck(): Promise<boolean>;\n\n /**\n * Close queue connection\n */\n close(): Promise<void>;\n\n // ─────────────────────────────────────────────────────────────\n // New Methods (optional - adapters may throw \"not implemented\")\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Add a recurring job (cron/interval)\n * @throws {Error} If adapter doesn't support recurring jobs\n */\n addRecurring?(\n name: string,\n data: T,\n repeat: RepeatOptions,\n options?: Omit<JobOptions, \"repeat\">,\n ): Promise<Job<T>>;\n\n /**\n * Get jobs by state\n */\n getJobs?(\n state: JobState | JobState[],\n start?: number,\n end?: number,\n ): Promise<Job<T>[]>;\n\n /**\n * Get failed jobs (dead letter queue)\n */\n getFailedJobs?(start?: number, end?: number): Promise<Job<T>[]>;\n\n /**\n * Retry a failed job\n */\n retryJob?(id: string): Promise<void>;\n\n /**\n * Replay all failed jobs\n */\n replayAllFailed?(): Promise<number>;\n\n /**\n * Update job progress\n */\n updateProgress?(id: string, progress: number): Promise<void>;\n\n /**\n * Clean old jobs\n */\n clean?(grace: number, limit: number, state: JobState): Promise<string[]>;\n\n /**\n * Remove all jobs\n */\n obliterate?(options?: { force?: boolean }): Promise<void>;\n\n /**\n * Subscribe to job events\n */\n on?(event: JobEventType, handler: JobEventHandler<T>): void;\n\n /**\n * Unsubscribe from job events\n */\n off?(event: JobEventType, handler: JobEventHandler<T>): void;\n\n /**\n * Get queue name\n */\n getName?(): string;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// HELPER FUNCTIONS\n// ═══════════════════════════════════════════════════════════════\n\nimport { randomBytes } from \"crypto\";\n\n/**\n * Calculate exponential backoff delay\n */\nexport function calculateBackoff(\n attempt: number,\n options: BackoffOptions,\n): number {\n if (options.type === \"fixed\") {\n return options.delay;\n }\n const delay = options.delay * Math.pow(2, attempt - 1);\n const maxDelay = options.maxDelay ?? options.delay * 32;\n return Math.min(delay, maxDelay);\n}\n\n/**\n * Generate a unique job ID\n */\nexport function generateJobId(): string {\n const timestamp = Date.now().toString(36);\n const random = randomBytes(4).toString(\"hex\");\n return `job_${timestamp}_${random}`;\n}\n","/**\n * Correlation Context using AsyncLocalStorage\n *\n * Provides automatic propagation of trace/correlation IDs and request context\n * across async operations without explicit passing.\n *\n * Design Principles:\n * - Zero external dependencies (uses Node.js built-in AsyncLocalStorage)\n * - Self-hosted compatible\n * - Integrates with logging, metrics, and tracing\n */\n\nimport { AsyncLocalStorage } from \"async_hooks\";\nimport { randomBytes } from \"crypto\";\n\n// ═══════════════════════════════════════════════════════════════\n// CONTEXT TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport interface CorrelationData {\n /** Unique trace ID for distributed tracing */\n traceId?: string;\n /** Span ID for current operation */\n spanId?: string;\n /** Request ID for HTTP requests */\n requestId?: string;\n /** Correlation ID for job/event processing */\n correlationId?: string;\n /** User ID if authenticated */\n userId?: string;\n /** Tenant ID for multi-tenant applications */\n tenantId?: string;\n /** Session ID */\n sessionId?: string;\n /** Custom metadata */\n metadata?: Record<string, unknown>;\n /** Operation name (for logging) */\n operation?: string;\n /** Start time of the context */\n startTime?: number;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// CORRELATION CONTEXT CLASS\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Singleton correlation context using AsyncLocalStorage\n */\nclass CorrelationContextManager {\n private storage = new AsyncLocalStorage<CorrelationData>();\n private idGenerator: () => string;\n\n constructor() {\n // Default ID generator (can be overridden)\n this.idGenerator = () => {\n const timestamp = Date.now().toString(36);\n const random = randomBytes(4).toString(\"hex\");\n return `${timestamp}-${random}`;\n };\n }\n\n /**\n * Set custom ID generator\n */\n setIdGenerator(generator: () => string): void {\n this.idGenerator = generator;\n }\n\n /**\n * Generate a new ID\n */\n generateId(): string {\n return this.idGenerator();\n }\n\n /**\n * Run a function with correlation context\n */\n run<T>(data: CorrelationData, fn: () => T): T {\n return this.storage.run(\n {\n ...data,\n startTime: data.startTime ?? Date.now(),\n },\n fn,\n );\n }\n\n /**\n * Run an async function with correlation context\n */\n async runAsync<T>(data: CorrelationData, fn: () => Promise<T>): Promise<T> {\n return this.storage.run(\n {\n ...data,\n startTime: data.startTime ?? Date.now(),\n },\n fn,\n );\n }\n\n /**\n * Get current correlation data\n */\n get(): CorrelationData | undefined {\n return this.storage.getStore();\n }\n\n /**\n * Get current correlation data or empty object\n */\n getOrEmpty(): CorrelationData {\n return this.storage.getStore() ?? {};\n }\n\n /**\n * Get trace ID from current context\n */\n getTraceId(): string | undefined {\n return this.get()?.traceId;\n }\n\n /**\n * Get correlation ID from current context\n */\n getCorrelationId(): string | undefined {\n return this.get()?.correlationId ?? this.get()?.traceId;\n }\n\n /**\n * Get request ID from current context\n */\n getRequestId(): string | undefined {\n return this.get()?.requestId;\n }\n\n /**\n * Get user ID from current context\n */\n getUserId(): string | undefined {\n return this.get()?.userId;\n }\n\n /**\n * Get tenant ID from current context\n */\n getTenantId(): string | undefined {\n return this.get()?.tenantId;\n }\n\n /**\n * Check if we're in a correlation context\n */\n isInContext(): boolean {\n return this.storage.getStore() !== undefined;\n }\n\n /**\n * Update current context (merge data)\n * Note: This doesn't actually update the store, but returns merged data\n * for use in nested contexts\n */\n extend(data: Partial<CorrelationData>): CorrelationData {\n const current = this.get() ?? {};\n return {\n ...current,\n ...data,\n metadata: {\n ...current.metadata,\n ...data.metadata,\n },\n };\n }\n\n /**\n * Run a nested context with extended data\n */\n runNested<T>(data: Partial<CorrelationData>, fn: () => T): T {\n return this.run(this.extend(data), fn);\n }\n\n /**\n * Run a nested async context with extended data\n */\n async runNestedAsync<T>(\n data: Partial<CorrelationData>,\n fn: () => Promise<T>,\n ): Promise<T> {\n return this.runAsync(this.extend(data), fn);\n }\n\n /**\n * Get context as log metadata (for structured logging)\n */\n getLogMeta(): Record<string, unknown> {\n const ctx = this.get();\n if (!ctx) return {};\n\n const meta: Record<string, unknown> = {};\n\n if (ctx.traceId) meta.traceId = ctx.traceId;\n if (ctx.spanId) meta.spanId = ctx.spanId;\n if (ctx.requestId) meta.requestId = ctx.requestId;\n if (ctx.correlationId) meta.correlationId = ctx.correlationId;\n if (ctx.userId) meta.userId = ctx.userId;\n if (ctx.tenantId) meta.tenantId = ctx.tenantId;\n if (ctx.sessionId) meta.sessionId = ctx.sessionId;\n if (ctx.operation) meta.operation = ctx.operation;\n\n return meta;\n }\n\n /**\n * Get context as HTTP headers (for propagation)\n */\n getHeaders(): Record<string, string> {\n const ctx = this.get();\n if (!ctx) return {};\n\n const headers: Record<string, string> = {};\n\n if (ctx.traceId) {\n // W3C Trace Context format\n const spanId = ctx.spanId ?? this.generateId().substring(0, 16);\n headers[\"traceparent\"] = `00-${ctx.traceId}-${spanId}-01`;\n }\n\n if (ctx.requestId) {\n headers[\"x-request-id\"] = ctx.requestId;\n }\n\n if (ctx.correlationId) {\n headers[\"x-correlation-id\"] = ctx.correlationId;\n }\n\n return headers;\n }\n\n /**\n * Parse context from HTTP headers\n */\n parseHeaders(\n headers: Record<string, string | string[] | undefined>,\n ): CorrelationData {\n const data: CorrelationData = {};\n\n // Parse W3C Trace Context\n const traceparent = headers[\"traceparent\"];\n if (traceparent && typeof traceparent === \"string\") {\n const parts = traceparent.split(\"-\");\n if (parts.length >= 3 && parts[0] === \"00\") {\n data.traceId = parts[1];\n data.spanId = parts[2];\n }\n }\n\n // Parse request ID\n const requestId = headers[\"x-request-id\"];\n if (requestId) {\n data.requestId = Array.isArray(requestId) ? requestId[0] : requestId;\n }\n\n // Parse correlation ID\n const correlationId = headers[\"x-correlation-id\"];\n if (correlationId) {\n data.correlationId = Array.isArray(correlationId)\n ? correlationId[0]\n : correlationId;\n }\n\n return data;\n }\n\n /**\n * Get elapsed time since context start (ms)\n */\n getElapsed(): number {\n const ctx = this.get();\n if (!ctx?.startTime) return 0;\n return Date.now() - ctx.startTime;\n }\n\n /**\n * Create a child span context\n */\n createChildSpan(operation: string): CorrelationData {\n const current = this.get() ?? {};\n return {\n ...current,\n spanId: this.generateId().substring(0, 16),\n operation,\n startTime: Date.now(),\n };\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// SINGLETON INSTANCE & EXPORTS\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Global correlation context instance\n */\nexport const correlationContext = new CorrelationContextManager();\n\n// Convenience exports\nexport const runWithContext = correlationContext.run.bind(correlationContext);\nexport const runWithContextAsync =\n correlationContext.runAsync.bind(correlationContext);\nexport const getContext = correlationContext.get.bind(correlationContext);\nexport const getTraceId =\n correlationContext.getTraceId.bind(correlationContext);\nexport const getCorrelationId =\n correlationContext.getCorrelationId.bind(correlationContext);\nexport const getRequestId =\n correlationContext.getRequestId.bind(correlationContext);\nexport const getUserId = correlationContext.getUserId.bind(correlationContext);\nexport const getTenantId =\n correlationContext.getTenantId.bind(correlationContext);\nexport const getLogMeta =\n correlationContext.getLogMeta.bind(correlationContext);\nexport const isInContext =\n correlationContext.isInContext.bind(correlationContext);\n\n// ═══════════════════════════════════════════════════════════════\n// MIDDLEWARE HELPERS\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Create correlation context from incoming HTTP request\n */\nexport function createRequestContext(\n headers: Record<string, string | string[] | undefined>,\n options?: {\n generateTraceId?: boolean;\n generateRequestId?: boolean;\n operation?: string;\n userId?: string;\n tenantId?: string;\n },\n): CorrelationData {\n const parsed = correlationContext.parseHeaders(headers);\n\n return {\n ...parsed,\n traceId:\n parsed.traceId ??\n (options?.generateTraceId ? correlationContext.generateId() : undefined),\n requestId:\n parsed.requestId ??\n (options?.generateRequestId\n ? correlationContext.generateId()\n : undefined),\n operation: options?.operation,\n userId: options?.userId,\n tenantId: options?.tenantId,\n startTime: Date.now(),\n };\n}\n\n/**\n * Create correlation context for queue job processing\n */\nexport function createJobContext(job: {\n id: string;\n name: string;\n correlationId?: string;\n metadata?: Record<string, unknown>;\n}): CorrelationData {\n return {\n correlationId: job.correlationId ?? job.id,\n traceId: correlationContext.generateId(),\n operation: `job:${job.name}`,\n metadata: job.metadata,\n startTime: Date.now(),\n };\n}\n\n/**\n * Decorator to wrap a function with correlation context\n */\nexport function withCorrelation<TArgs extends unknown[], TReturn>(\n fn: (...args: TArgs) => TReturn,\n getContext: (...args: TArgs) => CorrelationData,\n): (...args: TArgs) => TReturn {\n return (...args: TArgs) => {\n const ctx = getContext(...args);\n return correlationContext.run(ctx, () => fn(...args));\n };\n}\n\n/**\n * Decorator to wrap an async function with correlation context\n */\nexport function withCorrelationAsync<TArgs extends unknown[], TReturn>(\n fn: (...args: TArgs) => Promise<TReturn>,\n getContext: (...args: TArgs) => CorrelationData,\n): (...args: TArgs) => Promise<TReturn> {\n return async (...args: TArgs) => {\n const ctx = getContext(...args);\n return correlationContext.runAsync(ctx, () => fn(...args));\n };\n}\n","/**\n * Enhanced Memory Queue Implementation\n *\n * Full-featured in-memory queue for testing with:\n * - Retry/backoff support\n * - Job state management\n * - Event emitters\n * - Dead letter queue (failed jobs)\n * - Recurring job support\n *\n * Design: Self-contained, no external dependencies, full IQueue compliance\n */\nimport {\n IQueue,\n Job,\n JobOptions,\n JobState,\n QueueStats,\n RepeatOptions,\n JobEventType,\n JobEventHandler,\n JobEvent,\n calculateBackoff,\n generateJobId,\n} from \"../../interfaces/IQueue\";\nimport { createJobContext, runWithContext } from \"../../context\";\n\ninterface InternalJob<T> extends Job<T> {\n options?: JobOptions;\n repeatKey?: string;\n}\n\nexport class MemoryQueue<T = unknown> implements IQueue<T> {\n private jobs: Map<string, InternalJob<T>> = new Map();\n private handlers: Array<(job: Job<T>) => Promise<unknown>> = [];\n private eventHandlers: Map<JobEventType, Set<JobEventHandler<T>>> = new Map();\n private paused = false;\n private processingConcurrency = 1;\n private activeCount = 0;\n private repeatIntervals: Map<string, NodeJS.Timeout> = new Map();\n private queueName: string;\n private processingQueue: string[] = [];\n private isProcessing = false;\n\n constructor(name: string = \"default\") {\n this.queueName = name;\n }\n\n // ═══════════════════════════════════════════════════════════════\n // CORE METHODS (IQueue interface)\n // ═══════════════════════════════════════════════════════════════\n\n async add(name: string, data: T, options?: JobOptions): Promise<Job<T>> {\n const jobId = options?.jobId || generateJobId();\n const now = Date.now();\n\n const job: InternalJob<T> = {\n id: jobId,\n name,\n data,\n attemptsMade: 0,\n progress: 0,\n timestamp: now,\n state: options?.delay ? \"delayed\" : \"waiting\",\n correlationId: options?.correlationId,\n metadata: options?.metadata,\n options,\n };\n\n this.jobs.set(jobId, job);\n\n // Handle delayed jobs\n if (options?.delay && options.delay > 0) {\n setTimeout(() => {\n const j = this.jobs.get(jobId);\n if (j && j.state === \"delayed\") {\n j.state = \"waiting\";\n this.processNext();\n }\n }, options.delay);\n } else {\n this.processNext();\n }\n\n return this.toPublicJob(job);\n }\n\n async addBulk(\n jobs: Array<{ name: string; data: T; options?: JobOptions }>,\n ): Promise<Job<T>[]> {\n return Promise.all(jobs.map((j) => this.add(j.name, j.data, j.options)));\n }\n\n process(\n handler: (job: Job<T>) => Promise<unknown>,\n options?: { concurrency?: number },\n ): void {\n this.handlers.push(handler);\n if (options?.concurrency) {\n this.processingConcurrency = options.concurrency;\n }\n this.processNext();\n }\n\n async getJob(id: string): Promise<Job<T> | null> {\n const job = this.jobs.get(id);\n return job ? this.toPublicJob(job) : null;\n }\n\n async removeJob(id: string): Promise<void> {\n this.jobs.delete(id);\n }\n\n async pause(): Promise<void> {\n this.paused = true;\n }\n\n async resume(): Promise<void> {\n this.paused = false;\n this.processNext();\n }\n\n async getStats(): Promise<QueueStats> {\n const stats: QueueStats = {\n waiting: 0,\n active: 0,\n completed: 0,\n failed: 0,\n delayed: 0,\n };\n\n for (const job of this.jobs.values()) {\n switch (job.state) {\n case \"waiting\":\n stats.waiting++;\n break;\n case \"active\":\n stats.active++;\n break;\n case \"completed\":\n stats.completed++;\n break;\n case \"failed\":\n stats.failed++;\n break;\n case \"delayed\":\n stats.delayed++;\n break;\n }\n }\n\n return stats;\n }\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n async close(): Promise<void> {\n // Clear all intervals for recurring jobs\n for (const interval of this.repeatIntervals.values()) {\n clearInterval(interval);\n }\n this.repeatIntervals.clear();\n this.jobs.clear();\n this.handlers = [];\n this.eventHandlers.clear();\n this.paused = true;\n }\n\n // ═══════════════════════════════════════════════════════════════\n // OPTIONAL METHODS (new in enhanced interface)\n // ═══════════════════════════════════════════════════════════════\n\n async addRecurring(\n name: string,\n data: T,\n repeat: RepeatOptions,\n options?: Omit<JobOptions, \"repeat\">,\n ): Promise<Job<T>> {\n const repeatKey = `repeat:${name}:${Date.now()}`;\n\n // Create initial job\n const job = await this.add(name, data, { ...options, jobId: repeatKey });\n const internalJob = this.jobs.get(repeatKey);\n if (internalJob) {\n internalJob.repeatKey = repeatKey;\n }\n\n // Set up recurring execution\n if (repeat.every) {\n let execCount = 0;\n const interval = setInterval(async () => {\n if (repeat.limit && execCount >= repeat.limit) {\n clearInterval(interval);\n this.repeatIntervals.delete(repeatKey);\n return;\n }\n execCount++;\n await this.add(name, data, options);\n }, repeat.every);\n\n this.repeatIntervals.set(repeatKey, interval);\n }\n\n // Note: Cron support would require a cron parser library\n // For memory adapter, we support interval-based repeat only\n if (repeat.cron) {\n console.warn(\n \"MemoryQueue: Cron expressions not supported, use 'every' for intervals\",\n );\n }\n\n return job;\n }\n\n async getJobs(\n state: JobState | JobState[],\n start: number = 0,\n end: number = -1,\n ): Promise<Job<T>[]> {\n const states = Array.isArray(state) ? state : [state];\n const filtered = Array.from(this.jobs.values())\n .filter((j) => states.includes(j.state || \"waiting\"))\n .sort((a, b) => a.timestamp - b.timestamp);\n\n const endIndex = end === -1 ? filtered.length : end + 1;\n return filtered.slice(start, endIndex).map((j) => this.toPublicJob(j));\n }\n\n async getFailedJobs(start: number = 0, end: number = -1): Promise<Job<T>[]> {\n return this.getJobs(\"failed\", start, end);\n }\n\n async retryJob(id: string): Promise<void> {\n const job = this.jobs.get(id);\n if (!job || job.state !== \"failed\") {\n return;\n }\n\n job.state = \"waiting\";\n job.attemptsMade = 0;\n job.failedReason = undefined;\n this.processNext();\n }\n\n async replayAllFailed(): Promise<number> {\n const failedJobs = Array.from(this.jobs.values()).filter(\n (j) => j.state === \"failed\",\n );\n\n for (const job of failedJobs) {\n job.state = \"waiting\";\n job.attemptsMade = 0;\n job.failedReason = undefined;\n }\n\n this.processNext();\n return failedJobs.length;\n }\n\n async updateProgress(id: string, progress: number): Promise<void> {\n const job = this.jobs.get(id);\n if (job) {\n job.progress = Math.min(100, Math.max(0, progress));\n this.emitEvent(\"progress\", job, { progress });\n }\n }\n\n async clean(\n grace: number,\n limit: number,\n state: JobState,\n ): Promise<string[]> {\n const now = Date.now();\n const removed: string[] = [];\n\n for (const [id, job] of this.jobs.entries()) {\n if (removed.length >= limit) break;\n\n if (job.state === state) {\n const finishedTime = job.finishedOn || job.timestamp;\n if (now - finishedTime > grace) {\n this.jobs.delete(id);\n removed.push(id);\n }\n }\n }\n\n return removed;\n }\n\n async obliterate(options?: { force?: boolean }): Promise<void> {\n // Clear all intervals\n for (const interval of this.repeatIntervals.values()) {\n clearInterval(interval);\n }\n this.repeatIntervals.clear();\n this.jobs.clear();\n }\n\n on(event: JobEventType, handler: JobEventHandler<T>): void {\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, new Set());\n }\n this.eventHandlers.get(event)!.add(handler);\n }\n\n off(event: JobEventType, handler: JobEventHandler<T>): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n\n getName(): string {\n return this.queueName;\n }\n\n // ═══════════════════════════════════════════════════════════════\n // TESTING UTILITIES (not part of IQueue interface)\n // ═══════════════════════════════════════════════════════════════\n\n /**\n * Clear all jobs (for testing)\n */\n clear(): void {\n for (const interval of this.repeatIntervals.values()) {\n clearInterval(interval);\n }\n this.repeatIntervals.clear();\n this.jobs.clear();\n this.handlers = [];\n this.paused = false;\n this.activeCount = 0;\n }\n\n /**\n * Get all jobs regardless of state (for testing)\n */\n getAllJobs(): Job<T>[] {\n return Array.from(this.jobs.values()).map((j) => this.toPublicJob(j));\n }\n\n /**\n * Get pending (waiting) jobs (for testing)\n */\n getPendingJobs(): Job<T>[] {\n return Array.from(this.jobs.values())\n .filter((j) => j.state === \"waiting\")\n .map((j) => this.toPublicJob(j));\n }\n\n /**\n * Get number of jobs (for testing)\n */\n get size(): number {\n return this.jobs.size;\n }\n\n /**\n * Wait for all jobs to complete (for testing)\n */\n async drain(timeout: number = 5000): Promise<void> {\n const start = Date.now();\n while (this.activeCount > 0 || this.hasWaitingJobs()) {\n if (Date.now() - start > timeout) {\n throw new Error(\"Queue drain timeout\");\n }\n await new Promise((resolve) => setTimeout(resolve, 10));\n }\n }\n\n // ═══════════════════════════════════════════════════════════════\n // PRIVATE METHODS\n // ═══════════════════════════════════════════════════════════════\n\n private hasWaitingJobs(): boolean {\n for (const job of this.jobs.values()) {\n if (job.state === \"waiting\") return true;\n }\n return false;\n }\n\n private async processNext(): Promise<void> {\n if (this.paused || this.handlers.length === 0 || this.isProcessing) {\n return;\n }\n\n if (this.activeCount >= this.processingConcurrency) {\n return;\n }\n\n // Find next waiting job\n let nextJob: InternalJob<T> | undefined;\n for (const job of this.jobs.values()) {\n if (job.state === \"waiting\") {\n nextJob = job;\n break;\n }\n }\n\n if (!nextJob) {\n return;\n }\n\n this.activeCount++;\n nextJob.state = \"active\";\n nextJob.processedOn = Date.now();\n\n this.emitEvent(\"active\", nextJob);\n\n try {\n // Execute all handlers\n for (const handler of this.handlers) {\n await this.executeWithTimeout(handler, nextJob);\n }\n\n // Success\n nextJob.state = \"completed\";\n nextJob.finishedOn = Date.now();\n nextJob.progress = 100;\n\n this.emitEvent(\"completed\", nextJob);\n\n // Handle removeOnComplete\n if (nextJob.options?.removeOnComplete === true) {\n this.jobs.delete(nextJob.id);\n }\n } catch (error) {\n await this.handleJobFailure(nextJob, error as Error);\n } finally {\n this.activeCount--;\n // Process next job\n setImmediate(() => this.processNext());\n }\n }\n\n private async executeWithTimeout(\n handler: (job: Job<T>) => Promise<unknown>,\n job: InternalJob<T>,\n ): Promise<void> {\n const timeout = job.options?.timeout;\n const publicJob = this.toPublicJob(job);\n\n // Create correlation context for this job\n const jobContext = createJobContext({\n id: job.id,\n name: job.name,\n correlationId: job.correlationId,\n metadata: job.metadata,\n });\n\n // Execute handler within correlation context\n const executeHandler = () =>\n runWithContext(jobContext, () => handler(publicJob));\n\n if (!timeout) {\n await executeHandler();\n return;\n }\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error(\"Job timeout\")), timeout);\n });\n\n await Promise.race([executeHandler(), timeoutPromise]);\n }\n\n private async handleJobFailure(\n job: InternalJob<T>,\n error: Error,\n ): Promise<void> {\n job.attemptsMade++;\n const maxAttempts = job.options?.attempts || 1;\n\n if (job.attemptsMade < maxAttempts) {\n // Retry with backoff\n job.state = \"delayed\";\n const backoffDelay = job.options?.backoff\n ? calculateBackoff(job.attemptsMade, job.options.backoff)\n : 1000;\n\n setTimeout(() => {\n const j = this.jobs.get(job.id);\n if (j && j.state === \"delayed\") {\n j.state = \"waiting\";\n this.processNext();\n }\n }, backoffDelay);\n } else {\n // Move to failed (dead letter queue)\n job.state = \"failed\";\n job.finishedOn = Date.now();\n job.failedReason = error.message;\n\n this.emitEvent(\"failed\", job, { error });\n\n // Handle removeOnFail\n if (job.options?.removeOnFail === true) {\n this.jobs.delete(job.id);\n }\n }\n }\n\n private emitEvent(\n type: JobEventType,\n job: InternalJob<T>,\n extra?: { error?: Error; progress?: number; result?: unknown },\n ): void {\n const handlers = this.eventHandlers.get(type);\n if (!handlers) return;\n\n const event: JobEvent<T> = {\n type,\n job: this.toPublicJob(job),\n timestamp: Date.now(),\n ...extra,\n };\n\n for (const handler of handlers) {\n try {\n handler(event);\n } catch {\n // Ignore handler errors\n }\n }\n }\n\n private toPublicJob(job: InternalJob<T>): Job<T> {\n return {\n id: job.id,\n name: job.name,\n data: job.data,\n attemptsMade: job.attemptsMade,\n progress: job.progress,\n timestamp: job.timestamp,\n state: job.state,\n processedOn: job.processedOn,\n finishedOn: job.finishedOn,\n failedReason: job.failedReason,\n correlationId: job.correlationId,\n metadata: job.metadata,\n };\n }\n}\n","/**\n * Console Email Adapter\n * Development implementation that logs emails to console instead of sending\n */\n\nimport {\n IEmail,\n EmailMessage,\n EmailResult,\n EmailAddress,\n} from \"../../interfaces/IEmail\";\nimport { randomBytes } from \"crypto\";\n\nexport class ConsoleEmail implements IEmail {\n private sentEmails: EmailMessage[] = [];\n\n async send(message: EmailMessage): Promise<EmailResult> {\n const id = `console_${Date.now()}_${randomBytes(4).toString(\"hex\")}`;\n\n console.log(\"\\n\" + \"=\".repeat(60));\n console.log(\"📧 EMAIL SENT (Console Adapter)\");\n console.log(\"=\".repeat(60));\n console.log(`ID: ${id}`);\n console.log(`To: ${this.formatAddresses(message.to)}`);\n console.log(\n `From: ${message.from ? this.formatAddress(message.from) : \"(default)\"}`,\n );\n console.log(`Subject: ${message.subject}`);\n\n if (message.replyTo) {\n console.log(`Reply-To: ${this.formatAddress(message.replyTo)}`);\n }\n\n if (message.tags && message.tags.length > 0) {\n console.log(`Tags: ${message.tags.join(\", \")}`);\n }\n\n if (message.attachments && message.attachments.length > 0) {\n console.log(\n `Attachments: ${message.attachments.map((a) => a.filename).join(\", \")}`,\n );\n }\n\n console.log(\"-\".repeat(60));\n\n if (message.text) {\n console.log(\"TEXT BODY:\");\n console.log(\n message.text.slice(0, 500) +\n (message.text.length > 500 ? \"\\n...(truncated)\" : \"\"),\n );\n }\n\n if (message.html) {\n console.log(\n \"HTML BODY: [HTML content - \" + message.html.length + \" chars]\",\n );\n }\n\n console.log(\"=\".repeat(60) + \"\\n\");\n\n this.sentEmails.push(message);\n\n return {\n id,\n success: true,\n };\n }\n\n async sendBatch(messages: EmailMessage[]): Promise<EmailResult[]> {\n const results: EmailResult[] = [];\n\n for (const message of messages) {\n results.push(await this.send(message));\n }\n\n return results;\n }\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n /**\n * Get all sent emails (for testing)\n */\n getSentEmails(): EmailMessage[] {\n return [...this.sentEmails];\n }\n\n /**\n * Clear sent emails (for testing)\n */\n clearSentEmails(): void {\n this.sentEmails = [];\n }\n\n private formatAddress(address: EmailAddress): string {\n if (address.name) {\n return `${address.name} <${address.email}>`;\n }\n return address.email;\n }\n\n private formatAddresses(addresses: EmailAddress | EmailAddress[]): string {\n const list = Array.isArray(addresses) ? addresses : [addresses];\n return list.map((addr) => this.formatAddress(addr)).join(\", \");\n }\n}\n","/**\n * Secrets Management Interface\n *\n * Provides a vendor-agnostic abstraction for secrets management.\n * Supports various backends: Environment variables, HashiCorp Vault,\n * AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, etc.\n */\n\n/**\n * Secret metadata\n */\nexport interface SecretMetadata {\n /** Secret version or ETag */\n version?: string;\n\n /** Creation timestamp */\n createdAt?: Date;\n\n /** Last updated timestamp */\n updatedAt?: Date;\n\n /** Expiration timestamp */\n expiresAt?: Date;\n\n /** Custom tags/labels */\n tags?: Record<string, string>;\n}\n\n/**\n * Secret with metadata\n */\nexport interface Secret<T = string> {\n /** Secret key/name */\n key: string;\n\n /** Secret value */\n value: T;\n\n /** Secret metadata */\n metadata?: SecretMetadata;\n}\n\n/**\n * Options for getting secrets\n */\nexport interface GetSecretOptions {\n /** Specific version to retrieve */\n version?: string;\n\n /** Include metadata in response */\n includeMetadata?: boolean;\n\n /** Cache TTL in seconds (0 = no cache) */\n cacheTtl?: number;\n}\n\n/**\n * Options for setting secrets\n */\nexport interface SetSecretOptions {\n /** Expiration timestamp */\n expiresAt?: Date;\n\n /** Custom tags/labels */\n tags?: Record<string, string>;\n\n /** Description */\n description?: string;\n}\n\n/**\n * Options for rotating secrets\n */\nexport interface RotateSecretOptions {\n /** Custom rotation function */\n rotationFn?: () => Promise<string>;\n\n /** Rotation period in days */\n rotationPeriodDays?: number;\n\n /** Keep previous version count */\n keepPreviousVersions?: number;\n}\n\n/**\n * Result of a rotation operation\n */\nexport interface RotationResult {\n /** New secret value */\n newValue: string;\n\n /** Previous secret value (for rollback) */\n previousValue?: string;\n\n /** New version identifier */\n newVersion: string;\n\n /** Previous version identifier */\n previousVersion?: string;\n}\n\n/**\n * Secrets Management Interface\n */\nexport interface ISecrets {\n /**\n * Get a secret value by key\n */\n get(key: string, options?: GetSecretOptions): Promise<string | null>;\n\n /**\n * Get a secret with metadata\n */\n getWithMetadata(\n key: string,\n options?: GetSecretOptions,\n ): Promise<Secret | null>;\n\n /**\n * Get multiple secrets at once\n */\n mget(keys: string[]): Promise<Map<string, string | null>>;\n\n /**\n * Set a secret value\n */\n set(key: string, value: string, options?: SetSecretOptions): Promise<void>;\n\n /**\n * Delete a secret\n */\n delete(key: string): Promise<void>;\n\n /**\n * Check if a secret exists\n */\n exists(key: string): Promise<boolean>;\n\n /**\n * List all secret keys (optionally filtered by prefix)\n */\n list(prefix?: string): Promise<string[]>;\n\n /**\n * Rotate a secret (generate new value)\n */\n rotate(key: string, options?: RotateSecretOptions): Promise<RotationResult>;\n\n /**\n * Get all versions of a secret\n */\n getVersions(key: string): Promise<SecretMetadata[]>;\n\n /**\n * Health check\n */\n healthCheck(): Promise<boolean>;\n}\n\n/**\n * Environment Variables Secrets Adapter\n * Simple implementation using process.env - suitable for development\n * and containerized deployments with injected secrets\n */\nexport class EnvSecrets implements ISecrets {\n private prefix: string;\n private cache: Map<string, { value: string; expiresAt: number }> = new Map();\n\n constructor(options: { prefix?: string } = {}) {\n this.prefix = options.prefix ?? \"\";\n }\n\n private getEnvKey(key: string): string {\n const normalizedKey = key.toUpperCase().replace(/[.-]/g, \"_\");\n return this.prefix ? `${this.prefix}_${normalizedKey}` : normalizedKey;\n }\n\n async get(key: string, options?: GetSecretOptions): Promise<string | null> {\n // Check cache first\n if (options?.cacheTtl) {\n const cached = this.cache.get(key);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.value;\n }\n }\n\n const envKey = this.getEnvKey(key);\n const value = process.env[envKey] ?? null;\n\n // Cache if requested\n if (value && options?.cacheTtl) {\n this.cache.set(key, {\n value,\n expiresAt: Date.now() + options.cacheTtl * 1000,\n });\n }\n\n return value;\n }\n\n async getWithMetadata(\n key: string,\n options?: GetSecretOptions,\n ): Promise<Secret | null> {\n const value = await this.get(key, options);\n if (value === null) {\n return null;\n }\n\n return {\n key,\n value,\n metadata: {\n // Environment variables don't have native metadata\n createdAt: undefined,\n updatedAt: undefined,\n },\n };\n }\n\n async mget(keys: string[]): Promise<Map<string, string | null>> {\n const result = new Map<string, string | null>();\n for (const key of keys) {\n result.set(key, await this.get(key));\n }\n return result;\n }\n\n async set(\n key: string,\n value: string,\n _options?: SetSecretOptions,\n ): Promise<void> {\n const envKey = this.getEnvKey(key);\n process.env[envKey] = value;\n\n // Update cache\n this.cache.delete(key);\n }\n\n async delete(key: string): Promise<void> {\n const envKey = this.getEnvKey(key);\n delete process.env[envKey];\n this.cache.delete(key);\n }\n\n async exists(key: string): Promise<boolean> {\n const envKey = this.getEnvKey(key);\n return process.env[envKey] !== undefined;\n }\n\n async list(prefix?: string): Promise<string[]> {\n const keys: string[] = [];\n const envPrefix = this.prefix ? `${this.prefix}_` : \"\";\n const searchPrefix = prefix\n ? `${envPrefix}${prefix.toUpperCase().replace(/[.-]/g, \"_\")}`\n : envPrefix;\n\n for (const key of Object.keys(process.env)) {\n if (key.startsWith(searchPrefix || \"\")) {\n // Convert back to normalized key format\n const normalizedKey = key\n .slice(envPrefix.length)\n .toLowerCase()\n .replace(/_/g, \"-\");\n keys.push(normalizedKey);\n }\n }\n\n return keys;\n }\n\n async rotate(\n key: string,\n options?: RotateSecretOptions,\n ): Promise<RotationResult> {\n const previousValue = await this.get(key);\n\n // Generate new value\n const newValue = options?.rotationFn\n ? await options.rotationFn()\n : this.generateSecureValue();\n\n await this.set(key, newValue);\n\n return {\n newValue,\n previousValue: previousValue ?? undefined,\n newVersion: \"current\",\n previousVersion: previousValue ? \"previous\" : undefined,\n };\n }\n\n async getVersions(_key: string): Promise<SecretMetadata[]> {\n // Environment variables don't support versioning\n return [];\n }\n\n async healthCheck(): Promise<boolean> {\n // Environment is always available\n return true;\n }\n\n private generateSecureValue(length: number = 32): string {\n const chars =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*\";\n let result = \"\";\n const randomValues = new Uint32Array(length);\n crypto.getRandomValues(randomValues);\n for (let i = 0; i < length; i++) {\n result += chars[randomValues[i]! % chars.length];\n }\n return result;\n }\n\n /**\n * Clear the internal cache\n */\n clearCache(): void {\n this.cache.clear();\n }\n}\n\nimport { randomBytes } from \"crypto\";\n\n/**\n * Memory-based Secrets Adapter\n * For testing purposes only - stores secrets in memory\n */\nexport class MemorySecrets implements ISecrets {\n private secrets: Map<string, Secret> = new Map();\n private versions: Map<string, SecretMetadata[]> = new Map();\n\n async get(key: string, _options?: GetSecretOptions): Promise<string | null> {\n const secret = this.secrets.get(key);\n if (!secret) {\n return null;\n }\n\n // Check expiration\n if (secret.metadata?.expiresAt && secret.metadata.expiresAt < new Date()) {\n await this.delete(key);\n return null;\n }\n\n return secret.value;\n }\n\n async getWithMetadata(\n key: string,\n options?: GetSecretOptions,\n ): Promise<Secret | null> {\n const value = await this.get(key, options);\n if (value === null) {\n return null;\n }\n\n return this.secrets.get(key) ?? null;\n }\n\n async mget(keys: string[]): Promise<Map<string, string | null>> {\n const result = new Map<string, string | null>();\n for (const key of keys) {\n result.set(key, await this.get(key));\n }\n return result;\n }\n\n async set(\n key: string,\n value: string,\n options?: SetSecretOptions,\n ): Promise<void> {\n const now = new Date();\n const version = `v${Date.now()}`;\n\n // Store version history\n const currentSecret = this.secrets.get(key);\n if (currentSecret?.metadata) {\n const history = this.versions.get(key) ?? [];\n history.push(currentSecret.metadata);\n this.versions.set(key, history);\n }\n\n this.secrets.set(key, {\n key,\n value,\n metadata: {\n version,\n createdAt: currentSecret?.metadata?.createdAt ?? now,\n updatedAt: now,\n expiresAt: options?.expiresAt,\n tags: options?.tags,\n },\n });\n }\n\n async delete(key: string): Promise<void> {\n this.secrets.delete(key);\n this.versions.delete(key);\n }\n\n async exists(key: string): Promise<boolean> {\n return this.secrets.has(key);\n }\n\n async list(prefix?: string): Promise<string[]> {\n const keys: string[] = [];\n for (const key of this.secrets.keys()) {\n if (!prefix || key.startsWith(prefix)) {\n keys.push(key);\n }\n }\n return keys;\n }\n\n async rotate(\n key: string,\n options?: RotateSecretOptions,\n ): Promise<RotationResult> {\n const currentSecret = this.secrets.get(key);\n const previousValue = currentSecret?.value;\n const previousVersion = currentSecret?.metadata?.version;\n\n // Generate new value\n const newValue = options?.rotationFn\n ? await options.rotationFn()\n : this.generateSecureValue();\n\n await this.set(key, newValue);\n const newVersion = this.secrets.get(key)?.metadata?.version ?? \"unknown\";\n\n return {\n newValue,\n previousValue,\n newVersion,\n previousVersion,\n };\n }\n\n async getVersions(key: string): Promise<SecretMetadata[]> {\n const current = this.secrets.get(key)?.metadata;\n const history = this.versions.get(key) ?? [];\n\n if (current) {\n return [...history, current];\n }\n\n return history;\n }\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n private generateSecureValue(length: number = 32): string {\n return randomBytes(length).toString(\"base64url\").slice(0, length);\n }\n\n /**\n * Clear all secrets (for testing)\n */\n clear(): void {\n this.secrets.clear();\n this.versions.clear();\n }\n\n /**\n * Get count of secrets (for testing)\n */\n get size(): number {\n return this.secrets.size;\n }\n}\n","/**\n * Platform Configuration\n * Comprehensive Zod schema for all platform options with validation\n */\n\nimport { z } from \"zod\";\n\n// ═══════════════════════════════════════════════════════════════\n// PROVIDER SCHEMAS\n// ═══════════════════════════════════════════════════════════════\n\nexport const DatabaseProviderSchema = z.enum([\n \"memory\",\n \"postgres\",\n \"supabase\",\n]);\nexport const CacheProviderSchema = z.enum([\"memory\", \"redis\", \"upstash\"]);\nexport const StorageProviderSchema = z.enum([\n \"memory\",\n \"s3\",\n \"minio\",\n \"r2\",\n \"supabase\",\n]);\nexport const EmailProviderSchema = z.enum([\n \"memory\",\n \"console\",\n \"smtp\",\n \"resend\",\n]);\nexport const QueueProviderSchema = z.enum([\"memory\", \"bullmq\"]);\nexport const TracingProviderSchema = z.enum([\"noop\", \"memory\", \"otlp\"]);\nexport const LogLevelSchema = z.enum([\"debug\", \"info\", \"warn\", \"error\"]);\nexport const AIProviderSchema = z.enum([\n \"memory\",\n \"openai\",\n \"anthropic\",\n \"google\",\n]);\nexport const RAGProviderSchema = z.enum([\"memory\", \"pinecone\", \"weaviate\"]);\n\n// ═══════════════════════════════════════════════════════════════\n// SERVICE CONFIGURATION SCHEMAS\n// ═══════════════════════════════════════════════════════════════\n\nexport const DatabaseConfigSchema = z\n .object({\n provider: DatabaseProviderSchema.default(\"memory\"),\n url: z.string().optional().describe(\"PostgreSQL connection URL\"),\n connectionString: z\n .string()\n .optional()\n .describe(\"PostgreSQL connection string (alias for url)\"),\n supabaseUrl: z.string().url().optional().describe(\"Supabase project URL\"),\n supabaseAnonKey: z.string().optional().describe(\"Supabase anonymous key\"),\n supabaseServiceRoleKey: z\n .string()\n .optional()\n .describe(\"Supabase service role key\"),\n poolSize: z\n .number()\n .int()\n .min(1)\n .max(100)\n .default(10)\n .describe(\"Connection pool size\"),\n connectionTimeout: z\n .number()\n .int()\n .min(1000)\n .max(60000)\n .default(5000)\n .describe(\"Connection timeout in ms\"),\n ssl: z\n .union([\n z.boolean(),\n z.object({ rejectUnauthorized: z.boolean().optional() }),\n ])\n .optional()\n .describe(\"SSL configuration\"),\n })\n .refine(\n (data) => {\n if (data.provider === \"supabase\") {\n return data.supabaseUrl && data.supabaseAnonKey;\n }\n if (data.provider === \"postgres\") {\n return data.url || data.connectionString;\n }\n return true;\n },\n {\n message:\n \"Supabase requires supabaseUrl and supabaseAnonKey; PostgreSQL requires url or connectionString\",\n },\n );\n\nexport const CacheConfigSchema = z\n .object({\n provider: CacheProviderSchema.default(\"memory\"),\n url: z.string().url().optional().describe(\"Redis connection URL\"),\n upstashUrl: z.string().url().optional().describe(\"Upstash REST URL\"),\n upstashToken: z.string().optional().describe(\"Upstash REST token\"),\n defaultTTL: z\n .number()\n .int()\n .min(0)\n .default(3600)\n .describe(\"Default TTL in seconds\"),\n keyPrefix: z.string().default(\"\").describe(\"Prefix for all cache keys\"),\n maxRetries: z\n .number()\n .int()\n .min(0)\n .max(10)\n .default(3)\n .describe(\"Max retries for cache operations\"),\n })\n .refine(\n (data) => {\n if (data.provider === \"upstash\") {\n return data.upstashUrl && data.upstashToken;\n }\n if (data.provider === \"redis\") {\n return data.url;\n }\n return true;\n },\n {\n message:\n \"Upstash requires upstashUrl and upstashToken; Redis requires url\",\n },\n );\n\nexport const StorageConfigSchema = z\n .object({\n provider: StorageProviderSchema.default(\"memory\"),\n endpoint: z\n .string()\n .url()\n .optional()\n .describe(\"S3-compatible endpoint URL\"),\n region: z.string().default(\"us-east-1\").describe(\"AWS region\"),\n accessKey: z.string().optional().describe(\"AWS access key ID\"),\n secretKey: z.string().optional().describe(\"AWS secret access key\"),\n bucket: z.string().optional().describe(\"S3 bucket name\"),\n publicUrl: z\n .string()\n .url()\n .optional()\n .describe(\"Public URL for accessing files\"),\n forcePathStyle: z\n .boolean()\n .default(false)\n .describe(\"Use path-style URLs (required for MinIO)\"),\n signedUrlExpiry: z\n .number()\n .int()\n .min(60)\n .max(604800)\n .default(3600)\n .describe(\"Signed URL expiry in seconds\"),\n })\n .refine(\n (data) => {\n if ([\"s3\", \"minio\", \"r2\"].includes(data.provider)) {\n return data.accessKey && data.secretKey && data.bucket;\n }\n return true;\n },\n {\n message: \"S3/MinIO/R2 requires accessKey, secretKey, and bucket\",\n },\n );\n\nexport const EmailConfigSchema = z\n .object({\n provider: EmailProviderSchema.default(\"memory\"),\n host: z.string().optional().describe(\"SMTP host\"),\n port: z.number().int().min(1).max(65535).optional().describe(\"SMTP port\"),\n secure: z.boolean().default(false).describe(\"Use TLS for SMTP\"),\n username: z.string().optional().describe(\"SMTP username\"),\n password: z.string().optional().describe(\"SMTP password\"),\n apiKey: z.string().optional().describe(\"Resend API key\"),\n from: z\n .string()\n .email()\n .or(z.string().regex(/^.+\\s<.+@.+>$/))\n .optional()\n .describe(\"Default from address\"),\n replyTo: z.string().email().optional().describe(\"Default reply-to address\"),\n rateLimitPerSecond: z\n .number()\n .int()\n .min(1)\n .max(100)\n .default(10)\n .describe(\"Max emails per second\"),\n })\n .refine(\n (data) => {\n if (data.provider === \"smtp\") {\n return data.host && data.port;\n }\n if (data.provider === \"resend\") {\n return data.apiKey;\n }\n return true;\n },\n {\n message: \"SMTP requires host and port; Resend requires apiKey\",\n },\n );\n\nexport const QueueConfigSchema = z\n .object({\n provider: QueueProviderSchema.default(\"memory\"),\n redisUrl: z\n .string()\n .url()\n .optional()\n .describe(\"Redis connection URL for BullMQ\"),\n queueName: z\n .string()\n .default(\"platform-jobs\")\n .describe(\"Default queue name\"),\n concurrency: z\n .number()\n .int()\n .min(1)\n .max(100)\n .default(5)\n .describe(\"Worker concurrency\"),\n maxRetries: z\n .number()\n .int()\n .min(0)\n .max(10)\n .default(3)\n .describe(\"Max job retries\"),\n retryDelay: z\n .number()\n .int()\n .min(0)\n .default(1000)\n .describe(\"Retry delay in ms\"),\n removeOnComplete: z\n .boolean()\n .default(true)\n .describe(\"Remove completed jobs\"),\n removeOnFail: z.boolean().default(false).describe(\"Remove failed jobs\"),\n })\n .refine(\n (data) => {\n if (data.provider === \"bullmq\") {\n return data.redisUrl;\n }\n return true;\n },\n {\n message: \"BullMQ requires redisUrl\",\n },\n );\n\nexport const AIConfigSchema = z\n .object({\n enabled: z.boolean().default(false).describe(\"Enable AI capabilities\"),\n provider: AIProviderSchema.default(\"memory\"),\n apiKey: z.string().optional().describe(\"API key for the AI provider\"),\n model: z.string().optional().describe(\"Default model to use\"),\n maxTokens: z\n .number()\n .int()\n .min(1)\n .max(200000)\n .default(4096)\n .describe(\"Default max tokens\"),\n temperature: z\n .number()\n .min(0)\n .max(2)\n .default(0.7)\n .describe(\"Default temperature\"),\n timeout: z\n .number()\n .int()\n .min(1000)\n .max(300000)\n .default(60000)\n .describe(\"Request timeout in ms\"),\n baseUrl: z.string().url().optional().describe(\"Custom base URL for API\"),\n })\n .refine(\n (data) => {\n if (data.enabled && data.provider !== \"memory\") {\n return data.apiKey;\n }\n return true;\n },\n {\n message: \"Production AI providers require an API key\",\n },\n );\n\nexport const RAGConfigSchema = z\n .object({\n enabled: z.boolean().default(false).describe(\"Enable RAG capabilities\"),\n provider: RAGProviderSchema.default(\"memory\"),\n apiKey: z.string().optional().describe(\"API key for the RAG provider\"),\n environment: z.string().optional().describe(\"Pinecone environment\"),\n indexName: z\n .string()\n .optional()\n .describe(\"Pinecone index name or Weaviate class\"),\n namespace: z.string().optional().describe(\"Default namespace\"),\n host: z.string().url().optional().describe(\"Weaviate host URL\"),\n embeddingProvider: AIProviderSchema.default(\"memory\").describe(\n \"Provider for generating embeddings\",\n ),\n embeddingApiKey: z\n .string()\n .optional()\n .describe(\"API key for embedding provider\"),\n embeddingModel: z\n .string()\n .optional()\n .describe(\"Model for generating embeddings\"),\n })\n .refine(\n (data) => {\n if (data.enabled && data.provider === \"pinecone\") {\n return data.apiKey && data.indexName;\n }\n if (data.enabled && data.provider === \"weaviate\") {\n return data.host;\n }\n return true;\n },\n {\n message: \"Pinecone requires apiKey and indexName; Weaviate requires host\",\n },\n );\n\n// ═══════════════════════════════════════════════════════════════\n// CRYPTO CONFIGURATION SCHEMA\n// ═══════════════════════════════════════════════════════════════\n\nexport const CryptoConfigSchema = z\n .object({\n enabled: z\n .boolean()\n .default(false)\n .describe(\"Enable field-level encryption\"),\n masterKey: z\n .string()\n .optional()\n .describe(\"256-bit master key as hex (64 chars). Required when enabled.\"),\n hmacKey: z\n .string()\n .optional()\n .describe(\n \"HMAC key for deterministic hashing (derived from master key if not provided)\",\n ),\n })\n .refine(\n (data) => {\n if (data.enabled) {\n return data.masterKey && data.masterKey.length >= 64;\n }\n return true;\n },\n {\n message:\n \"Crypto requires a 256-bit master key (64 hex characters) when enabled\",\n },\n );\n\n// ═══════════════════════════════════════════════════════════════\n// SECURITY CONFIGURATION SCHEMA\n// ═══════════════════════════════════════════════════════════════\n\nexport const SecurityConfigSchema = z.object({\n enforceTls: z\n .boolean()\n .default(true)\n .describe(\"Enforce TLS for production connections\"),\n tlsWarnOnly: z\n .boolean()\n .default(false)\n .describe(\"Warn instead of throwing when TLS is missing in production\"),\n});\n\n// ═══════════════════════════════════════════════════════════════\n// RESILIENCE CONFIGURATION SCHEMAS\n// ═══════════════════════════════════════════════════════════════\n\nexport const RetryConfigSchema = z.object({\n enabled: z\n .boolean()\n .default(true)\n .describe(\"Enable retry for failed operations\"),\n maxAttempts: z\n .number()\n .int()\n .min(1)\n .max(10)\n .default(3)\n .describe(\"Maximum retry attempts\"),\n baseDelay: z\n .number()\n .int()\n .min(0)\n .max(10000)\n .default(100)\n .describe(\"Base delay in ms\"),\n maxDelay: z\n .number()\n .int()\n .min(0)\n .max(60000)\n .default(5000)\n .describe(\"Maximum delay in ms\"),\n backoffMultiplier: z\n .number()\n .min(1)\n .max(5)\n .default(2)\n .describe(\"Exponential backoff multiplier\"),\n jitter: z.boolean().default(true).describe(\"Add jitter to retry delays\"),\n});\n\nexport const CircuitBreakerConfigSchema = z.object({\n enabled: z.boolean().default(true).describe(\"Enable circuit breaker\"),\n failureThreshold: z\n .number()\n .int()\n .min(1)\n .max(100)\n .default(5)\n .describe(\"Failures before opening circuit\"),\n resetTimeout: z\n .number()\n .int()\n .min(1000)\n .max(300000)\n .default(30000)\n .describe(\"Reset timeout in ms\"),\n halfOpenRequests: z\n .number()\n .int()\n .min(1)\n .max(10)\n .default(3)\n .describe(\"Requests allowed in half-open state\"),\n monitorInterval: z\n .number()\n .int()\n .min(1000)\n .max(60000)\n .default(10000)\n .describe(\"Health monitor interval in ms\"),\n});\n\nexport const TimeoutConfigSchema = z.object({\n enabled: z.boolean().default(true).describe(\"Enable operation timeouts\"),\n default: z\n .number()\n .int()\n .min(100)\n .max(300000)\n .default(30000)\n .describe(\"Default timeout in ms\"),\n database: z\n .number()\n .int()\n .min(100)\n .max(300000)\n .default(10000)\n .describe(\"Database operation timeout\"),\n cache: z\n .number()\n .int()\n .min(100)\n .max(60000)\n .default(5000)\n .describe(\"Cache operation timeout\"),\n storage: z\n .number()\n .int()\n .min(100)\n .max(600000)\n .default(60000)\n .describe(\"Storage operation timeout\"),\n email: z\n .number()\n .int()\n .min(100)\n .max(120000)\n .default(30000)\n .describe(\"Email operation timeout\"),\n queue: z\n .number()\n .int()\n .min(100)\n .max(60000)\n .default(10000)\n .describe(\"Queue operation timeout\"),\n});\n\nexport const BulkheadConfigSchema = z.object({\n enabled: z.boolean().default(false).describe(\"Enable bulkhead isolation\"),\n maxConcurrent: z\n .number()\n .int()\n .min(1)\n .max(1000)\n .default(10)\n .describe(\"Maximum concurrent operations\"),\n maxQueued: z\n .number()\n .int()\n .min(0)\n .max(10000)\n .default(100)\n .describe(\"Maximum queued operations\"),\n timeout: z\n .number()\n .int()\n .min(0)\n .max(300000)\n .default(30000)\n .describe(\"Queue timeout in ms\"),\n});\n\nexport const ResilienceConfigSchema = z.object({\n retry: RetryConfigSchema.default({}),\n circuitBreaker: CircuitBreakerConfigSchema.default({}),\n timeout: TimeoutConfigSchema.default({}),\n bulkhead: BulkheadConfigSchema.default({}),\n});\n\n// ═══════════════════════════════════════════════════════════════\n// OBSERVABILITY CONFIGURATION SCHEMAS\n// ═══════════════════════════════════════════════════════════════\n\nexport const LoggingConfigSchema = z.object({\n level: LogLevelSchema.default(\"info\").describe(\"Minimum log level\"),\n format: z\n .enum([\"json\", \"pretty\"])\n .default(\"json\")\n .describe(\"Log output format\"),\n includeTimestamp: z\n .boolean()\n .default(true)\n .describe(\"Include timestamp in logs\"),\n includeCorrelationId: z\n .boolean()\n .default(true)\n .describe(\"Include correlation ID in logs\"),\n redactKeys: z\n .array(z.string())\n .default([\"password\", \"token\", \"secret\", \"apiKey\", \"authorization\"])\n .describe(\"Keys to redact from logs\"),\n});\n\nexport const MetricsConfigSchema = z.object({\n enabled: z.boolean().default(false).describe(\"Enable metrics collection\"),\n prefix: z.string().default(\"platform\").describe(\"Metric name prefix\"),\n defaultTags: z\n .record(z.string())\n .default({})\n .describe(\"Default tags for all metrics\"),\n flushInterval: z\n .number()\n .int()\n .min(1000)\n .max(60000)\n .default(10000)\n .describe(\"Flush interval in ms\"),\n histogramBuckets: z\n .array(z.number())\n .default([5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000])\n .describe(\"Histogram bucket boundaries in ms\"),\n});\n\nexport const TracingConfigSchema = z.object({\n enabled: z.boolean().default(false).describe(\"Enable distributed tracing\"),\n provider: TracingProviderSchema.default(\"noop\").describe(\"Tracing provider\"),\n serviceName: z.string().optional().describe(\"Service name for traces\"),\n serviceVersion: z.string().optional().describe(\"Service version\"),\n environment: z\n .string()\n .optional()\n .describe(\"Environment (dev, staging, production)\"),\n sampleRate: z\n .number()\n .min(0)\n .max(1)\n .default(1)\n .describe(\"Trace sampling rate\"),\n propagateContext: z\n .boolean()\n .default(true)\n .describe(\"Propagate trace context to downstream services\"),\n endpoint: z.string().url().optional().describe(\"OTLP exporter endpoint\"),\n exporterType: z\n .enum([\"otlp-http\", \"otlp-grpc\", \"console\"])\n .default(\"otlp-http\")\n .describe(\"Exporter type\"),\n});\n\nexport const ObservabilityConfigSchema = z.object({\n logging: LoggingConfigSchema.default({}),\n metrics: MetricsConfigSchema.default({}),\n tracing: TracingConfigSchema.default({}),\n});\n\n// ═══════════════════════════════════════════════════════════════\n// MIDDLEWARE CONFIGURATION SCHEMA\n// ═══════════════════════════════════════════════════════════════\n\nexport const MiddlewareConfigSchema = z.object({\n enabled: z.boolean().default(true).describe(\"Enable middleware chain\"),\n logging: z.boolean().default(true).describe(\"Enable logging middleware\"),\n metrics: z.boolean().default(false).describe(\"Enable metrics middleware\"),\n slowQuery: z\n .object({\n enabled: z.boolean().default(true),\n thresholdMs: z.number().int().min(1).default(1000),\n })\n .default({}),\n cache: z\n .object({\n enabled: z.boolean().default(false),\n defaultTTL: z.number().int().min(0).default(300),\n })\n .default({}),\n});\n\n// ═══════════════════════════════════════════════════════════════\n// MAIN PLATFORM CONFIGURATION SCHEMA\n// ═══════════════════════════════════════════════════════════════\n\nexport const PlatformConfigSchema = z.object({\n // Service configurations\n database: DatabaseConfigSchema.default({ provider: \"memory\" }),\n cache: CacheConfigSchema.default({ provider: \"memory\" }),\n storage: StorageConfigSchema.default({ provider: \"memory\" }),\n email: EmailConfigSchema.default({ provider: \"memory\" }),\n queue: QueueConfigSchema.default({ provider: \"memory\" }),\n\n // AI configurations\n ai: AIConfigSchema.default({ enabled: false }),\n rag: RAGConfigSchema.default({ enabled: false }),\n\n // Crypto configuration\n crypto: CryptoConfigSchema.default({ enabled: false }),\n\n // Security configuration\n security: SecurityConfigSchema.default({}),\n\n // Resilience configuration\n resilience: ResilienceConfigSchema.default({}),\n\n // Observability configuration\n observability: ObservabilityConfigSchema.default({}),\n\n // Middleware configuration\n middleware: MiddlewareConfigSchema.default({}),\n});\n\nexport type PlatformConfig = z.infer<typeof PlatformConfigSchema>;\nexport type DatabaseConfig = z.infer<typeof DatabaseConfigSchema>;\nexport type CacheConfig = z.infer<typeof CacheConfigSchema>;\nexport type StorageConfig = z.infer<typeof StorageConfigSchema>;\nexport type EmailConfig = z.infer<typeof EmailConfigSchema>;\nexport type QueueConfig = z.infer<typeof QueueConfigSchema>;\nexport type AIConfig = z.infer<typeof AIConfigSchema>;\nexport type RAGConfig = z.infer<typeof RAGConfigSchema>;\nexport type ResilienceConfig = z.infer<typeof ResilienceConfigSchema>;\nexport type ObservabilityConfig = z.infer<typeof ObservabilityConfigSchema>;\nexport type TracingConfig = z.infer<typeof TracingConfigSchema>;\nexport type MiddlewareConfig = z.infer<typeof MiddlewareConfigSchema>;\nexport type CryptoConfig = z.infer<typeof CryptoConfigSchema>;\nexport type SecurityConfig = z.infer<typeof SecurityConfigSchema>;\n\n// ═══════════════════════════════════════════════════════════════\n// CONFIGURATION LOADING\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Load configuration from environment variables\n */\nexport function loadConfig(): PlatformConfig {\n return PlatformConfigSchema.parse({\n database: {\n provider:\n process.env.PLATFORM_DB_PROVIDER ||\n process.env.DATABASE_PROVIDER ||\n \"memory\",\n url: process.env.DATABASE_URL,\n supabaseUrl: process.env.SUPABASE_URL,\n supabaseAnonKey: process.env.SUPABASE_ANON_KEY,\n supabaseServiceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY,\n poolSize: process.env.DATABASE_POOL_SIZE\n ? parseInt(process.env.DATABASE_POOL_SIZE)\n : undefined,\n connectionTimeout: process.env.DATABASE_TIMEOUT\n ? parseInt(process.env.DATABASE_TIMEOUT)\n : undefined,\n },\n cache: {\n provider:\n process.env.PLATFORM_CACHE_PROVIDER ||\n process.env.CACHE_PROVIDER ||\n \"memory\",\n url: process.env.REDIS_URL,\n upstashUrl: process.env.UPSTASH_REDIS_REST_URL,\n upstashToken: process.env.UPSTASH_REDIS_REST_TOKEN,\n defaultTTL: process.env.CACHE_DEFAULT_TTL\n ? parseInt(process.env.CACHE_DEFAULT_TTL)\n : undefined,\n keyPrefix: process.env.CACHE_KEY_PREFIX,\n },\n storage: {\n provider:\n process.env.PLATFORM_STORAGE_PROVIDER ||\n process.env.STORAGE_PROVIDER ||\n \"memory\",\n endpoint: process.env.S3_ENDPOINT,\n region: process.env.S3_REGION || process.env.AWS_REGION || \"us-east-1\",\n accessKey: process.env.S3_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY_ID,\n secretKey:\n process.env.S3_SECRET_ACCESS_KEY || process.env.AWS_SECRET_ACCESS_KEY,\n bucket: process.env.S3_BUCKET,\n publicUrl: process.env.S3_PUBLIC_URL,\n forcePathStyle: process.env.S3_FORCE_PATH_STYLE === \"true\",\n signedUrlExpiry: process.env.S3_SIGNED_URL_EXPIRY\n ? parseInt(process.env.S3_SIGNED_URL_EXPIRY)\n : undefined,\n },\n email: {\n provider:\n process.env.PLATFORM_EMAIL_PROVIDER ||\n process.env.EMAIL_PROVIDER ||\n \"memory\",\n host: process.env.SMTP_HOST,\n port: process.env.SMTP_PORT ? parseInt(process.env.SMTP_PORT) : undefined,\n secure: process.env.SMTP_SECURE === \"true\",\n username: process.env.SMTP_USERNAME,\n password: process.env.SMTP_PASSWORD,\n apiKey: process.env.RESEND_API_KEY,\n from: process.env.EMAIL_FROM,\n replyTo: process.env.EMAIL_REPLY_TO,\n },\n queue: {\n provider:\n process.env.PLATFORM_QUEUE_PROVIDER ||\n process.env.QUEUE_PROVIDER ||\n \"memory\",\n redisUrl: process.env.REDIS_URL,\n queueName: process.env.QUEUE_NAME,\n concurrency: process.env.QUEUE_CONCURRENCY\n ? parseInt(process.env.QUEUE_CONCURRENCY)\n : undefined,\n maxRetries: process.env.QUEUE_MAX_RETRIES\n ? parseInt(process.env.QUEUE_MAX_RETRIES)\n : undefined,\n },\n ai: {\n enabled: process.env.AI_ENABLED === \"true\",\n provider:\n (process.env.AI_PROVIDER as\n | \"memory\"\n | \"openai\"\n | \"anthropic\"\n | \"google\") || \"memory\",\n apiKey:\n process.env.OPENAI_API_KEY ||\n process.env.ANTHROPIC_API_KEY ||\n process.env.GOOGLE_AI_API_KEY,\n model: process.env.AI_MODEL,\n maxTokens: process.env.AI_MAX_TOKENS\n ? parseInt(process.env.AI_MAX_TOKENS)\n : undefined,\n temperature: process.env.AI_TEMPERATURE\n ? parseFloat(process.env.AI_TEMPERATURE)\n : undefined,\n timeout: process.env.AI_TIMEOUT\n ? parseInt(process.env.AI_TIMEOUT)\n : undefined,\n baseUrl: process.env.AI_BASE_URL,\n },\n rag: {\n enabled: process.env.RAG_ENABLED === \"true\",\n provider:\n (process.env.RAG_PROVIDER as \"memory\" | \"pinecone\" | \"weaviate\") ||\n \"memory\",\n apiKey: process.env.PINECONE_API_KEY,\n environment: process.env.PINECONE_ENVIRONMENT,\n indexName: process.env.PINECONE_INDEX || process.env.RAG_INDEX_NAME,\n namespace: process.env.RAG_NAMESPACE,\n host: process.env.WEAVIATE_HOST,\n embeddingProvider:\n (process.env.EMBEDDING_PROVIDER as\n | \"memory\"\n | \"openai\"\n | \"anthropic\"\n | \"google\") || \"memory\",\n embeddingApiKey:\n process.env.EMBEDDING_API_KEY || process.env.OPENAI_API_KEY,\n embeddingModel: process.env.EMBEDDING_MODEL,\n },\n crypto: {\n enabled: process.env.CRYPTO_ENABLED === \"true\",\n masterKey: process.env.CRYPTO_MASTER_KEY,\n hmacKey: process.env.CRYPTO_HMAC_KEY,\n },\n security: {\n enforceTls: process.env.SECURITY_ENFORCE_TLS !== \"false\",\n tlsWarnOnly: process.env.SECURITY_TLS_WARN_ONLY === \"true\",\n },\n resilience: {\n retry: {\n enabled: process.env.RESILIENCE_RETRY_ENABLED !== \"false\",\n maxAttempts: process.env.RESILIENCE_RETRY_MAX_ATTEMPTS\n ? parseInt(process.env.RESILIENCE_RETRY_MAX_ATTEMPTS)\n : undefined,\n baseDelay: process.env.RESILIENCE_RETRY_BASE_DELAY\n ? parseInt(process.env.RESILIENCE_RETRY_BASE_DELAY)\n : undefined,\n maxDelay: process.env.RESILIENCE_RETRY_MAX_DELAY\n ? parseInt(process.env.RESILIENCE_RETRY_MAX_DELAY)\n : undefined,\n },\n circuitBreaker: {\n enabled: process.env.RESILIENCE_CIRCUIT_BREAKER_ENABLED !== \"false\",\n failureThreshold: process.env.RESILIENCE_CIRCUIT_BREAKER_THRESHOLD\n ? parseInt(process.env.RESILIENCE_CIRCUIT_BREAKER_THRESHOLD)\n : undefined,\n resetTimeout: process.env.RESILIENCE_CIRCUIT_BREAKER_RESET_TIMEOUT\n ? parseInt(process.env.RESILIENCE_CIRCUIT_BREAKER_RESET_TIMEOUT)\n : undefined,\n },\n timeout: {\n enabled: process.env.RESILIENCE_TIMEOUT_ENABLED !== \"false\",\n default: process.env.RESILIENCE_TIMEOUT_DEFAULT\n ? parseInt(process.env.RESILIENCE_TIMEOUT_DEFAULT)\n : undefined,\n },\n },\n observability: {\n logging: {\n level:\n (process.env.LOG_LEVEL as \"debug\" | \"info\" | \"warn\" | \"error\") ||\n \"info\",\n format: (process.env.LOG_FORMAT as \"json\" | \"pretty\") || \"json\",\n },\n metrics: {\n enabled: process.env.METRICS_ENABLED === \"true\",\n prefix: process.env.METRICS_PREFIX,\n },\n tracing: {\n enabled: process.env.TRACING_ENABLED === \"true\",\n provider:\n (process.env.TRACING_PROVIDER as \"noop\" | \"memory\" | \"otlp\") ||\n \"noop\",\n serviceName: process.env.SERVICE_NAME || process.env.OTEL_SERVICE_NAME,\n serviceVersion: process.env.SERVICE_VERSION,\n environment: process.env.NODE_ENV,\n sampleRate: process.env.TRACING_SAMPLE_RATE\n ? parseFloat(process.env.TRACING_SAMPLE_RATE)\n : undefined,\n endpoint:\n process.env.OTEL_EXPORTER_OTLP_ENDPOINT ||\n process.env.TRACING_ENDPOINT,\n exporterType:\n (process.env.OTEL_EXPORTER_TYPE as\n | \"otlp-http\"\n | \"otlp-grpc\"\n | \"console\") || \"otlp-http\",\n },\n },\n middleware: {\n enabled: process.env.MIDDLEWARE_ENABLED !== \"false\",\n logging: process.env.MIDDLEWARE_LOGGING !== \"false\",\n metrics: process.env.MIDDLEWARE_METRICS === \"true\",\n slowQuery: {\n enabled: process.env.MIDDLEWARE_SLOW_QUERY !== \"false\",\n thresholdMs: process.env.MIDDLEWARE_SLOW_QUERY_THRESHOLD\n ? parseInt(process.env.MIDDLEWARE_SLOW_QUERY_THRESHOLD)\n : undefined,\n },\n },\n });\n}\n\n/**\n * Validate configuration object\n * @throws ZodError if validation fails\n */\nexport function validateConfig(config: unknown): PlatformConfig {\n return PlatformConfigSchema.parse(config);\n}\n\n/**\n * Safely validate configuration, returning errors instead of throwing\n */\nexport function safeValidateConfig(config: unknown): {\n success: boolean;\n data?: PlatformConfig;\n errors?: z.ZodError;\n} {\n const result = PlatformConfigSchema.safeParse(config);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return { success: false, errors: result.error };\n}\n\n/**\n * Get configuration with defaults applied\n */\nexport function getDefaultConfig(): PlatformConfig {\n return PlatformConfigSchema.parse({});\n}\n","/**\n * Distributed Tracing Interface\n *\n * Provides vendor-agnostic distributed tracing for observability.\n * Supports OpenTelemetry, Jaeger, Zipkin, and custom implementations.\n */\n\n// ═══════════════════════════════════════════════════════════════\n// TYPES\n// ═══════════════════════════════════════════════════════════════\n\nexport type SpanKind =\n | \"internal\"\n | \"server\"\n | \"client\"\n | \"producer\"\n | \"consumer\";\n\nexport type SpanStatusCode = \"unset\" | \"ok\" | \"error\";\n\nexport interface SpanStatus {\n code: SpanStatusCode;\n message?: string;\n}\n\nexport interface SpanContext {\n traceId: string;\n spanId: string;\n traceFlags: number;\n traceState?: string;\n}\n\nexport interface SpanOptions {\n /** Type of span */\n kind?: SpanKind;\n\n /** Initial attributes */\n attributes?: Record<string, string | number | boolean>;\n\n /** Parent span (for manual context propagation) */\n parent?: ISpan;\n\n /** Links to other spans */\n links?: SpanContext[];\n\n /** Start time (defaults to now) */\n startTime?: number;\n}\n\nexport interface SpanEvent {\n name: string;\n timestamp: number;\n attributes?: Record<string, string | number | boolean>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// SPAN INTERFACE\n// ═══════════════════════════════════════════════════════════════\n\nexport interface ISpan {\n /** Span name */\n readonly name: string;\n\n /** Span context (trace ID, span ID) */\n readonly context: SpanContext;\n\n /** Whether the span is recording */\n readonly isRecording: boolean;\n\n /**\n * Set a single attribute\n */\n setAttribute(key: string, value: string | number | boolean): this;\n\n /**\n * Set multiple attributes\n */\n setAttributes(attributes: Record<string, string | number | boolean>): this;\n\n /**\n * Add an event to the span\n */\n addEvent(\n name: string,\n attributes?: Record<string, string | number | boolean>,\n ): this;\n\n /**\n * Set the span status\n */\n setStatus(status: SpanStatus): this;\n\n /**\n * Record an exception\n */\n recordException(\n exception: Error,\n attributes?: Record<string, string | number | boolean>,\n ): this;\n\n /**\n * Update the span name\n */\n updateName(name: string): this;\n\n /**\n * End the span (required to export)\n */\n end(endTime?: number): void;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// TRACING INTERFACE\n// ═══════════════════════════════════════════════════════════════\n\nexport interface ITracing {\n /**\n * Create and start a new span\n */\n startSpan(name: string, options?: SpanOptions): ISpan;\n\n /**\n * Get the currently active span\n */\n getCurrentSpan(): ISpan | undefined;\n\n /**\n * Execute a function within a span context\n */\n withSpan<T>(name: string, fn: (span: ISpan) => T, options?: SpanOptions): T;\n\n /**\n * Execute an async function within a span context\n */\n withSpanAsync<T>(\n name: string,\n fn: (span: ISpan) => Promise<T>,\n options?: SpanOptions,\n ): Promise<T>;\n\n /**\n * Instrument a function with automatic span creation\n */\n instrument<TArgs extends unknown[], TReturn>(\n name: string,\n fn: (...args: TArgs) => TReturn,\n options?: SpanOptions,\n ): (...args: TArgs) => TReturn;\n\n /**\n * Instrument an async function with automatic span creation\n */\n instrumentAsync<TArgs extends unknown[], TReturn>(\n name: string,\n fn: (...args: TArgs) => Promise<TReturn>,\n options?: SpanOptions,\n ): (...args: TArgs) => Promise<TReturn>;\n\n /**\n * Extract trace context from headers (for incoming requests)\n */\n extractContext(\n headers: Record<string, string | string[] | undefined>,\n ): SpanContext | undefined;\n\n /**\n * Inject trace context into headers (for outgoing requests)\n */\n injectContext(headers: Record<string, string>): void;\n\n /**\n * Check if tracing is enabled and healthy\n */\n healthCheck(): Promise<boolean>;\n\n /**\n * Flush pending spans to the exporter\n */\n flush(): Promise<void>;\n\n /**\n * Shutdown the tracer\n */\n close(): Promise<void>;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// TRACING CONFIGURATION\n// ═══════════════════════════════════════════════════════════════\n\nexport interface TracingConfig {\n /** Enable tracing */\n enabled: boolean;\n\n /** Service name for traces */\n serviceName: string;\n\n /** Service version */\n serviceVersion?: string;\n\n /** Environment (dev, staging, production) */\n environment?: string;\n\n /** Sampling rate (0.0 to 1.0) */\n sampleRate?: number;\n\n /** Exporter type */\n exporter?: \"console\" | \"otlp\" | \"jaeger\" | \"zipkin\" | \"none\";\n\n /** Exporter endpoint */\n endpoint?: string;\n\n /** Additional resource attributes */\n resourceAttributes?: Record<string, string>;\n\n /** Propagation format */\n propagation?: \"w3c\" | \"b3\" | \"jaeger\";\n}\n\n// ═══════════════════════════════════════════════════════════════\n// MEMORY TRACING (For Testing)\n// ═══════════════════════════════════════════════════════════════\n\nclass MemorySpan implements ISpan {\n readonly name: string;\n readonly context: SpanContext;\n readonly isRecording: boolean = true;\n\n private _attributes: Record<string, string | number | boolean> = {};\n private _events: SpanEvent[] = [];\n private _status: SpanStatus = { code: \"unset\" };\n private _endTime?: number;\n private _startTime: number;\n\n constructor(name: string, traceId: string, parentSpanId?: string) {\n this.name = name;\n this._startTime = Date.now();\n this.context = {\n traceId,\n spanId: this.generateSpanId(),\n traceFlags: 1,\n };\n }\n\n private generateSpanId(): string {\n return randomBytes(8).toString(\"hex\");\n }\n\n setAttribute(key: string, value: string | number | boolean): this {\n this._attributes[key] = value;\n return this;\n }\n\n setAttributes(attributes: Record<string, string | number | boolean>): this {\n Object.assign(this._attributes, attributes);\n return this;\n }\n\n addEvent(\n name: string,\n attributes?: Record<string, string | number | boolean>,\n ): this {\n this._events.push({ name, timestamp: Date.now(), attributes });\n return this;\n }\n\n setStatus(status: SpanStatus): this {\n this._status = status;\n return this;\n }\n\n recordException(\n exception: Error,\n attributes?: Record<string, string | number | boolean>,\n ): this {\n this.addEvent(\"exception\", {\n \"exception.type\": exception.name,\n \"exception.message\": exception.message,\n \"exception.stacktrace\": exception.stack || \"\",\n ...attributes,\n });\n this.setStatus({ code: \"error\", message: exception.message });\n return this;\n }\n\n updateName(name: string): this {\n (this as { name: string }).name = name;\n return this;\n }\n\n end(endTime?: number): void {\n this._endTime = endTime ?? Date.now();\n }\n\n // Testing helpers\n getAttributes(): Record<string, string | number | boolean> {\n return { ...this._attributes };\n }\n\n getEvents(): SpanEvent[] {\n return [...this._events];\n }\n\n getStatus(): SpanStatus {\n return { ...this._status };\n }\n\n getDuration(): number | undefined {\n return this._endTime ? this._endTime - this._startTime : undefined;\n }\n\n isEnded(): boolean {\n return this._endTime !== undefined;\n }\n}\n\nimport { randomBytes } from \"crypto\";\n\nexport class MemoryTracing implements ITracing {\n private spans: MemorySpan[] = [];\n private currentSpan: MemorySpan | undefined;\n private traceId: string;\n\n constructor() {\n this.traceId = this.generateTraceId();\n }\n\n private generateTraceId(): string {\n return randomBytes(16).toString(\"hex\");\n }\n\n startSpan(name: string, options?: SpanOptions): ISpan {\n const span = new MemorySpan(\n name,\n this.traceId,\n this.currentSpan?.context.spanId,\n );\n\n if (options?.attributes) {\n span.setAttributes(options.attributes);\n }\n\n this.spans.push(span);\n this.currentSpan = span;\n\n return span;\n }\n\n getCurrentSpan(): ISpan | undefined {\n return this.currentSpan;\n }\n\n withSpan<T>(name: string, fn: (span: ISpan) => T, options?: SpanOptions): T {\n const span = this.startSpan(name, options);\n try {\n const result = fn(span);\n span.setStatus({ code: \"ok\" });\n return result;\n } catch (error) {\n span.recordException(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n } finally {\n span.end();\n }\n }\n\n async withSpanAsync<T>(\n name: string,\n fn: (span: ISpan) => Promise<T>,\n options?: SpanOptions,\n ): Promise<T> {\n const span = this.startSpan(name, options);\n try {\n const result = await fn(span);\n span.setStatus({ code: \"ok\" });\n return result;\n } catch (error) {\n span.recordException(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n } finally {\n span.end();\n }\n }\n\n instrument<TArgs extends unknown[], TReturn>(\n name: string,\n fn: (...args: TArgs) => TReturn,\n options?: SpanOptions,\n ): (...args: TArgs) => TReturn {\n return (...args: TArgs) => this.withSpan(name, () => fn(...args), options);\n }\n\n instrumentAsync<TArgs extends unknown[], TReturn>(\n name: string,\n fn: (...args: TArgs) => Promise<TReturn>,\n options?: SpanOptions,\n ): (...args: TArgs) => Promise<TReturn> {\n return (...args: TArgs) =>\n this.withSpanAsync(name, () => fn(...args), options);\n }\n\n extractContext(\n headers: Record<string, string | string[] | undefined>,\n ): SpanContext | undefined {\n const traceparent = headers[\"traceparent\"];\n if (!traceparent || typeof traceparent !== \"string\") return undefined;\n\n // Parse W3C Trace Context format: version-traceId-spanId-flags\n const parts = traceparent.split(\"-\");\n if (parts.length !== 4) return undefined;\n\n return {\n traceId: parts[1]!,\n spanId: parts[2]!,\n traceFlags: parseInt(parts[3]!, 16),\n };\n }\n\n injectContext(headers: Record<string, string>): void {\n if (this.currentSpan) {\n const ctx = this.currentSpan.context;\n headers[\"traceparent\"] =\n `00-${ctx.traceId}-${ctx.spanId}-${ctx.traceFlags.toString(16).padStart(2, \"0\")}`;\n }\n }\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n async flush(): Promise<void> {\n // No-op for memory implementation\n }\n\n async close(): Promise<void> {\n this.spans = [];\n this.currentSpan = undefined;\n }\n\n // Testing helpers\n getSpans(): MemorySpan[] {\n return [...this.spans];\n }\n\n getCompletedSpans(): MemorySpan[] {\n return this.spans.filter((s) => s.isEnded());\n }\n\n clear(): void {\n this.spans = [];\n this.currentSpan = undefined;\n this.traceId = this.generateTraceId();\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// NOOP TRACING (Disabled)\n// ═══════════════════════════════════════════════════════════════\n\nclass NoopSpan implements ISpan {\n readonly name: string = \"\";\n readonly context: SpanContext = { traceId: \"\", spanId: \"\", traceFlags: 0 };\n readonly isRecording: boolean = false;\n\n setAttribute(): this {\n return this;\n }\n setAttributes(): this {\n return this;\n }\n addEvent(): this {\n return this;\n }\n setStatus(): this {\n return this;\n }\n recordException(): this {\n return this;\n }\n updateName(): this {\n return this;\n }\n end(): void {}\n}\n\nexport class NoopTracing implements ITracing {\n private noopSpan = new NoopSpan();\n\n startSpan(): ISpan {\n return this.noopSpan;\n }\n\n getCurrentSpan(): ISpan | undefined {\n return undefined;\n }\n\n withSpan<T>(_name: string, fn: (span: ISpan) => T): T {\n return fn(this.noopSpan);\n }\n\n async withSpanAsync<T>(\n _name: string,\n fn: (span: ISpan) => Promise<T>,\n ): Promise<T> {\n return fn(this.noopSpan);\n }\n\n instrument<TArgs extends unknown[], TReturn>(\n _name: string,\n fn: (...args: TArgs) => TReturn,\n ): (...args: TArgs) => TReturn {\n return fn;\n }\n\n instrumentAsync<TArgs extends unknown[], TReturn>(\n _name: string,\n fn: (...args: TArgs) => Promise<TReturn>,\n ): (...args: TArgs) => Promise<TReturn> {\n return fn;\n }\n\n extractContext(): SpanContext | undefined {\n return undefined;\n }\n\n injectContext(): void {}\n\n async healthCheck(): Promise<boolean> {\n return true;\n }\n\n async flush(): Promise<void> {}\n\n async close(): Promise<void> {}\n}\n","/**\n * Logger Interface\n * Standardizes logging across the platform\n */\n\n/**\n * Log levels in order of severity\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\n/**\n * Metadata that can be attached to log entries\n */\nexport interface LogMeta {\n /** Error object if logging an error */\n error?: Error;\n /** Duration in milliseconds (for timing operations) */\n duration?: number;\n /** Request ID for tracing */\n requestId?: string;\n /** User ID if applicable */\n userId?: string;\n /** Any additional key-value pairs */\n [key: string]: unknown;\n}\n\n/**\n * A structured log entry\n */\nexport interface LogEntry {\n /** Log level */\n level: LogLevel;\n /** Log message */\n message: string;\n /** When the log was created */\n timestamp: Date;\n /** Optional metadata */\n meta?: LogMeta;\n /** Logger context (e.g., service name) */\n context?: Record<string, unknown>;\n}\n\n/**\n * Logger interface for structured logging\n */\nexport interface ILogger {\n /**\n * Log a debug message (for development/troubleshooting)\n */\n debug(message: string, meta?: LogMeta): void;\n\n /**\n * Log an informational message\n */\n info(message: string, meta?: LogMeta): void;\n\n /**\n * Log a warning message\n */\n warn(message: string, meta?: LogMeta): void;\n\n /**\n * Log an error message\n */\n error(message: string, meta?: LogMeta): void;\n\n /**\n * Create a child logger with additional context\n * @param context Additional context to include in all logs from this child\n */\n child(context: Record<string, unknown>): ILogger;\n}\n\n/**\n * Configuration options for loggers\n */\nexport interface LoggerConfig {\n /** Minimum level to log */\n level?: LogLevel;\n /** Whether to pretty print (for development) */\n pretty?: boolean;\n /** Service name to include in logs */\n service?: string;\n /** Environment name */\n environment?: string;\n}\n\n/**\n * Console logger implementation (for development)\n */\nexport class ConsoleLogger implements ILogger {\n private context: Record<string, unknown>;\n private level: LogLevel;\n\n private static levelPriority: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n };\n\n constructor(config: LoggerConfig = {}) {\n this.context = {\n service: config.service,\n environment: config.environment,\n };\n this.level = config.level || \"info\";\n }\n\n private shouldLog(level: LogLevel): boolean {\n return (\n ConsoleLogger.levelPriority[level] >=\n ConsoleLogger.levelPriority[this.level]\n );\n }\n\n private log(level: LogLevel, message: string, meta?: LogMeta): void {\n if (!this.shouldLog(level)) return;\n\n const entry: LogEntry = {\n level,\n message,\n timestamp: new Date(),\n meta,\n context: this.context,\n };\n\n const prefix = `[${entry.timestamp.toISOString()}] [${level.toUpperCase()}]`;\n const contextStr =\n Object.keys(this.context).length > 0\n ? ` [${Object.entries(this.context)\n .map(([k, v]) => `${k}=${v}`)\n .join(\" \")}]`\n : \"\";\n\n switch (level) {\n case \"debug\":\n console.debug(`${prefix}${contextStr} ${message}`, meta || \"\");\n break;\n case \"info\":\n console.info(`${prefix}${contextStr} ${message}`, meta || \"\");\n break;\n case \"warn\":\n console.warn(`${prefix}${contextStr} ${message}`, meta || \"\");\n break;\n case \"error\":\n console.error(`${prefix}${contextStr} ${message}`, meta || \"\");\n if (meta?.error) {\n console.error(meta.error);\n }\n break;\n }\n }\n\n debug(message: string, meta?: LogMeta): void {\n this.log(\"debug\", message, meta);\n }\n\n info(message: string, meta?: LogMeta): void {\n this.log(\"info\", message, meta);\n }\n\n warn(message: string, meta?: LogMeta): void {\n this.log(\"warn\", message, meta);\n }\n\n error(message: string, meta?: LogMeta): void {\n this.log(\"error\", message, meta);\n }\n\n child(context: Record<string, unknown>): ILogger {\n const childLogger = new ConsoleLogger({ level: this.level });\n childLogger.context = { ...this.context, ...context };\n return childLogger;\n }\n}\n\n/**\n * No-op logger for testing or when logging is disabled\n */\nexport class NoopLogger implements ILogger {\n debug(): void {}\n info(): void {}\n warn(): void {}\n error(): void {}\n child(): ILogger {\n return this;\n }\n}\n","/**\n * Metrics Interface\n *\n * Provides observability through counters, gauges, histograms, and timers.\n */\n\n/**\n * Tags for metrics (key-value pairs for dimensions)\n */\nexport type MetricTags = Record<string, string | number | boolean>;\n\n/**\n * Metrics interface for observability\n */\nexport interface IMetrics {\n /**\n * Increment a counter by a value (default 1)\n *\n * @example\n * metrics.increment('api.requests', 1, { method: 'GET', path: '/users' })\n */\n increment(name: string, value?: number, tags?: MetricTags): void;\n\n /**\n * Decrement a counter by a value (default 1)\n *\n * @example\n * metrics.decrement('active.connections', 1, { server: 'api-1' })\n */\n decrement(name: string, value?: number, tags?: MetricTags): void;\n\n /**\n * Set a gauge to a specific value\n *\n * @example\n * metrics.gauge('queue.size', 42, { queue: 'emails' })\n */\n gauge(name: string, value: number, tags?: MetricTags): void;\n\n /**\n * Record a value in a histogram (for distributions)\n *\n * @example\n * metrics.histogram('response.size', 1024, { endpoint: '/api/users' })\n */\n histogram(name: string, value: number, tags?: MetricTags): void;\n\n /**\n * Record a timing value in milliseconds\n *\n * @example\n * metrics.timing('db.query.duration', 42, { table: 'users' })\n */\n timing(name: string, value: number, tags?: MetricTags): void;\n\n /**\n * Start a timer and return a function to stop it\n *\n * @example\n * const stop = metrics.startTimer('api.request.duration', { method: 'GET' })\n * // ... do work ...\n * stop() // Records the duration\n */\n startTimer(name: string, tags?: MetricTags): () => void;\n\n /**\n * Record a distribution value (similar to histogram but for Datadog)\n *\n * @example\n * metrics.distribution('payment.amount', 99.99, { currency: 'USD' })\n */\n distribution?(name: string, value: number, tags?: MetricTags): void;\n\n /**\n * Record a set value (count unique elements)\n *\n * @example\n * metrics.set('unique.users', 'user-123')\n */\n set?(name: string, value: string | number, tags?: MetricTags): void;\n\n /**\n * Flush all pending metrics to the backend\n */\n flush(): Promise<void>;\n\n /**\n * Close the metrics client\n */\n close(): Promise<void>;\n}\n\n/**\n * Memory-based metrics implementation for testing\n */\nexport class MemoryMetrics implements IMetrics {\n private counters: Map<string, { value: number; tags: MetricTags }[]> =\n new Map();\n private gauges: Map<\n string,\n { value: number; tags: MetricTags; timestamp: number }\n > = new Map();\n private histograms: Map<string, { values: number[]; tags: MetricTags }[]> =\n new Map();\n private timings: Map<string, { values: number[]; tags: MetricTags }[]> =\n new Map();\n private sets: Map<string, Set<string | number>> = new Map();\n\n increment(name: string, value = 1, tags: MetricTags = {}): void {\n const key = this.createKey(name, tags);\n const existing = this.counters.get(key);\n\n if (existing && existing[0]) {\n existing[0].value += value;\n } else {\n this.counters.set(key, [{ value, tags }]);\n }\n }\n\n decrement(name: string, value = 1, tags: MetricTags = {}): void {\n this.increment(name, -value, tags);\n }\n\n gauge(name: string, value: number, tags: MetricTags = {}): void {\n const key = this.createKey(name, tags);\n this.gauges.set(key, { value, tags, timestamp: Date.now() });\n }\n\n histogram(name: string, value: number, tags: MetricTags = {}): void {\n const key = this.createKey(name, tags);\n const existing = this.histograms.get(key);\n\n if (existing && existing[0]) {\n existing[0].values.push(value);\n } else {\n this.histograms.set(key, [{ values: [value], tags }]);\n }\n }\n\n timing(name: string, value: number, tags: MetricTags = {}): void {\n const key = this.createKey(name, tags);\n const existing = this.timings.get(key);\n\n if (existing && existing[0]) {\n existing[0].values.push(value);\n } else {\n this.timings.set(key, [{ values: [value], tags }]);\n }\n }\n\n startTimer(name: string, tags: MetricTags = {}): () => void {\n const start = Date.now();\n return () => {\n const duration = Date.now() - start;\n this.timing(name, duration, tags);\n };\n }\n\n distribution(name: string, value: number, tags: MetricTags = {}): void {\n this.histogram(name, value, tags);\n }\n\n set(name: string, value: string | number, tags: MetricTags = {}): void {\n const key = this.createKey(name, tags);\n let existing = this.sets.get(key);\n\n if (!existing) {\n existing = new Set();\n this.sets.set(key, existing);\n }\n\n existing.add(value);\n }\n\n async flush(): Promise<void> {\n // No-op for memory implementation\n }\n\n async close(): Promise<void> {\n // No-op for memory implementation\n }\n\n // ═══════════════════════════════════════════════════════════════\n // Test helpers\n // ═══════════════════════════════════════════════════════════════\n\n /**\n * Get counter value\n */\n getCounter(name: string, tags: MetricTags = {}): number {\n const key = this.createKey(name, tags);\n const data = this.counters.get(key);\n return data?.[0]?.value ?? 0;\n }\n\n /**\n * Get gauge value\n */\n getGauge(name: string, tags: MetricTags = {}): number | undefined {\n const key = this.createKey(name, tags);\n return this.gauges.get(key)?.value;\n }\n\n /**\n * Get histogram values\n */\n getHistogram(name: string, tags: MetricTags = {}): number[] {\n const key = this.createKey(name, tags);\n return this.histograms.get(key)?.[0]?.values ?? [];\n }\n\n /**\n * Get timing values\n */\n getTiming(name: string, tags: MetricTags = {}): number[] {\n const key = this.createKey(name, tags);\n return this.timings.get(key)?.[0]?.values ?? [];\n }\n\n /**\n * Get set size\n */\n getSetSize(name: string, tags: MetricTags = {}): number {\n const key = this.createKey(name, tags);\n return this.sets.get(key)?.size ?? 0;\n }\n\n /**\n * Get all metrics as a summary\n */\n getSummary(): MetricsSummary {\n const summary: MetricsSummary = {\n counters: {},\n gauges: {},\n histograms: {},\n timings: {},\n sets: {},\n };\n\n for (const [key, data] of this.counters) {\n const first = data[0];\n if (first) {\n summary.counters[key] = first.value;\n }\n }\n\n for (const [key, data] of this.gauges) {\n summary.gauges[key] = data.value;\n }\n\n for (const [key, data] of this.histograms) {\n const first = data[0];\n if (first) {\n const values = first.values;\n summary.histograms[key] = {\n count: values.length,\n sum: values.reduce((a, b) => a + b, 0),\n min: Math.min(...values),\n max: Math.max(...values),\n avg:\n values.length > 0\n ? values.reduce((a, b) => a + b, 0) / values.length\n : 0,\n };\n }\n }\n\n for (const [key, data] of this.timings) {\n const first = data[0];\n if (first) {\n const values = first.values;\n summary.timings[key] = {\n count: values.length,\n sum: values.reduce((a, b) => a + b, 0),\n min: Math.min(...values),\n max: Math.max(...values),\n avg:\n values.length > 0\n ? values.reduce((a, b) => a + b, 0) / values.length\n : 0,\n p50: this.percentile(values, 50),\n p95: this.percentile(values, 95),\n p99: this.percentile(values, 99),\n };\n }\n }\n\n for (const [key, data] of this.sets) {\n summary.sets[key] = data.size;\n }\n\n return summary;\n }\n\n /**\n * Reset all metrics\n */\n reset(): void {\n this.counters.clear();\n this.gauges.clear();\n this.histograms.clear();\n this.timings.clear();\n this.sets.clear();\n }\n\n private createKey(name: string, tags: MetricTags): string {\n const tagStr = Object.entries(tags)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}:${v}`)\n .join(\",\");\n return tagStr ? `${name}|${tagStr}` : name;\n }\n\n private percentile(values: number[], p: number): number {\n if (values.length === 0) return 0;\n\n const sorted = [...values].sort((a, b) => a - b);\n const index = Math.ceil((p / 100) * sorted.length) - 1;\n const safeIndex = Math.max(0, index);\n return sorted[safeIndex] ?? 0;\n }\n}\n\n/**\n * No-op metrics implementation\n */\nexport class NoopMetrics implements IMetrics {\n increment(): void {}\n decrement(): void {}\n gauge(): void {}\n histogram(): void {}\n timing(): void {}\n startTimer(): () => void {\n return () => {};\n }\n distribution(): void {}\n set(): void {}\n async flush(): Promise<void> {}\n async close(): Promise<void> {}\n}\n\n/**\n * Summary of all metrics\n */\nexport interface MetricsSummary {\n counters: Record<string, number>;\n gauges: Record<string, number>;\n histograms: Record<string, HistogramStats>;\n timings: Record<string, TimingStats>;\n sets: Record<string, number>;\n}\n\n/**\n * Histogram statistics\n */\nexport interface HistogramStats {\n count: number;\n sum: number;\n min: number;\n max: number;\n avg: number;\n}\n\n/**\n * Timing statistics\n */\nexport interface TimingStats extends HistogramStats {\n p50: number;\n p95: number;\n p99: number;\n}\n\n/**\n * Create a scoped metrics instance with a prefix\n */\nexport function createScopedMetrics(\n metrics: IMetrics,\n prefix: string,\n defaultTags: MetricTags = {},\n): IMetrics {\n const prefixedName = (name: string) => `${prefix}.${name}`;\n const mergedTags = (tags?: MetricTags) => ({ ...defaultTags, ...tags });\n\n return {\n increment(name, value, tags) {\n metrics.increment(prefixedName(name), value, mergedTags(tags));\n },\n decrement(name, value, tags) {\n metrics.decrement(prefixedName(name), value, mergedTags(tags));\n },\n gauge(name, value, tags) {\n metrics.gauge(prefixedName(name), value, mergedTags(tags));\n },\n histogram(name, value, tags) {\n metrics.histogram(prefixedName(name), value, mergedTags(tags));\n },\n timing(name, value, tags) {\n metrics.timing(prefixedName(name), value, mergedTags(tags));\n },\n startTimer(name, tags) {\n return metrics.startTimer(prefixedName(name), mergedTags(tags));\n },\n distribution(name, value, tags) {\n metrics.distribution?.(prefixedName(name), value, mergedTags(tags));\n },\n set(name, value, tags) {\n metrics.set?.(prefixedName(name), value, mergedTags(tags));\n },\n flush: () => metrics.flush(),\n close: () => metrics.close(),\n };\n}\n","/**\n * Platform Factory\n * Create a platform instance with configured adapters\n */\n\nimport {\n IPlatform,\n PlatformHealthStatus,\n IDatabase,\n ICache,\n IStorage,\n IEmail,\n IQueue,\n ILogger,\n IMetrics,\n ITracing,\n} from \"./interfaces\";\nimport type { IAI, IRAG, ICrypto } from \"./interfaces\";\nimport { PlatformConfig, loadConfig } from \"./config\";\n\n// Memory adapters (always available)\nimport { MemoryDatabase } from \"./adapters/memory/MemoryDatabase\";\nimport { MemoryCache } from \"./adapters/memory/MemoryCache\";\nimport { MemoryStorage } from \"./adapters/memory/MemoryStorage\";\nimport { MemoryEmail } from \"./adapters/memory/MemoryEmail\";\nimport { MemoryQueue } from \"./adapters/memory/MemoryQueue\";\n\n// Console adapters\nimport { ConsoleEmail } from \"./adapters/console/ConsoleEmail\";\n\n// Tracing adapters (always available)\nimport { MemoryTracing, NoopTracing } from \"./interfaces/ITracing\";\n\n// Logger and Metrics (always available)\nimport { ConsoleLogger, NoopLogger } from \"./interfaces/ILogger\";\nimport { MemoryMetrics, NoopMetrics } from \"./interfaces/IMetrics\";\n\n// AI/RAG Memory adapters (always available)\nimport { MemoryAI } from \"./interfaces/IAI\";\nimport { MemoryRAG } from \"./interfaces/IRAG\";\n\n// Crypto adapters\nimport { MemoryCrypto } from \"./adapters/memory/MemoryCrypto\";\n\n/**\n * Create a database adapter based on configuration\n */\nasync function createDatabaseAdapter(\n config: PlatformConfig,\n): Promise<IDatabase> {\n switch (config.database.provider) {\n case \"postgres\": {\n const connectionString =\n config.database.connectionString ||\n config.database.url ||\n process.env.DATABASE_URL;\n if (!connectionString) {\n throw new Error(\n \"PostgreSQL requires DATABASE_URL, url, or connectionString configuration\",\n );\n }\n const { PostgresDatabase } =\n await import(\"./adapters/postgres/PostgresDatabase\");\n return PostgresDatabase.create({\n connectionString,\n max: config.database.poolSize,\n ssl: config.database.ssl,\n connectionTimeoutMillis: config.database.connectionTimeout,\n });\n }\n case \"supabase\": {\n if (!config.database.supabaseUrl || !config.database.supabaseAnonKey) {\n throw new Error(\n \"Supabase requires SUPABASE_URL and SUPABASE_ANON_KEY environment variables\",\n );\n }\n const { createClient } = await import(\"@supabase/supabase-js\");\n const { SupabaseDatabase } =\n await import(\"./adapters/supabase/SupabaseDatabase\");\n const client = createClient(\n config.database.supabaseUrl,\n config.database.supabaseServiceRoleKey ||\n config.database.supabaseAnonKey,\n );\n return new SupabaseDatabase(client);\n }\n case \"memory\":\n default:\n return new MemoryDatabase();\n }\n}\n\n/**\n * Create a cache adapter based on configuration\n */\nasync function createCacheAdapter(config: PlatformConfig): Promise<ICache> {\n switch (config.cache.provider) {\n case \"redis\": {\n const url = config.cache.url || process.env.REDIS_URL;\n if (!url) {\n throw new Error(\"Redis requires REDIS_URL or cache.url configuration\");\n }\n const { RedisCache } = await import(\"./adapters/redis/RedisCache\");\n return RedisCache.create({\n url,\n keyPrefix: config.cache.keyPrefix,\n });\n }\n case \"upstash\": {\n if (!config.cache.upstashUrl || !config.cache.upstashToken) {\n throw new Error(\n \"Upstash requires UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN environment variables\",\n );\n }\n const { Redis } = await import(\"@upstash/redis\");\n const { UpstashCache } = await import(\"./adapters/upstash/UpstashCache\");\n const client = new Redis({\n url: config.cache.upstashUrl,\n token: config.cache.upstashToken,\n });\n return new UpstashCache(client);\n }\n case \"memory\":\n default:\n return new MemoryCache();\n }\n}\n\n/**\n * Create a storage adapter based on configuration\n */\nasync function createStorageAdapter(config: PlatformConfig): Promise<IStorage> {\n switch (config.storage.provider) {\n case \"supabase\": {\n const url = config.database.supabaseUrl || process.env.SUPABASE_URL;\n const apiKey =\n config.database.supabaseServiceRoleKey ||\n config.database.supabaseAnonKey ||\n process.env.SUPABASE_ANON_KEY;\n const bucket =\n config.storage.bucket ||\n process.env.SUPABASE_STORAGE_BUCKET ||\n \"uploads\";\n\n if (!url || !apiKey) {\n throw new Error(\n \"Supabase storage requires SUPABASE_URL and SUPABASE_ANON_KEY\",\n );\n }\n\n const { SupabaseStorage } =\n await import(\"./adapters/supabase-storage/SupabaseStorage\");\n return SupabaseStorage.create({\n url,\n apiKey,\n bucket,\n publicBucket: config.storage.publicUrl !== undefined,\n signedUrlExpiry: config.storage.signedUrlExpiry,\n });\n }\n case \"s3\":\n case \"minio\":\n case \"r2\": {\n if (\n !config.storage.accessKey ||\n !config.storage.secretKey ||\n !config.storage.bucket\n ) {\n throw new Error(\n \"S3 requires S3_ACCESS_KEY, S3_SECRET_KEY, and S3_BUCKET environment variables\",\n );\n }\n const { S3Client } = await import(\"@aws-sdk/client-s3\");\n const { getSignedUrl } = await import(\"@aws-sdk/s3-request-presigner\");\n const { S3Storage } = await import(\"./adapters/s3/S3Storage\");\n\n const client = new S3Client({\n endpoint: config.storage.endpoint,\n region: config.storage.region || \"us-east-1\",\n credentials: {\n accessKeyId: config.storage.accessKey,\n secretAccessKey: config.storage.secretKey,\n },\n forcePathStyle:\n config.storage.forcePathStyle || config.storage.provider === \"minio\",\n });\n\n return new S3Storage(\n client,\n config.storage.bucket,\n getSignedUrl,\n config.storage.publicUrl,\n );\n }\n case \"memory\":\n default:\n return new MemoryStorage();\n }\n}\n\n/**\n * Create an email adapter based on configuration\n */\nasync function createEmailAdapter(config: PlatformConfig): Promise<IEmail> {\n switch (config.email.provider) {\n case \"smtp\": {\n if (!config.email.host || !config.email.port) {\n throw new Error(\n \"SMTP requires host and port configuration (SMTP_HOST, SMTP_PORT)\",\n );\n }\n const { SmtpEmail } = await import(\"./adapters/smtp/SmtpEmail\");\n return SmtpEmail.create({\n host: config.email.host,\n port: config.email.port,\n secure: config.email.secure,\n username: config.email.username,\n password: config.email.password,\n from: config.email.from,\n });\n }\n case \"resend\": {\n if (!config.email.apiKey) {\n throw new Error(\"Resend requires RESEND_API_KEY environment variable\");\n }\n const { Resend } = await import(\"resend\");\n const { ResendEmail } = await import(\"./adapters/resend/ResendEmail\");\n const client = new Resend(config.email.apiKey);\n return new ResendEmail(client, config.email.from);\n }\n case \"console\":\n return new ConsoleEmail();\n case \"memory\":\n default:\n return new MemoryEmail();\n }\n}\n\n/**\n * Create a queue adapter based on configuration\n */\nasync function createQueueAdapter(config: PlatformConfig): Promise<IQueue> {\n switch (config.queue.provider) {\n case \"bullmq\": {\n if (!config.queue.redisUrl && !config.cache.url) {\n throw new Error(\"BullMQ requires REDIS_URL environment variable\");\n }\n const { BullMQQueue } = await import(\"./adapters/bullmq/BullMQQueue\");\n return new BullMQQueue({\n redisUrl: config.queue.redisUrl || config.cache.url,\n queueName: \"platform-jobs\",\n });\n }\n case \"memory\":\n default:\n return new MemoryQueue();\n }\n}\n\n/**\n * Create a tracing adapter based on configuration\n */\nasync function createTracingAdapter(config: PlatformConfig): Promise<ITracing> {\n const tracingConfig = config.observability.tracing;\n\n // If tracing is disabled, return noop\n if (!tracingConfig.enabled) {\n return new NoopTracing();\n }\n\n switch (tracingConfig.provider) {\n case \"otlp\": {\n // OpenTelemetry adapter - dynamically imported\n const { OpenTelemetryTracing } =\n await import(\"./adapters/opentelemetry/OpenTelemetryTracing\");\n return OpenTelemetryTracing.create({\n serviceName: tracingConfig.serviceName || \"unknown-service\",\n serviceVersion: tracingConfig.serviceVersion,\n environment: tracingConfig.environment,\n endpoint: tracingConfig.endpoint,\n exporterType: tracingConfig.exporterType,\n sampleRate: tracingConfig.sampleRate,\n });\n }\n case \"memory\":\n return new MemoryTracing();\n case \"noop\":\n default:\n return new NoopTracing();\n }\n}\n\n/**\n * Create a logger based on configuration\n */\nfunction createLogger(config: PlatformConfig): ILogger {\n if (!config.observability.logging) {\n return new NoopLogger();\n }\n\n return new ConsoleLogger({\n level: config.observability.logging.level,\n service: config.observability.tracing.serviceName,\n environment: config.observability.tracing.environment,\n });\n}\n\n/**\n * Create a metrics collector based on configuration\n */\nfunction createMetrics(config: PlatformConfig): IMetrics {\n if (!config.observability.metrics.enabled) {\n return new NoopMetrics();\n }\n\n // MemoryMetrics is a simple in-memory implementation\n // Production metrics would use a dedicated backend (Prometheus, StatsD, etc.)\n return new MemoryMetrics();\n}\n\n/**\n * Create an AI adapter based on configuration\n */\nasync function createAIAdapter(config: PlatformConfig): Promise<IAI | null> {\n if (!config.ai.enabled) {\n return null;\n }\n\n switch (config.ai.provider) {\n case \"openai\": {\n if (!config.ai.apiKey) {\n throw new Error(\"OpenAI requires OPENAI_API_KEY environment variable\");\n }\n const { OpenAIAdapter } = await import(\"./adapters/openai/OpenAIAdapter\");\n return new OpenAIAdapter({\n apiKey: config.ai.apiKey,\n defaultChatModel: config.ai.model || \"gpt-4o\",\n defaultTimeoutMs: config.ai.timeout,\n baseURL: config.ai.baseUrl,\n });\n }\n case \"anthropic\": {\n if (!config.ai.apiKey) {\n throw new Error(\n \"Anthropic requires ANTHROPIC_API_KEY environment variable\",\n );\n }\n const { AnthropicAdapter } =\n await import(\"./adapters/anthropic/AnthropicAdapter\");\n return new AnthropicAdapter({\n apiKey: config.ai.apiKey,\n defaultChatModel: config.ai.model || \"claude-sonnet-4-20250514\",\n defaultTimeoutMs: config.ai.timeout,\n baseURL: config.ai.baseUrl,\n });\n }\n case \"google\": {\n if (!config.ai.apiKey) {\n throw new Error(\n \"Google AI requires GOOGLE_AI_API_KEY environment variable\",\n );\n }\n const { GoogleAIAdapter } =\n await import(\"./adapters/google/GoogleAIAdapter\");\n return new GoogleAIAdapter({\n apiKey: config.ai.apiKey,\n defaultChatModel: config.ai.model || \"gemini-1.5-pro\",\n defaultTimeoutMs: config.ai.timeout,\n });\n }\n case \"memory\":\n default:\n return new MemoryAI();\n }\n}\n\n/**\n * Create a RAG adapter based on configuration\n */\nasync function createRAGAdapter(\n config: PlatformConfig,\n ai?: IAI | null,\n): Promise<IRAG | null> {\n if (!config.rag.enabled) {\n return null;\n }\n\n switch (config.rag.provider) {\n case \"pinecone\": {\n if (!config.rag.apiKey || !config.rag.indexName) {\n throw new Error(\n \"Pinecone requires PINECONE_API_KEY and PINECONE_INDEX environment variables\",\n );\n }\n if (!ai) {\n throw new Error(\n \"Pinecone RAG requires an AI adapter for embeddings. Enable AI with AI_ENABLED=true\",\n );\n }\n const { createPineconeRAG } =\n await import(\"./adapters/pinecone/PineconeRAG\");\n return createPineconeRAG({\n apiKey: config.rag.apiKey,\n indexName: config.rag.indexName,\n defaultNamespace: config.rag.namespace,\n ai,\n });\n }\n case \"weaviate\": {\n if (!config.rag.host) {\n throw new Error(\"Weaviate requires WEAVIATE_HOST environment variable\");\n }\n const { createWeaviateRAG } =\n await import(\"./adapters/weaviate/WeaviateRAG\");\n return createWeaviateRAG({\n host: config.rag.host,\n apiKey: config.rag.apiKey,\n ai: ai || undefined,\n });\n }\n case \"memory\":\n default:\n return new MemoryRAG();\n }\n}\n\n/**\n * Create a crypto adapter based on configuration\n */\nasync function createCryptoAdapter(\n config: PlatformConfig,\n): Promise<ICrypto | null> {\n if (!config.crypto.enabled) {\n return null;\n }\n\n if (config.crypto.masterKey && config.crypto.masterKey.length >= 64) {\n const { NodeCrypto } = await import(\"./adapters/node-crypto/NodeCrypto\");\n return new NodeCrypto({\n masterKey: config.crypto.masterKey,\n hmacKey: config.crypto.hmacKey,\n });\n }\n\n // Fallback to memory adapter (testing/development)\n return new MemoryCrypto();\n}\n\n/**\n * Validate TLS configuration for production environments\n */\nfunction validateTlsSecurity(config: PlatformConfig): void {\n const isProduction = process.env.NODE_ENV === \"production\";\n if (!isProduction || !config.security.enforceTls) {\n return;\n }\n\n const warnings: string[] = [];\n\n // Check PostgreSQL SSL\n if (config.database.provider === \"postgres\") {\n const connStr =\n config.database.connectionString || config.database.url || \"\";\n const hasSSL =\n config.database.ssl ||\n connStr.includes(\"sslmode=require\") ||\n connStr.includes(\"sslmode=verify\");\n if (!hasSSL) {\n warnings.push(\n \"PostgreSQL: TLS/SSL not configured. Set database.ssl=true or add sslmode=require to connection string.\",\n );\n }\n }\n\n // Check Redis TLS\n if (config.cache.provider === \"redis\") {\n const url = config.cache.url || \"\";\n if (url && !url.startsWith(\"rediss://\")) {\n warnings.push(\n \"Redis: Connection URL uses redis:// instead of rediss:// (TLS). Consider enabling TLS.\",\n );\n }\n }\n\n // Check SMTP TLS\n if (config.email.provider === \"smtp\") {\n if (!config.email.secure) {\n warnings.push(\n \"SMTP: secure=false in production. Set email.secure=true for TLS.\",\n );\n }\n }\n\n if (warnings.length > 0) {\n const message = `[Security] TLS warnings in production:\\n - ${warnings.join(\"\\n - \")}`;\n if (config.security.tlsWarnOnly) {\n console.warn(message);\n } else {\n throw new Error(message);\n }\n }\n}\n\n/**\n * Create a platform instance (async version)\n */\nexport async function createPlatformAsync(\n config?: Partial<PlatformConfig>,\n): Promise<IPlatform> {\n const finalConfig = config ? deepMerge(loadConfig(), config) : loadConfig();\n\n // Validate TLS configuration for production\n validateTlsSecurity(finalConfig);\n\n const [db, cache, storage, email, queue, tracing, crypto] = await Promise.all(\n [\n createDatabaseAdapter(finalConfig),\n createCacheAdapter(finalConfig),\n createStorageAdapter(finalConfig),\n createEmailAdapter(finalConfig),\n createQueueAdapter(finalConfig),\n createTracingAdapter(finalConfig),\n createCryptoAdapter(finalConfig),\n ],\n );\n\n const logger = createLogger(finalConfig);\n const metrics = createMetrics(finalConfig);\n\n // Create AI adapter first (RAG may depend on it for embeddings)\n const ai = await createAIAdapter(finalConfig);\n const rag = await createRAGAdapter(finalConfig, ai);\n\n return createPlatformFromAdapters(\n db,\n cache,\n storage,\n email,\n queue,\n logger,\n metrics,\n tracing,\n ai,\n rag,\n crypto,\n );\n}\n\n/**\n * Create a platform instance (sync version - uses memory adapters only)\n * For production adapters, use createPlatformAsync\n */\nexport function createPlatform(config?: Partial<PlatformConfig>): IPlatform {\n const finalConfig = config ? deepMerge(loadConfig(), config) : loadConfig();\n\n // Check if any production adapters are requested\n const hasProductionAdapters =\n finalConfig.database.provider !== \"memory\" ||\n finalConfig.cache.provider !== \"memory\" ||\n finalConfig.storage.provider !== \"memory\" ||\n (finalConfig.email.provider !== \"memory\" &&\n finalConfig.email.provider !== \"console\") ||\n finalConfig.observability.tracing.provider === \"otlp\" ||\n (finalConfig.ai.enabled && finalConfig.ai.provider !== \"memory\") ||\n (finalConfig.rag.enabled && finalConfig.rag.provider !== \"memory\");\n\n if (hasProductionAdapters) {\n console.warn(\n \"createPlatform() is synchronous and cannot initialize production adapters. \" +\n \"Use createPlatformAsync() for production adapters, or use memory/console adapters.\",\n );\n }\n\n // Create sync-compatible adapters\n const db = new MemoryDatabase();\n const cache = new MemoryCache();\n const storage = new MemoryStorage();\n const email =\n finalConfig.email.provider === \"console\"\n ? new ConsoleEmail()\n : new MemoryEmail();\n const queue = new MemoryQueue();\n const logger = createLogger(finalConfig);\n const metrics = createMetrics(finalConfig);\n const tracing =\n finalConfig.observability.tracing.provider === \"memory\"\n ? new MemoryTracing()\n : new NoopTracing();\n\n // Create memory AI/RAG if enabled\n const ai = finalConfig.ai.enabled ? new MemoryAI() : null;\n const rag = finalConfig.rag.enabled ? new MemoryRAG() : null;\n const crypto = finalConfig.crypto.enabled ? new MemoryCrypto() : null;\n\n return createPlatformFromAdapters(\n db,\n cache,\n storage,\n email,\n queue,\n logger,\n metrics,\n tracing,\n ai,\n rag,\n crypto,\n );\n}\n\n/**\n * Create platform object from adapters\n */\nfunction createPlatformFromAdapters(\n db: IDatabase,\n cache: ICache,\n storage: IStorage,\n email: IEmail,\n queue: IQueue,\n logger: ILogger,\n metrics: IMetrics,\n tracing: ITracing,\n ai?: IAI | null,\n rag?: IRAG | null,\n crypto?: ICrypto | null,\n): IPlatform {\n const platform: IPlatform = {\n db,\n cache,\n storage,\n email,\n queue,\n logger,\n metrics,\n tracing,\n\n async healthCheck(): Promise<PlatformHealthStatus> {\n const [\n dbHealth,\n cacheHealth,\n storageHealth,\n emailHealth,\n queueHealth,\n tracingHealth,\n ] = await Promise.all([\n db.healthCheck(),\n cache.healthCheck(),\n storage.healthCheck(),\n email.healthCheck(),\n queue.healthCheck(),\n tracing.healthCheck(),\n ]);\n\n return {\n healthy:\n dbHealth &&\n cacheHealth &&\n storageHealth &&\n emailHealth &&\n queueHealth &&\n tracingHealth,\n services: {\n database: dbHealth,\n cache: cacheHealth,\n storage: storageHealth,\n email: emailHealth,\n queue: queueHealth,\n tracing: tracingHealth,\n },\n timestamp: Date.now(),\n };\n },\n\n async close(): Promise<void> {\n await Promise.all([\n db.close(),\n cache.close(),\n queue.close(),\n tracing.close(),\n ]);\n },\n };\n\n // Add optional AI adapter\n if (ai) {\n (platform as IPlatform & { ai: IAI }).ai = ai;\n }\n\n // Add optional RAG adapter\n if (rag) {\n (platform as IPlatform & { rag: IRAG }).rag = rag;\n }\n\n // Add optional Crypto adapter\n if (crypto) {\n (platform as IPlatform & { crypto: ICrypto }).crypto = crypto;\n }\n\n return platform;\n}\n\n/**\n * Deep merge two objects\n */\nfunction deepMerge<T extends Record<string, unknown>>(\n target: T,\n source: Partial<T>,\n): T {\n const result = { ...target };\n\n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (\n sourceValue !== undefined &&\n typeof sourceValue === \"object\" &&\n sourceValue !== null &&\n !Array.isArray(sourceValue) &&\n typeof targetValue === \"object\" &&\n targetValue !== null &&\n !Array.isArray(targetValue)\n ) {\n result[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>,\n ) as T[Extract<keyof T, string>];\n } else if (sourceValue !== undefined) {\n result[key] = sourceValue as T[Extract<keyof T, string>];\n }\n }\n }\n\n return result;\n}\n","/**\n * MemoryCrypto - In-memory ICrypto adapter for testing\n * Uses Node.js built-in crypto module with keys stored in memory.\n */\n\nimport {\n randomBytes,\n createCipheriv,\n createDecipheriv,\n createHmac,\n} from \"crypto\";\nimport type {\n ICrypto,\n EncryptedField,\n DeterministicEncryptedField,\n CryptoKeyMetadata,\n CryptoKeyStatus,\n EncryptOptions,\n KeyRotationResult,\n} from \"../../interfaces/ICrypto\";\n\ninterface StoredKey {\n id: string;\n key: Buffer;\n status: CryptoKeyStatus;\n createdAt: Date;\n}\n\nexport class MemoryCrypto implements ICrypto {\n private keys: Map<string, StoredKey> = new Map();\n private activeKeyId: string;\n private hmacKey: Buffer;\n\n constructor(options?: { masterKey?: string; hmacKey?: string }) {\n // Derive or generate keys\n const masterKeyBuf = options?.masterKey\n ? Buffer.from(options.masterKey, \"hex\")\n : randomBytes(32);\n this.hmacKey = options?.hmacKey\n ? Buffer.from(options.hmacKey, \"hex\")\n : randomBytes(32);\n\n // Create initial DEK\n const keyId = this.generateKeyId();\n this.keys.set(keyId, {\n id: keyId,\n key: masterKeyBuf,\n status: \"active\",\n createdAt: new Date(),\n });\n this.activeKeyId = keyId;\n }\n\n async encrypt(\n plaintext: string,\n options?: EncryptOptions,\n ): Promise<EncryptedField> {\n const keyId = options?.keyId || this.activeKeyId;\n const stored = this.keys.get(keyId);\n if (!stored) {\n throw new Error(`Key not found: ${keyId}`);\n }\n if (stored.status === \"retired\") {\n throw new Error(`Key is retired: ${keyId}`);\n }\n if (stored.status === \"decrypt-only\" && !options?.keyId) {\n throw new Error(`Key is decrypt-only: ${keyId}`);\n }\n\n const iv = randomBytes(12); // 96-bit IV for GCM\n const cipher = createCipheriv(\"aes-256-gcm\", stored.key, iv);\n\n if (options?.aad) {\n cipher.setAAD(Buffer.from(options.aad, \"utf8\"));\n }\n\n const encrypted = Buffer.concat([\n cipher.update(plaintext, \"utf8\"),\n cipher.final(),\n ]);\n const tag = cipher.getAuthTag();\n\n return {\n ciphertext: encrypted.toString(\"base64\"),\n iv: iv.toString(\"base64\"),\n tag: tag.toString(\"base64\"),\n keyId,\n algorithm: \"aes-256-gcm\",\n version: 1,\n };\n }\n\n async decrypt(\n field: EncryptedField,\n options?: EncryptOptions,\n ): Promise<string> {\n const stored = this.keys.get(field.keyId);\n if (!stored) {\n throw new Error(`Key not found: ${field.keyId}`);\n }\n if (stored.status === \"retired\") {\n throw new Error(`Key is retired and cannot decrypt: ${field.keyId}`);\n }\n\n const decipher = createDecipheriv(\n \"aes-256-gcm\",\n stored.key,\n Buffer.from(field.iv, \"base64\"),\n );\n decipher.setAuthTag(Buffer.from(field.tag, \"base64\"));\n\n if (options?.aad) {\n decipher.setAAD(Buffer.from(options.aad, \"utf8\"));\n }\n\n const decrypted = Buffer.concat([\n decipher.update(Buffer.from(field.ciphertext, \"base64\")),\n decipher.final(),\n ]);\n\n return decrypted.toString(\"utf8\");\n }\n\n async encryptDeterministic(\n plaintext: string,\n options?: EncryptOptions,\n ): Promise<DeterministicEncryptedField> {\n const hash = await this.computeHash(plaintext);\n const encrypted = await this.encrypt(plaintext, options);\n return { hash, encrypted };\n }\n\n async computeHash(plaintext: string): Promise<string> {\n return createHmac(\"sha256\", this.hmacKey)\n .update(plaintext, \"utf8\")\n .digest(\"hex\");\n }\n\n async encryptBatch(\n fields: Record<string, string>,\n options?: EncryptOptions,\n ): Promise<Record<string, EncryptedField>> {\n const result: Record<string, EncryptedField> = {};\n for (const [key, value] of Object.entries(fields)) {\n result[key] = await this.encrypt(value, options);\n }\n return result;\n }\n\n async decryptBatch(\n fields: Record<string, EncryptedField>,\n options?: EncryptOptions,\n ): Promise<Record<string, string>> {\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(fields)) {\n result[key] = await this.decrypt(value, options);\n }\n return result;\n }\n\n async rotateKey(): Promise<KeyRotationResult> {\n const previousKeyId = this.activeKeyId;\n\n // Mark current key as decrypt-only\n const currentKey = this.keys.get(previousKeyId);\n if (currentKey) {\n currentKey.status = \"decrypt-only\";\n }\n\n // Generate new active key\n const newKeyId = this.generateKeyId();\n this.keys.set(newKeyId, {\n id: newKeyId,\n key: randomBytes(32),\n status: \"active\",\n createdAt: new Date(),\n });\n this.activeKeyId = newKeyId;\n\n return { newKeyId, previousKeyId };\n }\n\n async reEncrypt(\n field: EncryptedField,\n options?: EncryptOptions,\n ): Promise<EncryptedField> {\n const plaintext = await this.decrypt(field);\n return this.encrypt(plaintext, options);\n }\n\n async listKeys(): Promise<CryptoKeyMetadata[]> {\n return Array.from(this.keys.values()).map((k) => ({\n keyId: k.id,\n createdAt: k.createdAt,\n status: k.status,\n }));\n }\n\n async getActiveKeyId(): Promise<string> {\n return this.activeKeyId;\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n const testPlain = \"health-check-test\";\n const encrypted = await this.encrypt(testPlain);\n const decrypted = await this.decrypt(encrypted);\n return decrypted === testPlain;\n } catch {\n return false;\n }\n }\n\n private generateKeyId(): string {\n return `key_${randomBytes(8).toString(\"hex\")}`;\n }\n}\n"],"mappings":"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","names":["import_crypto","import_crypto","import_crypto","import_crypto","import_crypto","import_crypto","crypto"]}